Wasser Wellen-Animation in Monogame

    • .NET (FX) 4.5–4.8
    • C#

    Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von φConst.

      Wasser Wellen-Animation in Monogame

      [UPDATE FÜR SOURCE-CODE AUSTAUSCH]
      @Moderation : Danke sehr ( = !

      Guten Tag liebe Community,
      im Folgenden möchte ich Euch die Source für eine Wellen-Animation in Monogame bereitstellen...

      Es umfasst zwei Klassen, jeweils der WaterManager und eine individuelle Vertex Deklaration ( die ich WaterMolecule nenne ^^ )...

      Die WaterManager-Klasse

      C#-Quellcode

      1. public class WaterManager
      2. {
      3. public GraphicsDevice Device { get; private set; }
      4. public ContentManager Content { get; private set; }
      5. public DynamicVertexBuffer VertexBuffer { get; private set; }
      6. public DynamicIndexBuffer IndexBuffer { get; private set; }
      7. private List<WaterMolecule> mainVertices = new List<WaterMolecule>();
      8. private Dictionary<Vector3, int> hashTable = new Dictionary<Vector3, int>();
      9. private List<int> vertexIndices = new List<int>();
      10. private static Random RAND = new Random();
      11. private Texture2D waterTexture;
      12. private Effect waveEffect;
      13. private float animationTime;
      14. private WaterMolecule[] vertexPuffer;
      15. public WaterManager(GraphicsDevice device, ContentManager content)
      16. {
      17. Device = device;
      18. Content = content;
      19. waterTexture = Content.Load<Texture2D>(@"water");
      20. waveEffect = Content.Load<Effect>(@"wave");
      21. }
      22. public void AddWaterTile(Vector3 position)
      23. {
      24. // ADD VERTICES
      25. var wavefactor = (float)RAND.NextDouble() * 0.35f;
      26. wavefactor = RAND.NextDouble() >= 0.5 ? -wavefactor : wavefactor;
      27. if (vertexPuffer != null)
      28. mainVertices = new List<WaterMolecule>(vertexPuffer);
      29. else mainVertices = new List<WaterMolecule>();
      30. // CORNERS
      31. Vector3 local = position;
      32. Vector3 forward = new Vector3(position.X, position.Y, position.Z + 1);
      33. Vector3 left = new Vector3(position.X + 1, position.Y, position.Z);
      34. Vector3 leftForward = new Vector3(position.X + 1, position.Y, position.Z + 1);
      35. if (!mainVertices.Exists(p => p.Position.Equals(local)))
      36. {
      37. mainVertices.Add(new WaterMolecule(local, Vector3.Zero, new Vector2(position.X, position.Z), new Vector2(wavefactor)));
      38. hashTable.Add(local, mainVertices.Count - 1);
      39. }
      40. if (!mainVertices.Exists(p => p.Position.Equals(forward)))
      41. {
      42. mainVertices.Add(new WaterMolecule(forward, Vector3.Zero, new Vector2(forward.X, forward.Z), new Vector2(wavefactor)));
      43. hashTable.Add(forward, mainVertices.Count - 1);
      44. }
      45. if (!mainVertices.Exists(p => p.Position.Equals(left)))
      46. {
      47. mainVertices.Add(new WaterMolecule(left, Vector3.Zero, new Vector2(left.X, left.Z), new Vector2(wavefactor)));
      48. hashTable.Add(left, mainVertices.Count - 1);
      49. }
      50. if (!mainVertices.Exists(p => p.Position.Equals(leftForward)))
      51. {
      52. mainVertices.Add(new WaterMolecule(leftForward, Vector3.Zero, new Vector2(leftForward.X, leftForward.Z), new Vector2(wavefactor)));
      53. hashTable.Add(leftForward, mainVertices.Count - 1);
      54. }
      55. vertexIndices.Add(hashTable[local]);
      56. vertexIndices.Add(hashTable[left]);
      57. vertexIndices.Add(hashTable[leftForward]);
      58. vertexIndices.Add(hashTable[leftForward]);
      59. vertexIndices.Add(hashTable[forward]);
      60. vertexIndices.Add(hashTable[local]);
      61. ReInitialize();
      62. }
      63. private void ReInitialize()
      64. {
      65. VertexBuffer = new DynamicVertexBuffer(Device, typeof(WaterMolecule), mainVertices.Count, BufferUsage.None);
      66. IndexBuffer = new DynamicIndexBuffer(Device, IndexElementSize.ThirtyTwoBits, vertexIndices.Count, BufferUsage.None);
      67. VertexBuffer.SetData<WaterMolecule>(mainVertices.ToArray());
      68. IndexBuffer.SetData<int>(vertexIndices.ToArray());
      69. vertexPuffer = mainVertices.ToArray();
      70. mainVertices.Clear();
      71. }
      72. private void SetUpN()
      73. {
      74. Task.Run(() =>
      75. {
      76. for (int i = 0; i < vertexPuffer.Length; i++)
      77. {
      78. WaterMolecule molecule = vertexPuffer[i];
      79. float waveFactor = molecule.WaveFactor.X;
      80. Vector3 suVector = molecule.Position;
      81. Vector3 aVector = Vector3.Zero;
      82. Vector3 bVecot = Vector3.Zero;
      83. int index0 = 0;
      84. int index1 = 0;
      85. var a = hashTable.TryGetValue(new Vector3(suVector.X + 1, suVector.Y, suVector.Z), out index0);
      86. var b = hashTable.TryGetValue(new Vector3(suVector.X, suVector.Y, suVector.Z + 1), out index1);
      87. if (a)
      88. aVector = vertexPuffer[index0].Position;
      89. if (b)
      90. bVecot = vertexPuffer[index1].Position;
      91. suVector.Y += 0.35f * (float)(Math.Sin(animationTime * waveFactor));
      92. Vector3 dir0 = aVector - suVector;
      93. Vector3 dir1 = bVecot - suVector;
      94. Vector3 n = Vector3.Cross(dir0, dir1);
      95. molecule.Normal = n * n;
      96. vertexPuffer[i] = molecule;
      97. }
      98. });
      99. }
      100. public void Update(GameTime gTime)
      101. {
      102. animationTime += 25.0f * (float)gTime.ElapsedGameTime.TotalSeconds;
      103. SetUpN();
      104. waveEffect.Parameters["GlobalTime"].SetValue(animationTime);
      105. }
      106. public void Render(Matrix view, Matrix projection, Matrix world)
      107. {
      108. if (VertexBuffer == null)
      109. return;
      110. Task.Run(() =>
      111. {
      112. VertexBuffer.SetData<WaterMolecule>(vertexPuffer);
      113. });
      114. Device.SetVertexBuffer(VertexBuffer);
      115. Device.Indices = IndexBuffer;
      116. waveEffect.CurrentTechnique = waveEffect.Techniques["main"];
      117. waveEffect.Parameters["Texture0"].SetValue(waterTexture);
      118. waveEffect.Parameters["World"].SetValue(world);
      119. waveEffect.Parameters["View"].SetValue(view);
      120. waveEffect.Parameters["Projection"].SetValue(projection);
      121. waveEffect.Parameters["WorldInverseTranspose"].SetValue(Matrix.Transpose(Matrix.Invert(world)));
      122. waveEffect.CurrentTechnique.Passes[0].Apply();
      123. Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexPuffer.Length * 2);
      124. }
      125. }


      WaterMolecule-Vertex-Deklaration:

      C#-Quellcode

      1. [StructLayout(LayoutKind.Sequential, Pack = 1)]
      2. public struct WaterMolecule : IVertexType
      3. {
      4. private static VertexDeclaration VertexPositionMolecule = new VertexDeclaration
      5. (
      6. new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
      7. new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0),
      8. new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
      9. new VertexElement(32, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 1)
      10. );
      11. public VertexDeclaration VertexDeclaration
      12. {
      13. get { return VertexPositionMolecule; }
      14. }
      15. public Vector3 Position;
      16. public Vector3 Normal;
      17. public Vector2 TextureCoordinate;
      18. public Vector2 WaveFactor;
      19. public WaterMolecule(Vector3 position, Vector3 normal, Vector2 textureCoordinate, Vector2 wavefac)
      20. : this()
      21. {
      22. Position = position;
      23. Normal = normal;
      24. TextureCoordinate = textureCoordinate;
      25. WaveFactor = wavefac;
      26. }
      27. }


      Die HLSL Klasse:

      C#-Quellcode

      1. #if OPENGL
      2. #define VS_SHADERMODEL vs_4_0
      3. #define PS_SHADERMODEL ps_4_0
      4. #else
      5. #define VS_SHADERMODEL vs_4_0_level_9_1
      6. #define PS_SHADERMODEL ps_4_0_level_9_1
      7. #endif
      8. float4x4 World;
      9. float4x4 View;
      10. float4x4 Projection;
      11. Texture Texture0;
      12. sampler Sampler0 = sampler_state {
      13. Texture = (Texture0);
      14. MinFilter = Linear;
      15. MagFilter = Linear;
      16. AddressU = Clamp;
      17. AddressV = Clamp;
      18. };
      19. float GlobalTime;
      20. float4 AmbientColor = float4(1, 1, 1, 1);
      21. float AmbientIntensity = 0.1;
      22. float4x4 WorldInverseTranspose;
      23. float3 DiffuseLightDirection = float3(1, 0, 0);
      24. float4 DiffuseColor = float4(1, 1, 1, 1);
      25. float DiffuseIntensity = 5;
      26. float Shininess = 450;
      27. float4 SpecularColor = float4(1, 1, 1, 1);
      28. float SpecularIntensity = .15f;
      29. float3 ViewVector = float3(1, 0, .1f);
      30. struct VertexShaderInput
      31. {
      32. float4 Position : POSITION0;
      33. float4 Normal : NORMAL0;
      34. float2 TextureCoordinates : TEXCOORD0;
      35. float2 WaveValue: TEXCOORD1;
      36. };
      37. struct VertexShaderOutput
      38. {
      39. float4 Position : POSITION0;
      40. float2 TextureCoordinates : TEXCOORD0;
      41. float3 Normal : TEXCOORD1;
      42. float4 Color : COLOR0;
      43. };
      44. VertexShaderOutput MainVS(VertexShaderInput input)
      45. {
      46. VertexShaderOutput output;
      47. float4 worldPosition = mul(input.Position, World);
      48. float4 viewPosition = mul(worldPosition, View);
      49. float4 pos = mul(viewPosition, Projection);
      50. output.Position = float4(pos.x, pos.y + 0.45f * sin(GlobalTime * input.WaveValue.x), pos.z, pos.w);
      51. float4 normal = normalize(mul(input.Normal, WorldInverseTranspose));
      52. float lightIntensity = dot(normal, float4(DiffuseLightDirection.x,DiffuseLightDirection.y,DiffuseLightDirection.z, .3f));
      53. output.Color = saturate(DiffuseColor * DiffuseIntensity * lightIntensity);
      54. output.Normal = float3(input.Normal.x, input.Normal.y, input.Normal.z);
      55. output.TextureCoordinates = input.TextureCoordinates;
      56. return output;
      57. }
      58. float4 MainPS(VertexShaderOutput input) : COLOR
      59. {
      60. float3 light = normalize(DiffuseLightDirection);
      61. float3 normal = normalize(input.Normal);
      62. float3 r = normalize(2 * dot(light, normal) * normal - light);
      63. float4 multiplication = mul(normalize(float4(ViewVector.x,ViewVector.y,ViewVector.z,1)), World);
      64. float3 v = normalize(multiplication.xyz);
      65. float dotProduct = dot(r, v.xyz);
      66. float4 specular = SpecularIntensity * SpecularColor * max(pow(abs(dotProduct), Shininess), 0) * length(input.Color);
      67. float4 textureColor = tex2D(Sampler0, input.TextureCoordinates);
      68. textureColor.a = .35f;
      69. return saturate(textureColor * (input.Color) + AmbientColor * AmbientIntensity + specular);
      70. }
      71. technique main
      72. {
      73. pass P0
      74. {
      75. VertexShader = compile VS_SHADERMODEL MainVS();
      76. PixelShader = compile PS_SHADERMODEL MainPS();
      77. }
      78. };




      Im Anhang ein Exempel ( =
      Dateien
      • WaterWaves.zip

        (452,14 kB, 212 mal heruntergeladen, zuletzt: )
      Und Gott alleine weiß alles am allerbesten und besser.

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „φConst“ ()

      Gibt es einen Grund, dass du das als extra task laufen lässt?
      Bedenke, Tasks starten braucht auch Leistung. Außerdem wartest du nirgends darauf, dass der Task abgeschlossen wird. Ist das so richtig?


      Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
      Mit neuem Task auf einem relativ alten Laptop ~58-60 FPS ohne 28-30.
      Im Moment versuche ich sowieso die Methode im Shader zu implementieren.
      Sollte theoretisch über eine individuelle Vertex Deklaration möglich sein; also die Höhe der beiden anliegenden Vertices in die Grafikkarte zu übertragen und dann eben den Prozess (sinus) für die beiden Vertices zu simulieren.



      Und Gott alleine weiß alles am allerbesten und besser.
      *Würg* Der Versuch die Senkrechte auf der Grafikkarte zu berechnen...: Das Ergebnis ist ** ;
      (eigentlich gar nicht schlecht; eben aber nicht perfekt wie mit der CPU):



      Das Problem ist, dass das Licht scheinbar wabenförmig ist... was ja jedoch nicht sein darf lol.

      Hier die Ausschnitte aus dem Projekt:
      Shader:

      C#-Quellcode

      1. #if OPENGL
      2. #define VS_SHADERMODEL vs_4_0
      3. #define PS_SHADERMODEL ps_4_0
      4. #else
      5. #define VS_SHADERMODEL vs_4_0_level_9_1
      6. #define PS_SHADERMODEL ps_4_0_level_9_1
      7. #endif
      8. float4x4 World;
      9. float4x4 View;
      10. float4x4 Projection;
      11. float4x4 Light;
      12. Texture Texture0;
      13. sampler Sampler0 = sampler_state {
      14. Texture = (Texture0);
      15. MinFilter = Linear;
      16. MagFilter = Linear;
      17. AddressU = Clamp;
      18. AddressV = Clamp;
      19. };
      20. float GlobalTime;
      21. float4 AmbientColor = float4(1, 1, 1, 1);
      22. float AmbientIntensity = 0.1;
      23. float4x4 WorldInverseTranspose;
      24. float3 DiffuseLightDirection = float3(1, 0, .01f);
      25. float4 DiffuseColor = float4(1, 1, 1, 1);
      26. float DiffuseIntensity = 10;
      27. float Shininess = 450;
      28. float4 SpecularColor = float4(1, 1, 1, 1);
      29. float SpecularIntensity = .15f;
      30. float3 ViewVector = float3(1, 0, 0);
      31. struct VertexShaderInput
      32. {
      33. float4 Position : POSITION0;
      34. //float4 Normal : NORMAL0;
      35. float2 TextureCoordinates : TEXCOORD0;
      36. float2 WaveValue: TEXCOORD1;
      37. float2 WaveValue_Right: TEXCOORD2;
      38. float2 WaveValue_Forward: TEXCOORD3;
      39. };
      40. struct VertexShaderOutput
      41. {
      42. float4 Position : POSITION0;
      43. float2 TextureCoordinates : TEXCOORD0;
      44. float3 Normal : TEXCOORD1;
      45. float4 Color : COLOR0;
      46. };
      47. VertexShaderOutput MainVS(VertexShaderInput input)
      48. {
      49. VertexShaderOutput output;
      50. // LOCAL
      51. float4 worldPositionLocal = mul(input.Position, World);
      52. float4 viewPositionLocal = mul(worldPositionLocal, Light);
      53. float4 posLocal = mul(viewPositionLocal, Projection);
      54. float4 vecO = float4(posLocal.x, posLocal.y + 0.45f * cos(GlobalTime * input.WaveValue.x), posLocal.z, posLocal.w);
      55. //RIGHT
      56. float4 worldPositionU = mul(float4(input.Position.x + 1, input.Position.y, input.Position.z, input.Position.w), World);
      57. float4 viewPositionU = mul(worldPositionU, Light);
      58. float4 posU = mul(viewPositionU, Projection);
      59. float4 vecU = float4(posU.x, posU.y + 0.45f * cos(GlobalTime * input.WaveValue_Right.x), posU.z, posU.w);
      60. // FORWARD
      61. float4 worldPositionV = mul(float4(input.Position.x, input.Position.y, input.Position.z + 1, input.Position.w), World);
      62. float4 viewPositionV = mul(worldPositionV, Light);
      63. float4 posV = mul(viewPositionV, Projection);
      64. float4 vecV = float4(posV.x, posV.y + 0.45f * cos(GlobalTime * input.WaveValue_Forward.x), posV.z, posV.w);
      65. // DIRECTIONS
      66. float4 directU = vecU - vecO;
      67. float4 directV = vecV - vecO;
      68. // CROSS
      69. float3 crossVec = cross(directU, directV);
      70. float3 vecN = crossVec * crossVec * crossVec* crossVec;
      71. // ---
      72. worldPositionLocal = mul(input.Position, World);
      73. viewPositionLocal = mul(worldPositionLocal, View);
      74. posLocal = mul(viewPositionLocal, Projection);
      75. vecO = float4(posLocal.x, posLocal.y + 0.45f * cos(GlobalTime * input.WaveValue.x), posLocal.z, posLocal.w);
      76. output.Position = vecO;
      77. float4 normal = normalize(mul(float4(vecN.x, vecN.y, vecN.z, 1), WorldInverseTranspose));
      78. float lightIntensity = dot(normal, float4(DiffuseLightDirection.x,DiffuseLightDirection.y,DiffuseLightDirection.z, .3f));
      79. output.Color = saturate(DiffuseColor * DiffuseIntensity * lightIntensity);
      80. output.Normal = float3(vecN.x, vecN.y, vecN.z);
      81. output.TextureCoordinates = input.TextureCoordinates;
      82. return output;
      83. }
      84. float4 MainPS(VertexShaderOutput input) : COLOR
      85. {
      86. float3 light = normalize(DiffuseLightDirection);
      87. float3 normal = normalize(input.Normal);
      88. float3 r = normalize(2 * dot(light, normal) * normal - light);
      89. float4 multiplication = mul(normalize(float4(ViewVector.x,ViewVector.y,ViewVector.z,1)), World);
      90. float3 v = normalize(multiplication.xyz);
      91. float dotProduct = dot(r, v.xyz);
      92. float4 specular = SpecularIntensity * SpecularColor * max(pow(abs(dotProduct), Shininess), 0) * length(input.Color);
      93. float4 textureColor = tex2D(Sampler0, input.TextureCoordinates);
      94. textureColor.a = .35f;
      95. return saturate(textureColor * (input.Color) + AmbientColor * AmbientIntensity + specular);
      96. }
      97. technique main
      98. {
      99. pass P0
      100. {
      101. VertexShader = compile VS_SHADERMODEL MainVS();
      102. PixelShader = compile PS_SHADERMODEL MainPS();
      103. }
      104. };​


      WaterMolecule ( Vertex-Deklaration):

      C#-Quellcode

      1. ​using Microsoft.Xna.Framework;
      2. using Microsoft.Xna.Framework.Graphics;
      3. using Microsoft.Xna.Framework.Input;
      4. using System;
      5. using System.Collections.Generic;
      6. using System.Runtime.InteropServices;
      7. namespace WaterWaves
      8. {
      9. [StructLayout(LayoutKind.Sequential, Pack = 1)]
      10. public struct WaterMolecule : IVertexType
      11. {
      12. private static VertexDeclaration VertexPositionMolecule = new VertexDeclaration
      13. (
      14. new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
      15. new VertexElement(12, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
      16. new VertexElement(20, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 1),
      17. new VertexElement(28, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 2),
      18. new VertexElement(36, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 3)
      19. );
      20. public VertexDeclaration VertexDeclaration
      21. {
      22. get { return VertexPositionMolecule; }
      23. }
      24. public Vector3 Position;
      25. //public Vector3 Normal;
      26. public Vector2 TextureCoordinate;
      27. public Vector2 WaveFactor;
      28. public Vector2 WaveFactor_Right;
      29. public Vector2 WaveFacot_Forward;
      30. public WaterMolecule(Vector3 position, Vector2 textureCoordinate, Vector2 wavefac, Vector2 wavefac_right, Vector2 wavefac_forward)
      31. : this()
      32. {
      33. Position = position;
      34. //Normal = normal;
      35. TextureCoordinate = textureCoordinate;
      36. WaveFactor = wavefac;
      37. WaveFactor_Right = wavefac_right;
      38. WaveFacot_Forward = wavefac_forward;
      39. }
      40. }
      41. }


      WaterManager
      (Ich verwende SimplexNoiseGenerator damit ich auf die Höhen der anliegenden Vertices zugreifen kann):

      C#-Quellcode

      1. public void AddWaterTile(Vector3 position)
      2. {
      3. // ADD VERTICES
      4. var wavefactor = (float)simplex.GetNoise2D((int)position.X, (int)position.Z);
      5. wavefactor *= 0.25f;
      6. var wavefactor_right = (float)simplex.GetNoise2D((int)position.X + 1, (int)position.Z);
      7. wavefactor_right *= 0.25f;
      8. var wavefactor_forward = (float)simplex.GetNoise2D((int)position.X, (int)position.Z + 1);
      9. wavefactor_forward *= 0.25f;
      10. Vector3 local = position;
      11. Vector3 forward = new Vector3(position.X, position.Y, position.Z + 1);
      12. Vector3 left = new Vector3(position.X + 1, position.Y, position.Z);
      13. Vector3 leftForward = new Vector3(position.X + 1, position.Y, position.Z + 1);
      14. if (!hashTable.ContainsKey(local))
      15. {
      16. mainVertices.Add(new WaterMolecule(local, new Vector2(position.X, position.Z), new Vector2(wavefactor), new Vector2(wavefactor_right), new Vector2(wavefactor_forward)));
      17. hashTable.Add(local, mainVertices.Count - 1);
      18. }
      19. if (!hashTable.ContainsKey(forward))
      20. {
      21. mainVertices.Add(new WaterMolecule(forward, new Vector2(forward.X, forward.Z), new Vector2(wavefactor), new Vector2(wavefactor_right), new Vector2(wavefactor_forward)));
      22. hashTable.Add(forward, mainVertices.Count - 1);
      23. }
      24. if (!hashTable.ContainsKey(left))
      25. {
      26. mainVertices.Add(new WaterMolecule(left, new Vector2(left.X, left.Z), new Vector2(wavefactor), new Vector2(wavefactor_right), new Vector2(wavefactor_forward)));
      27. hashTable.Add(left, mainVertices.Count - 1);
      28. }
      29. if (!hashTable.ContainsKey(leftForward))
      30. {
      31. mainVertices.Add(new WaterMolecule(leftForward, new Vector2(leftForward.X, leftForward.Z), new Vector2(wavefactor), new Vector2(wavefactor_right), new Vector2(wavefactor_forward)));
      32. hashTable.Add(leftForward, mainVertices.Count - 1);
      33. }
      34. vertexIndices.Add(hashTable[position]);
      35. vertexIndices.Add(hashTable[left]);
      36. vertexIndices.Add(hashTable[leftForward]);
      37. vertexIndices.Add(hashTable[leftForward]);
      38. vertexIndices.Add(hashTable[forward]);
      39. vertexIndices.Add(hashTable[position]);
      40. }
      Woran mag das liegen?
      Und Gott alleine weiß alles am allerbesten und besser.
      Die Orthogonalen werden nun im Shader berechnet!
      Ein 450 * 450 großer Ozean kann perpetuell bei 55-60 Fps visualisiert werden.

      Der Shader:

      C-Quellcode

      1. #if OPENGL
      2. #define VS_SHADERMODEL vs_4_0
      3. #define PS_SHADERMODEL ps_4_0
      4. #else
      5. #define VS_SHADERMODEL vs_4_0_level_9_1
      6. #define PS_SHADERMODEL ps_4_0_level_9_1
      7. #endif
      8. float4x4 World;
      9. float4x4 View;
      10. float4x4 Projection;
      11. float4x4 Light;
      12. Texture Texture0;
      13. sampler Sampler0 = sampler_state {
      14. Texture = (Texture0);
      15. MinFilter = Linear;
      16. MagFilter = Linear;
      17. AddressU = Clamp;
      18. AddressV = Clamp;
      19. };
      20. float GlobalTime;
      21. float4 AmbientColor = float4(1, 1, 1, 1);
      22. float AmbientIntensity = 0.1;
      23. float4x4 WorldInverseTranspose;
      24. float3 DiffuseLightDirection = float3(1, 0, 0);
      25. float4 DiffuseColor = float4(1, 1, 1, 1);
      26. float DiffuseIntensity = 10;
      27. float Shininess = 450;
      28. float4 SpecularColor = float4(1, 1, 1, 1);
      29. float SpecularIntensity = .15f;
      30. float3 ViewVector = float3(1, 0, 0.1f);
      31. struct VertexShaderInput
      32. {
      33. float4 Position : POSITION0;
      34. float4 Position_Left : POSITION1;
      35. float4 Position_Top : POSITION2;
      36. float2 TextureCoordinates : TEXCOORD0;
      37. float2 WaveValue: TEXCOORD1;
      38. };
      39. struct VertexShaderOutput
      40. {
      41. float4 Position : POSITION0;
      42. float2 TextureCoordinates : TEXCOORD0;
      43. float3 Normal : TEXCOORD1;
      44. float4 Color : COLOR0;
      45. };
      46. VertexShaderOutput MainVS(VertexShaderInput input)
      47. {
      48. VertexShaderOutput output;
      49. // LOCAL
      50. float4 worldPositionLocal = mul(input.Position, World);
      51. float4 viewPositionLocal = mul(worldPositionLocal, Light);
      52. float4 posLocal = mul(viewPositionLocal, Projection);
      53. float4 vecO = float4(posLocal.x, posLocal.y + 0.55f * cos(GlobalTime * input.WaveValue.x), posLocal.z, posLocal.w);
      54. //RIGHT
      55. float4 worldPositionU = mul(input.Position_Left, World);
      56. float4 viewPositionU = mul(worldPositionU, Light);
      57. float4 posU = mul(viewPositionU, Projection);
      58. float4 vecU = posU;
      59. // FORWARD
      60. float4 worldPositionV = mul(input.Position_Top, World);
      61. float4 viewPositionV = mul(worldPositionV, Light);
      62. float4 posV = mul(viewPositionV, Projection);
      63. float4 vecV = posV;
      64. // DIRECTIONS
      65. float4 directU = vecU - vecO;
      66. float4 directV = vecV - vecO;
      67. // CROSS
      68. float3 crossVec = cross(float3(directU.x, directU.y, directU.z), float3(directV.x, directV.y, directV.z));
      69. float3 vecN = crossVec * crossVec;
      70. worldPositionLocal = mul(input.Position, World);
      71. viewPositionLocal = mul(worldPositionLocal, View);
      72. posLocal = mul(viewPositionLocal, Projection);
      73. vecO = float4(posLocal.x, posLocal.y + 0.45f * sin(GlobalTime * input.WaveValue.x), posLocal.z, posLocal.w);
      74. output.Position = vecO;
      75. float4 normal = normalize(mul(float4(vecN.x, vecN.y, vecN.z, 1), WorldInverseTranspose));
      76. float lightIntensity = dot(normal, float4(DiffuseLightDirection.x, DiffuseLightDirection.y, DiffuseLightDirection.z, .3f));
      77. output.Color = saturate(DiffuseColor * DiffuseIntensity * lightIntensity);
      78. output.Normal = float3(vecN.x, vecN.y, vecN.z);
      79. output.TextureCoordinates = input.TextureCoordinates;
      80. return output;
      81. }
      82. float4 MainPS(VertexShaderOutput input) : COLOR
      83. {
      84. float3 light = normalize(DiffuseLightDirection);
      85. float3 normal = normalize(input.Normal);
      86. float3 r = normalize(2 * dot(light, normal) * normal - light);
      87. float4 multiplication = mul(normalize(float4(ViewVector.x, ViewVector.y, ViewVector.z, 1)), World);
      88. float3 v = normalize(multiplication.xyz);
      89. float dotProduct = dot(r, v.xyz);
      90. float4 specular = SpecularIntensity * SpecularColor * max(pow(abs(dotProduct), Shininess), 0) * length(input.Color);
      91. float4 textureColor = tex2D(Sampler0, input.TextureCoordinates);
      92. textureColor.a = .35f;
      93. return saturate(textureColor * (input.Color) + AmbientColor * AmbientIntensity + specular);
      94. }
      95. technique main
      96. {
      97. pass P0
      98. {
      99. VertexShader = compile VS_SHADERMODEL MainVS();
      100. PixelShader = compile PS_SHADERMODEL MainPS();
      101. }
      102. };


      Die neue Vertex Deklaration:

      C#-Quellcode

      1. using Microsoft.Xna.Framework;
      2. using Microsoft.Xna.Framework.Graphics;
      3. using Microsoft.Xna.Framework.Input;
      4. using System;
      5. using System.Collections.Generic;
      6. using System.Runtime.InteropServices;
      7. namespace WaterWaves
      8. {
      9. [StructLayout(LayoutKind.Sequential, Pack = 1)]
      10. public struct WaterMolecule : IVertexType
      11. {
      12. private static VertexDeclaration VertexPositionMolecule = new VertexDeclaration
      13. (
      14. new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
      15. new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Position, 1),
      16. new VertexElement(24, VertexElementFormat.Vector3, VertexElementUsage.Position, 2),
      17. new VertexElement(36, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
      18. new VertexElement(44, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 1)
      19. );
      20. public VertexDeclaration VertexDeclaration
      21. {
      22. get { return VertexPositionMolecule; }
      23. }
      24. public Vector3 Position;
      25. public Vector3 Position_Left;
      26. public Vector3 Position_Top;
      27. public Vector2 TextureCoordinate;
      28. public Vector2 WaveFactor;
      29. public WaterMolecule(Vector3 position, Vector3 pos_left, Vector3 pos_top, Vector2 textureCoordinate, Vector2 wavefac)
      30. : this()
      31. {
      32. Position = position;
      33. Position_Left = pos_left;
      34. Position_Top = pos_top;
      35. TextureCoordinate = textureCoordinate;
      36. WaveFactor = wavefac;
      37. }
      38. }
      39. }



      WaterManager:

      C#-Quellcode

      1. using Microsoft.Xna.Framework;
      2. using Microsoft.Xna.Framework.Content;
      3. using Microsoft.Xna.Framework.Graphics;
      4. using Microsoft.Xna.Framework.Input;
      5. using System;
      6. using System.Collections.Generic;
      7. using System.Runtime.InteropServices;
      8. using System.Threading.Tasks;
      9. namespace WaterWaves
      10. {
      11. public class WaterManager
      12. {
      13. public GraphicsDevice Device { get; private set; }
      14. public ContentManager Content { get; private set; }
      15. public DynamicVertexBuffer VertexBuffer { get; private set; }
      16. public DynamicIndexBuffer IndexBuffer { get; private set; }
      17. private List<WaterMolecule> mainVertices = new List<WaterMolecule>();
      18. private Dictionary<Vector3, int> hashTable = new Dictionary<Vector3, int>();
      19. private List<int> vertexIndices = new List<int>();
      20. private static Random RAND = new Random();
      21. private Texture2D waterTexture;
      22. private Effect waveEffect;
      23. private float animationTime;
      24. private WaterMolecule[] vertexPuffer;
      25. private SimplexNoiseGenerator simplex;
      26. public WaterManager(GraphicsDevice device, ContentManager content)
      27. {
      28. Device = device;
      29. Content = content;
      30. waterTexture = Content.Load<Texture2D>(@"water");
      31. waveEffect = Content.Load<Effect>(@"waves");
      32. simplex = new SimplexNoiseGenerator(299292, 1.0f / 256.0f, 1.0f / 256.0f, 1.0f / 256.0f);
      33. simplex.Factor = 1;
      34. simplex.Sealevel = 1;
      35. simplex.Octaves = 5;
      36. }
      37. public void AddWaterTile(Vector3 position)
      38. {
      39. // ADD VERTICES
      40. var wavefactor = (float)RAND.NextDouble() * 0.35f;
      41. wavefactor = RAND.NextDouble() >= 0.5 ? -wavefactor : wavefactor;
      42. Vector3 local = position;
      43. Vector3 forward = new Vector3(position.X, position.Y, position.Z + 1);
      44. Vector3 left = new Vector3(position.X + 1, position.Y, position.Z);
      45. Vector3 leftForward = new Vector3(position.X + 1, position.Y, position.Z + 1);
      46. if (!hashTable.ContainsKey(local))
      47. {
      48. mainVertices.Add(new WaterMolecule(local, local + Vector3.Right , local + Vector3.Forward, new Vector2(position.X, position.Z), new Vector2(wavefactor)));
      49. hashTable.Add(local, mainVertices.Count - 1);
      50. }
      51. if (!hashTable.ContainsKey(forward))
      52. {
      53. mainVertices.Add(new WaterMolecule(forward, forward + Vector3.Right, forward + Vector3.Forward, new Vector2(position.X, position.Z), new Vector2(wavefactor)));
      54. hashTable.Add(forward, mainVertices.Count - 1);
      55. }
      56. if (!hashTable.ContainsKey(left))
      57. {
      58. mainVertices.Add(new WaterMolecule(left, left + Vector3.Right, left + Vector3.Forward, new Vector2(position.X, position.Z), new Vector2(wavefactor)));
      59. hashTable.Add(left, mainVertices.Count - 1);
      60. }
      61. if (!hashTable.ContainsKey(leftForward))
      62. {
      63. mainVertices.Add(new WaterMolecule(leftForward, leftForward + Vector3.Right, leftForward + Vector3.Forward, new Vector2(position.X, position.Z), new Vector2(wavefactor)));
      64. hashTable.Add(leftForward, mainVertices.Count - 1);
      65. }
      66. vertexIndices.Add(hashTable[position]);
      67. vertexIndices.Add(hashTable[left]);
      68. vertexIndices.Add(hashTable[leftForward]);
      69. vertexIndices.Add(hashTable[leftForward]);
      70. vertexIndices.Add(hashTable[forward]);
      71. vertexIndices.Add(hashTable[position]);
      72. }
      73. public void Initialize()
      74. {
      75. VertexBuffer = new DynamicVertexBuffer(Device, typeof(WaterMolecule), mainVertices.Count, BufferUsage.None);
      76. IndexBuffer = new DynamicIndexBuffer(Device, IndexElementSize.ThirtyTwoBits, vertexIndices.Count, BufferUsage.None);
      77. VertexBuffer.SetData<WaterMolecule>(mainVertices.ToArray());
      78. IndexBuffer.SetData<int>(vertexIndices.ToArray());
      79. vertexPuffer = mainVertices.ToArray();
      80. mainVertices.Clear();
      81. }
      82. public void Update(GameTime gTime)
      83. {
      84. animationTime += 25.0f * (float)gTime.ElapsedGameTime.TotalSeconds;
      85. waveEffect.Parameters["GlobalTime"].SetValue(animationTime);
      86. }
      87. public void Render(Matrix view, Matrix projection, Matrix world)
      88. {
      89. if (VertexBuffer == null)
      90. return;
      91. Task.Run(() =>
      92. {
      93. VertexBuffer.SetData<WaterMolecule>(vertexPuffer);
      94. });
      95. Device.SetVertexBuffer(VertexBuffer);
      96. Device.Indices = IndexBuffer;
      97. waveEffect.CurrentTechnique = waveEffect.Techniques["main"];
      98. waveEffect.Parameters["Texture0"].SetValue(waterTexture);
      99. waveEffect.Parameters["Light"].SetValue(Camera.Light);
      100. waveEffect.Parameters["World"].SetValue(world);
      101. waveEffect.Parameters["View"].SetValue(view);
      102. waveEffect.Parameters["Projection"].SetValue(projection);
      103. waveEffect.Parameters["WorldInverseTranspose"].SetValue(Matrix.Transpose(Matrix.Invert(world)));
      104. waveEffect.CurrentTechnique.Passes[0].Apply();
      105. Device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertexPuffer.Length * 2);
      106. }
      107. }
      108. }
      Und Gott alleine weiß alles am allerbesten und besser.

      Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „φConst“ ()