riversong code showcase
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using Random = Unity.Mathematics.Random;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
[BurstCompile]
|
||||
public struct GenerateGrassChunkJob<T> : IJobParallelFor where T : unmanaged, IGrassTileMask
|
||||
{
|
||||
public int2 WorldSize;
|
||||
|
||||
[ReadOnly]
|
||||
public NativeArray<int2> ChunkCoordsArray;
|
||||
|
||||
public int ChunkSize;
|
||||
|
||||
[ReadOnly]
|
||||
public T Mask;
|
||||
|
||||
[ReadOnly]
|
||||
public NativeArray<int> Heightmap;
|
||||
|
||||
[NativeDisableParallelForRestriction]
|
||||
public Mesh.MeshDataArray MeshDataArray;
|
||||
|
||||
public NativeArray<Random> RandomArray;
|
||||
|
||||
public int Density;
|
||||
|
||||
public float NoiseScale;
|
||||
|
||||
public float DiscardThreshold;
|
||||
|
||||
public float BladeWidth;
|
||||
|
||||
public float2 BladeHeightRange;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
var chunkCoords = ChunkCoordsArray[index];
|
||||
var random = RandomArray[index];
|
||||
|
||||
var vertexAttributes = new NativeArray<VertexAttributeDescriptor>(3, Allocator.Temp);
|
||||
vertexAttributes[0] = new VertexAttributeDescriptor(VertexAttribute.Position);
|
||||
vertexAttributes[1] = new VertexAttributeDescriptor(VertexAttribute.Color);
|
||||
vertexAttributes[2] = new VertexAttributeDescriptor(VertexAttribute.TexCoord0, dimension: 2);
|
||||
|
||||
var triangleCount = ChunkSize * ChunkSize * Density * Density;
|
||||
var vertexTemp = new NativeList<Vertex>(3 * triangleCount, Allocator.Temp);
|
||||
var indexTemp = new NativeList<int>(3 * triangleCount, Allocator.Temp);
|
||||
|
||||
var tileMin = chunkCoords * ChunkSize;
|
||||
var tileMax = math.min(tileMin + ChunkSize, WorldSize);
|
||||
var tile = int2.zero;
|
||||
|
||||
var spacing = 1f / Density;
|
||||
|
||||
var triangle = 0;
|
||||
for (tile.y = tileMin.y; tile.y < tileMax.y; tile.y++)
|
||||
for (tile.x = tileMin.x; tile.x < tileMax.x; tile.x++)
|
||||
{
|
||||
var tileIndex = math.mad(tile.y, WorldSize.x, tile.x);
|
||||
|
||||
if (!Mask.CanGenerateAtTile(tileIndex)) continue;
|
||||
|
||||
var worldY = Heightmap[tileIndex];
|
||||
|
||||
for (var stepZ = 0; stepZ < Density; stepZ++)
|
||||
{
|
||||
var worldZ = math.mad(0.5f + stepZ, spacing, tile.y);
|
||||
|
||||
for (var stepX = 0; stepX < Density; stepX++)
|
||||
{
|
||||
var worldX = math.mad(0.5f + stepX, spacing, tile.x);
|
||||
|
||||
var bladeOrigin = new float3(worldX, worldY, worldZ);
|
||||
bladeOrigin += 0.25f * spacing * new float3(random.NextFloat(-1, 1), 0, random.NextFloat(-1, 1));
|
||||
|
||||
const float edgeDistance = 0.3f;
|
||||
var d = math.frac(bladeOrigin.xz);
|
||||
if ((d.x < edgeDistance && (tile.x == 0 || Heightmap[tileIndex - 1] != worldY)) ||
|
||||
(d.x > 1 - edgeDistance && (tile.x == WorldSize.x - 1 || Heightmap[tileIndex + 1] != worldY)) ||
|
||||
(d.y < edgeDistance && (tile.y == 0 || Heightmap[tileIndex - WorldSize.x] != worldY)) ||
|
||||
(d.y > 1 - edgeDistance && (tile.y == WorldSize.y - 1 || Heightmap[tileIndex + WorldSize.x] != worldY)) ||
|
||||
(d is { x: < edgeDistance, y: < edgeDistance } && Heightmap[tileIndex - 1 - WorldSize.x] != worldY) ||
|
||||
(d is { x: > 1 - edgeDistance, y: < edgeDistance } && Heightmap[tileIndex + 1 - WorldSize.x] != worldY) ||
|
||||
(d is { x: < edgeDistance, y: > 1 - edgeDistance } && Heightmap[tileIndex - 1 + WorldSize.x] != worldY) ||
|
||||
(d is { x: > 1 - edgeDistance, y: > 1 - edgeDistance } && Heightmap[tileIndex + 1 + WorldSize.x] != worldY))
|
||||
continue;
|
||||
|
||||
var n = noise.snoise(NoiseScale * bladeOrigin);
|
||||
n = math.remap(-1, 1, 0, 1, n);
|
||||
if (n < DiscardThreshold) continue;
|
||||
|
||||
var rotation = quaternion.Euler(0, random.NextFloat(math.PI2), 0);
|
||||
var halfBladeWidth = 0.5f * BladeWidth;
|
||||
var bladeHeight = math.lerp(BladeHeightRange.x, BladeHeightRange.y, n);
|
||||
|
||||
var side = math.mul(rotation, new float3(halfBladeWidth, 0, 0));
|
||||
var v0 = bladeOrigin - side;
|
||||
var v1 = bladeOrigin + bladeHeight * math.up();
|
||||
var v2 = bladeOrigin + side;
|
||||
|
||||
vertexTemp.AddNoResize(new Vertex(v0, bladeOrigin, new float2(0, bladeHeight)));
|
||||
vertexTemp.AddNoResize(new Vertex(v1, bladeOrigin, new float2(bladeHeight, bladeHeight)));
|
||||
vertexTemp.AddNoResize(new Vertex(v2, bladeOrigin, new float2(0, bladeHeight)));
|
||||
|
||||
indexTemp.AddNoResize(triangle);
|
||||
indexTemp.AddNoResize(triangle + 1);
|
||||
indexTemp.AddNoResize(triangle + 2);
|
||||
triangle += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var mesh = MeshDataArray[index];
|
||||
|
||||
mesh.SetVertexBufferParams(vertexTemp.Length, vertexAttributes);
|
||||
|
||||
var chunkVertexData = mesh.GetVertexData<Vertex>();
|
||||
chunkVertexData.CopyFrom(vertexTemp.AsArray());
|
||||
|
||||
mesh.SetIndexBufferParams(indexTemp.Length, IndexFormat.UInt32);
|
||||
var chunkIndexData = mesh.GetIndexData<int>();
|
||||
chunkIndexData.CopyFrom(indexTemp.AsArray());
|
||||
|
||||
mesh.subMeshCount = 1;
|
||||
mesh.SetSubMesh(0, new SubMeshDescriptor(0, indexTemp.Length));
|
||||
}
|
||||
|
||||
private struct Vertex
|
||||
{
|
||||
public float3 Position;
|
||||
|
||||
public float3 Color;
|
||||
|
||||
public float2 TexCoord0;
|
||||
|
||||
public Vertex(float3 position, float3 color, float2 texCoord0)
|
||||
{
|
||||
Position = position;
|
||||
Color = color;
|
||||
TexCoord0 = texCoord0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user