예제 #1
0
        public override void OnInspectorGUI()
        {
            TerrainVolumeData data = target as TerrainVolumeData;

            EditorGUILayout.LabelField("Full path to voxel database:", EditorStyles.boldLabel);
            EditorGUILayout.HelpBox(data.fullPathToVoxelDatabase, MessageType.None);
        }
        void OnWizardCreate()
        {
            TerrainVolumeData data = VolumeDataAsset.CreateEmptyVolumeData <TerrainVolumeData>(new Region(0, 0, 0, width - 1, height - 1, depth - 1));

            if (generateFloor)
            {
                // Create some ground in the terrain so it shows up in the editor.
                // Soil as a base (mat 1) and then a couple of layers of grass (mat 2).
                TerrainVolumeGenerator.GenerateFloor(data, 6, (uint)1, 8, (uint)2);
            }
        }
        static void CreateTerrainVolume()
        {
            int width  = 128;
            int height = 32;
            int depth  = 128;

            TerrainVolumeData data = VolumeDataAsset.CreateEmptyVolumeData <TerrainVolumeData>(new Region(0, 0, 0, width - 1, height - 1, depth - 1));

            // Create some ground in the terrain so it shows up in the editor.
            // Soil as a base (mat 1) and then a couple of layers of grass (mat 2).
            TerrainVolumeGenerator.GenerateFloor(data, 6, (uint)1, 8, (uint)2);

            // Now create the terrain game object from the data.
            GameObject terrain = TerrainVolume.CreateGameObject(data, true, true);

            // And select it, so the user can get straight on with editing.
            Selection.activeGameObject = terrain;
        }
예제 #4
0
		/// Convinience method for creating a GameObject with a set of terrain components attached.
		/**
		 * Adding a volume to a scene requires creating a GameObject and then attching the required Cubiquity components such a renderer and a
		 * collider. This method simply automates the process and also attaches the provided volume data.
		 * 
		 * \param data The volume data which should be attached to the construced volume.
		 * \param addRenderer Specifies whether a renderer component should be added so that the volume is displayed.
		 * \param addCollider Specifies whether a collider component should be added so that the volume can participate in collisions.
		 */
		public static GameObject CreateGameObject(TerrainVolumeData data, bool addRenderer, bool addCollider)
		{
			// Create our main game object representing the volume.
			GameObject terrainVolumeGameObject = new GameObject("Terrain Volume");
			
			//Add the required volume component.
			TerrainVolume terrainVolume = terrainVolumeGameObject.GetOrAddComponent<TerrainVolume>();
			
			// Set the provided data.
			terrainVolume.data = data;
			
			// Add the renderer and collider if desired.
			if(addRenderer) { terrainVolumeGameObject.AddComponent<TerrainVolumeRenderer>(); }
			if(addCollider) { terrainVolumeGameObject.AddComponent<TerrainVolumeCollider>(); }
			
			// Return the created object
			return terrainVolumeGameObject;
		}
예제 #5
0
        void Start()
        {
            int planetRadius = 60;

            // Randomize the filename incase the file already exists
            System.Random randomIntGenerator = new System.Random();
            int           randomInt          = randomIntGenerator.Next();
            string        saveLocation       = Paths.voxelDatabases + "/planet-" + randomInt + ".vdb";

            Region            volumeBounds = new Region(-planetRadius, -planetRadius, -planetRadius, planetRadius, planetRadius, planetRadius);
            TerrainVolumeData data         = VolumeData.CreateEmptyVolumeData <TerrainVolumeData>(volumeBounds, saveLocation);

            // The numbers below control the thickness of the various layers.
            TerrainVolumeGenerator.GeneratePlanet(data, planetRadius, planetRadius - 1, planetRadius - 10, planetRadius - 35);

            // We need to commit this so that the changes made by the previous,line are actually written
            // to the voxel database. Otherwise they are just kept in temporary storage and will be lost.
            data.CommitChanges();
        }
        /// Convinience method for creating a GameObject with a set of terrain components attached.

        /**
         * Adding a volume to a scene requires creating a GameObject and then attching the required Cubiquity components such a renderer and a
         * collider. This method simply automates the process and also attaches the provided volume data.
         *
         * \param data The volume data which should be attached to the construced volume.
         * \param addRenderer Specifies whether a renderer component should be added so that the volume is displayed.
         * \param addCollider Specifies whether a collider component should be added so that the volume can participate in collisions.
         */
        public static GameObject CreateGameObject(TerrainVolumeData data, bool addRenderer, bool addCollider)
        {
            // Create our main game object representing the volume.
            GameObject terrainVolumeGameObject = new GameObject("Terrain Volume");

            //Add the required volume component.
            TerrainVolume terrainVolume = terrainVolumeGameObject.GetOrAddComponent <TerrainVolume>();

            // Set the provided data.
            terrainVolume.data = data;

            // Add the renderer and collider if desired.
            if (addRenderer)
            {
                terrainVolumeGameObject.AddComponent <TerrainVolumeRenderer>();
            }
            if (addCollider)
            {
                terrainVolumeGameObject.AddComponent <TerrainVolumeCollider>();
            }

            // Return the created object
            return(terrainVolumeGameObject);
        }
