/// <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); }
/// <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); }