private static VertexNormal interpolateVerts(float isoLevel, NoiseVal v1, NoiseVal v2) { float t = (isoLevel - v1.Noise) / (v2.Noise - v1.Noise); float3 normal = math.lerp(v1.Grad, v2.Grad, t); return(new VertexNormal { position = v1.Pos + t * (v2.Pos - v1.Pos), normal = -normal }); }
protected override JobHandle OnUpdate(JobHandle inputDeps) { EntityCommandBuffer.ParallelWriter commandBufferPR = EndSimulationCBS.CreateCommandBuffer().AsParallelWriter(); NativeArray <int> Triangles = this.Triangles; NativeArray <int> CornerIndexAFromEdge = this.CornerIndexAFromEdge; NativeArray <int> CornerIndexBFromEdge = this.CornerIndexBFromEdge; //, ref DynamicBuffer<Normals> normalsBuf, ref DynamicBuffer<Index> trianglesBuf JobHandle job = Entities.WithAll <BuffersPresentTag>().WithNone <NoiseBufferTag>().ForEach((Entity thisEntity, int entityInQueryIndex, ref NoiseOrderComponent noiseOrder , ref DynamicBuffer <Vertices> verticesBuf, ref DynamicBuffer <Normals> normalsBuf, ref DynamicBuffer <Index> trianglesBuf) => { commandBufferPR.AddComponent(entityInQueryIndex, thisEntity, new NoiseBufferTag()); DynamicBuffer <float3> vertices = verticesBuf.Reinterpret <float3>(); DynamicBuffer <float3> normals = normalsBuf.Reinterpret <float3>(); DynamicBuffer <int> triangles = trianglesBuf.Reinterpret <int>(); float3 sampleDist = noiseOrder.size / noiseOrder.sampleCount; int3 samples = (int3)(noiseOrder.size / sampleDist) + 1; int numOfSamples = samples.x * samples.y * samples.z; NativeArray <NoiseVal> noiseValues = new NativeArray <NoiseVal>(numOfSamples, Allocator.Temp, NativeArrayOptions.UninitializedMemory); float3 maxPoint = noiseOrder.minPoint + noiseOrder.size; for (int3 iter = default; iter.z < samples.z; iter.z++) { for (iter.y = 0; iter.y < samples.y; iter.y++) { for (iter.x = 0; iter.x < samples.x; iter.x++) { int index = GetIndex(samples, iter); float3 pos = noiseOrder.minPoint + iter * sampleDist; float4 noise = Noise.snoise_grad(pos * noiseOrder.noiseFactor); noiseValues[index] = new NoiseVal(pos, noise);// new float4(pos, (noise.w+1f)*0.5f); } } } NativeHashMap <float3, int> newLayerPosIdDict = new NativeHashMap <float3, int>(noiseOrder.sampleCount.x * noiseOrder.sampleCount.y * 2, Allocator.Temp); NativeHashMap <float3, int> oldLayerPosIdDict = new NativeHashMap <float3, int>(noiseOrder.sampleCount.x * noiseOrder.sampleCount.y * 2, Allocator.Temp); for (int3 id = default; id.z < samples.z - 1; id.z++) { NativeHashMap <float3, int> temp = oldLayerPosIdDict; oldLayerPosIdDict = newLayerPosIdDict; newLayerPosIdDict = temp; newLayerPosIdDict.Clear(); for (id.y = 0; id.y < samples.y - 1; id.y++) { for (id.x = 0; id.x < samples.x - 1; id.x++) { // 8 corners of the current cube NativeArray <NoiseVal> cubeCorners = new NativeArray <NoiseVal>(8, Allocator.Temp, NativeArrayOptions.UninitializedMemory); cubeCorners[0] = noiseValues[GetIndex(samples, new int3(id.x, id.y, id.z))]; cubeCorners[1] = noiseValues[GetIndex(samples, new int3(id.x + 1, id.y, id.z))]; cubeCorners[2] = noiseValues[GetIndex(samples, new int3(id.x + 1, id.y, id.z + 1))]; cubeCorners[3] = noiseValues[GetIndex(samples, new int3(id.x, id.y, id.z + 1))]; cubeCorners[4] = noiseValues[GetIndex(samples, new int3(id.x, id.y + 1, id.z))]; cubeCorners[5] = noiseValues[GetIndex(samples, new int3(id.x + 1, id.y + 1, id.z))]; cubeCorners[6] = noiseValues[GetIndex(samples, new int3(id.x + 1, id.y + 1, id.z + 1))]; cubeCorners[7] = noiseValues[GetIndex(samples, new int3(id.x, id.y + 1, id.z + 1))]; float3 topPoint = noiseValues[GetIndex(samples, new int3(id.x + 1, id.y + 1, id.z + 1))].Pos; // Calculate unique index for each cube configuration. // There are 256 possible values // A value of 0 means cube is entirely inside surface; 255 entirely outside. // The value is used to look up the edge table, which indicates which edges of the cube are cut by the isosurface. int cubeIndex = 0; if (cubeCorners[0].Noise < noiseOrder.isoSurfaceLevel) { cubeIndex |= 1; } if (cubeCorners[1].Noise < noiseOrder.isoSurfaceLevel) { cubeIndex |= 2; } if (cubeCorners[2].Noise < noiseOrder.isoSurfaceLevel) { cubeIndex |= 4; } if (cubeCorners[3].Noise < noiseOrder.isoSurfaceLevel) { cubeIndex |= 8; } if (cubeCorners[4].Noise < noiseOrder.isoSurfaceLevel) { cubeIndex |= 16; } if (cubeCorners[5].Noise < noiseOrder.isoSurfaceLevel) { cubeIndex |= 32; } if (cubeCorners[6].Noise < noiseOrder.isoSurfaceLevel) { cubeIndex |= 64; } if (cubeCorners[7].Noise < noiseOrder.isoSurfaceLevel) { cubeIndex |= 128; } // Create triangles for current cube configuration for (int i = 0; Triangles[16 * cubeIndex + i] != -1; i += 3) { // Get indices of corner points A and B for each of the three edges // of the cube that need to be joined to form the triangle. int a0 = CornerIndexAFromEdge[Triangles[16 * cubeIndex + i]]; int b0 = CornerIndexBFromEdge[Triangles[16 * cubeIndex + i]]; int a1 = CornerIndexAFromEdge[Triangles[16 * cubeIndex + i + 1]]; int b1 = CornerIndexBFromEdge[Triangles[16 * cubeIndex + i + 1]]; int a2 = CornerIndexAFromEdge[Triangles[16 * cubeIndex + i + 2]]; int b2 = CornerIndexBFromEdge[Triangles[16 * cubeIndex + i + 2]]; VertexNormal vertexA = interpolateVerts(noiseOrder.isoSurfaceLevel, cubeCorners[a0], cubeCorners[b0]); VertexNormal vertexB = interpolateVerts(noiseOrder.isoSurfaceLevel, cubeCorners[a1], cubeCorners[b1]); VertexNormal vertexC = interpolateVerts(noiseOrder.isoSurfaceLevel, cubeCorners[a2], cubeCorners[b2]); int len = vertices.Length; int vertCId = GetVertId(ref vertices, ref normals, oldLayerPosIdDict, newLayerPosIdDict, vertexC, topPoint, ref len); int vertBId = GetVertId(ref vertices, ref normals, oldLayerPosIdDict, newLayerPosIdDict, vertexB, topPoint, ref len); int vertAId = GetVertId(ref vertices, ref normals, oldLayerPosIdDict, newLayerPosIdDict, vertexA, topPoint, ref len); //vertices.Add(vertexC.position); //vertices.Add(vertexB.position); //vertices.Add(vertexA.position); //normals.Add(vertexC.normal); //normals.Add(vertexB.normal); //normals.Add(vertexA.normal); triangles.Add(vertCId); triangles.Add(vertBId); triangles.Add(vertAId); } } } } }).Schedule(inputDeps); EndSimulationCBS.AddJobHandleForProducer(job); return(job); }
static public GameObject CreateChunkGameObject(SpawnChunkData chunk) { GameObject gameObject = new GameObject("meshGO", typeof(MeshFilter), typeof(MeshRenderer)); float3 sampleDist = chunk.size / chunk.sampleCount; int3 samples = (int3)(chunk.size / sampleDist) + 1; int numOfSamples = samples.x * samples.y * samples.z; NoiseVal[] noiseValues = new NoiseVal[numOfSamples]; float3 maxPoint = chunk.minPoint + chunk.size; List <Vector3> vertices = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); List <int> triangles = new List <int>(); float startTime = Time.realtimeSinceStartup * 1000; for (int3 iter = default; iter.z < samples.z; iter.z++) { for (iter.y = 0; iter.y < samples.y; iter.y++) { for (iter.x = 0; iter.x < samples.x; iter.x++) { int index = GetIndex(samples, iter); float3 pos = chunk.minPoint + iter * sampleDist; float4 noise = Noise.snoise_grad(pos * chunk.noiseFactor); noiseValues[index] = new NoiseVal(pos, noise);// new float4(pos, (noise.w+1f)*0.5f); } } } float timeAfterNoise = Time.realtimeSinceStartup * 1000; // float4[] oldPoints = new float4[8]; Dictionary <float3, int> newLayerPosIdDict = new Dictionary <float3, int>(); for (int3 id = default; id.z < samples.z - 1; id.z++) { Dictionary <float3, int> oldLayerPosIdDict = newLayerPosIdDict; newLayerPosIdDict = new Dictionary <float3, int>(); for (id.y = 0; id.y < samples.y - 1; id.y++) { for (id.x = 0; id.x < samples.x - 1; id.x++) { // 8 corners of the current cube NoiseVal[] cubeCorners = { noiseValues[GetIndex(samples, new int3(id.x, id.y, id.z))], noiseValues[GetIndex(samples, new int3(id.x + 1, id.y, id.z))], noiseValues[GetIndex(samples, new int3(id.x + 1, id.y, id.z + 1))], noiseValues[GetIndex(samples, new int3(id.x, id.y, id.z + 1))], noiseValues[GetIndex(samples, new int3(id.x, id.y + 1, id.z))], noiseValues[GetIndex(samples, new int3(id.x + 1, id.y + 1, id.z))], noiseValues[GetIndex(samples, new int3(id.x + 1, id.y + 1, id.z + 1))], noiseValues[GetIndex(samples, new int3(id.x, id.y + 1, id.z + 1))] }; float3 topPoint = noiseValues[GetIndex(samples, new int3(id.x + 1, id.y + 1, id.z + 1))].Pos; for (int i = 0; i < 8; i++) { bool3 cmp = (cubeCorners[i].Pos > topPoint.xyz); if (cmp.x || cmp.y || cmp.z) { throw new Exception("Top point is not top: " + topPoint + " " + i + " " + cubeCorners[i]); } } // Calculate unique index for each cube configuration. // There are 256 possible values // A value of 0 means cube is entirely inside surface; 255 entirely outside. // The value is used to look up the edge table, which indicates which edges of the cube are cut by the isosurface. int cubeIndex = 0; if (cubeCorners[0].Noise < chunk.isoSurfaceLevel) { cubeIndex |= 1; } if (cubeCorners[1].Noise < chunk.isoSurfaceLevel) { cubeIndex |= 2; } if (cubeCorners[2].Noise < chunk.isoSurfaceLevel) { cubeIndex |= 4; } if (cubeCorners[3].Noise < chunk.isoSurfaceLevel) { cubeIndex |= 8; } if (cubeCorners[4].Noise < chunk.isoSurfaceLevel) { cubeIndex |= 16; } if (cubeCorners[5].Noise < chunk.isoSurfaceLevel) { cubeIndex |= 32; } if (cubeCorners[6].Noise < chunk.isoSurfaceLevel) { cubeIndex |= 64; } if (cubeCorners[7].Noise < chunk.isoSurfaceLevel) { cubeIndex |= 128; } // Create triangles for current cube configuration for (int i = 0; Table.Triangles2dArray[cubeIndex, i] != -1; i += 3) { // Get indices of corner points A and B for each of the three edges // of the cube that need to be joined to form the triangle. int a0 = Table.CornerIndexAFromEdge[Table.Triangles2dArray[cubeIndex, i]]; int b0 = Table.CornerIndexBFromEdge[Table.Triangles2dArray[cubeIndex, i]]; int a1 = Table.CornerIndexAFromEdge[Table.Triangles2dArray[cubeIndex, i + 1]]; int b1 = Table.CornerIndexBFromEdge[Table.Triangles2dArray[cubeIndex, i + 1]]; int a2 = Table.CornerIndexAFromEdge[Table.Triangles2dArray[cubeIndex, i + 2]]; int b2 = Table.CornerIndexBFromEdge[Table.Triangles2dArray[cubeIndex, i + 2]]; VertexNormal vertexA = interpolateVerts(chunk.isoSurfaceLevel, cubeCorners[a0], cubeCorners[b0]); VertexNormal vertexB = interpolateVerts(chunk.isoSurfaceLevel, cubeCorners[a1], cubeCorners[b1]); VertexNormal vertexC = interpolateVerts(chunk.isoSurfaceLevel, cubeCorners[a2], cubeCorners[b2]); // Triangle should be C - B - A //oldPoints.Clear(); int len = vertices.Count; //oldLayerPosIdDict.Clear(); //newLayerPosIdDict.Clear(); int vertCId = GetVertId(vertices, normals, oldLayerPosIdDict, newLayerPosIdDict, vertexC, topPoint, ref len); int vertBId = GetVertId(vertices, normals, oldLayerPosIdDict, newLayerPosIdDict, vertexB, topPoint, ref len); int vertAId = GetVertId(vertices, normals, oldLayerPosIdDict, newLayerPosIdDict, vertexA, topPoint, ref len); //normals.Add(vertexC.normal); //normals.Add(vertexB.normal); //normals.Add(vertexA.normal); //vertices.Add(vertexA); //vertices.Add(vertexB); //vertices.Add(vertexC); triangles.Add(vertCId); triangles.Add(vertBId); triangles.Add(vertAId); } } } maxDictSize = math.max(maxDictSize, oldLayerPosIdDict.Count); } float timeAfterMesh = Time.realtimeSinceStartup * 1000; //Debug.Log("triangles: " + triangles.Count + " vertices: " + vertices.Count); Mesh mesh = new Mesh(); mesh.vertices = vertices.ToArray(); mesh.triangles = triangles.ToArray(); mesh.normals = normals.ToArray(); //mesh.uv = uv.ToArray(); //mesh.RecalculateNormals(); gameObject.GetComponent <MeshFilter>().mesh = mesh; float timeAfterGO = Time.realtimeSinceStartup * 1000; Debug.Log("Time for noise: " + (timeAfterNoise - startTime) + " time for mesh: " + (timeAfterMesh - timeAfterNoise) + " GO: " + (timeAfterGO - timeAfterMesh)); Debug.Log("maxDictSize : " + maxDictSize); return(gameObject); }