//threaded mesh creation // basically just creates the triangles and vertices on a thread then adds them to a mesh //in the main thread /// <summary> /// Creates the vertices. /// </summary> public void CreateVertices() { canCreatemesh = false; //create the verts verts = MarchingCubes.CreateVertices(Voxels, this, 2, 2, lodLevel); //store the size so as to avoid garbage creation size = verts.Length; //create normals normals = MeshFactory.CalculateNormals(Voxels, size, verts, lodLevel); //create colors int V = size; uv = new Color[size]; for (int i = 0; i < size; i++) { int x = Mathf.RoundToInt((verts[i].x - normals[i].x) / VoxelTerrainEngine.TriSize[lodLevel]); int y = Mathf.RoundToInt((verts[i].y - normals[i].y) / VoxelTerrainEngine.TriSize[lodLevel]); int z = Mathf.RoundToInt((verts[i].z - normals[i].z) / VoxelTerrainEngine.TriSize[lodLevel]); //conversion from voxel value to voxel type //seems to work well byte vox = Materials[x, y, z]; //basically each value gets assigned a color of 0.5 to 1.0 //in theory each decimal could be a voxel type if (vox == (int)VoxelType.Stone) { uv[i] = new Color(1, 0, 0, 0); } else if (vox == (int)VoxelType.Grass) { uv[i] = new Color(0, 1, 0, 0); } else if (vox == (int)VoxelType.SandStone) { uv[i] = new Color(0, 0, 1, 0); } else if (vox == (int)VoxelType.Dirt) { uv[i] = new Color(0, 0, 0, 1); } } canCreatemesh = true; VoxelTerrainEngine.MeshChunks.Enqueue(this); }
/// <summary> /// Creates the voxels. /// </summary> public void CreateVoxels() { if (VoxelSaver.GetBool("hasSavedChunk") == false && hasVoxels == false) { Voxels = MeshFactory.CreateVoxels(Voxels, RealPos - new Vector3(2, 2, 2), this, lodLevel); hasVoxels = true; } else if (VoxelSaver.GetBool("hasSavedChunk") && hasVoxels == false && hasloaded == false) { LoadVoxels(); hasVoxels = true; hasloaded = true; } VoxelTerrainEngine.GenerateVertices.Enqueue(this); }
//calculate normals for the mesh public static Vector3[] CalculateNormals(byte[,,] m_voxels, int size, Vector3 [] verts, int lod) { Vector3[,,] m_normals; Vector3[] normals = new Vector3[size]; int w = m_voxels.GetLength(0); int h = m_voxels.GetLength(1); int l = m_voxels.GetLength(2); //This calculates the normal of each voxel. If you have a 3d array of data //the normal is the derivitive of the x, y and z axis. //Normally you need to flip the normal (*-1) but it is not needed in this case. //If you dont call this function the normals that Unity generates for a mesh are used. m_normals = new Vector3[w, h, l]; for (int x = 2; x < w - 2; x++) { for (int y = 2; y < h - 2; y++) { for (int z = 2; z < l - 2; z++) { float dx = m_voxels[x + 1, y, z] - m_voxels[x - 1, y, z]; float dy = m_voxels[x, y + 1, z] - m_voxels[x, y - 1, z]; float dz = m_voxels[x, y, z + 1] - m_voxels[x, y, z - 1]; m_normals[x, y, z] = Vector3.Normalize(new Vector3(dx, dy, dz)); } } } for (int i = 0; i < size; i++) { normals[i] = MeshFactory.TriLinearInterpNormal(verts[i] / VoxelTerrainEngine.TriSize[lod], m_normals); } return(normals); }
public static Vector3[] CalculateNormalsRemove(byte[,,] m_voxels, int size, Vector3 [] verts) { Vector3[] normals = new Vector3[size]; //float startTime = Time.realtimeSinceStartup; int w = m_voxels.GetLength(0); int h = m_voxels.GetLength(1); int l = m_voxels.GetLength(2); //This calculates the normal of each voxel. If you have a 3d array of data //the normal is the derivitive of the x, y and z axis. //Normally you need to flip the normal (*-1) but it is not needed in this case. //If you dont call this function the normals that Unity generates for a mesh are used. m_normals2 = new Vector3[w, h, l]; for (int x = 2; x < w - 2; x++) { for (int y = 2; y < h - 2; y++) { for (int z = 2; z < l - 2; z++) { float dx = m_voxels[x + 1, y, z] - m_voxels[x - 1, y, z]; float dy = m_voxels[x, y + 1, z] - m_voxels[x, y - 1, z]; float dz = m_voxels[x, y, z + 1] - m_voxels[x, y, z - 1]; m_normals2[x, y, z] = Vector3.Normalize(new Vector3(dx, dy, dz)); } } } for (int i = 0; i < size; i++) { normals[i] = MeshFactory.TriLinearInterp(verts[i]); } //Debug.Log("Calculate normals time = " + (Time.realtimeSinceStartup-startTime).ToString() ); return(normals); }
//this is called if the voxel has changed and needs to be reloaded //had to do it this way or else we end up with strange terrain errors public void CreateMeshesWithVoxels() { //set flag so this mesh wont get created twice canCreatemesh = false; verts = MeshFactory.CreateverticesVoxels(Voxels, this); //cache vertices size to avoid gc allocation size = verts.Length; normals = MeshFactory.CalculateNormalsRemove(Voxels, size, verts); control = new Color[size]; float R = 0; float G = 0; float B = 0; float A = 0; for (int i = 0; i < size; i++) { R = 0; G = 0; B = 0; A = 0; int x = Mathf.RoundToInt(verts[i].x - normals[i].x); int y = Mathf.RoundToInt(verts[i].y - normals[i].y); int z = Mathf.RoundToInt(verts[i].z - normals[i].z); byte vox = (byte)((float)Voxels[x, y, z] / 255 * 8); if (vox == (int)VoxelType.Dirt) { R = 0.5f; } if (vox == (int)VoxelType.Stone) { G = 0.5f; } if (vox == (int)VoxelType.SandStone) { B = 0.5f; } if (vox == (int)VoxelType.Grass) { A = 0.5f; } if (vox == (int)VoxelType.Iron) { R = 1; } if (vox == (int)VoxelType.Gold) { G = 1; } if (vox == (int)VoxelType.GunPowder) { B = 1; } if (vox == (int)VoxelType.Tungsten) { A = 1; } control[i] = new Color(R, G, B, A); } canCreatemesh = true; }
//threaded mesh creation // basically just creates the triangles and vertices on a thread then adds them to a mesh //in the main thread public void CreateMeshesAndvoxels(bool MakeNewVoxels) { canCreatemesh = false; if (MakeNewVoxels && VoxelSaver.GetBool("hasSavedChunk") == false) { Voxels = MeshFactory.CreateVoxels(Voxels, m_pos, this, generator.noise); } else { LoadVoxels(); } //create the verts verts = MeshFactory.MarchingCubes.CreateVertices(Voxels, this, 2, 2); //store the size so as to avoid garbage creation size = verts.Length; //create normals normals = MeshFactory.CalculateNormals(Voxels, size, verts); //create colors control = new Color[size]; float R = 0; float G = 0; float B = 0; float A = 0; for (int i = 0; i < size; i++) { R = 0; G = 0; B = 0; A = 0; int x = Mathf.RoundToInt(verts[i].x - normals[i].x); int y = Mathf.RoundToInt(verts[i].y - normals[i].y); int z = Mathf.RoundToInt(verts[i].z - normals[i].z); //conversion from voxel value to voxel type //seems to work well byte vox = (byte)((float)Voxels[x, y, z] / 255 * 8); //basically each value gets assigned a color of 0.5 to 1.0 //in theory each decimal could be a voxel type if (vox == (int)VoxelType.Dirt) { R = 0.5f; } if (vox == (int)VoxelType.Stone) { G = 0.5f; } if (vox == (int)VoxelType.SandStone) { B = 0.5f; } if (vox == (int)VoxelType.Grass) { A = 0.5f; } if (vox == (int)VoxelType.Iron) { R = 1; } if (vox == (int)VoxelType.Gold) { G = 1; } if (vox == (int)VoxelType.GunPowder) { B = 1; } if (vox == (int)VoxelType.Tungsten) { A = 1; } control[i] = new Color(R, G, B, A); } canCreatemesh = true; }