Represents a structure used to compute terrain geometry.
Example #1
0
        /// <summary>
        /// Computes interpolated vertices on all cube edges.
        /// </summary>
        /// <param name="voxels">Voxels representing a cube.</param>
        /// <returns>Array of interpolated vertices.</returns>
        private static VoxelMeshVertex[] ComputeEdges(Voxel[] voxels)
        {
            VoxelMeshVertex[] interpolatedVertices = new VoxelMeshVertex[12];

            interpolatedVertices[0] = ComputeEdge(voxels[0], voxels[1]);
            interpolatedVertices[1] = ComputeEdge(voxels[1], voxels[2]);
            interpolatedVertices[2] = ComputeEdge(voxels[2], voxels[3]);
            interpolatedVertices[3] = ComputeEdge(voxels[3], voxels[0]);
            interpolatedVertices[4] = ComputeEdge(voxels[4], voxels[5]);
            interpolatedVertices[5] = ComputeEdge(voxels[5], voxels[6]);
            interpolatedVertices[6] = ComputeEdge(voxels[6], voxels[7]);
            interpolatedVertices[7] = ComputeEdge(voxels[7], voxels[4]);
            interpolatedVertices[8] = ComputeEdge(voxels[0], voxels[4]);
            interpolatedVertices[9] = ComputeEdge(voxels[1], voxels[5]);
            interpolatedVertices[10] = ComputeEdge(voxels[3], voxels[7]);
            interpolatedVertices[11] = ComputeEdge(voxels[2], voxels[6]);

            return interpolatedVertices;
        }
Example #2
0
        /// <summary>
        /// Computes voxel mesh triangles based on voxel cube points.
        /// </summary>
        /// <param name="cubeVoxels">Voxel cube points.</param>
        /// <returns>List with triangles.</returns>
        public static List<VoxelMeshVertex> ComputeTriangles(Voxel[] cubeVoxels)
        {
            List<VoxelMeshVertex> result = new List<VoxelMeshVertex>();
            VoxelMeshVertex[] interpolatedVertices = ComputeEdges(cubeVoxels);

            int caseNumber = CaseNumber(cubeVoxels);
            bool useDirectTable = !(IsAmbigous(caseNumber) && !useAmbigous);
            int offset = useDirectTable ? caseNumber * 15 : (255 - caseNumber) * 15;

            for (int i = 0; i < 5; i++, offset += 3)
            {
                if (faces[offset] != -1)
                {                  
                    result.Add(interpolatedVertices[faces[offset + 0]]);
                    result.Add(interpolatedVertices[faces[offset + 1]]);
                    result.Add(interpolatedVertices[faces[offset + 2]]);
                }
            }

            return result;
        }
Example #3
0
 /// <summary>
 /// Computes case number based on voxels.
 /// </summary>
 /// <param name="voxels">Voxels used in computation.</param>
 /// <returns>Case number.</returns>
 private static int CaseNumber(Voxel[] voxels)
 {
     int caseNumber = 0;
     for (int i = -1; ++i < voxels.Length; caseNumber += voxels[i].Weight - seekValue > 0 ? 1 << i : 0) ;
     return caseNumber;
 }
Example #4
0
        /// <summary>
        /// Computes interpolated vertex on a cube edge between two voxels.
        /// </summary>
        /// <param name="v1">First voxel.</param>
        /// <param name="v2">Second voxel.</param>
        /// <returns>Interpolated vertex.</returns>
        private static VoxelMeshVertex ComputeEdge(Voxel v1, Voxel v2)
        {
            VoxelMeshVertex vertex = new VoxelMeshVertex();

            float interpolation = (seekValue - v1.Weight) / (v2.Weight - v1.Weight);

            if (interpolation >= 0 && interpolation <= 1)
            {
                vertex.Position = v1.Position + (v2.Position - v1.Position) * interpolation;
                vertex.Normal = v1.Normal + (v2.Normal - v1.Normal) * interpolation;
                vertex.Ambient = v1.Ambient + (v2.Ambient - v1.Ambient) * interpolation;
            }

            return vertex;
        }