예제 #7
0
        void Create3DSimplexNoiseVolumeVDB()
        {
            // Randomize the filename incase the file already exists
            System.Random randomIntGenerator = new System.Random();
            int           randomInt          = randomIntGenerator.Next();
            string        saveLocation       = Paths.voxelDatabases + "/3d-simplex-noise-" + randomInt + ".vdb";

            // The size of the volume we will generate
            int width  = 256;
            int height = 256;
            int depth  = 256;

            TerrainVolumeData data = VolumeData.CreateEmptyVolumeData <TerrainVolumeData>(new Region(0, 0, 0, width - 1, height - 1, depth - 1), saveLocation);

            // This scale factor comtrols the size of the rocks which are generated.
            float rockScale    = 32.0f;
            float invRockScale = 1.0f / rockScale;

            // Let's keep the allocation outside of the loop.
            MaterialSet materialSet = new MaterialSet();

            // Iterate over every voxel of our volume
            for (int z = 0; z < depth; z++)
            {
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        // Make sure we don't have anything left in here from the previous voxel
                        materialSet.weights[0] = 0;
                        materialSet.weights[1] = 0;
                        materialSet.weights[2] = 0;

                        // Simplex noise is quite high frequency. We scale the sample position to reduce this.
                        float sampleX = (float)x * invRockScale;
                        float sampleY = (float)y * invRockScale;
                        float sampleZ = (float)z * invRockScale;

                        // Get the noise value for the current position.
                        // Returned value should be in the range -1 to +1.
                        float simplexNoiseValue = SimplexNoise.Noise.Generate(sampleX, sampleY, sampleZ);

                        // Cubiquity renders anything below the threshold as empty and anythng above as solid, but
                        // in general it is easiest if empty space is completly empty and solid space is completly
                        // solid. The exception to this is the region near our surface, where a gentle transition helps
                        // obtain smooth shading. By scaling by a large number and then clamping we achieve this effect
                        // of making most voxels fully solid or fully empty except near the surface..
                        simplexNoiseValue *= 5.0f;
                        simplexNoiseValue  = Mathf.Clamp(simplexNoiseValue, -0.5f, 0.5f);

                        // Go back to the range 0.0 to 1.0;
                        simplexNoiseValue += 0.5f;

                        // And then to 0 to 255, ready to convert into a byte.
                        simplexNoiseValue *= 255;

                        // Write the final value value into the first material channel (the one with the rock texture).
                        // The value being written is usually 0 (empty) or 255 (solid) except around the transition.
                        materialSet.weights[0] = (byte)simplexNoiseValue;

                        // We can now write our computed voxel value into the volume.
                        data.SetVoxel(x, y, z, materialSet);
                    }
                }
            }

            // We need to commit this so that the changes made by the previous,line are actually written
            // to the voxel database. Otherwise they are just kept in temporary storage and will be lost.
            data.CommitChanges();

            Debug.Log("Voxel database has been saved to '" + saveLocation + "'");
        }
