|
@@ -1,4 +1,5 @@
|
|
|
import envFragSource from "./shader-env.frag?raw";
|
|
|
+import envCubeFragSource from "./shader-env-cube.frag?raw";
|
|
|
import envVertSource from "./shader-env.vert?raw";
|
|
|
import { loadImage } from "@/util";
|
|
|
import { createFPSCamera, createProgram, generateVao, useTex } from "@/util/gl";
|
|
@@ -7,27 +8,29 @@ import { setUniforms } from "./setUniform";
|
|
|
|
|
|
const generatePreset = (gl: WebGL2RenderingContext) => {
|
|
|
const skyCubeTex = gl.createTexture();
|
|
|
- // const updateSky1 = (images: HTMLImageElement[]) => {
|
|
|
- // gl.bindTexture(gl.TEXTURE_CUBE_MAP, skyCubeTex);
|
|
|
- // const mapper = [2, 4, 0, 5, 1, 3];
|
|
|
- // for (let i = 0; i < 6; i++) {
|
|
|
- // gl.texImage2D(
|
|
|
- // gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
|
|
|
- // 0,
|
|
|
- // gl.RGB,
|
|
|
- // gl.RGB,
|
|
|
- // gl.UNSIGNED_BYTE,
|
|
|
- // images[mapper[i]]
|
|
|
- // );
|
|
|
- // }
|
|
|
- // gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
|
- // gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
|
- // gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
|
|
|
- // gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
|
- // gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
|
- // gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
|
|
|
- // gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
|
|
|
- // };
|
|
|
+ const skyCubeTex1 = gl.createTexture();
|
|
|
+ const updateSky1 = (images: HTMLImageElement[]) => {
|
|
|
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, skyCubeTex1);
|
|
|
+ const mapper = [2, 4, 0, 5, 1, 3];
|
|
|
+ for (let i = 0; i < 6; i++) {
|
|
|
+ gl.texImage2D(
|
|
|
+ gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
|
|
|
+ 0,
|
|
|
+ gl.RGB,
|
|
|
+ gl.RGB,
|
|
|
+ gl.UNSIGNED_BYTE,
|
|
|
+ images[mapper[i]]
|
|
|
+ );
|
|
|
+ }
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE);
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
|
+ gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
|
+ gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
|
|
|
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, null);
|
|
|
+ };
|
|
|
+
|
|
|
const updateSky = (image: HTMLImageElement) => {
|
|
|
gl.bindTexture(gl.TEXTURE_2D, skyCubeTex);
|
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
|
@@ -38,13 +41,19 @@ const generatePreset = (gl: WebGL2RenderingContext) => {
|
|
|
|
|
|
return {
|
|
|
skyCubeTex,
|
|
|
+ skyCubeTex1,
|
|
|
// async preset(urls: string[]) {
|
|
|
// const images = await Promise.all(urls.map(loadImage));
|
|
|
// updateSky(images);
|
|
|
// },
|
|
|
- async preset(url: string) {
|
|
|
- const image = await loadImage(url);
|
|
|
- updateSky(image);
|
|
|
+ async preset(url: string | string[]) {
|
|
|
+ if (Array.isArray(url)) {
|
|
|
+ const images = await Promise.all(url.map(loadImage));
|
|
|
+ updateSky1(images);
|
|
|
+ } else {
|
|
|
+ const image = await loadImage(url);
|
|
|
+ updateSky(image);
|
|
|
+ }
|
|
|
},
|
|
|
};
|
|
|
};
|
|
@@ -71,16 +80,25 @@ const getDrawVaring = (gl: WebGL2RenderingContext) => {
|
|
|
};
|
|
|
|
|
|
export const init = (canvas: HTMLCanvasElement) => {
|
|
|
- const size = [canvas.width, canvas.height];
|
|
|
+ let activeTex: "skyCubeTex1" | "skyCubeTex" = "skyCubeTex1";
|
|
|
const gl = canvas.getContext("webgl2", { preserveDrawingBuffer: true })!;
|
|
|
const program = createProgram(gl, envVertSource, envFragSource);
|
|
|
- const projectionMat = mat4.perspective(
|
|
|
- mat4.create(),
|
|
|
- glMatrix.toRadian(45),
|
|
|
- size[0] / size[1],
|
|
|
- 0.1,
|
|
|
- 100
|
|
|
- );
|
|
|
+ const program1 = createProgram(gl, envVertSource, envCubeFragSource);
|
|
|
+
|
|
|
+ const setSize = (size: number[]) => {
|
|
|
+ mat4.perspective(
|
|
|
+ projectionMat,
|
|
|
+ glMatrix.toRadian(45),
|
|
|
+ size[0] / size[1],
|
|
|
+ 0.1,
|
|
|
+ 100
|
|
|
+ );
|
|
|
+ gl.viewport(0, 0, size[0], size[1]);
|
|
|
+ updateInv();
|
|
|
+ redraw();
|
|
|
+ };
|
|
|
+
|
|
|
+ const projectionMat = mat4.create();
|
|
|
const invProjectionViewMat = mat4.create();
|
|
|
const viewMat = mat4.create();
|
|
|
const varing = getDrawVaring(gl);
|
|
@@ -89,20 +107,24 @@ export const init = (canvas: HTMLCanvasElement) => {
|
|
|
mat4.invert(invProjectionViewMat, invProjectionViewMat);
|
|
|
};
|
|
|
|
|
|
- gl.viewport(0, 0, size[0], size[1]);
|
|
|
const redraw = () => {
|
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
|
gl.enable(gl.DEPTH_TEST);
|
|
|
gl.depthFunc(gl.LEQUAL);
|
|
|
- gl.useProgram(program);
|
|
|
+ const g = activeTex === "skyCubeTex" ? program : program1;
|
|
|
+ gl.useProgram(g);
|
|
|
gl.bindVertexArray(varing.vao);
|
|
|
- setUniforms(gl, program, {
|
|
|
+ setUniforms(gl, g, {
|
|
|
invProjectionViewMat,
|
|
|
- envTex: useTex(gl, varing.skyCubeTex!),
|
|
|
+ envTex:
|
|
|
+ activeTex === "skyCubeTex1"
|
|
|
+ ? useTex(gl, varing.skyCubeTex1!, gl.TEXTURE_CUBE_MAP, 1)
|
|
|
+ : useTex(gl, varing.skyCubeTex!, gl.TEXTURE_2D),
|
|
|
});
|
|
|
gl.drawArrays(gl.TRIANGLES, 0, varing.numArrays);
|
|
|
};
|
|
|
|
|
|
+ setSize([canvas.width, canvas.height]);
|
|
|
const fps = createFPSCamera(
|
|
|
canvas.parentElement!,
|
|
|
(nViewMat) => {
|
|
@@ -116,10 +138,14 @@ export const init = (canvas: HTMLCanvasElement) => {
|
|
|
80
|
|
|
);
|
|
|
return {
|
|
|
+ setSize,
|
|
|
redraw,
|
|
|
- changeUrls(urls: string) {
|
|
|
+ changeUrls(urls: string | string[]) {
|
|
|
fps.recovery();
|
|
|
- return varing.preset(urls).then(redraw);
|
|
|
+ return varing.preset(urls).then(() => {
|
|
|
+ activeTex = Array.isArray(urls) ? "skyCubeTex1" : "skyCubeTex";
|
|
|
+ redraw();
|
|
|
+ });
|
|
|
},
|
|
|
destory: fps.destory,
|
|
|
};
|