You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

199 lines
5.7 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. import { mat4, vec3, vec4 } from "gl-matrix";
  2. import { Corner, GAT, Tile } from "../format/gat";
  3. import { createProgram, createShader, ShaderType } from "../util/render";
  4. /* @ts-ignore */
  5. import fragmentSource from "./gat.frag";
  6. /* @ts-ignore */
  7. import vertexSource from "./gat.vert";
  8. const ORIGIN = vec4.fromValues(0, 0, 0, 1);
  9. const UP = vec3.fromValues(0, 1, 0);
  10. const printMat4 = (name: string, m: mat4) => {
  11. console.log(name);
  12. console.log([m[0], m[4], m[8], m[12]]);
  13. console.log([m[1], m[5], m[9], m[13]]);
  14. console.log([m[2], m[6], m[10], m[11]]);
  15. console.log([m[3], m[7], m[14], m[15]]);
  16. };
  17. // Function to download data to a file
  18. function download(data: BlobPart, filename: string, type: string) {
  19. var file = new Blob([data], { type: type });
  20. // Others
  21. var a = document.createElement("a"),
  22. url = URL.createObjectURL(file);
  23. a.href = url;
  24. a.download = filename;
  25. document.body.appendChild(a);
  26. a.click();
  27. setTimeout(function () {
  28. document.body.removeChild(a);
  29. window.URL.revokeObjectURL(url);
  30. }, 0);
  31. }
  32. const exportObj = (vertices: number[]): string => {
  33. let obj = "";
  34. for (let i = 0; i < vertices.length / 3; ++i) {
  35. obj += `v ${vertices[i]} ${vertices[i + 1]} ${vertices[i + 2]}\n`;
  36. }
  37. for (let i = 0; i < vertices.length / (3 * 2); ++i) {
  38. obj += `f ${i + 1} ${i + 2} ${i + 3}\n`;
  39. obj += `f ${i + 4} ${i + 5} ${i + 6}\n`;
  40. }
  41. return obj;
  42. };
  43. export const renderGAT = (gl: WebGLRenderingContext, gat: GAT) => {
  44. console.log("gat", gat);
  45. const fragmentShader = createShader(gl, ShaderType.FRAGMENT, fragmentSource);
  46. const vertexShader = createShader(gl, ShaderType.VERTEX, vertexSource);
  47. const program = createProgram(gl, vertexShader, fragmentShader);
  48. gl.useProgram(program);
  49. gl.enable(gl.DEPTH_TEST);
  50. const maxAltitude = getMaxAltitude(gat);
  51. console.log("altitude", maxAltitude);
  52. const camera = vec3.fromValues(
  53. gat.width / 2,
  54. maxAltitude + 10,
  55. gat.height / 2
  56. );
  57. console.log("camera", camera);
  58. const centerX = Math.floor(gat.width / 2);
  59. const centerZ = Math.floor(gat.height / 2);
  60. const centerTile = gat.tiles[gat.width * centerZ + centerX];
  61. const center = vec3.fromValues(centerX, avgTileHeight(centerTile), centerZ);
  62. console.log("center", center);
  63. const model = mat4.create();
  64. mat4.translate(
  65. model,
  66. model,
  67. vec3.fromValues(-camera[0], -camera[1], -camera[2])
  68. );
  69. const view = mat4.create();
  70. mat4.rotateX(view, view, -Math.PI / 2);
  71. // mat4.lookAt(view, camera, center, UP);
  72. const modelview = model;
  73. mat4.multiply(modelview, view, model);
  74. const perspective = mat4.create();
  75. const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
  76. mat4.perspective(perspective, Math.PI / 4, aspect, -0.5, 1000);
  77. const matrix = mat4.create();
  78. mat4.multiply(matrix, modelview, perspective);
  79. const matrixLoc = gl.getUniformLocation(program, "u_matrix");
  80. gl.uniformMatrix4fv(matrixLoc, false, matrix);
  81. printMat4("model", model);
  82. printMat4("view", view);
  83. printMat4("view * model", modelview);
  84. printMat4("projection", perspective);
  85. printMat4("projection * view * model", matrix);
  86. const origin = vec4.create();
  87. vec4.transformMat4(origin, ORIGIN, model);
  88. console.log("origin (model)", origin);
  89. vec4.transformMat4(origin, ORIGIN, modelview);
  90. console.log("origin (modelview)", origin);
  91. vec4.transformMat4(origin, ORIGIN, matrix);
  92. console.log("origin (projection)", origin);
  93. const vertices: number[] = [];
  94. gat.tiles.forEach((tile, i) => {
  95. const x = i % gat.width;
  96. const z = Math.floor(i / gat.width);
  97. const topLeft = [x, tile.altitude[Corner.TOP_LEFT], z];
  98. const topRight = [x + 1, tile.altitude[Corner.TOP_RIGHT], z];
  99. const bottomLeft = [x, tile.altitude[Corner.BOTTOM_LEFT], z + 1];
  100. const bottomRight = [x + 1, tile.altitude[Corner.BOTTOM_RIGHT], z + 1];
  101. vertices.push(
  102. ...topLeft,
  103. ...bottomLeft,
  104. ...topRight,
  105. ...topRight,
  106. ...bottomLeft,
  107. ...bottomRight
  108. );
  109. });
  110. console.log("# vertices", vertices.length / 3);
  111. // download(exportObj(vertices), "heightmap.obj", "text/plain");
  112. let failCount = 0;
  113. for (let i = 0; i < vertices.length / 3; ++i) {
  114. const vec = vec4.fromValues(
  115. vertices[i],
  116. vertices[i + 1],
  117. vertices[i + 2],
  118. 1
  119. );
  120. const result = checkPixelCoord(vec, matrix);
  121. if (result) {
  122. if (failCount < 10) {
  123. console.log("vertex clipped, (pre-xform)", vec, "(post-xform)", result);
  124. }
  125. failCount++;
  126. }
  127. }
  128. console.log("clipCount", failCount);
  129. console.log("totalCount", vertices.length / 3);
  130. const vertexBuffer = gl.createBuffer();
  131. gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  132. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
  133. const positionLoc = gl.getAttribLocation(program, "a_position");
  134. gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  135. gl.vertexAttribPointer(positionLoc, 3, gl.FLOAT, false, 0, 0);
  136. gl.enableVertexAttribArray(positionLoc);
  137. gl.clearColor(0, 0, 0, 1);
  138. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  139. gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  140. gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 3);
  141. };
  142. const checkPixelCoord = (x: vec4, mat: mat4): vec4 | null => {
  143. const vec = vec4.create();
  144. vec4.transformMat4(vec, x, mat);
  145. for (let i = 0; i < vec.length; ++i) {
  146. if (Math.abs(vec[i]) >= 1) {
  147. return vec;
  148. }
  149. }
  150. return null;
  151. };
  152. const getMaxAltitude = (gat: GAT): number =>
  153. gat.tiles.reduce(
  154. (max, tile) =>
  155. Object.values(tile.altitude).reduce(
  156. (max1, altitude) => Math.max(max1, altitude),
  157. max
  158. ),
  159. 0
  160. );
  161. const avgTileHeight = (tile: Tile): number => {
  162. const heights = [...Object.values(tile.altitude)];
  163. const s = heights.reduce((x, y) => x + y, 0);
  164. return s / heights.length;
  165. };