env.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. import envFragSource from "./shader-env.frag?raw";
  2. import envVertSource from "./shader-env.vert?raw";
  3. import { loadImage } from "@/util";
  4. import { createFPSCamera, createProgram, generateVao, useTex } from "@/util/gl";
  5. import { mat4, glMatrix } from "gl-matrix";
  6. import { setUniforms } from "./setUniform";
  7. const generatePreset = (gl: WebGL2RenderingContext) => {
  8. const skyCubeTex = gl.createTexture();
  9. const updateSky1 = (images: HTMLImageElement[]) => {
  10. gl.bindTexture(gl.TEXTURE_CUBE_MAP, skyCubeTex);
  11. const mapper = [2, 4, 0, 5, 1, 3];
  12. for (let i = 0; i < 6; i++) {
  13. gl.texImage2D(
  14. gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
  15. 0,
  16. gl.RGB,
  17. gl.RGB,
  18. gl.UNSIGNED_BYTE,
  19. images[mapper[i]]
  20. );
  21. }
  22. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  23. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  24. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
  25. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  26. gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  27. gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
  28. gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
  29. };
  30. const updateSky = (image: HTMLImageElement) => {
  31. gl.bindTexture(gl.TEXTURE_2D, skyCubeTex);
  32. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
  33. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  34. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  35. gl.bindTexture(gl.TEXTURE_2D, null);
  36. };
  37. return {
  38. skyCubeTex,
  39. // async preset(urls: string[]) {
  40. // const images = await Promise.all(urls.map(loadImage));
  41. // updateSky(images);
  42. // },
  43. async preset(url: string) {
  44. const image = await loadImage(url);
  45. updateSky(image);
  46. },
  47. };
  48. };
  49. const getDrawVaring = (gl: WebGL2RenderingContext) => {
  50. const positions = new Float32Array([
  51. -1, -1, 1, 1, -1, 1, 1, 1, -1, -1, 1, -1,
  52. ]);
  53. const vao = generateVao(gl, { positions }, [
  54. {
  55. loc: 0,
  56. key: "positions",
  57. size: 2,
  58. type: gl.FLOAT,
  59. stride: 0,
  60. offset: 0,
  61. },
  62. ]);
  63. return {
  64. ...generatePreset(gl),
  65. vao,
  66. numArrays: positions.length / 2,
  67. };
  68. };
  69. export const init = (canvas: HTMLCanvasElement) => {
  70. const size = [canvas.width, canvas.height];
  71. const gl = canvas.getContext("webgl2", { preserveDrawingBuffer: true })!;
  72. const program = createProgram(gl, envVertSource, envFragSource);
  73. const projectionMat = mat4.perspective(
  74. mat4.create(),
  75. glMatrix.toRadian(45),
  76. size[0] / size[1],
  77. 0.1,
  78. 100
  79. );
  80. const invProjectionViewMat = mat4.create();
  81. const viewMat = mat4.create();
  82. const varing = getDrawVaring(gl);
  83. const updateInv = () => {
  84. mat4.multiply(invProjectionViewMat, projectionMat, viewMat);
  85. mat4.invert(invProjectionViewMat, invProjectionViewMat);
  86. };
  87. gl.viewport(0, 0, size[0], size[1]);
  88. const redraw = () => {
  89. gl.clear(gl.COLOR_BUFFER_BIT);
  90. gl.enable(gl.DEPTH_TEST);
  91. gl.depthFunc(gl.LEQUAL);
  92. gl.useProgram(program);
  93. gl.bindVertexArray(varing.vao);
  94. setUniforms(gl, program, {
  95. invProjectionViewMat,
  96. envTex: useTex(gl, varing.skyCubeTex!),
  97. });
  98. gl.drawArrays(gl.TRIANGLES, 0, varing.numArrays);
  99. };
  100. const fps = createFPSCamera(
  101. canvas.parentElement!,
  102. (nViewMat) => {
  103. mat4.copy(viewMat, nViewMat);
  104. updateInv();
  105. redraw();
  106. },
  107. [0, 1, 0],
  108. [0, 0, 0],
  109. { yaw: glMatrix.toRadian(-180) },
  110. 80
  111. );
  112. return {
  113. redraw,
  114. changeUrls(urls: string) {
  115. fps.recovery();
  116. return varing.preset(urls).then(redraw);
  117. },
  118. destory: fps.destory,
  119. };
  120. };