コード例 #1
0
ファイル: 3DModelGenerator.cs プロジェクト: crissian/planets
        /// <summary>
        /// Génère un modèle 3D en forme de planète à partir de plusieurs bruits.
        /// </summary>
        /// <param name="aabb">Bounding box du morceau de planète généré.</param>
        /// <param name="gridLevelScale">Echelle du morceau de grille à générer. L'échelle est divisée par 2
        /// à chaque étage du quadtree</param>
        /// <param name="gridSize">Taille de la grille à générer.</param>
        /// <param name="highNoise">Bruit "high"</param>
        /// <param name="iBuffer">Index buffer en du mesh créé en sortie.</param>
        /// <param name="initialGridPos">Position du coin supérieur gauche de la grille à générer dans la grille initiale de range [0, 1]</param>
        /// <param name="lowNoise">Bruit "low"</param>
        /// <param name="repNoise">Bruit de répartition</param>
        /// <param name="vBuffer">Vertex buffer en du mesh créé en sortie.</param>
        /// <param name="chunkGeography">Informations de sortie concernant la géographie du morceau généré.</param>
        /// <param name="planetPosition">Position de la planète.</param>
        /// <param name="radius">Rayon de la planète.</param>
        /// <returns></returns>
        public static void GeneratePlanet(Vector3 planetPosition,
            float radius,
            int gridSize, 
            Vector2 initialGridPos,
            float gridLevelScale,
            Noise.NoiseBase lowNoise,
            Noise.NoiseBase highNoise,
            Noise.NoiseBase repNoise,
            out SlimDX.Direct3D11.Buffer vBuffer,
            out BoundingBox aabb,
            out ChunkAltitude geo)
        {
            // Geography
            geo = new ChunkAltitude();

            // Taille du buffer.
            int size = gridSize * gridSize ;
            const bool computeNormals = true;
            Vector3 min = new Vector3(float.MaxValue);
            Vector3 max = new Vector3(float.MinValue);

            // Création du vertex buffer contenant tous les vertex à dessiner.
            VWrapper[] vertexBuffer = new VWrapper[size];

            // Texture noise
            Noise.NoiseMapGenerator.NoiseParameters p = new Noise.NoiseMapGenerator.NoiseParameters()
            {
                Frequency = 128.0f,
                Lacunarity = 2.5f,
                NoiseEnd = new Vector2(initialGridPos.X + gridLevelScale, initialGridPos.Y + gridLevelScale),
                NoiseStart = new Vector2(initialGridPos.X, initialGridPos.Y),
                NoiseType = Noise.NoiseMapGenerator.NoiseParameters.RIDGED_ID,
                Persistence = 0.94f,
                Seed = 456464560
            };
            Noise.NoiseBase texNoise = p.CreateNoise();

            float theta, phi;
            Vector3 transformedPos;
            for (int y = 0; y < gridSize; y++)
            {
                for (int x = 0; x < gridSize; x++)
                {
                    // Cette section a pour but de calculer la normale par rapport au "sol" de la planète, pour cela
                    // Elle calcule les positions des verte
                    Vector2 pos2D = new Vector2(x / ((float)gridSize - 1),
                                    (y / ((float)gridSize - 1)));

                    // Transformation en sphère.
                    float noisePosX = initialGridPos.X + pos2D.X * gridLevelScale;
                    float noisePosY = initialGridPos.Y + pos2D.Y * gridLevelScale;
                    phi = (noisePosX) * (float)Math.PI * 2;
                    theta = (noisePosY) * (float)Math.PI;

                    // TODO : optimiser pour éviter les calculs redondants.
                    transformedPos = Util.SphericalCoords.ToCartesian(theta, phi, radius);//new Vector3(xSph, ySph, zSph);

                    // Création de la normale au sol.
                    Vector3 normal = Vector3.Normalize(transformedPos);

                    // Valeur du bruit
                    float noiseValue = Noise.NoiseMapGenerator.GetMultiNoiseValue(repNoise, highNoise, lowNoise,
                        transformedPos.X / radius, transformedPos.Y / radius, transformedPos.Z / radius);
                    float tNoiseValue = texNoise.GetValue(transformedPos.X / radius, transformedPos.Y / radius, transformedPos.Z / radius);

                    // Création de la position finale
                    Vector3 finalPos = transformedPos + normal * noiseValue;
                    Vector4 pos = new Vector4(finalPos, 1.0f);

                    // Informations de géométrie.
                    min = Util.MathHelper.Min(finalPos, min);
                    max = Util.MathHelper.Max(finalPos, max);
                    geo.MinAltitude = Math.Min(noiseValue, geo.MinAltitude);
                    geo.MaxAltitude = Math.Max(noiseValue, geo.MaxAltitude);

                    // Ajout des données dans le VBuffer.
                    int index = (x + y * gridSize);

                    vertexBuffer[index] = new VWrapper();
                    vertexBuffer[index].SphereNormal = normal;

                    // Position 3D du point avec displacement.
                    vertexBuffer[index].Vertex.Position = pos;
                    // Position 3D du point sans displacement.
                    vertexBuffer[index].Vertex.SpherePosition = new Vector4(transformedPos, 1.0f);
                    vertexBuffer[index].Vertex.SphereNormal = new Vector4(normal, 1.0f);
                    // Coordonnées de texture.
                    vertexBuffer[index].Vertex.Texture = new Vector2(noisePosX, noisePosY);
                    vertexBuffer[index].Vertex.Normal = new Vector4(0);
                    vertexBuffer[index].Vertex.Altitude = noiseValue;

                    // Valeurs additionnelles.
                    vertexBuffer[index].Vertex.TextureId = tNoiseValue;
                }

            }

            // Index buffer contenant l'ordre dans lequel dessiner les vertex. (sous forme de carrés).
            int iBufferSize = (gridSize - 1) * (gridSize - 1) * 6;
            int[] indexBuffer = GetIndexBufferCpu(gridSize);
            if (computeNormals)
            {
                //Thread.Sleep(1);
                for (int i = 0; i < indexBuffer.Length / 3; i++)
                {
                    Vector4 firstvec = vertexBuffer[indexBuffer[i * 3 + 1]].Vertex.Position - vertexBuffer[indexBuffer[i * 3]].Vertex.Position;
                    Vector4 secondvec = vertexBuffer[indexBuffer[i * 3]].Vertex.Position - vertexBuffer[indexBuffer[i * 3 + 2]].Vertex.Position;
                    Vector4 normal = new Vector4(Vector3.Cross(
                        new Vector3(firstvec.X, firstvec.Y, firstvec.Z),
                        new Vector3(secondvec.X, secondvec.Y, secondvec.Z)), 1.0f);
                    normal.Normalize();
                    vertexBuffer[indexBuffer[(i * 3)]].Vertex.Normal += normal;
                    vertexBuffer[indexBuffer[(i * 3 + 1)]].Vertex.Normal += normal;
                    vertexBuffer[indexBuffer[(i * 3 + 2)]].Vertex.Normal += normal;
                }
                for (int i = 0; i < vertexBuffer.Length; i++)
                {
                    var v = Util.MathHelper.ReduceXYZ(vertexBuffer[i].Vertex.Normal);
                    v.Normalize();
                    vertexBuffer[i].Vertex.Normal = new Vector4(v, 1.0f);
                    vertexBuffer[i].Vertex.SphereNormal = new Vector4(Util.MathHelper.ReduceXYZ(vertexBuffer[i].Vertex.Normal) - vertexBuffer[i].SphereNormal, 1.0f);

                }
            }

            // Création des buffers.
            DataStream vBuffStream = new DataStream(size * Vertex.Stride, true, true);
            for (int i = 0; i < size; i++)
                vBuffStream.Write<Vertex>(vertexBuffer[i].Vertex);
            vBuffStream.Position = 0;

            vBuffer = new SlimDX.Direct3D11.Buffer(Scene.GetGraphicsDevice(), vBuffStream, new BufferDescription()
            {
                BindFlags = BindFlags.VertexBuffer,
                CpuAccessFlags = CpuAccessFlags.None,
                OptionFlags = ResourceOptionFlags.None,
                SizeInBytes = (int)vBuffStream.Length,
                Usage = ResourceUsage.Default
            });

            vBuffStream.Dispose();

            aabb = new BoundingBox(min, max);
        }