Example #5
0
        /// <summary>
        /// Generates mesh using mathematical functions.
        /// </summary>
        /// <param name="width">Mesh width.</param>
        /// <param name="height">Mesh height.</param>
        /// <param name="depth">Mesh depth.</param>
        public void GenerateFromFormula(int width, int height, int depth)
        {
            Voxel[, ,] voxels = new Voxel[width, height, depth];

            float area = (float)Math.Sqrt(width * depth);

            Vector3 center = new Vector3(width / 2.0f, height / 2.0f, depth / 2.0f);

            Vector3[] pillars = new Vector3[]
			{
				new Vector3(width / 4.0f, 0, depth / 4.0f),
				new Vector3(width * 3.0f / 4.0f, 0, depth * 3.0f / 4.0f),
				new Vector3(width * 2.0f / 4.0f, 0, depth / 4.0f)
			};

            NoiseCube n1 = new NoiseCube(16, 16, 16);
            NoiseCube n2 = new NoiseCube(16, 16, 16);
            NoiseCube n3 = new NoiseCube(16, 16, 16);
            NoiseCube n4 = new NoiseCube(16, 16, 16);

            Parallel.For(0, width, (x) =>
            {
                for (int y = 0; y < height; y++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        Vector3 position = new Vector3(x, y, z);
                        float weight = 0;

                        float distanceFromCenter = new Vector2(x - center.X, z - center.Z).Length();
                        distanceFromCenter = distanceFromCenter < 0.1f ? 0.1f : distanceFromCenter;

                        // Create pillars.
                        for (int i = 0; i < pillars.Length; i++)
                        {
                            float distance = new Vector2(x - pillars[i].X, z - pillars[i].Z).Length();
                            distance = distance < 0.1f ? 0.1f : distance;
                            weight += area / distance;
                        }

                        // Subtract values near center.
                        weight -= area / distanceFromCenter;

                        // Subtract big values at outer edge.
                        weight -= (float)Math.Pow(distanceFromCenter, 3) / (float)Math.Pow(area, 1.5f);

                        // Create helix.
                        double coordinate = 3 * Math.PI * y / height;
                        Vector2 helix = new Vector2((float)Math.Cos(coordinate), (float)Math.Sin(coordinate));
                        weight += Vector2.Dot(helix, new Vector2(x - center.X, z - center.Z));

                        // Create shelves.
                        weight += 10 * (float)Math.Cos(coordinate * 4 / 3);

                        // Add a little randomness.
                        weight += n1.GetInterpolatedValue(x / 32.04, y / 32.01, z / 31.97) * 8.0f;
                        weight += n2.GetInterpolatedValue(x / 8.01, y / 7.96, z / 7.98) * 4.0f;
                        weight += n3.GetInterpolatedValue(x / 4.01, y / 4.04, z / 3.96) * 2.0f;
                        weight += n4.GetInterpolatedValue(x / 2.02, y / 1.98, z / 1.97) * 1.0f;

                        voxels[x, y, z] = new Voxel()
                        {
                            Position = position,
                            Weight = weight
                        };
                    }
                }
            });

            ComputeNormal(voxels);
            ComputeAmbient(voxels);
            CreateGeometryBuffer(ComputeTriangles(voxels, container.Settings.LevelOfDetail));
        }
Example #6
0
        /// <summary>
        /// Computes triangle positions and normal vectors based on array of voxels.
        /// </summary>
        /// <param name="voxels">Array of voxels.</param>
        /// <param name="levelOfDetail">Lower value makes more triangles.</param>
        /// <returns>List of triangles.</returns>
        private List<VoxelMeshVertex> ComputeTriangles(Voxel[, ,] voxels, int levelOfDetail)
        {
            List<VoxelMeshVertex> triangles = new List<VoxelMeshVertex>();

            for (int x = 0; x < voxels.GetLength(0) - levelOfDetail; x += levelOfDetail)
            {
                for (int y = 0; y < voxels.GetLength(1) - levelOfDetail; y += levelOfDetail)
                {
                    for (int z = 0; z < voxels.GetLength(2) - levelOfDetail; z += levelOfDetail)
                    {
                        Voxel[] cubeVoxels = new Voxel[]
						{
						   voxels[x, y, z],
						   voxels[x, y, z + levelOfDetail],
						   voxels[x + levelOfDetail, y, z + levelOfDetail],
						   voxels[x + levelOfDetail, y, z],
						   voxels[x, y + levelOfDetail, z],
						   voxels[x, y + levelOfDetail, z + levelOfDetail],
						   voxels[x + levelOfDetail, y + levelOfDetail, z + levelOfDetail],
						   voxels[x + levelOfDetail, y + levelOfDetail, z]
						};

                        triangles.AddRange(VoxelCube.ComputeTriangles(cubeVoxels));
                    }
                }
            }

            return triangles;
        }