예제 #8
0
        void Create2DSimplexNoiseVolumeVDB()
        {
            // Randomize the filename incase the file already exists
            System.Random randomIntGenerator = new System.Random();
            int           randomInt          = randomIntGenerator.Next();
            string        saveLocation       = Paths.voxelDatabases + "/2d-simplex-noise-" + randomInt + ".vdb";

            // The size of the volume we will generate
            int width  = 256;
            int height = 32;
            int depth  = 256;

            TerrainVolumeData data = VolumeData.CreateEmptyVolumeData <TerrainVolumeData>(new Region(0, 0, 0, width - 1, height - 1, depth - 1), saveLocation);

            // This scale factor comtrols the size of the rocks which are generated.
            float rockScale    = 32.0f;
            float invRockScale = 1.0f / rockScale;

            // Let's keep the allocation outside of the loop.
            MaterialSet materialSet = new MaterialSet();

            // Iterate over every voxel of our volume
            for (int z = 0; z < depth; z++)
            {
                for (int x = 0; x < width; x++)
                {
                    // Simplex noise is quite high frequency. We scale the sample position to reduce this.
                    float sampleX = (float)x * invRockScale;
                    float sampleZ = (float)z * invRockScale;

                    // Get the noise value for the current position.
                    // Returned value should be in the range -1 to +1.
                    float simplexNoiseValue = SimplexNoise.Noise.Generate(sampleX, sampleZ);

                    simplexNoiseValue += 1.0f;
                    simplexNoiseValue *= 16.0f;

                    for (int y = 0; y < height; y++)
                    {
                        // Make sure we don't have anything left in here from the previous voxel
                        materialSet.weights[0] = 0;
                        materialSet.weights[1] = 0;
                        materialSet.weights[2] = 0;

                        if (y < simplexNoiseValue)
                        {
                            // Write the final value value into the first material channel (the one with the rock texture).
                            // The value being written is usually 0 (empty) or 255 (solid) except around the transition.
                            materialSet.weights[0] = (byte)255;
                        }

                        // We can now write our computed voxel value into the volume.
                        data.SetVoxel(x, y, z, materialSet);
                    }
                }
            }

            // We need to commit this so that the changes made by the previous,line are actually written
            // to the voxel database. Otherwise they are just kept in temporary storage and will be lost.
            data.CommitChanges();

            Debug.Log("Voxel database has been saved to '" + saveLocation + "'");
        }
		public static void GeneratePlanet(TerrainVolumeData volumeData, float planetRadius, float mat1Radius, float mat2Radius, float mat3Radius)
		{
			Region volumeBounds = volumeData.enclosingRegion;
			MaterialSet materialSet = new MaterialSet();
			
			for(int z = volumeBounds.lowerCorner.z; z <= volumeBounds.upperCorner.z; z++)
			{
				for(int y = volumeBounds.lowerCorner.y; y <= volumeBounds.upperCorner.y; y++)
				{
					for(int x = volumeBounds.lowerCorner.x; x <= volumeBounds.upperCorner.x; x++)
					{
						// We are going to compute our density value based on the distance of a voxel from the center of our planet.
						// This is a function which (by definition) is zero at the center of the planet and has a smoothly increasing
						// value as we move away from the center.
						//
						// Note: For efficiency we could probably adapt this to work with squared distances (thereby eliminating
						// the square root operation), but we'd like to keep this example as intuitive as possible.
						float distFromCenter = Mathf.Sqrt(x * x + y * y + z * z);
						
						// We actually want our volume to have high values in the center and low values as we move out, because our
						// eath should be a solid sphere surrounded by empty space. If we invert the distance then this is a step in
						// the right direction. We still have zero in the center, but lower (negative) values as we move out.
						float density = -distFromCenter;
						
						// By adding the 'planetRadius' we now have a function which starts at 'planetRadius' and still decreases as it
						// moves out. The function passes through zero at a distance of 'planetRadius' and then continues do decrease
						// as it gets even further out.
						density += planetRadius;
						
						// Ideally we would like our final density value to be '255' for voxels inside the planet and '0' for voxels
						// outside the planet. At the surface there should be a transition but this should occur not too quickly and
						// not too slowly, as both of these will result in a jagged appearance to the mesh.
						//
						// We probably want the transition to occur over a few voxels, whereas it currently occurs over 255 voxels
						// because it was derived from the distance. By scaling the density field we effectivly compress the rate
						// at which it changes at the surface. We also make the center much too high and the outside very low, but
						// we will clamp these to the corect range later.
						//
						// Note: You can try commenting out or changing the value on this line to see the effect it has.
						density *= 50;
						
						// Until now we've been defining our density field as if the threshold was at zero, with positive densities
						// being solid and negative densities being empty. But actually Cubiquity operates on the range 0 to 255, and
						// uses a threashold of 127 to decide where to place the generated surface.  Therefore we shift and clamp our
						// density value and store it in a byte.
						density += 127;						
						byte densityAsByte = (byte)(Mathf.Clamp(density, 0, 255));
						
						if(distFromCenter < mat3Radius)
						{
							materialSet.weights[0] = 0;
							materialSet.weights[1] = 0;
							materialSet.weights[2] = 0;
							materialSet.weights[3] = densityAsByte;
						}
						else if(distFromCenter < mat2Radius)
						{
							materialSet.weights[0] = 0;
							materialSet.weights[1] = 0;
							materialSet.weights[2] = densityAsByte;
							materialSet.weights[3] = 0;
						}
						else if(distFromCenter < mat1Radius)
						{
							materialSet.weights[0] = 0;
							materialSet.weights[1] = densityAsByte;
							materialSet.weights[2] = 0;
							materialSet.weights[3] = 0;
						}
						else //Surface material
						{
							materialSet.weights[0] = densityAsByte;
							materialSet.weights[1] = 0;
							materialSet.weights[2] = 0;
							materialSet.weights[3] = 0;
						}
						
						volumeData.SetVoxel(x, y, z, materialSet);
						
					}
				}
			}
		}
		public static void GenerateFloor(TerrainVolumeData volumeData, int lowerLayerHeight, uint lowerLayerMaterial, int upperLayerHeight, uint upperLayerMaterial)
		{
			CubiquityDLL.GenerateFloor(volumeData.volumeHandle.Value, lowerLayerHeight, lowerLayerMaterial, upperLayerHeight, upperLayerMaterial);
		}
