public override _16x256x16VoxChunk GenerateVoxChunk(int uniqueID) { int[] position = _16x256x16VoxChunk.DefaultDecoderFromUniqueID2StPosition(uniqueID); offset = new Vector2(position[0], position[1]); GenNodes(); byte[] data = new byte[_16x256x16VoxChunk.Count]; _16x256x16VoxChunk chunk = new _16x256x16VoxChunk(uniqueID, data); for (int x = 0; x < _16x256x16VoxChunk.Width; x++) { for (int z = 0; z < _16x256x16VoxChunk.Length; z++) { TNode node = nodes[x, z]; int height = (int)node.elevation; byte type = (byte)(node.ttype); for (int y = 0; y < height; y++) { chunk.SetVoxel(x, y, z, type); } } } return(chunk); }
// Mesh chunk private GameObject CreateMeshObj(_16x256x16VoxChunk chunk, MeshingMaterial meshingMaterial, MeshingMaterial coliderMeshingMaterial) { Mesh mesh = meshingMaterial.ToMesh(); Mesh coliderMesh = coliderMeshingMaterial.ToMesh(); return(CreateMeshObj(chunk, mesh, coliderMesh)); }
// 获得射线交点所在Voxel的世界坐标信息 public Vector3 SetSelectedVoxel(RaycastHit hit) { if (hit.point.x < 0 || hit.point.y < 0 || hit.point.z < 0) { return(new Vector3(0, 0, 0)); } float acc = 0.00001f; int[] delta = new int[] { 0, 0, 0 }; int[] start = new int[] { 0, 0, 0 }; int[] local = new int[] { 0, 0, 0 }; if ((hit.point.x % 1) < acc) { delta[0] = 1; } else if ((hit.point.y % 1) < acc) { delta[1] = 1; } else if ((hit.point.z % 1) < acc) { delta[2] = 1; } start[0] = (int)hit.point.x; start[1] = (int)hit.point.y; start[2] = (int)hit.point.z; int uniqueID = GetUniqueIDByVoxelWorldPosition(start[0], start[2]); var chunk = GetChunkByUniqueID(uniqueID); if (chunk == null) { selectChunk = null; selectVoxelPosition = new Vector3(0, 0, 0); return(selectVoxelPosition); } local[0] = start[0] % _16x256x16VoxChunk.Width; local[1] = start[1] % _16x256x16VoxChunk.Height; local[2] = start[2] % _16x256x16VoxChunk.Length; byte voxType = chunk.GetVoxel(local[0], local[1], local[2]); if (voxType != _16x256x16VoxChunk.EmptyType) { selectChunk = chunk; selectVoxelPosition = new Vector3(start[0], start[1], start[2]); } else { selectChunk = GetChunkByUniqueID(GetUniqueIDByVoxelWorldPosition(start[0] - delta[0], start[2] - delta[2])); selectVoxelPosition = new Vector3(start[0] - delta[0], start[1] - delta[1], start[2] - delta[2]); } return(selectVoxelPosition); }
public void SetChunk(_16x256x16VoxChunk chunk) { if (!ExistWT()) { OpenWT(); } wt.WriteChunk(chunk); }
public void SetChunk(int index, _16x256x16VoxChunk chunk) { if (index < 0 || index >= MaxChunkSize) { return; } chunkData[index] = chunk; }
// 查找在Terrain中是否存在该chunk private bool HasTheChunk(_16x256x16VoxChunk chunk) { foreach (var lchunk in chunksInLastArea) { if (lchunk == chunk) { return(true); } } return(false); }
// 更新指定Chunk private void UpdateChunk(_16x256x16VoxChunk chunk) { if (!HasTheChunk(chunk)) { return; } MeshingMaterial meshMat = VoxTerrainMeshingTool.GreedyMeshing(chunk); MeshingMaterial coliderMeshMat = VoxTerrainMeshingTool.GreedyMeshing_ColiderMesh(chunk); Mesh mesh = meshMat.ToMesh(); Mesh coliderMesh = coliderMeshMat.ToMesh(); var oldMeshObj = GetMeshObj(chunk.UniqueID); DestroyImmediate(oldMeshObj); CreateMeshObj(chunk, mesh, coliderMesh); }
public override _16x256x16VoxChunk GenerateVoxChunk(int uniqueID) { byte[] voxData = new byte[_16x256x16VoxChunk.Count]; _16x256x16VoxChunk res = new _16x256x16VoxChunk(uniqueID, voxData); for (int x = 0; x < _16x256x16VoxChunk.Width; x++) { for (int z = 0; z < _16x256x16VoxChunk.Length; z++) { int plainHeight = (int)(PlainSample(uniqueID, x, z) + 0.5f); for (int y = 0; y < plainHeight; y++) { res.SetVoxel(x, y, z, 0x02); } } } return(res); }
public override _16x256x16VoxChunk GenerateVoxChunk(int uniqueID) { byte[] voxData = new byte[_16x256x16VoxChunk.Count]; _16x256x16VoxChunk result = new _16x256x16VoxChunk(uniqueID, voxData); offset = _16x256x16VoxChunk.DefaultDecoderFromUniqueID2StPosition(uniqueID); for (int lx = 0; lx < _16x256x16VoxChunk.Width; lx++) { for (int lz = 0; lz < _16x256x16VoxChunk.Length; lz++) { int groundHeight = GenBaseGround(lx, lz); int SnowLayerHeight = GenSnowLayer(lx, lz); int GlassLayerHeight = GenGlassLayer(lx, lz); for (int h = 0; h < groundHeight; h++) { result.SetVoxel(lx, h, lz, (byte)VoxelType.Ground); } int snowSubGround = SnowLayerHeight - groundHeight; if (snowSubGround > 0 && snowSubGround < snowDepth) { for (int h = SnowLayerHeight; h >= groundHeight; h--) { result.SetVoxel(lx, h, lz, (byte)VoxelType.Snow); } } int glassSubGround = GlassLayerHeight - groundHeight; if (glassSubGround > 0 && glassSubGround < glassDepth) { for (int h = glassSubGround; h >= groundHeight; h--) { result.SetVoxel(lx, h, lz, (byte)VoxelType.Glass); } } } } return(result); }
// Write chunk to WT public void WriteChunk(_16x256x16VoxChunk chunk) { if (SearchChunk(chunk.UniqueID)) { int index; uniqueID2Index.TryGetValue(chunk.UniqueID, out index); bw.BaseStream.Seek(Version.Length + index * ChunkLength + UniqueIDLength, SeekOrigin.Begin); bw.Write(chunk.VoxData); } else { int index = uniqueID2Index.Count; uniqueID2Index.Add(chunk.UniqueID, index); bw.BaseStream.Seek(0, SeekOrigin.End); bw.Write(chunk.UniqueID); bw.Write(chunk.VoxData); } }
private GameObject CreateMeshObj(_16x256x16VoxChunk chunk, Mesh mesh, Mesh coliderMesh) { GameObject meshObj = new GameObject(chunk.UniqueID.ToString()); meshObj.transform.parent = transform; meshObj.AddComponent <MeshRenderer>(); meshObj.AddComponent <MeshFilter>(); meshObj.GetComponent <MeshRenderer>().material = voxMaterial; meshObj.GetComponent <MeshFilter>().mesh = mesh; // Set Position meshObj.transform.position = new Vector3(_16x256x16VoxChunk.Width * chunk.Position[0] * scale, 0, _16x256x16VoxChunk.Length * chunk.Position[1] * scale); meshObj.transform.localScale = new Vector3(scale, scale, scale); var colider = meshObj.AddComponent <MeshCollider>(); colider.sharedMesh = coliderMesh; meshObj.layer = LayerMask.NameToLayer("VoxTerrain"); return(meshObj); }
// 区域更新:加载未加载区域内的chunks private IEnumerator LoadChunks() { List <_16x256x16VoxChunk> loadChunks = new List <_16x256x16VoxChunk>(); foreach (var uniqueID in uniqueIDsInArea) { bool equal = false; foreach (var chunk in chunksInLastArea) { if (uniqueID == chunk.UniqueID) { equal = true; } } if (!equal) // 若uniqueID不在老区域内,则被加载 { _16x256x16VoxChunk loadChunk = wtAsset.GetChunk(uniqueID); if (loadChunk == null) // 若在wt文件中不存在,则重新创建一个 { loadChunk = rule.GenerateVoxChunk(uniqueID); } loadChunks.Add(loadChunk); } } foreach (var loadChunk in loadChunks) { chunksInLastArea.Add(loadChunk); } if (meshingThread == null) { meshingThread = new MeshingThread(); } meshingThread.MeshingChunk = loadChunks; meshingThread.Run(); int cur = 0; while (cur < meshingThread.MeshingChunk.Count) { MeshingMaterial meshingMaterial = meshingThread.MeshingMaterials[cur]; MeshingMaterial coliderMeshingMaterial = meshingThread.ColiderMeshMaterials[cur]; if (meshingMaterial == null || coliderMeshingMaterial == null) { yield return(null); } else { CreateMeshObj(meshingThread.MeshingChunk[cur], meshingMaterial, coliderMeshingMaterial); cur++; } } IsMeshing = false; }
public static MeshingMaterial GreedyMeshing_ColiderMesh(_16x256x16VoxChunk voxChunk) { if (voxChunk == null) { return(null); } int[] size = { _16x256x16VoxChunk.Width, _16x256x16VoxChunk.Height, _16x256x16VoxChunk.Length }; int[] position = { 0, 0, 0 }; List <Vector3> vertices = new List <Vector3>(); List <int> triangles = new List <int>(); // 遍历扫描三个维度 for (int d = 0; d < 3; d++) { // 当前维度的二维截面的u,v坐标轴所代表的其余二个维度 int u = (d + 1) % 3, v = (d + 2) % 3; // 用于辅助计算 int[] q = { 0, 0, 0 }; q[d] = 1; // 用于记录当前维度截面的数据 byte[] mask = new byte[size[u] * size[v]]; // 用于记录Quad的方向 int[] direction = new int[size[u] * size[v]]; // 遍历该维度每个深度的截面数据 for (position[d] = -1; position[d] < size[d];) { // 求得截面数据 for (position[v] = 0; position[v] < size[v]; position[v]++) { for (position[u] = 0; position[u] < size[u]; position[u]++) { // 前后两层体素对比,使用异或规则(T = True,F = False),计算获得可见面 // Front || Back // T || T --> F // T || F --> T // F || T --> T // F || F --> F byte frontVoxelType = voxChunk.GetVoxel(position[0], position[1], position[2]); byte backVoxelType = voxChunk.GetVoxel(position[0] + q[0], position[1] + q[1], position[2] + q[2]); bool frontExist = frontVoxelType != emptyVoxelType; bool backExist = backVoxelType != emptyVoxelType; // 计算当前Voxel是否可显示 bool canDisplay = frontExist ^ backExist; // 计算当前截面位置的类型 int index = position[v] * size[u] + position[u]; if (canDisplay) { //if (frontExist) mask[index] = frontVoxelType; //else mask[index] = backVoxelType; mask[index] = 0x01; } else { mask[index] = emptyVoxelType; } if (!canDisplay) { direction[index] = 0; } else { direction[index] = frontExist ? 1 : -1; } } } // 累加深度 position[d]++; // 简化截面 for (position[v] = 0; position[v] < size[v]; position[v]++) { for (position[u] = 0; position[u] < size[u];) { int stIndex = position[v] * size[u] + position[u]; if (mask[stIndex] == emptyVoxelType) { position[u]++; continue; } // 当前起始面朝向 int stDirection = direction[stIndex]; // 当前体素类型 byte curVoxelType = mask[stIndex]; // 计算最大宽度 int width = 1; while (true) { if (width + position[u] >= size[u]) { break; } if (mask[stIndex + width] != curVoxelType || direction[stIndex + width] != stDirection) { break; } width++; } // 计算最大高度 int height = 1; bool flag = true; while (flag) { if (height + position[v] >= size[v]) { break; } int temp = (height + position[v]) * size[u]; for (int k = 0; k < width; k++) { int index = position[u] + k + temp; if (mask[index] != curVoxelType || direction[index] != stDirection) { flag = false; break; } } if (flag) { height++; } } // 记录结果 int[] du = { 0, 0, 0 }, dv = { 0, 0, 0 }; du[u] = width; dv[v] = height; stIndex = vertices.Count; vertices.Add(new Vector3(position[0], position[1], position[2])); vertices.Add(new Vector3(position[0] + du[0], position[1] + du[1], position[2] + du[2])); vertices.Add(new Vector3(position[0] + du[0] + dv[0], position[1] + du[1] + dv[1], position[2] + du[2] + dv[2])); vertices.Add(new Vector3(position[0] + dv[0], position[1] + dv[1], position[2] + dv[2])); float sU = (uMask & curVoxelType) * scale; float sV = ((uMask & curVoxelType) >> 4) * scale; if (stDirection == 1) { triangles.Add(stIndex); triangles.Add(stIndex + 1); triangles.Add(stIndex + 2); triangles.Add(stIndex + 2); triangles.Add(stIndex + 3); triangles.Add(stIndex); } else if (stDirection == -1) { triangles.Add(stIndex + 2); triangles.Add(stIndex + 1); triangles.Add(stIndex); triangles.Add(stIndex); triangles.Add(stIndex + 3); triangles.Add(stIndex + 2); } // 在截面涂黑已记录结果 for (int j = 0; j < height; j++) { int temp = (j + position[v]) * size[u]; for (int i = 0; i < width; i++) { mask[temp + position[u] + i] = emptyVoxelType; } } // 累加 position[u] += width; } } } } return(new MeshingMaterial(vertices, triangles, null)); }
public static void GreedyMeshing(_16x256x16VoxChunk voxChunk, out Mesh mesh) { if (voxChunk == null) { mesh = new Mesh(); return; } int[] size = { _16x256x16VoxChunk.Width, _16x256x16VoxChunk.Height, _16x256x16VoxChunk.Length }; int[] position = { 0, 0, 0 }; List <Vector3> vertices = new List <Vector3>(); List <int> triangles = new List <int>(); List <Vector2> uvs = new List <Vector2>(); // 遍历扫描三个维度 for (int d = 0; d < 3; d++) { // 当前维度的二维截面的u,v坐标轴所代表的其余二个维度 int u = (d + 1) % 3, v = (d + 2) % 3; // 用于辅助计算 int[] q = { 0, 0, 0 }; q[d] = 1; // 用于记录当前维度截面的数据 byte[] mask = new byte[size[u] * size[v]]; // 用于记录Quad的方向 int[] direction = new int[size[u] * size[v]]; // 遍历该维度每个深度的截面数据 for (position[d] = -1; position[d] < size[d];) { // 求得截面数据 for (position[v] = 0; position[v] < size[v]; position[v]++) { for (position[u] = 0; position[u] < size[u]; position[u]++) { // 前后两层体素对比,使用异或规则(T = True,F = False),计算获得可见面 // Front || Back // T || T --> F // T || F --> T // F || T --> T // F || F --> F byte frontVoxelType = voxChunk.GetVoxel(position[0], position[1], position[2]); byte backVoxelType = voxChunk.GetVoxel(position[0] + q[0], position[1] + q[1], position[2] + q[2]); bool frontExist = frontVoxelType != emptyVoxelType; bool backExist = backVoxelType != emptyVoxelType; // 计算当前Voxel是否可显示 bool canDisplay = frontExist ^ backExist; // 计算当前截面位置的类型 int index = position[v] * size[u] + position[u]; if (canDisplay) { if (frontExist) { mask[index] = frontVoxelType; } else { mask[index] = backVoxelType; } } else { mask[index] = emptyVoxelType; } if (!canDisplay) { direction[index] = 0; } else { direction[index] = frontExist ? 1 : -1; } } } // 累加深度 position[d]++; // 简化截面 for (position[v] = 0; position[v] < size[v]; position[v]++) { for (position[u] = 0; position[u] < size[u];) { int stIndex = position[v] * size[u] + position[u]; if (mask[stIndex] == emptyVoxelType) { position[u]++; continue; } // 当前起始面朝向 int stDirection = direction[stIndex]; // 当前体素类型 byte curVoxelType = mask[stIndex]; // 计算最大宽度 int width = 1; while (true) { if (width + position[u] >= size[u]) { break; } if (mask[stIndex + width] != curVoxelType || direction[stIndex + width] != stDirection) { break; } width++; } // 计算最大高度 int height = 1; bool flag = true; while (flag) { if (height + position[v] >= size[v]) { break; } int temp = (height + position[v]) * size[u]; for (int k = 0; k < width; k++) { int index = position[u] + k + temp; if (mask[index] != curVoxelType || direction[index] != stDirection) { flag = false; break; } } if (flag) { height++; } } // 记录结果 int[] du = { 0, 0, 0 }, dv = { 0, 0, 0 }; du[u] = width; dv[v] = height; stIndex = vertices.Count; vertices.Add(new Vector3(position[0], position[1], position[2])); vertices.Add(new Vector3(position[0] + du[0], position[1] + du[1], position[2] + du[2])); vertices.Add(new Vector3(position[0] + du[0] + dv[0], position[1] + du[1] + dv[1], position[2] + du[2] + dv[2])); vertices.Add(new Vector3(position[0] + dv[0], position[1] + dv[1], position[2] + dv[2])); float sU = (uMask & curVoxelType) * scale; float sV = ((uMask & curVoxelType) >> 4) * scale; uvs.Add(new Vector2(sU, sV)); uvs.Add(new Vector2(sU + scale, sV)); uvs.Add(new Vector2(sU + scale, sV + scale)); uvs.Add(new Vector2(sU, sV + scale)); if (stDirection == 1) { triangles.Add(stIndex); triangles.Add(stIndex + 1); triangles.Add(stIndex + 2); triangles.Add(stIndex + 2); triangles.Add(stIndex + 3); triangles.Add(stIndex); } else if (stDirection == -1) { triangles.Add(stIndex + 2); triangles.Add(stIndex + 1); triangles.Add(stIndex); triangles.Add(stIndex); triangles.Add(stIndex + 3); triangles.Add(stIndex + 2); } // 在截面涂黑已记录结果 for (int j = 0; j < height; j++) { int temp = (j + position[v]) * size[u]; for (int i = 0; i < width; i++) { mask[temp + position[u] + i] = emptyVoxelType; } } // 累加 position[u] += width; } } } } mesh = new Mesh(); mesh.subMeshCount = vertices.Count / maxVerticeIndexes + 1; mesh.SetVertices(vertices); for (int i = 0; i < mesh.subMeshCount; i++) { List <int> range; int sub = -i * maxVerticeIndexes; if (i + 1 == mesh.subMeshCount) { range = triangles.GetRange(i * maxTrianglesIndexes, triangles.Count % maxTrianglesIndexes); } else { range = triangles.GetRange(i * maxTrianglesIndexes, maxTrianglesIndexes); } for (int j = 0; j < range.Count; j++) { range[j] += sub; } mesh.SetTriangles(range, i, true, i * maxVerticeIndexes); } mesh.uv = uvs.ToArray(); mesh.RecalculateNormals(); }