Example #7
0
        /// <summary>
        /// Computes normal vectors based on weight of each voxel.
        /// </summary>
        /// <param name="voxels">Array of voxels.</param>
        private void ComputeNormal(Voxel[, ,] voxels)
        {
            int width = voxels.GetLength(0);
            int height = voxels.GetLength(1);
            int depth = voxels.GetLength(2);

            Parallel.For(0, width, (x) =>
            {
                for (int y = 0; y < height; y++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        int xi = x == width - 1 ? x : x + 1;
                        int xd = x == 0 ? x : x - 1;

                        int yi = y == height - 1 ? y : y + 1;
                        int yd = y == 0 ? y : y - 1;

                        int zi = z == depth - 1 ? z : z + 1;
                        int zd = z == 0 ? z : z - 1;

                        Vector3 normal = new Vector3()
                        {
                            X = voxels[xi, y, z].Weight - voxels[xd, y, z].Weight,
                            Y = voxels[x, yi, z].Weight - voxels[x, yd, z].Weight,
                            Z = voxels[x, y, zi].Weight - voxels[x, y, zd].Weight
                        };

                        normal = -normal;
                        normal.Normalize();

                        voxels[x, y, z].Normal = normal;
                    }
                }
            });
        }
Example #8
0
        /// <summary>
        /// Computes ambient color for each voxel.
        /// </summary>
        /// <param name="voxels">Array of voxels.</param>
        private void ComputeAmbient(Voxel[, ,] voxels)
        {
            int width = voxels.GetLength(0);
            int height = voxels.GetLength(1);
            int depth = voxels.GetLength(2);

            float stepLength = (width * container.Settings.AmbientRayWidth / 100.0f) / container.Settings.AmbientSamplesCount;

            Parallel.For(0, width, (x) =>
            {
                for (int y = 0; y < height; y++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        float ambient = 0;
                        Vector3 position = voxels[x, y, z].Position;

                        for (int i = 0; i < poissonDisc.Length; i++)
                        {
                            float sample = 0;

                            for (int j = 0; j < container.Settings.AmbientSamplesCount; j++)
                            {
                                // Ray starting point is situated in a small distance from center to avoid rendering artifacts.
                                int stepNumber = j + 2;

                                int cx = (int)Helper.Clamp(position.X + stepNumber * stepLength * poissonDisc[i].X, 0, width - 1);
                                int cy = (int)Helper.Clamp(position.Y + stepNumber * stepLength * poissonDisc[i].Y, 0, height - 1);
                                int cz = (int)Helper.Clamp(position.Z + stepNumber * stepLength * poissonDisc[i].Z, 0, depth - 1);

                                sample += voxels[cx, cy, cz].Weight > 0 ? 0 : 1;
                            }

                            ambient += sample / container.Settings.AmbientSamplesCount;
                        }

                        voxels[x, y, z].Ambient = ambient / poissonDisc.Length;
                    }
                }
            });
        }
Example #9
0
        /// <summary>
        /// Generates mesh using some random values interpolated with trilinear interpolation.
        /// Uses coordinates transformed with warp values.
        /// </summary>
        /// <param name="width">Mesh widht.</param>
        /// <param name="height">Mesh height.</param>
        /// <param name="depth">Mesh depth.</param>
        public void GenerateFromNoiseCubeWithWarp(int width, int height, int depth)
        {
            Voxel[, ,] voxels = new Voxel[width, height, depth];

            Vector3 center = new Vector3(width / 2, height / 2, depth / 2);

            NoiseCube n0 = new NoiseCube(16, 16, 16);
            NoiseCube n1 = new NoiseCube(16, 16, 16);
            NoiseCube n2 = new NoiseCube(16, 16, 16);
            NoiseCube n3 = new NoiseCube(16, 16, 16);
            NoiseCube n4 = new NoiseCube(16, 16, 16);

            Parallel.For(0, width, (x) =>
            {
                for (int y = 0; y < height; y++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        Vector3 position = new Vector3(x, y, z);
                        float weight = center.Y - y;

                        float warp = n0.GetInterpolatedValue(x * 0.004, y * 0.004, z * 0.004);
                        float cx = x + warp * 8;
                        float cy = y + warp * 8;
                        float cz = z + warp * 8;

                        weight += n1.GetInterpolatedValue(cx / 32.04, cy / 32.01, cz / 31.97) * 64.0f;
                        weight += n2.GetInterpolatedValue(cx / 8.01, cy / 7.96, cz / 7.98) * 4.0f;
                        weight += n3.GetInterpolatedValue(cx / 4.01, cy / 4.04, cz / 3.96) * 2.0f;
                        weight += n4.GetInterpolatedValue(cx / 2.02, cy / 1.98, cz / 1.97) * 1.0f;

                        voxels[x, y, z] = new Voxel()
                        {
                            Position = position,
                            Weight = weight
                        };
                    }
                }
            });

            ComputeNormal(voxels);
            ComputeAmbient(voxels);
            CreateGeometryBuffer(ComputeTriangles(voxels, container.Settings.LevelOfDetail));
        }