public static Vector3[] GenerateTerrainMesh(Vector3[] parentVertices, float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve) { AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys); int width = heightMap.GetLength(0); int height = heightMap.GetLength(1); float topLeftX = (width - 1) / -2f; float topLeftZ = (height - 1) / 2f; int verticesPerLine = Mathf.RoundToInt(Mathf.Sqrt(parentVertices.Length)); ChunkMeshData meshData = new ChunkMeshData(width, height); int vertexIndex = 0; for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier, topLeftZ - y); ++vertexIndex; } } return(meshData.vertices); }
public void GenerateSegment() { var meshData = new ChunkMeshData(); // Generate mesh Greedy(meshData); // Hide chunk with old data if chunk mesh is empty since we can't push empty mesh /*chunkCollider.IsActive = */ chunkModel.IsActive = meshData.Triangles.Count > 0; // Early out (upload only if we have some mesh) if (meshData.Triangles.Count == 0) { return; } // Wait until chunk is loaded // while(!chunkMesh.IsLoaded && chunkMesh.LoadedLODs < 1) Thread.Sleep(10); // UpdateSegment mesh //chunkMesh.LODs[0].Meshes[0].BuildMesh(meshData.Vertices.ToArray(), meshData.Triangles.ToArray(), meshData.Normals.ToArray()); // UpdateSegment collisions // chunkCollisionData.CookCollision(CollisionDataType.TriangleMesh, chunkMesh); latestMeshData = meshData; }
private void Quad(ChunkMeshData meshData, Vector3 bottomLeft, Vector3 topLeft, Vector3 topRight, Vector3 bottomRight, int width, int height, Block voxel, bool backFace) { bottomLeft.Y += yOffset; bottomRight.Y += yOffset; topLeft.Y += yOffset; topRight.Y += yOffset; int offset = (int)meshData.Vertices.Count; meshData.Vertices.AddRange(new [] { topLeft, topRight, bottomLeft, bottomRight }); meshData.Triangles.AddRange(backFace ? new int[] { 2 + offset, 3 + offset, 1 + offset, 1 + offset, 0 + offset, 2 + offset } : new int[] { 2 + offset, 0 + offset, 1 + offset, 1 + offset, 3 + offset, 2 + offset }); var normal = Vector3.Normalize(Vector3.Cross(topRight - topLeft, bottomRight - topLeft)); if (backFace) { normal *= -1; } meshData.Normals.AddRange(new [] { normal, normal, normal, normal }); }
public void Update() { if (latestMeshData != null && chunkModel && latestMeshData.Triangles.Count > 0) { chunkMesh.LODs[0].Meshes[0].UpdateMesh(latestMeshData.Vertices.ToArray(), latestMeshData.Triangles.ToArray(), latestMeshData.Normals.ToArray()); latestMeshData = null; } }
public void GenerateMeshData(int ChunkX, int ChunkY, HeightsGenerator generator) { this.ChunkX = ChunkX; this.ChunkY = ChunkY; bool create = ChunkData == null; if (ChunkData == null) { ChunkData = new ChunkMeshData(); } int ThisChunkSize = ChunkSize + 1; if (create) { ChunkData.vertices = new Vector3[ThisChunkSize * ThisChunkSize]; Heights = new float[ThisChunkSize * ThisChunkSize]; ChunkData.triangles = new int[(ThisChunkSize - 1) * (ThisChunkSize - 1) * 6]; ChunkData.colors = new Color32[ThisChunkSize * ThisChunkSize]; ChunkData.uv = new Vector2[ThisChunkSize * ThisChunkSize]; } for (int vertex_index = 0, i = 0; i <= ChunkSize; i++) { for (int j = 0; j <= ChunkSize; j++, vertex_index++) { if (create) { float h = generator.GetHeight(i + (ChunkX * (ChunkSize)), j + (ChunkY * (ChunkSize))); SetHeight(i, j, h); Color color = generator.GetColor(i + (ChunkX * (ChunkSize)), j + (ChunkY * (ChunkSize)), h); SetColor(i, j, color); ChunkData.vertices[vertex_index] = new Vector3(); ChunkData.uv[vertex_index] = new Vector2((float)i / (float)ThisChunkSize, (float)j / (float)ThisChunkSize); } float height = GetHeight(i, j); ChunkData.vertices[vertex_index].Set(i, height, j); if (i < ChunkSize && j < ChunkSize) { ChunkData.AddTriangle(vertex_index, vertex_index + ThisChunkSize + 1, vertex_index + ThisChunkSize); ChunkData.AddTriangle(vertex_index + ThisChunkSize + 1, vertex_index, vertex_index + 1); } } } ChunkData.vertex_index = 0; NeedsUpdate = true; }
public static Mesh Generate(float[,] heightMap, float scale) { int borderedSize = heightMap.GetLength(0); int meshSize = borderedSize - 2; int[,] vertexIndicesMap = new int[borderedSize, borderedSize]; int meshVertexIndex = 0; int borderVertexIndex = -1; ChunkMeshData meshData = new ChunkMeshData(meshSize); for (int y = 0; y < borderedSize; y++) { for (int x = 0; x < borderedSize; x++) { bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1; if (isBorderVertex) { vertexIndicesMap[x, y] = borderVertexIndex; borderVertexIndex--; } else { vertexIndicesMap[x, y] = meshVertexIndex; meshVertexIndex++; } } } for (int y = 0; y < borderedSize; y++) { for (int x = 0; x < borderedSize; x++) { Vector3 vertexPosition = new Vector3((x - 1) * scale, heightMap[x, y], (y - 1) * scale); meshData.AddVertex(vertexPosition, vertexIndicesMap[x, y]); if (x < borderedSize - 1 && y < borderedSize - 1) { int a = vertexIndicesMap[x, y]; int b = vertexIndicesMap[x, y + 1]; int c = vertexIndicesMap[x + 1, y]; int d = vertexIndicesMap[x + 1, y + 1]; meshData.AddTriangle(a, d, c); meshData.AddTriangle(d, a, b); } } } return(meshData.CreateMesh()); }
/// <summary> /// 异步构建chunk /// </summary> public async void BuildChunkForAsync(Action callBackForComplete) { //只有初始化之后的chunk才能刷新 if (!isInit) { isBuildChunk = false; callBackForComplete?.Invoke(); return; } if (isBuildChunk) { return; } isBuildChunk = true; await Task.Run(() => { //遍历chunk, 生成其中的每一个Block try { lock (lockForBlcok) { #if UNITY_EDITOR Stopwatch stopwatch = TimeUtil.GetMethodTimeStart(); #endif chunkMeshData = new ChunkMeshData(); chunkData.InitRoundChunk(); //遍历每一个子区块 for (int i = 0; i < chunkData.chunkSectionDatas.Length; i++) { ChunkSectionData chunkSection = chunkData.chunkSectionDatas[i]; if (!chunkSection.IsRender()) { continue; } for (int x = 0; x < chunkSection.sectionSize; x++) { for (int y = 0; y < chunkSection.sectionSize; y++) { for (int z = 0; z < chunkSection.sectionSize; z++) { Block block = chunkData.GetBlockForLocal(x, y + chunkSection.yBase, z);; if (block == null || block.blockType == BlockTypeEnum.None) { continue; } Vector3Int localPosition = new Vector3Int(x, y + chunkSection.yBase, z); block.BuildBlock(this, localPosition); block.InitBlock(this, localPosition, 0); } } } } #if UNITY_EDITOR TimeUtil.GetMethodTimeEnd("Time_BuildChunkForAsync:", stopwatch); #endif } } catch (Exception e) { LogUtil.LogError("BuildChunkForAsync:" + e.ToString()); } finally { } }); isBuildChunk = false; callBackForComplete?.Invoke(); }
} // CalculateFace void CreateChunkMesh (ChunkMeshData chunkData) { // Data GameObject chunk = new GameObject("Chunk(" + chunkData.x + "|" + chunkData.y + ")"); Mesh mesh = chunk.AddComponent<MeshFilter>().mesh; chunk.transform.position = new Vector3(chunkData.x, chunkData.y, 0); chunk.AddComponent<MeshRenderer>().materials = materials; chunk.transform.parent = this.transform; // Set submesh data mesh.subMeshCount = 9; // Insert data mesh.vertices = chunkData.vertices.ToArray(); mesh.SetTriangles(chunkData.triangles[0], 0); mesh.SetTriangles(chunkData.triangles[1], 1); mesh.SetTriangles(chunkData.triangles[2], 2); mesh.SetTriangles(chunkData.triangles[3], 3); mesh.SetTriangles(chunkData.triangles[4], 4); mesh.SetTriangles(chunkData.triangles[5], 5); mesh.SetTriangles(chunkData.triangles[6], 6); mesh.SetTriangles(chunkData.triangles[7], 7); mesh.SetTriangles(chunkData.triangles[8], 8); mesh.uv = chunkData.uv.ToArray(); // Collider mesh Mesh colliderMesh = new Mesh(); colliderMesh.vertices = chunkData.colliderVertices.ToArray(); colliderMesh.triangles = chunkData.colliderTriangles.ToArray (); // Collider object GameObject chunkCollider = new GameObject (); chunkCollider.AddComponent<MeshCollider> ().sharedMesh = colliderMesh; chunkCollider.transform.parent = chunk.transform; chunkCollider.transform.position = chunk.transform.position; chunkCollider.name = "Collider"; chunkCollider.tag = "Chunk"; // Do other shit mesh.RecalculateNormals(); // Remove old chunk, if destroyOld == true if (chunkData.destroyOld) { string name = "Chunk(" + chunkData.x + "|" + chunkData.y + ")"; Destroy(GameObject.Find(name)); } } // CreateChunkMesh
} // CalculateMeshData void CalculateFace (int x, int y, ref ChunkMeshData chunkData, ref int squareCount, ref int squareCountCollider, int side) { Vector3[] tempVertices = new Vector3[0]; switch (side) { case 0: { // Add vertices tempVertices = new Vector3[] { new Vector3 (x, y, -.5f), new Vector3 (x, y + 1f, -.5f), new Vector3 (x + 1f, y + 1f, -.5f), new Vector3 (x + 1f, y, -.5f) }; } break; case 1: { // Add vertices tempVertices = new Vector3[] { new Vector3 (x, y + 1f, -.5f), new Vector3 (x, y + 1f, .5f), new Vector3 (x + 1f, y + 1f, .5f), new Vector3 (x + 1f, y + 1f, -.5f) }; } break; case 2: { // Add vertices tempVertices = new Vector3[] { new Vector3 (x, y, .5f), new Vector3 (x, y, -.5f), new Vector3 (x + 1f, y, -.5f), new Vector3 (x + 1f, y, .5f) }; } break; case 3: { // Add vertices tempVertices = new Vector3[] { new Vector3 (x, y, .5f), new Vector3 (x, y + 1f, .5f), new Vector3 (x, y + 1f, -.5f), new Vector3 (x, y, -.5f) }; } break; case 4: { // Add vertices tempVertices = new Vector3[] { new Vector3 (x + 1f, y, -.5f), new Vector3 (x + 1f, y + 1f, -.5f), new Vector3 (x + 1f, y + 1f, .5f), new Vector3 (x + 1f, y, .5f) }; } break; } chunkData.vertices.AddRange(tempVertices); // Visual vertices chunkData.colliderVertices.AddRange(tempVertices); // Collider vertices // Triangles for collider List<int> colliderTriangles = new List<int>(); colliderTriangles.AddRange(new int[] { squareCountCollider * 4, (squareCountCollider * 4) + 1, (squareCountCollider * 4) + 3, (squareCountCollider * 4) + 1, (squareCountCollider * 4) + 2, (squareCountCollider * 4) + 3 }); chunkData.colliderTriangles.AddRange(colliderTriangles.ToArray()); // Collider triangles // Add triangles List<int> tempTriangles = new List<int>(); tempTriangles.AddRange(new int[] { squareCount * 4, (squareCount * 4) + 1, (squareCount * 4) + 3, (squareCount * 4) + 1, (squareCount * 4) + 2, (squareCount * 4) + 3 }); switch (worldBlocks [chunkData.x + x, chunkData.y + y].id) // Insert triangles into correct chunkData.triangles { case 1: // Grass { if (side == 1) chunkData.triangles [0].AddRange (tempTriangles.ToArray ()); else if (side == 2) chunkData.triangles [2].AddRange (tempTriangles.ToArray ()); else chunkData.triangles [1].AddRange (tempTriangles.ToArray ()); } break; case 2: // Dirt { chunkData.triangles [2].AddRange (tempTriangles.ToArray ()); } break; case 3: // Stone { chunkData.triangles [3].AddRange (tempTriangles.ToArray ()); } break; case 4: // Cobblestone { chunkData.triangles [4].AddRange (tempTriangles.ToArray ()); } break; case 5: // Wood { if (side == 1 || side == 2) chunkData.triangles [5].AddRange (tempTriangles.ToArray ()); else chunkData.triangles [6].AddRange (tempTriangles.ToArray ()); } break; case 6: // Planks { chunkData.triangles [7].AddRange (tempTriangles.ToArray ()); } break; case 7: // Leaves { chunkData.triangles [8].AddRange (tempTriangles.ToArray ()); } break; } // Add UV chunkData.uv.AddRange(new Vector2[] { new Vector3(0f, 0f), new Vector3(0f, 1f), new Vector3(1f, 1f), new Vector3(1f, 0f) }); // Increase squareCount squareCount++; squareCountCollider++; } // CalculateFace
void CalculateChunkMeshData (int chunkX, int chunkY, bool destroyOld) { ChunkMeshData chunkData = new ChunkMeshData(); // Set chunkData position chunkData.x = chunkX * chunkSize; chunkData.y = chunkY * chunkSize; // Destroy old chunk chunkData.destroyOld = destroyOld; // Visual data chunkData.vertices = new List<Vector3>(); chunkData.triangles = new List<int>[9]{ new List<int>(), new List<int>(), new List<int>(), new List<int>(), new List<int>(), new List<int>(), new List<int>(), new List<int>(), new List<int>() }; chunkData.uv = new List<Vector2>(); // Collider data chunkData.colliderVertices = new List<Vector3>(); chunkData.colliderTriangles = new List<int >(); int squareCount = 0; int squareCountCollider = 0; for (int x = 0; x < chunkSize; x++) { for (int y = 0; y < chunkSize; y++) { Block thisBlock = worldBlocks [chunkData.x + x, chunkData.y + y]; if (thisBlock.id != 0) // Dont do these calculations if the block is air { // Calculate front CalculateFace (x, y, ref chunkData, ref squareCount, ref squareCountCollider, 0); // Calculate top if (worldHeight * chunkSize == chunkData.y + y + 1 || worldBlocks[chunkData.x + x, chunkData.y + y + 1].id == 0 || worldBlocks[chunkData.x + x, chunkData.y + y + 1].id == 7 && worldBlocks[chunkData.x + x, chunkData.y + y].id != 7) CalculateFace (x, y, ref chunkData, ref squareCount, ref squareCountCollider, 1); // Calculate bottom if (chunkData.y + y == 0 || worldBlocks[chunkData.x + x, chunkData.y + y - 1].id == 0) CalculateFace (x, y, ref chunkData, ref squareCount, ref squareCountCollider, 2); // Calculate left if (chunkData.x + x == 0 || worldBlocks[chunkData.x + x - 1, chunkData.y + y].id == 0) CalculateFace (x, y, ref chunkData, ref squareCount, ref squareCountCollider, 3); // Calculate right if (worldWidth * chunkSize == chunkData.x + x + 1 || worldBlocks[chunkData.x + x + 1, chunkData.y + y].id == 0) CalculateFace (x, y, ref chunkData, ref squareCount, ref squareCountCollider, 4); } } } // Add the ChunkMeshData to the queu queu.Add(chunkData); } // CalculateMeshData
private void UpdateMeshes() { EntityManager.AddChunkComponentData(_spriteMissingMesh, new ChunkSpriteMeshComponent { ChunkMeshId = -1 }); using (var chunks = _spriteEntities.CreateArchetypeChunkArray(Allocator.TempJob)) { var materialType = GetArchetypeChunkSharedComponentType <SharedSpriteMaterialComponent>(); var chunkSpriteMeshType = GetArchetypeChunkComponentType <ChunkSpriteMeshComponent>(); var spriteComponentType = GetArchetypeChunkComponentType <SpriteComponent>(true); var localToWorldType = GetArchetypeChunkComponentType <LocalToWorld>(true); for (int chunkIdx = 0; chunkIdx < chunks.Length; chunkIdx++) { var chunk = chunks[chunkIdx]; var spriteMaterial = chunk.GetSharedComponentData(materialType, EntityManager); // find mesh ChunkMeshData meshData; { var chunkSpriteMesh = chunk.GetChunkComponentData(chunkSpriteMeshType); if (chunkSpriteMesh.ChunkMeshId <= 0) { chunkSpriteMesh.ChunkMeshId = _nextMeshId++; chunk.SetChunkComponentData(chunkSpriteMeshType, chunkSpriteMesh); meshData = new ChunkMeshData { Material = chunk.GetSharedComponentData(materialType, EntityManager), Mesh = new Mesh(), MaterialVersion = LastSystemVersion, }; } else { meshData = _meshById[chunkSpriteMesh.ChunkMeshId]; bool hasMaterialChanged = chunk.DidChange(materialType, meshData.MaterialVersion) && !spriteMaterial.Equals(meshData.Material); if (!chunk.DidChange(localToWorldType, meshData.MeshVersion) && !chunk.DidChange(spriteComponentType, meshData.MeshVersion) && !hasMaterialChanged) { continue; } if (hasMaterialChanged) { meshData.Material = spriteMaterial; meshData.MaterialVersion = LastSystemVersion; } } meshData.MeshVersion = LastSystemVersion; _meshById[chunkSpriteMesh.ChunkMeshId] = meshData; } // generate mesh int numVertices = 4 * chunk.Count; var vertices = new NativeArray <float3>(numVertices, Allocator.Temp); var triangles = new NativeArray <int>(2 * 3 * chunk.Count, Allocator.Temp); var uvs = new NativeArray <float2>(numVertices, Allocator.Temp); var colors = new NativeArray <float4>(numVertices, Allocator.Temp); var localToWorld = chunk.GetNativeArray(localToWorldType); var sprites = chunk.GetNativeArray(spriteComponentType); for (int i = 0; i < chunk.Count; i++) { float4 size = new float4(-sprites[i].HalfSize, sprites[i].HalfSize); vertices[4 * i + 0] = math.mul(localToWorld[i].Value, new float4(size.xy, 0, 1)).xyz; vertices[4 * i + 1] = math.mul(localToWorld[i].Value, new float4(size.zy, 0, 1)).xyz; vertices[4 * i + 2] = math.mul(localToWorld[i].Value, new float4(size.zw, 0, 1)).xyz; vertices[4 * i + 3] = math.mul(localToWorld[i].Value, new float4(size.xw, 0, 1)).xyz; } for (int i = 0; i < chunk.Count; i++) { triangles[6 * i + 0] = 4 * i + 0; triangles[6 * i + 1] = 4 * i + 2; triangles[6 * i + 2] = 4 * i + 1; triangles[6 * i + 3] = 4 * i + 0; triangles[6 * i + 4] = 4 * i + 3; triangles[6 * i + 5] = 4 * i + 2; } for (int i = 0; i < chunk.Count; i++) { uvs[4 * i + 0] = sprites[i].MinUV; uvs[4 * i + 1] = new float2(sprites[i].MaxUV.x, sprites[i].MinUV.y); uvs[4 * i + 2] = sprites[i].MaxUV; uvs[4 * i + 3] = new float2(sprites[i].MinUV.x, sprites[i].MaxUV.y); colors[4 * i + 0] = sprites[i].Color; colors[4 * i + 1] = sprites[i].Color; colors[4 * i + 2] = sprites[i].Color; colors[4 * i + 3] = sprites[i].Color; } Mesh mesh = meshData.Mesh; mesh.Clear(); mesh.SetVertices(vertices); mesh.SetIndices(triangles, MeshTopology.Triangles, 0); mesh.SetUVs(0, uvs); mesh.SetColors(colors); vertices.Dispose(); triangles.Dispose(); uvs.Dispose(); colors.Dispose(); } } }
private void Greedy(ChunkMeshData meshData) { int i, j, k, l, w, h, u, v, n, side = 0; int[] x = new int[] { 0, 0, 0 }; int[] q = new int[] { 0, 0, 0 }; int[] du = new int[] { 0, 0, 0 }; int[] dv = new int[] { 0, 0, 0 }; Block[] mask = new Block[Chunk.SEGMENT_SIZE * Chunk.SEGMENT_SIZE]; Block block, block2; for (bool backFace = true, b = false; b != backFace; backFace = backFace && b, b = !b) { for (int d = 0; d < 3; d++) { u = (d + 1) % 3; v = (d + 2) % 3; x[0] = 0; x[1] = 0; x[2] = 0; q[0] = 0; q[1] = 0; q[2] = 0; q[d] = 1; if (d == 0) { side = backFace ? WEST : EAST; } else if (d == 1) { side = backFace ? BOTTOM : TOP; } else if (d == 2) { side = backFace ? SOUTH : NORTH; } for (x[d] = -1; x[d] < Chunk.SEGMENT_SIZE;) { n = 0; for (x[v] = 0; x[v] < Chunk.SEGMENT_SIZE; x[v]++) { for (x[u] = 0; x[u] < Chunk.SEGMENT_SIZE; x[u]++) { block = /*(x[d] >= 0) ?*/ GetVoxelFace(x[0], x[1], x[2], side) /* : null*/; block2 = /*(x[d] < Chunk.SEGMENT_SIZE - 1) ? */ GetVoxelFace(x[0] + q[0], x[1] + q[1], x[2] + q[2], side) /* : null*/; mask[n++] = ((block != null && block2 != null && block.Equals(block2))) ? null : backFace ? block2 : block; } } x[d]++; n = 0; for (j = 0; j < Chunk.SEGMENT_SIZE; j++) { for (i = 0; i < Chunk.SEGMENT_SIZE;) { if (mask[n] != null) { for (w = 1; i + w < Chunk.SEGMENT_SIZE && mask[n + w] != null && mask[n + w].Equals(mask[n]); w++) { } bool done = false; for (h = 1; j + h < Chunk.SEGMENT_SIZE; h++) { for (k = 0; k < w; k++) { if (mask[n + k + h * Chunk.SEGMENT_SIZE] == null || !mask[n + k + h * Chunk.SEGMENT_SIZE].Equals(mask[n])) { done = true; break; } } if (done) { break; } } if (!mask[n].Transparent) { x[u] = i; x[v] = j; du[0] = 0; du[1] = 0; du[2] = 0; du[u] = w; dv[0] = 0; dv[1] = 0; dv[2] = 0; dv[v] = h; Quad(meshData, new Vector3(x[0], x[1], x[2]), new Vector3(x[0] + du[0], x[1] + du[1], x[2] + du[2]), new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1], x[2] + du[2] + dv[2]), new Vector3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2]), w, h, mask[n], backFace); } for (l = 0; l < h; ++l) { for (k = 0; k < w; ++k) { mask[n + k + l * Chunk.SEGMENT_SIZE] = null; } } i += w; n += w; } else { i++; n++; } } } } } } }
public void CombineMesh(ChunkMeshData chunkMeshData) { //获取输出meshData Mesh.MeshDataArray outMeshDataArray = Mesh.AllocateWritableMeshData(1); Mesh.MeshData outMesh = outMeshDataArray[0]; Mesh.MeshDataArray outMeshDataArrayCollider = Mesh.AllocateWritableMeshData(1); Mesh.MeshData outMeshCollider = outMeshDataArrayCollider[0]; Mesh.MeshDataArray outMeshDataArrayTrigger = Mesh.AllocateWritableMeshData(1); Mesh.MeshData outMeshTrigger = outMeshDataArrayTrigger[0]; int subMeshCount = 0; int subMeshIndexCount = 0; List <int> trisDataAll = new List <int>(); List <SubMeshDescriptor> listSubMeshDescriptor = new List <SubMeshDescriptor>(); for (int i = 0; i < chunkMeshData.dicTris.Length; i++) { List <int> trisData = chunkMeshData.dicTris[i]; if (trisData.IsNull()) { continue; } trisDataAll.AddRange(trisData); SubMeshDescriptor subMeshDesc = new SubMeshDescriptor { indexStart = subMeshIndexCount, indexCount = trisData.Count }; listSubMeshDescriptor.Add(subMeshDesc); subMeshCount++; subMeshIndexCount += trisData.Count; } VertexStruct[] listVertex = chunkMeshData.GetVertexStruct(); outMesh.SetVertexBufferParams(listVertex.Length, vertexAttributeDescriptors); VertexStruct[] listVertexCollider = chunkMeshData.GetVertexStructCollider(); outMeshCollider.SetVertexBufferParams(listVertexCollider.Length, vertexAttributeDescriptors); VertexStruct[] listVertexTrigger = chunkMeshData.GetVertexStructTrigger(); outMeshTrigger.SetVertexBufferParams(listVertexTrigger.Length, vertexAttributeDescriptors); //获取点信息 NativeArray <VertexStruct> vertexData = outMesh.GetVertexData <VertexStruct>(); NativeArray <VertexStruct> vertexDataCollider = outMeshCollider.GetVertexData <VertexStruct>(); NativeArray <VertexStruct> vertexDataTrigger = outMeshTrigger.GetVertexData <VertexStruct>(); //设置点信息 NativeArray <VertexStruct> .Copy(listVertex, vertexData); NativeArray <VertexStruct> .Copy(listVertexCollider, vertexDataCollider); NativeArray <VertexStruct> .Copy(listVertexTrigger, vertexDataTrigger); //设置三角数量 outMesh.SetIndexBufferParams(trisDataAll.Count, IndexFormat.UInt32); outMeshCollider.SetIndexBufferParams(chunkMeshData.trisCollider.Count, IndexFormat.UInt32); outMeshTrigger.SetIndexBufferParams(chunkMeshData.trisTrigger.Count, IndexFormat.UInt32); //获取三角下标 NativeArray <int> triangelData = outMesh.GetIndexData <int>(); NativeArray <int> triangelDataCollider = outMeshCollider.GetIndexData <int>(); NativeArray <int> triangelDataTrigger = outMeshTrigger.GetIndexData <int>(); NativeArray <int> .Copy(trisDataAll.ToArray(), triangelData); NativeArray <int> .Copy(chunkMeshData.trisCollider.ToArray(), triangelDataCollider); NativeArray <int> .Copy(chunkMeshData.trisTrigger.ToArray(), triangelDataTrigger); outMesh.subMeshCount = subMeshCount; outMeshCollider.subMeshCount = 1; outMeshTrigger.subMeshCount = 1; for (int i = 0; i < listSubMeshDescriptor.Count; i++) { outMesh.SetSubMesh(i, listSubMeshDescriptor[i]); } outMeshCollider.SetSubMesh(0, new SubMeshDescriptor { indexStart = 0, indexCount = chunkMeshData.trisCollider.Count }); outMeshTrigger.SetSubMesh(0, new SubMeshDescriptor { indexStart = 0, indexCount = chunkMeshData.trisTrigger.Count }); Mesh.ApplyAndDisposeWritableMeshData(outMeshDataArray, chunkMesh); Mesh.ApplyAndDisposeWritableMeshData(outMeshDataArrayCollider, chunkMeshCollider); Mesh.ApplyAndDisposeWritableMeshData(outMeshDataArrayTrigger, chunkMeshTrigger); chunkMesh.RecalculateNormals(); chunkMesh.RecalculateBounds(); //chunkMeshCollider.RecalculateNormals(); //chunkMeshCollider.RecalculateBounds(); //chunkMeshTrigger.RecalculateNormals(); //chunkMeshTrigger.RecalculateBounds(); vertexData.Dispose(); triangelData.Dispose(); vertexDataCollider.Dispose(); triangelDataCollider.Dispose(); vertexDataTrigger.Dispose(); triangelDataTrigger.Dispose(); }
/// <summary> /// 设置数据 /// </summary> /// <param name="mapForBlock"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="minHeight"></param> public void SetData(Vector3Int worldPosition, int width, int height) { chunkData = new ChunkData(worldPosition, width, height); chunkMeshData = new ChunkMeshData(); }
public ChunkMeshData BuildChunk(int faceIndex, int chunkX, int chunkY, bool threaded) { //Init vars for for loop int chunkSize = 8; ChunkMeshData data = new ChunkMeshData(); Vector3[] verts = new Vector3[chunkSize * chunkSize * 20]; int[] tris = new int[chunkSize * chunkSize * 18 * 3]; Vector2[] uvs = new Vector2[chunkSize * chunkSize * 20]; PlanetFace face = faces[faceIndex]; int xOffset = chunkX * 8; int yOffset = chunkY * 8; float uvStepSize = 1f / 16; if (threaded) { //Create verts, tris and uvs Parallel.For(0, chunkSize * chunkSize, index => { //Debug.Log(Thread.CurrentThread.ManagedThreadId); //init local vars int vertIndex = index * 12; int trisIndex = index * 18 * 3; //Get the position in the data array int xPos = (index % 8) + xOffset; int yPos = Mathf.FloorToInt(index / 8f) + yOffset; //Set the top vertices float height = face.heightMap[xPos, yPos]; verts[vertIndex] = face.baseVertexPos[xPos, yPos] * height; verts[vertIndex + 1] = face.baseVertexPos[xPos + 1, yPos] * height; verts[vertIndex + 2] = face.baseVertexPos[xPos, yPos + 1] * height; verts[vertIndex + 3] = face.baseVertexPos[xPos + 1, yPos + 1] * height; //Set these values based on pillarType later, for now default to grass float topCornerX = uvStepSize * 2; float topCornerY = uvStepSize * 14; uvs[vertIndex] = new Vector2(topCornerX, topCornerY); uvs[vertIndex + 1] = new Vector2(topCornerX + uvStepSize, topCornerY); uvs[vertIndex + 2] = new Vector2(topCornerX, topCornerY - uvStepSize); uvs[vertIndex + 3] = new Vector2(topCornerX + uvStepSize, topCornerY - uvStepSize); //Set the middle vertices, double all because uvs height = (face.heightMap[xPos, yPos] - 1); verts[vertIndex + 4] = face.baseVertexPos[xPos, yPos] * height; verts[vertIndex + 5] = face.baseVertexPos[xPos, yPos] * height; verts[vertIndex + 6] = face.baseVertexPos[xPos + 1, yPos] * height; verts[vertIndex + 7] = face.baseVertexPos[xPos + 1, yPos] * height; verts[vertIndex + 8] = face.baseVertexPos[xPos + 1, yPos + 1] * height; verts[vertIndex + 9] = face.baseVertexPos[xPos + 1, yPos + 1] * height; verts[vertIndex + 10] = face.baseVertexPos[xPos, yPos + 1] * height; verts[vertIndex + 11] = face.baseVertexPos[xPos, yPos + 1] * height; float doubleStep = uvStepSize * 2; uvs[vertIndex + 4] = new Vector2(topCornerX - uvStepSize, topCornerY); uvs[vertIndex + 5] = new Vector2(topCornerX, topCornerY + uvStepSize); uvs[vertIndex + 6] = new Vector2(topCornerX + uvStepSize, topCornerY + uvStepSize); uvs[vertIndex + 7] = new Vector2(topCornerX + doubleStep, topCornerY); uvs[vertIndex + 8] = new Vector2(topCornerX + doubleStep, topCornerY - uvStepSize); uvs[vertIndex + 9] = new Vector2(topCornerX + uvStepSize, topCornerY - doubleStep); uvs[vertIndex + 10] = new Vector2(topCornerX, topCornerY - doubleStep); uvs[vertIndex + 11] = new Vector2(topCornerX - uvStepSize, topCornerY - uvStepSize); //Set the bottom vertices, double all because uvs verts[vertIndex + 12] = face.baseVertexPos[xPos, yPos]; verts[vertIndex + 13] = face.baseVertexPos[xPos, yPos]; verts[vertIndex + 14] = face.baseVertexPos[xPos + 1, yPos]; verts[vertIndex + 15] = face.baseVertexPos[xPos + 1, yPos]; verts[vertIndex + 16] = face.baseVertexPos[xPos + 1, yPos + 1]; verts[vertIndex + 17] = face.baseVertexPos[xPos + 1, yPos + 1]; verts[vertIndex + 18] = face.baseVertexPos[xPos, yPos + 1]; verts[vertIndex + 19] = face.baseVertexPos[xPos, yPos + 1]; uvStepSize *= 2; doubleStep *= 2; uvs[vertIndex + 12] = new Vector2(topCornerX - uvStepSize, topCornerY); uvs[vertIndex + 13] = new Vector2(topCornerX, topCornerY + uvStepSize); uvs[vertIndex + 14] = new Vector2(topCornerX + uvStepSize, topCornerY + uvStepSize); uvs[vertIndex + 15] = new Vector2(topCornerX + doubleStep, topCornerY); uvs[vertIndex + 16] = new Vector2(topCornerX + doubleStep, topCornerY - uvStepSize); uvs[vertIndex + 17] = new Vector2(topCornerX + uvStepSize, topCornerY - doubleStep); uvs[vertIndex + 18] = new Vector2(topCornerX, topCornerY - doubleStep); uvs[vertIndex + 19] = new Vector2(topCornerX - uvStepSize, topCornerY - uvStepSize); uvStepSize *= 0.5f; //Set the top face tris[trisIndex] = vertIndex; tris[trisIndex + 1] = vertIndex + 1; tris[trisIndex + 2] = vertIndex + 2; tris[trisIndex + 3] = vertIndex + 1; tris[trisIndex + 4] = vertIndex + 3; tris[trisIndex + 5] = vertIndex + 2; trisIndex += 6; //Set the side faces, once for top sides, once for sides that go to world center //Back side tris[trisIndex] = vertIndex; tris[trisIndex + 1] = vertIndex + 5; tris[trisIndex + 2] = vertIndex + 6; tris[trisIndex + 3] = vertIndex + 1; tris[trisIndex + 4] = vertIndex; tris[trisIndex + 5] = vertIndex + 6; //Right side tris[trisIndex + 6] = vertIndex + 1; tris[trisIndex + 7] = vertIndex + 7; tris[trisIndex + 8] = vertIndex + 8; tris[trisIndex + 9] = vertIndex + 3; tris[trisIndex + 10] = vertIndex + 1; tris[trisIndex + 11] = vertIndex + 8; //Front side tris[trisIndex + 12] = vertIndex + 3; tris[trisIndex + 13] = vertIndex + 9; tris[trisIndex + 14] = vertIndex + 10; tris[trisIndex + 15] = vertIndex + 2; tris[trisIndex + 16] = vertIndex + 3; tris[trisIndex + 17] = vertIndex + 10; //Left side tris[trisIndex + 18] = vertIndex + 2; tris[trisIndex + 19] = vertIndex + 11; tris[trisIndex + 20] = vertIndex + 4; tris[trisIndex + 21] = vertIndex; tris[trisIndex + 22] = vertIndex + 2; tris[trisIndex + 23] = vertIndex + 4; //Bottom side faces //Back side tris[trisIndex + 24] = vertIndex + 5; tris[trisIndex + 25] = vertIndex + 13; tris[trisIndex + 26] = vertIndex + 14; tris[trisIndex + 27] = vertIndex + 6; tris[trisIndex + 28] = vertIndex + 5; tris[trisIndex + 29] = vertIndex + 14; //Right side tris[trisIndex + 30] = vertIndex + 7; tris[trisIndex + 31] = vertIndex + 15; tris[trisIndex + 32] = vertIndex + 16; tris[trisIndex + 33] = vertIndex + 8; tris[trisIndex + 34] = vertIndex + 7; tris[trisIndex + 35] = vertIndex + 16; //Front side tris[trisIndex + 36] = vertIndex + 9; tris[trisIndex + 37] = vertIndex + 17; tris[trisIndex + 38] = vertIndex + 18; tris[trisIndex + 39] = vertIndex + 10; tris[trisIndex + 40] = vertIndex + 9; tris[trisIndex + 41] = vertIndex + 18; //Left side tris[trisIndex + 42] = vertIndex + 11; tris[trisIndex + 43] = vertIndex + 19; tris[trisIndex + 44] = vertIndex + 12; tris[trisIndex + 45] = vertIndex + 4; tris[trisIndex + 46] = vertIndex + 11; tris[trisIndex + 47] = vertIndex + 12; vertIndex += 20; trisIndex += 48; }); } else { int vertIndex = 0; int trisIndex = 0; for (int x = 0; x < chunkSize; x++) { for (int y = 0; y < chunkSize; y++) { //Get the position in the data array int xPos = x + xOffset; int yPos = y + yOffset; //Set the top vertices float height = face.heightMap[xPos, yPos]; verts[vertIndex] = face.baseVertexPos[xPos, yPos] * height; verts[vertIndex + 1] = face.baseVertexPos[xPos + 1, yPos] * height; verts[vertIndex + 2] = face.baseVertexPos[xPos, yPos + 1] * height; verts[vertIndex + 3] = face.baseVertexPos[xPos + 1, yPos + 1] * height; //Set these values based on pillarType later, for now default to grass float topCornerX = uvStepSize * 2; float topCornerY = uvStepSize * 14; uvs[vertIndex] = new Vector2(topCornerX, topCornerY); uvs[vertIndex + 1] = new Vector2(topCornerX + uvStepSize, topCornerY); uvs[vertIndex + 2] = new Vector2(topCornerX, topCornerY - uvStepSize); uvs[vertIndex + 3] = new Vector2(topCornerX + uvStepSize, topCornerY - uvStepSize); //Set the middle vertices, double all because uvs height = (face.heightMap[xPos, yPos] - 1); verts[vertIndex + 4] = face.baseVertexPos[xPos, yPos] * height; verts[vertIndex + 5] = face.baseVertexPos[xPos, yPos] * height; verts[vertIndex + 6] = face.baseVertexPos[xPos + 1, yPos] * height; verts[vertIndex + 7] = face.baseVertexPos[xPos + 1, yPos] * height; verts[vertIndex + 8] = face.baseVertexPos[xPos + 1, yPos + 1] * height; verts[vertIndex + 9] = face.baseVertexPos[xPos + 1, yPos + 1] * height; verts[vertIndex + 10] = face.baseVertexPos[xPos, yPos + 1] * height; verts[vertIndex + 11] = face.baseVertexPos[xPos, yPos + 1] * height; float doubleStep = uvStepSize * 2; uvs[vertIndex + 4] = new Vector2(topCornerX - uvStepSize, topCornerY); uvs[vertIndex + 5] = new Vector2(topCornerX, topCornerY + uvStepSize); uvs[vertIndex + 6] = new Vector2(topCornerX + uvStepSize, topCornerY + uvStepSize); uvs[vertIndex + 7] = new Vector2(topCornerX + doubleStep, topCornerY); uvs[vertIndex + 8] = new Vector2(topCornerX + doubleStep, topCornerY - uvStepSize); uvs[vertIndex + 9] = new Vector2(topCornerX + uvStepSize, topCornerY - doubleStep); uvs[vertIndex + 10] = new Vector2(topCornerX, topCornerY - doubleStep); uvs[vertIndex + 11] = new Vector2(topCornerX - uvStepSize, topCornerY - uvStepSize); //Set the bottom vertices, double all because uvs verts[vertIndex + 12] = face.baseVertexPos[xPos, yPos]; verts[vertIndex + 13] = face.baseVertexPos[xPos, yPos]; verts[vertIndex + 14] = face.baseVertexPos[xPos + 1, yPos]; verts[vertIndex + 15] = face.baseVertexPos[xPos + 1, yPos]; verts[vertIndex + 16] = face.baseVertexPos[xPos + 1, yPos + 1]; verts[vertIndex + 17] = face.baseVertexPos[xPos + 1, yPos + 1]; verts[vertIndex + 18] = face.baseVertexPos[xPos, yPos + 1]; verts[vertIndex + 19] = face.baseVertexPos[xPos, yPos + 1]; uvStepSize *= 2; doubleStep *= 2; uvs[vertIndex + 12] = new Vector2(topCornerX - uvStepSize, topCornerY); uvs[vertIndex + 13] = new Vector2(topCornerX, topCornerY + uvStepSize); uvs[vertIndex + 14] = new Vector2(topCornerX + uvStepSize, topCornerY + uvStepSize); uvs[vertIndex + 15] = new Vector2(topCornerX + doubleStep, topCornerY); uvs[vertIndex + 16] = new Vector2(topCornerX + doubleStep, topCornerY - uvStepSize); uvs[vertIndex + 17] = new Vector2(topCornerX + uvStepSize, topCornerY - doubleStep); uvs[vertIndex + 18] = new Vector2(topCornerX, topCornerY - doubleStep); uvs[vertIndex + 19] = new Vector2(topCornerX - uvStepSize, topCornerY - uvStepSize); uvStepSize *= 0.5f; //Set the top face tris[trisIndex] = vertIndex; tris[trisIndex + 1] = vertIndex + 1; tris[trisIndex + 2] = vertIndex + 2; tris[trisIndex + 3] = vertIndex + 1; tris[trisIndex + 4] = vertIndex + 3; tris[trisIndex + 5] = vertIndex + 2; trisIndex += 6; //Set the side faces, once for top sides, once for sides that go to world center //Back side tris[trisIndex] = vertIndex; tris[trisIndex + 1] = vertIndex + 5; tris[trisIndex + 2] = vertIndex + 6; tris[trisIndex + 3] = vertIndex + 1; tris[trisIndex + 4] = vertIndex; tris[trisIndex + 5] = vertIndex + 6; //Right side tris[trisIndex + 6] = vertIndex + 1; tris[trisIndex + 7] = vertIndex + 7; tris[trisIndex + 8] = vertIndex + 8; tris[trisIndex + 9] = vertIndex + 3; tris[trisIndex + 10] = vertIndex + 1; tris[trisIndex + 11] = vertIndex + 8; //Front side tris[trisIndex + 12] = vertIndex + 3; tris[trisIndex + 13] = vertIndex + 9; tris[trisIndex + 14] = vertIndex + 10; tris[trisIndex + 15] = vertIndex + 2; tris[trisIndex + 16] = vertIndex + 3; tris[trisIndex + 17] = vertIndex + 10; //Left side tris[trisIndex + 18] = vertIndex + 2; tris[trisIndex + 19] = vertIndex + 11; tris[trisIndex + 20] = vertIndex + 4; tris[trisIndex + 21] = vertIndex; tris[trisIndex + 22] = vertIndex + 2; tris[trisIndex + 23] = vertIndex + 4; //Bottom side faces //Back side tris[trisIndex + 24] = vertIndex + 5; tris[trisIndex + 25] = vertIndex + 13; tris[trisIndex + 26] = vertIndex + 14; tris[trisIndex + 27] = vertIndex + 6; tris[trisIndex + 28] = vertIndex + 5; tris[trisIndex + 29] = vertIndex + 14; //Right side tris[trisIndex + 30] = vertIndex + 7; tris[trisIndex + 31] = vertIndex + 15; tris[trisIndex + 32] = vertIndex + 16; tris[trisIndex + 33] = vertIndex + 8; tris[trisIndex + 34] = vertIndex + 7; tris[trisIndex + 35] = vertIndex + 16; //Front side tris[trisIndex + 36] = vertIndex + 9; tris[trisIndex + 37] = vertIndex + 17; tris[trisIndex + 38] = vertIndex + 18; tris[trisIndex + 39] = vertIndex + 10; tris[trisIndex + 40] = vertIndex + 9; tris[trisIndex + 41] = vertIndex + 18; //Left side tris[trisIndex + 42] = vertIndex + 11; tris[trisIndex + 43] = vertIndex + 19; tris[trisIndex + 44] = vertIndex + 12; tris[trisIndex + 45] = vertIndex + 4; tris[trisIndex + 46] = vertIndex + 11; tris[trisIndex + 47] = vertIndex + 12; vertIndex += 20; trisIndex += 48; } } } data.verts = verts; data.tris = tris; data.uvs = uvs; return(data); }
public ChunkMeshData[] GenerateChunkMeshData(ChunkColumn chunkCol, int yIndex) { ChunkMeshData[] chunkMeshData = new ChunkMeshData[2]; // Initializing mesh data's for (int i = 0; i < chunkMeshData.Length; i++) { chunkMeshData[i] = new ChunkMeshData(); } int yOffset = yIndex * ChunkColumn.chunkSize; Color32 currentColor; int currentFaceCount; int meshBufferIndex; for (int z = 0; z < ChunkColumn.chunkSize; z++) { for (int y = 0; y < ChunkColumn.chunkSize; y++) { for (int x = 0; x < ChunkColumn.chunkSize; x++) { byte currentBlockID = chunkCol.GetBlock(x, y + yOffset, z); if (currentBlockID == 0) { // Block is air, don't generate a mesh continue; } // Block is not air, generate a mesh currentFaceCount = 0; // Assume block is solid meshBufferIndex = 0; // Compare ID to transparent blockID's if (IsTransparentBlock(currentBlockID)) { // It's a transparent block, use transparent mesh buffer meshBufferIndex = 1; } // Block above if (ShouldDrawFace(currentBlockID, chunkCol.GetBlock(x, y + yOffset + 1, z), meshBufferIndex)) { chunkMeshData[meshBufferIndex].AddCubeFace(x, y, z, Faces.Top); currentFaceCount++; } // North block if (ShouldDrawFace(currentBlockID, chunkCol.GetBlock(x, y + yOffset, z + 1), meshBufferIndex)) { chunkMeshData[meshBufferIndex].AddCubeFace(x, y, z, Faces.North); currentFaceCount++; } // East block if (ShouldDrawFace(currentBlockID, chunkCol.GetBlock(x + 1, y + yOffset, z), meshBufferIndex)) { chunkMeshData[meshBufferIndex].AddCubeFace(x, y, z, Faces.East); currentFaceCount++; } // South block if (ShouldDrawFace(currentBlockID, chunkCol.GetBlock(x, y + yOffset, z - 1), meshBufferIndex)) { chunkMeshData[meshBufferIndex].AddCubeFace(x, y, z, Faces.South); currentFaceCount++; } // West block if (ShouldDrawFace(currentBlockID, chunkCol.GetBlock(x - 1, y + yOffset, z), meshBufferIndex)) { chunkMeshData[meshBufferIndex].AddCubeFace(x, y, z, Faces.West); currentFaceCount++; } // Bottom block if (ShouldDrawFace(currentBlockID, chunkCol.GetBlock(x, y + yOffset - 1, z), meshBufferIndex)) { chunkMeshData[meshBufferIndex].AddCubeFace(x, y, z, Faces.Bottom); currentFaceCount++; } if (currentFaceCount > 0) { // Block is visible (has faces) currentColor = EvaluateColor(chunkCol.colCoord.x * ChunkColumn.chunkSize + x, yIndex * ChunkColumn.chunkSize + y, chunkCol.colCoord.z * ChunkColumn.chunkSize + z, currentBlockID); chunkMeshData[meshBufferIndex].AddColor(currentColor, currentFaceCount); } } } } return(chunkMeshData); }
public void AddGeneratedChunkMesh(ChunkMeshData data) { _finishedMeshData.Enqueue(data); }