コード例 #2
0
ファイル: 3DModelGenerator.cs プロジェクト: crissian/planets
        /// <summary>
        /// Génère un modèle 3D en forme de planète à partir de plusieurs bruits.
        /// </summary>
        /// <param name="aabb">Bounding box du morceau de planète généré.</param>
        /// <param name="gridLevelScale">Echelle du morceau de grille à générer. L'échelle est divisée par 2
        /// à chaque étage du quadtree</param>
        /// <param name="gridSize">Taille de la grille à générer.</param>
        /// <param name="highNoise">Bruit "high"</param>
        /// <param name="iBuffer">Index buffer en du mesh créé en sortie.</param>
        /// <param name="initialGridPos">Position du coin supérieur gauche de la grille à générer dans la grille initiale de range [0, 1]</param>
        /// <param name="lowNoise">Bruit "low"</param>
        /// <param name="repNoise">Bruit de répartition</param>
        /// <param name="vBuffer">Vertex buffer en du mesh créé en sortie.</param>
        /// <param name="chunkGeography">Informations de sortie concernant la géographie du morceau généré.</param>
        /// <param name="planetPosition">Position de la planète.</param>
        /// <param name="radius">Rayon de la planète.</param>
        /// <returns></returns>
        public static void GeneratePlanet(Vector3 planetPosition,
                                          float radius,
                                          int gridSize,
                                          Vector2 initialGridPos,
                                          float gridLevelScale,
                                          Noise.NoiseBase lowNoise,
                                          Noise.NoiseBase highNoise,
                                          Noise.NoiseBase repNoise,
                                          out SlimDX.Direct3D11.Buffer vBuffer,
                                          out BoundingBox aabb,
                                          out ChunkAltitude geo)
        {
            // Geography
            geo = new ChunkAltitude();

            // Taille du buffer.
            int        size           = gridSize * gridSize;
            const bool computeNormals = true;
            Vector3    min            = new Vector3(float.MaxValue);
            Vector3    max            = new Vector3(float.MinValue);

            // Création du vertex buffer contenant tous les vertex à dessiner.
            VWrapper[] vertexBuffer = new VWrapper[size];

            // Texture noise
            Noise.NoiseMapGenerator.NoiseParameters p = new Noise.NoiseMapGenerator.NoiseParameters()
            {
                Frequency   = 128.0f,
                Lacunarity  = 2.5f,
                NoiseEnd    = new Vector2(initialGridPos.X + gridLevelScale, initialGridPos.Y + gridLevelScale),
                NoiseStart  = new Vector2(initialGridPos.X, initialGridPos.Y),
                NoiseType   = Noise.NoiseMapGenerator.NoiseParameters.RIDGED_ID,
                Persistence = 0.94f,
                Seed        = 456464560
            };
            Noise.NoiseBase texNoise = p.CreateNoise();

            float   theta, phi;
            Vector3 transformedPos;

            for (int y = 0; y < gridSize; y++)
            {
                for (int x = 0; x < gridSize; x++)
                {
                    // Cette section a pour but de calculer la normale par rapport au "sol" de la planète, pour cela
                    // Elle calcule les positions des verte
                    Vector2 pos2D = new Vector2(x / ((float)gridSize - 1),
                                                (y / ((float)gridSize - 1)));

                    // Transformation en sphère.
                    float noisePosX = initialGridPos.X + pos2D.X * gridLevelScale;
                    float noisePosY = initialGridPos.Y + pos2D.Y * gridLevelScale;
                    phi   = (noisePosX) * (float)Math.PI * 2;
                    theta = (noisePosY) * (float)Math.PI;


                    // TODO : optimiser pour éviter les calculs redondants.
                    transformedPos = Util.SphericalCoords.ToCartesian(theta, phi, radius);//new Vector3(xSph, ySph, zSph);


                    // Création de la normale au sol.
                    Vector3 normal = Vector3.Normalize(transformedPos);

                    // Valeur du bruit
                    float noiseValue = Noise.NoiseMapGenerator.GetMultiNoiseValue(repNoise, highNoise, lowNoise,
                                                                                  transformedPos.X / radius, transformedPos.Y / radius, transformedPos.Z / radius);
                    float tNoiseValue = texNoise.GetValue(transformedPos.X / radius, transformedPos.Y / radius, transformedPos.Z / radius);

                    // Création de la position finale
                    Vector3 finalPos = transformedPos + normal * noiseValue;
                    Vector4 pos      = new Vector4(finalPos, 1.0f);

                    // Informations de géométrie.
                    min             = Util.MathHelper.Min(finalPos, min);
                    max             = Util.MathHelper.Max(finalPos, max);
                    geo.MinAltitude = Math.Min(noiseValue, geo.MinAltitude);
                    geo.MaxAltitude = Math.Max(noiseValue, geo.MaxAltitude);

                    // Ajout des données dans le VBuffer.
                    int index = (x + y * gridSize);

                    vertexBuffer[index] = new VWrapper();
                    vertexBuffer[index].SphereNormal = normal;

                    // Position 3D du point avec displacement.
                    vertexBuffer[index].Vertex.Position = pos;
                    // Position 3D du point sans displacement.
                    vertexBuffer[index].Vertex.SpherePosition = new Vector4(transformedPos, 1.0f);
                    vertexBuffer[index].Vertex.SphereNormal   = new Vector4(normal, 1.0f);
                    // Coordonnées de texture.
                    vertexBuffer[index].Vertex.Texture  = new Vector2(noisePosX, noisePosY);
                    vertexBuffer[index].Vertex.Normal   = new Vector4(0);
                    vertexBuffer[index].Vertex.Altitude = noiseValue;

                    // Valeurs additionnelles.
                    vertexBuffer[index].Vertex.TextureId = tNoiseValue;
                }
            }


            // Index buffer contenant l'ordre dans lequel dessiner les vertex. (sous forme de carrés).
            int iBufferSize = (gridSize - 1) * (gridSize - 1) * 6;

            int[] indexBuffer = GetIndexBufferCpu(gridSize);
            if (computeNormals)
            {
                //Thread.Sleep(1);
                for (int i = 0; i < indexBuffer.Length / 3; i++)
                {
                    Vector4 firstvec  = vertexBuffer[indexBuffer[i * 3 + 1]].Vertex.Position - vertexBuffer[indexBuffer[i * 3]].Vertex.Position;
                    Vector4 secondvec = vertexBuffer[indexBuffer[i * 3]].Vertex.Position - vertexBuffer[indexBuffer[i * 3 + 2]].Vertex.Position;
                    Vector4 normal    = new Vector4(Vector3.Cross(
                                                        new Vector3(firstvec.X, firstvec.Y, firstvec.Z),
                                                        new Vector3(secondvec.X, secondvec.Y, secondvec.Z)), 1.0f);
                    normal.Normalize();
                    vertexBuffer[indexBuffer[(i * 3)]].Vertex.Normal     += normal;
                    vertexBuffer[indexBuffer[(i * 3 + 1)]].Vertex.Normal += normal;
                    vertexBuffer[indexBuffer[(i * 3 + 2)]].Vertex.Normal += normal;
                }
                for (int i = 0; i < vertexBuffer.Length; i++)
                {
                    var v = Util.MathHelper.ReduceXYZ(vertexBuffer[i].Vertex.Normal);
                    v.Normalize();
                    vertexBuffer[i].Vertex.Normal       = new Vector4(v, 1.0f);
                    vertexBuffer[i].Vertex.SphereNormal = new Vector4(Util.MathHelper.ReduceXYZ(vertexBuffer[i].Vertex.Normal) - vertexBuffer[i].SphereNormal, 1.0f);
                }
            }

            // Création des buffers.
            DataStream vBuffStream = new DataStream(size * Vertex.Stride, true, true);

            for (int i = 0; i < size; i++)
            {
                vBuffStream.Write <Vertex>(vertexBuffer[i].Vertex);
            }
            vBuffStream.Position = 0;

            vBuffer = new SlimDX.Direct3D11.Buffer(Scene.GetGraphicsDevice(), vBuffStream, new BufferDescription()
            {
                BindFlags      = BindFlags.VertexBuffer,
                CpuAccessFlags = CpuAccessFlags.None,
                OptionFlags    = ResourceOptionFlags.None,
                SizeInBytes    = (int)vBuffStream.Length,
                Usage          = ResourceUsage.Default
            });


            vBuffStream.Dispose();

            aabb = new BoundingBox(min, max);
        }