/// <summary> /// Génère un modèle 3D à partir d'une heightmap. /// Range : [0, 1] /// </summary> /// <param name="heightmap"></param> /// <returns></returns> public static void GenerateVertexBufferWithTransformFlat(float[,] heightmap, out SlimDX.Direct3D11.Buffer vBuffer, out SlimDX.Direct3D11.Buffer iBuffer, Matrix transform, Vector2 initialGridPos, float gridLevelScale) { // Taille du buffer. int size = heightmap.GetLength(0) * heightmap.GetLength(1); // Création du vertex buffer contenant tous les vertex à dessiner. Vertex[] vertexBuffer = new Vertex[size]; Noise.RidgedMultifractalNoise noise = new Noise.RidgedMultifractalNoise() { Frequency = 0.00400f, Lacunarity = 2.4f, OctaveCount = 2, Persistence = 0.9f, Quality = Noise.NoiseBase.NoiseQuality.QUALITY_FAST, Seed = 56549970 }; for (int y = 0; y < heightmap.GetLength(1); y++) { for (int x = 0; x < heightmap.GetLength(0); x++) { Vector2 pos2D = new Vector2(x / ((float)heightmap.GetLength(0) - 1), (y / ((float)heightmap.GetLength(1) - 1))); Vector4 pos = Vector4.Transform(new Vector4(pos2D.X, pos2D.Y, heightmap[x, y], 1.0f), transform); vertexBuffer[(x + y * heightmap.GetLength(0))].Position = pos; vertexBuffer[(x + y * heightmap.GetLength(0))].Texture = new Vector2(pos.X, pos.Y); float texGen = noise.GetValue(pos.X, pos.Y, 0); vertexBuffer[(x + y * heightmap.GetLength(0))].TextureId = texGen; } } //Thread.Sleep(1); // Index buffer contenant l'ordre dans lequel dessiner les vertex. (sous forme de carrés). int iBufferSize = (heightmap.GetLength(0) - 1) * (heightmap.GetLength(1) - 1) * 6; int[] indexBuffer = new int[iBufferSize]; int sizeX = heightmap.GetLength(0); int sizeY = heightmap.GetLength(1); int startIndex = 0; for (int x = 0; x < sizeX - 1; x++) { for (int y = 0; y < sizeY - 1; y++) { int firstIndex = x + y * (sizeX); int topLeft = firstIndex; int topRight = firstIndex + 1; int lowerLeft = topLeft + sizeX; int lowerRight = lowerLeft + 1; // Triangle 1 (up right) indexBuffer[startIndex++] = topLeft; indexBuffer[startIndex++] = lowerRight; indexBuffer[startIndex++] = lowerLeft; // Triangle 2 (bottom left) indexBuffer[startIndex++] = topLeft; indexBuffer[startIndex++] = topRight; indexBuffer[startIndex++] = lowerRight; } } //Thread.Sleep(1); // Calcule les normales aux surfaces. // Merci Riemer's XNA Tutorial :D for (int i = 0; i < vertexBuffer.Length; i++) vertexBuffer[i].Normal = new Vector4(0, 0, 0, 0); //Thread.Sleep(1); for (int i = 0; i < indexBuffer.Length / 3; i++) { Vector4 firstvec = vertexBuffer[indexBuffer[i * 3 + 1]].Position - vertexBuffer[indexBuffer[i * 3]].Position; Vector4 secondvec = vertexBuffer[indexBuffer[i * 3]].Position - vertexBuffer[indexBuffer[i * 3 + 2]].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)]].Normal += normal; vertexBuffer[indexBuffer[(i * 3 + 1)]].Normal += normal; vertexBuffer[indexBuffer[(i * 3 + 2)]].Normal += normal; } //Thread.Sleep(1); for (int i = 0; i < vertexBuffer.Length; i++) { vertexBuffer[i].Normal.Z = vertexBuffer[i].Normal.Z; var v = Util.MathHelper.ReduceXYZ(vertexBuffer[i].Normal); v.Normalize(); vertexBuffer[i].Normal = new Vector4(v, 1.0f); } //Thread.Sleep(1); DataStream vBuffStream = new DataStream(size * Vertex.Stride, true, true); vBuffStream.WriteRange<Vertex>(vertexBuffer); vBuffStream.Position = 0; //Thread.Sleep(1); DataStream iBuffStream = new DataStream(iBufferSize * sizeof(int), true, true); iBuffStream.WriteRange<int>(indexBuffer); iBuffStream.Position = 0; //Thread.Sleep(1); 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 }); iBuffer = new SlimDX.Direct3D11.Buffer(Scene.GetGraphicsDevice(), iBuffStream, new BufferDescription() { BindFlags = BindFlags.IndexBuffer, CpuAccessFlags = CpuAccessFlags.None, OptionFlags = ResourceOptionFlags.None, SizeInBytes = (int)iBuffStream.Length, Usage = ResourceUsage.Default }); vBuffStream.Dispose(); iBuffStream.Dispose(); }
/// <summary> /// Génère un modèle 3D à partir d'une heightmap. /// Range : [0, 1] /// </summary> /// <param name="heightmap"></param> /// <returns></returns> public static void GenerateVertexBufferWithTransformFlat(float[,] heightmap, out SlimDX.Direct3D11.Buffer vBuffer, out SlimDX.Direct3D11.Buffer iBuffer, Matrix transform, Vector2 initialGridPos, float gridLevelScale) { // Taille du buffer. int size = heightmap.GetLength(0) * heightmap.GetLength(1); // Création du vertex buffer contenant tous les vertex à dessiner. Vertex[] vertexBuffer = new Vertex[size]; Noise.RidgedMultifractalNoise noise = new Noise.RidgedMultifractalNoise() { Frequency = 0.00400f, Lacunarity = 2.4f, OctaveCount = 2, Persistence = 0.9f, Quality = Noise.NoiseBase.NoiseQuality.QUALITY_FAST, Seed = 56549970 }; for (int y = 0; y < heightmap.GetLength(1); y++) { for (int x = 0; x < heightmap.GetLength(0); x++) { Vector2 pos2D = new Vector2(x / ((float)heightmap.GetLength(0) - 1), (y / ((float)heightmap.GetLength(1) - 1))); Vector4 pos = Vector4.Transform(new Vector4(pos2D.X, pos2D.Y, heightmap[x, y], 1.0f), transform); vertexBuffer[(x + y * heightmap.GetLength(0))].Position = pos; vertexBuffer[(x + y * heightmap.GetLength(0))].Texture = new Vector2(pos.X, pos.Y); float texGen = noise.GetValue(pos.X, pos.Y, 0); vertexBuffer[(x + y * heightmap.GetLength(0))].TextureId = texGen; } } //Thread.Sleep(1); // Index buffer contenant l'ordre dans lequel dessiner les vertex. (sous forme de carrés). int iBufferSize = (heightmap.GetLength(0) - 1) * (heightmap.GetLength(1) - 1) * 6; int[] indexBuffer = new int[iBufferSize]; int sizeX = heightmap.GetLength(0); int sizeY = heightmap.GetLength(1); int startIndex = 0; for (int x = 0; x < sizeX - 1; x++) { for (int y = 0; y < sizeY - 1; y++) { int firstIndex = x + y * (sizeX); int topLeft = firstIndex; int topRight = firstIndex + 1; int lowerLeft = topLeft + sizeX; int lowerRight = lowerLeft + 1; // Triangle 1 (up right) indexBuffer[startIndex++] = topLeft; indexBuffer[startIndex++] = lowerRight; indexBuffer[startIndex++] = lowerLeft; // Triangle 2 (bottom left) indexBuffer[startIndex++] = topLeft; indexBuffer[startIndex++] = topRight; indexBuffer[startIndex++] = lowerRight; } } //Thread.Sleep(1); // Calcule les normales aux surfaces. // Merci Riemer's XNA Tutorial :D for (int i = 0; i < vertexBuffer.Length; i++) { vertexBuffer[i].Normal = new Vector4(0, 0, 0, 0); } //Thread.Sleep(1); for (int i = 0; i < indexBuffer.Length / 3; i++) { Vector4 firstvec = vertexBuffer[indexBuffer[i * 3 + 1]].Position - vertexBuffer[indexBuffer[i * 3]].Position; Vector4 secondvec = vertexBuffer[indexBuffer[i * 3]].Position - vertexBuffer[indexBuffer[i * 3 + 2]].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)]].Normal += normal; vertexBuffer[indexBuffer[(i * 3 + 1)]].Normal += normal; vertexBuffer[indexBuffer[(i * 3 + 2)]].Normal += normal; } //Thread.Sleep(1); for (int i = 0; i < vertexBuffer.Length; i++) { vertexBuffer[i].Normal.Z = vertexBuffer[i].Normal.Z; var v = Util.MathHelper.ReduceXYZ(vertexBuffer[i].Normal); v.Normalize(); vertexBuffer[i].Normal = new Vector4(v, 1.0f); } //Thread.Sleep(1); DataStream vBuffStream = new DataStream(size * Vertex.Stride, true, true); vBuffStream.WriteRange <Vertex>(vertexBuffer); vBuffStream.Position = 0; //Thread.Sleep(1); DataStream iBuffStream = new DataStream(iBufferSize * sizeof(int), true, true); iBuffStream.WriteRange <int>(indexBuffer); iBuffStream.Position = 0; //Thread.Sleep(1); 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 }); iBuffer = new SlimDX.Direct3D11.Buffer(Scene.GetGraphicsDevice(), iBuffStream, new BufferDescription() { BindFlags = BindFlags.IndexBuffer, CpuAccessFlags = CpuAccessFlags.None, OptionFlags = ResourceOptionFlags.None, SizeInBytes = (int)iBuffStream.Length, Usage = ResourceUsage.Default }); vBuffStream.Dispose(); iBuffStream.Dispose(); }