Terrain.pas 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. unit Terrain;
  2. interface
  3. uses
  4. Noise, Matrix, MemoryBuffer,
  5. GLTypes, GLUtils,
  6. WebGL, JS,
  7. Math;
  8. type
  9. TTerrain = class (TObject)
  10. public
  11. constructor Create (context: TJSWebGLRenderingContext; size, resolution: integer); overload;
  12. constructor Create (context: TJSWebGLRenderingContext; inNoise: TNoise; size, resolution: integer; offset: TVec2); overload;
  13. function GetHeightAtPoint (x, y: integer): single;
  14. function GetWidth: integer;
  15. function GetHeight: integer;
  16. procedure Draw;
  17. procedure Generate;
  18. protected
  19. noise: TNoise;
  20. function GetHeightForVertex (localX, localY, x, y: integer): TNoiseFloat; virtual;
  21. private
  22. gl: TJSWebGLRenderingContext;
  23. noiseOffset: TVec2;
  24. terrainSize: integer;
  25. terrainResolution: integer;
  26. heights: TMatrix;
  27. model: TModel;
  28. function CalculateNormal (localX, localY, x, y: integer): TVec3;
  29. end;
  30. implementation
  31. procedure TTerrain.Draw;
  32. begin
  33. model.Draw;
  34. end;
  35. function TTerrain.GetWidth: integer;
  36. begin
  37. result := heights.GetWidth;
  38. end;
  39. function TTerrain.GetHeight: integer;
  40. begin
  41. result := heights.GetHeight;
  42. end;
  43. function TTerrain.GetHeightAtPoint (x, y: integer): single;
  44. begin
  45. result := TNoiseFloat(heights.GetValue(x, y));
  46. end;
  47. function TTerrain.GetHeightForVertex (localX, localY, x, y: integer): TNoiseFloat;
  48. begin
  49. result := noise.GetNoise(x, y, heights.GetWidth, heights.GetHeight, 4, 3);
  50. result := Power(result, 5);
  51. result := (result * 20) - 6;
  52. end;
  53. function TTerrain.CalculateNormal (localX, localY, x, y: integer): TVec3;
  54. var
  55. heightL, heightR, heightD, heightU: TNoiseFloat;
  56. begin
  57. heightL := GetHeightForVertex(localX, localY, x-1, y);
  58. heightR := GetHeightForVertex(localX, localY, x+1, y);
  59. heightD := GetHeightForVertex(localX, localY, x, y-1);
  60. heightU := GetHeightForVertex(localX, localY, x, y+1);
  61. result := V3(heightL-heightR, 2.0, heightD - heightU);
  62. result := Normalize(result);
  63. end;
  64. procedure TTerrain.Generate;
  65. var
  66. vertex: TModelVertex;
  67. topLeft: integer;
  68. topRight: integer;
  69. bottomLeft: integer;
  70. bottomRight: integer;
  71. x, y, gz, gx: integer;
  72. verticies: TJSArray;
  73. indicies: TJSArray;
  74. data: TModelData;
  75. begin
  76. if noise = nil then
  77. noise := TNoise.Create(RandomNoiseSeed(1));
  78. heights := TMatrix.Create(terrainResolution, terrainResolution);
  79. verticies := TJSArray.new;
  80. indicies := TJSArray.new;
  81. for y := 0 to heights.GetWidth - 1 do
  82. for x := 0 to heights.GetHeight - 1 do
  83. begin
  84. vertex.pos.x := x/(heights.GetWidth - 1) * terrainSize;
  85. vertex.pos.y := GetHeightForVertex(x, y, Trunc(noiseOffset.x) + x, Trunc(noiseOffset.y) + y);
  86. vertex.pos.z := y/(heights.GetHeight - 1) * terrainSize;
  87. heights.SetValue(x, y, vertex.pos.y);
  88. vertex.normal := CalculateNormal(x, y, Trunc(noiseOffset.x) + x, Trunc(noiseOffset.y) + y);
  89. // distribute linearly between 0-1
  90. vertex.texCoord.x := x/(heights.GetWidth - 1);
  91. vertex.texCoord.y := y/(heights.GetHeight - 1);
  92. ModelVertexAddToArray(vertex, verticies);
  93. end;
  94. for gz := 0 to heights.GetWidth - 2 do
  95. for gx := 0 to heights.GetHeight - 2 do
  96. begin
  97. topLeft := (gz*heights.GetWidth)+gx;
  98. topRight := topLeft + 1;
  99. bottomLeft := ((gz+1)*heights.GetWidth)+gx;
  100. bottomRight := bottomLeft + 1;
  101. indicies.push(topLeft);
  102. indicies.push(bottomLeft);
  103. indicies.push(topRight);
  104. indicies.push(topRight);
  105. indicies.push(bottomLeft);
  106. indicies.push(bottomRight);
  107. end;
  108. data.verticies := TJSFloat32Array.New(TJSObject(verticies));
  109. data.indicies := TJSUint16Array.New(TJSObject(indicies));
  110. data.floatsPerVertex := kModelVertexFloats;
  111. model := TModel.Create(gl, data);
  112. end;
  113. constructor TTerrain.Create (context: TJSWebGLRenderingContext; inNoise: TNoise; size, resolution: integer; offset: TVec2);
  114. begin
  115. gl := context;
  116. noise := inNoise;
  117. noiseOffset := offset;
  118. terrainSize := size;
  119. terrainResolution := resolution;
  120. end;
  121. constructor TTerrain.Create (context: TJSWebGLRenderingContext; size, resolution: integer);
  122. begin
  123. gl := context;
  124. noiseOffset := V2(0, 0);
  125. terrainSize := size;
  126. terrainResolution := resolution;
  127. end;
  128. end.