예제 #11
0
 public static void GenerateFloor(TerrainVolumeData volumeData, int lowerLayerHeight, uint lowerLayerMaterial, int upperLayerHeight, uint upperLayerMaterial)
 {
     CubiquityDLL.GenerateFloor(volumeData.volumeHandle.Value, lowerLayerHeight, lowerLayerMaterial, upperLayerHeight, upperLayerMaterial);
 }
예제 #12
0
        public static void GeneratePlanet(TerrainVolumeData volumeData, float planetRadius, float mat1Radius, float mat2Radius, float mat3Radius)
        {
            Region      volumeBounds = volumeData.enclosingRegion;
            MaterialSet materialSet  = new MaterialSet();

            for (int z = volumeBounds.lowerCorner.z; z <= volumeBounds.upperCorner.z; z++)
            {
                for (int y = volumeBounds.lowerCorner.y; y <= volumeBounds.upperCorner.y; y++)
                {
                    for (int x = volumeBounds.lowerCorner.x; x <= volumeBounds.upperCorner.x; x++)
                    {
                        // We are going to compute our density value based on the distance of a voxel from the center of our planet.
                        // This is a function which (by definition) is zero at the center of the planet and has a smoothly increasing
                        // value as we move away from the center.
                        //
                        // Note: For efficiency we could probably adapt this to work with squared distances (thereby eliminating
                        // the square root operation), but we'd like to keep this example as intuitive as possible.
                        float distFromCenter = Mathf.Sqrt(x * x + y * y + z * z);

                        // We actually want our volume to have high values in the center and low values as we move out, because our
                        // eath should be a solid sphere surrounded by empty space. If we invert the distance then this is a step in
                        // the right direction. We still have zero in the center, but lower (negative) values as we move out.
                        float density = -distFromCenter;

                        // By adding the 'planetRadius' we now have a function which starts at 'planetRadius' and still decreases as it
                        // moves out. The function passes through zero at a distance of 'planetRadius' and then continues do decrease
                        // as it gets even further out.
                        density += planetRadius;

                        // Ideally we would like our final density value to be '255' for voxels inside the planet and '0' for voxels
                        // outside the planet. At the surface there should be a transition but this should occur not too quickly and
                        // not too slowly, as both of these will result in a jagged appearance to the mesh.
                        //
                        // We probably want the transition to occur over a few voxels, whereas it currently occurs over 255 voxels
                        // because it was derived from the distance. By scaling the density field we effectivly compress the rate
                        // at which it changes at the surface. We also make the center much too high and the outside very low, but
                        // we will clamp these to the corect range later.
                        //
                        // Note: You can try commenting out or changing the value on this line to see the effect it has.
                        density *= 50;

                        // Until now we've been defining our density field as if the threshold was at zero, with positive densities
                        // being solid and negative densities being empty. But actually Cubiquity operates on the range 0 to 255, and
                        // uses a threashold of 127 to decide where to place the generated surface.  Therefore we shift and clamp our
                        // density value and store it in a byte.
                        density += 127;
                        byte densityAsByte = (byte)(Mathf.Clamp(density, 0, 255));

                        if (distFromCenter < mat3Radius)
                        {
                            materialSet.weights[0] = 0;
                            materialSet.weights[1] = 0;
                            materialSet.weights[2] = 0;
                            materialSet.weights[3] = densityAsByte;
                        }
                        else if (distFromCenter < mat2Radius)
                        {
                            materialSet.weights[0] = 0;
                            materialSet.weights[1] = 0;
                            materialSet.weights[2] = densityAsByte;
                            materialSet.weights[3] = 0;
                        }
                        else if (distFromCenter < mat1Radius)
                        {
                            materialSet.weights[0] = 0;
                            materialSet.weights[1] = densityAsByte;
                            materialSet.weights[2] = 0;
                            materialSet.weights[3] = 0;
                        }
                        else //Surface material
                        {
                            materialSet.weights[0] = densityAsByte;
                            materialSet.weights[1] = 0;
                            materialSet.weights[2] = 0;
                            materialSet.weights[3] = 0;
                        }

                        volumeData.SetVoxel(x, y, z, materialSet);
                    }
                }
            }
        }