Javascript WebGL的斜投影计算 我试图在WebGL 2中创建一个门户渲染引擎(到目前为止我正在尝试移植这个C++项目:),并且我尝试实现斜投影,以便将门户相机的剪辑平面对齐到它们各自的门户中;尽管在不同的OpenGL平台上找到了多个实现,但是我无法让它在我的WebGL项目中工作。以下是与之相关的代码: const Mat4 = (() => { const { mat3, mat4, vec2, vec3, vec4 } = glMatrix; return { ...mat4, zAxis(out, mat) { return vec3.set(out, mat[2], mat[6], mat[10]); }, mulVec4(out, mat, vec) { const [x, y, z, w] = vec; return vec3.set(out, mat[ 0] * x + mat[ 1] * y + mat[ 2] * z + mat[ 3] * w, mat[ 4] * x + mat[ 5] * y + mat[ 6] * z + mat[ 7] * w, mat[ 8] * x + mat[ 9] * y + mat[10] * z + mat[11] * w, mat[12] * x + mat[13] * y + mat[14] * z + mat[15] * w); }, mulPoint(out, mat, vec) { const [x, y, z] = vec; const w = mat[12] * x + mat[13] * y + mat[14] * z + mat[15]; return vec3.set(out, (mat[0] * x + mat[1] * y + mat[ 2] * z + mat[ 3]) / w, (mat[4] * x + mat[5] * y + mat[ 6] * z + mat[ 7]) / w, (mat[8] * x + mat[9] * y + mat[10] * z + mat[11]) / w); }, }; })(); const Camera = () => { const { vec3, vec4 } = glMatrix; const projection = Mat4.create(); const view = Mat4.create(); return { width: 0, height: 0, aspect: 1, near: 0.1, far: 100.0, fov: Math.PI / 3, pos: [0, 0, 0], euler: [0, 0, 0], get view() { return view; }, set view(matrix) { return Mat4.copy(view, matrix); }, get matrix() { return Mat4.multiply(Mat4.create(), projection, view) }, get projection() { return projection; }, set transform([x = 0, y = 0, z = 0, rx = 0, ry = 0]) { const matrix = Mat4.fromXRotation(Mat4.create(), rx); Mat4.multiply(matrix, matrix, Mat4.fromYRotation(Mat4.create(), ry)); Mat4.multiply(matrix, matrix, Mat4.fromTranslation(Mat4.create(), [-x, -y, -z])); Mat4.copy(view, matrix); return view; }, inverse() { const inv = Mat4.create(); const a = projection[0]; const b = projection[5]; const c = projection[10]; const d = projection[11]; const e = projection[14]; inv[0] = 1 / a; inv[5] = 1 / b; inv[11] = 1 / e; inv[14] = 1 / d; inv[15] = -c / (d * e) return inv; }, clipOblique(pos, norm) { const cpos = Mat4.mulPoint(vec3.create(), view, pos); const cnorm = vec3.normalize(vec3.create(), Mat4.mulPoint(vec3.create(), view, norm)); const point = Mat4.mulPoint(vec3.create(), Mat4.invert(Mat4.create(), view), [0, 0, 0]); cpos[1] -= point[1]; const cplane = vec4.set(vec4.create(), cnorm[0], cnorm[1], cnorm[2], -vec3.dot(cpos, cnorm)); const q = Mat4.mulVec4(vec4.create(), Mat4.invert(Mat4.create(), projection), [ (cplane[0] > 0 ? 1 : -1), (cplane[1] > 0 ? 1 : -1), 1, 1]); const c = cplane.map(x => x * 2 / vec4.dot(cplane, q)); projection[ 2] = c[0] - projection[ 3]; projection[ 6] = c[1] - projection[ 7]; projection[10] = c[2] - projection[11]; projection[14] = c[3] - projection[15]; return this; }, copy(that) { this.setup(that.width, that.height, that.near, that.far, that.fov, that.aspect); Mat4.copy(view, that.view); Mat4.copy(projection, that.projection); return this; }, setup(width = this.width, height = this.height, near = this.near, far = this.far, fov = this.fov, aspect = height / width) { this.width = width; this.height = height; this.near = near; this.far = far; this.fov = fov; this.aspect = aspect; const f = 1.0 / Math.tan(fov / 2); const range = 1.0 / (near - far); projection[0] = f * aspect projection[1] = 0.0; projection[2] = 0.0; projection[3] = 0.0; projection[4] = 0.0; projection[5] = f; projection[6] = 0.0; projection[7] = 0.0; projection[8] = 0.0; projection[9] = 0.0; projection[10] = (near + far) * range; projection[11] = -1.0; projection[12] = 0.0; projection[13] = 0.0; projection[14] = 2 * near * far * range; projection[15] = 0.0; return this; } } }; const GameObject = (gl, mesh) => { const { vec3 } = glMatrix; return { pos: [0, 0, 0], euler: [0, 0, 0], scale: [1, 1, 1], mesh, forward() { const matrix = Mat4.fromZRotation(Mat4.create(), this.euler[2]); Mat4.multiply(matrix, matrix, Mat4.fromXRotation(Mat4.create(), this.euler[0])); Mat4.multiply(matrix, matrix, Mat4.fromYRotation(Mat4.create(), this.euler[1])); return vec3.negate(vec3.create(), Mat4.zAxis(vec3.create(), matrix)); }, localToWorld() { const matrix = Mat4.fromTranslation(Mat4.create(), this.pos); Mat4.multiply(matrix, matrix, Mat4.fromYRotation(Mat4.create(), this.euler[1])); Mat4.multiply(matrix, matrix, Mat4.fromXRotation(Mat4.create(), this.euler[0])); Mat4.multiply(matrix, matrix, Mat4.fromZRotation(Mat4.create(), this.euler[2])); Mat4.multiply(matrix, matrix, Mat4.fromScaling(Mat4.create(), this.scale)); return matrix; }, worldToLocal() { const matrix = Mat4.fromScaling(Mat4.create(), this.scale); Mat4.invert(matrix, matrix); Mat4.multiply(matrix, matrix, Mat4.fromZRotation(Mat4.create(), this.euler[2])); Mat4.multiply(matrix, matrix, Mat4.fromXRotation(Mat4.create(), this.euler[0])); Mat4.multiply(matrix, matrix, Mat4.fromYRotation(Mat4.create(), this.euler[1])); Mat4.multiply(matrix, matrix, Mat4.fromTranslation(Mat4.create(), vec3.negate(vec3.create(), this.pos))); return matrix; }, render(camera, fbo = null) { const mv = Mat4.transpose(Mat4.create(), this.worldToLocal()); const mvp = Mat4.multiply(Mat4.create(), camera.matrix, this.localToWorld()); this.mesh.render(mvp, mv); return this; }, }; }; const Portal = (() => { const { vec3 } = glMatrix; const Warp = (fromPortal = {}) => { const delta = Mat4.identity(Mat4.create()); const deltaInv = Mat4.identity(Mat4.create()); return { fromPortal, toPortal: null, delta, deltaInv, }; }; return { connectWarp(a, b) { a.toPortal = b.fromPortal; b.toPortal = a.toPortal; a.delta = Mat4.multiply(Mat4.create(), a.fromPortal.localToWorld(), b.fromPortal.worldToLocal()); b.delta = Mat4.multiply(Mat4.create(), b.fromPortal.localToWorld(), a.fromPortal.worldToLocal()); a.deltaInv = b.delta; b.deltaInv = a.delta; return this; }, connect(a, b) { this.connectWarp(a.front, b.back); this.connectWarp(b.front, a.back); return this; }, create: async (gl) => { const mesh = await Mesh.load('double_quad.obj'); const shader = await Shader(gl, '.', 'portal-shader'); const { a_position } = shader.attribute; const vao = gl.createVertexArray(); gl.bindVertexArray(vao); const buffers = createBuffers(gl, new Array(1)); setupArrayBuffer(gl, buffers[0], new Float32Array(mesh.geometries[0].data.position), 3, a_position); const portalCam = Camera(); return (self => { self.front = Warp(self); self.back = Warp(self); return self; })({ ...GameObject(gl, null), front: null, back: null, get cam() { return portalCam; }, /*Override*/ render(camera, fbo, func) { console.assert(this.euler[0] === 0); console.assert(this.euler[2] === 0); const normal = this.forward(); const camPos = Mat4.getTranslation(vec3.create(), Mat4.invert(Mat4.create(), camera.view)); const isFront = vec3.dot(vec3.subtract(vec3.create(), camPos, this.pos), normal) > 0; if (isFront) { vec3.negate(normal, normal); } const warp = isFront? this.front : this.back; const mvp = Mat4.multiply(Mat4.create(), camera.matrix, this.localToWorld()); portalCam.copy(camera); portalCam.clipOblique(vec3.add(vec3.create(), this.pos, normal.map(x => x * 0.1)), vec3.negate(vec3.create(), normal)); Mat4.multiply(portalCam.view, portalCam.view, warp.delta); shader.use(); gl.bindVertexArray(vao); const { u_mvp, u_texture } = shader.uniform; gl.uniform1i(u_texture, 0); gl.activeTexture(gl.TEXTURE0 + 0); fbo.use(); gl.uniformMatrix4fv(u_mvp, false, mvp); gl.drawArrays(gl.TRIANGLES, 0, mesh.geometries[0].data.position.length / 3); return this; }, }); }, }; })();

Javascript WebGL的斜投影计算 我试图在WebGL 2中创建一个门户渲染引擎(到目前为止我正在尝试移植这个C++项目:),并且我尝试实现斜投影,以便将门户相机的剪辑平面对齐到它们各自的门户中;尽管在不同的OpenGL平台上找到了多个实现,但是我无法让它在我的WebGL项目中工作。以下是与之相关的代码: const Mat4 = (() => { const { mat3, mat4, vec2, vec3, vec4 } = glMatrix; return { ...mat4, zAxis(out, mat) { return vec3.set(out, mat[2], mat[6], mat[10]); }, mulVec4(out, mat, vec) { const [x, y, z, w] = vec; return vec3.set(out, mat[ 0] * x + mat[ 1] * y + mat[ 2] * z + mat[ 3] * w, mat[ 4] * x + mat[ 5] * y + mat[ 6] * z + mat[ 7] * w, mat[ 8] * x + mat[ 9] * y + mat[10] * z + mat[11] * w, mat[12] * x + mat[13] * y + mat[14] * z + mat[15] * w); }, mulPoint(out, mat, vec) { const [x, y, z] = vec; const w = mat[12] * x + mat[13] * y + mat[14] * z + mat[15]; return vec3.set(out, (mat[0] * x + mat[1] * y + mat[ 2] * z + mat[ 3]) / w, (mat[4] * x + mat[5] * y + mat[ 6] * z + mat[ 7]) / w, (mat[8] * x + mat[9] * y + mat[10] * z + mat[11]) / w); }, }; })(); const Camera = () => { const { vec3, vec4 } = glMatrix; const projection = Mat4.create(); const view = Mat4.create(); return { width: 0, height: 0, aspect: 1, near: 0.1, far: 100.0, fov: Math.PI / 3, pos: [0, 0, 0], euler: [0, 0, 0], get view() { return view; }, set view(matrix) { return Mat4.copy(view, matrix); }, get matrix() { return Mat4.multiply(Mat4.create(), projection, view) }, get projection() { return projection; }, set transform([x = 0, y = 0, z = 0, rx = 0, ry = 0]) { const matrix = Mat4.fromXRotation(Mat4.create(), rx); Mat4.multiply(matrix, matrix, Mat4.fromYRotation(Mat4.create(), ry)); Mat4.multiply(matrix, matrix, Mat4.fromTranslation(Mat4.create(), [-x, -y, -z])); Mat4.copy(view, matrix); return view; }, inverse() { const inv = Mat4.create(); const a = projection[0]; const b = projection[5]; const c = projection[10]; const d = projection[11]; const e = projection[14]; inv[0] = 1 / a; inv[5] = 1 / b; inv[11] = 1 / e; inv[14] = 1 / d; inv[15] = -c / (d * e) return inv; }, clipOblique(pos, norm) { const cpos = Mat4.mulPoint(vec3.create(), view, pos); const cnorm = vec3.normalize(vec3.create(), Mat4.mulPoint(vec3.create(), view, norm)); const point = Mat4.mulPoint(vec3.create(), Mat4.invert(Mat4.create(), view), [0, 0, 0]); cpos[1] -= point[1]; const cplane = vec4.set(vec4.create(), cnorm[0], cnorm[1], cnorm[2], -vec3.dot(cpos, cnorm)); const q = Mat4.mulVec4(vec4.create(), Mat4.invert(Mat4.create(), projection), [ (cplane[0] > 0 ? 1 : -1), (cplane[1] > 0 ? 1 : -1), 1, 1]); const c = cplane.map(x => x * 2 / vec4.dot(cplane, q)); projection[ 2] = c[0] - projection[ 3]; projection[ 6] = c[1] - projection[ 7]; projection[10] = c[2] - projection[11]; projection[14] = c[3] - projection[15]; return this; }, copy(that) { this.setup(that.width, that.height, that.near, that.far, that.fov, that.aspect); Mat4.copy(view, that.view); Mat4.copy(projection, that.projection); return this; }, setup(width = this.width, height = this.height, near = this.near, far = this.far, fov = this.fov, aspect = height / width) { this.width = width; this.height = height; this.near = near; this.far = far; this.fov = fov; this.aspect = aspect; const f = 1.0 / Math.tan(fov / 2); const range = 1.0 / (near - far); projection[0] = f * aspect projection[1] = 0.0; projection[2] = 0.0; projection[3] = 0.0; projection[4] = 0.0; projection[5] = f; projection[6] = 0.0; projection[7] = 0.0; projection[8] = 0.0; projection[9] = 0.0; projection[10] = (near + far) * range; projection[11] = -1.0; projection[12] = 0.0; projection[13] = 0.0; projection[14] = 2 * near * far * range; projection[15] = 0.0; return this; } } }; const GameObject = (gl, mesh) => { const { vec3 } = glMatrix; return { pos: [0, 0, 0], euler: [0, 0, 0], scale: [1, 1, 1], mesh, forward() { const matrix = Mat4.fromZRotation(Mat4.create(), this.euler[2]); Mat4.multiply(matrix, matrix, Mat4.fromXRotation(Mat4.create(), this.euler[0])); Mat4.multiply(matrix, matrix, Mat4.fromYRotation(Mat4.create(), this.euler[1])); return vec3.negate(vec3.create(), Mat4.zAxis(vec3.create(), matrix)); }, localToWorld() { const matrix = Mat4.fromTranslation(Mat4.create(), this.pos); Mat4.multiply(matrix, matrix, Mat4.fromYRotation(Mat4.create(), this.euler[1])); Mat4.multiply(matrix, matrix, Mat4.fromXRotation(Mat4.create(), this.euler[0])); Mat4.multiply(matrix, matrix, Mat4.fromZRotation(Mat4.create(), this.euler[2])); Mat4.multiply(matrix, matrix, Mat4.fromScaling(Mat4.create(), this.scale)); return matrix; }, worldToLocal() { const matrix = Mat4.fromScaling(Mat4.create(), this.scale); Mat4.invert(matrix, matrix); Mat4.multiply(matrix, matrix, Mat4.fromZRotation(Mat4.create(), this.euler[2])); Mat4.multiply(matrix, matrix, Mat4.fromXRotation(Mat4.create(), this.euler[0])); Mat4.multiply(matrix, matrix, Mat4.fromYRotation(Mat4.create(), this.euler[1])); Mat4.multiply(matrix, matrix, Mat4.fromTranslation(Mat4.create(), vec3.negate(vec3.create(), this.pos))); return matrix; }, render(camera, fbo = null) { const mv = Mat4.transpose(Mat4.create(), this.worldToLocal()); const mvp = Mat4.multiply(Mat4.create(), camera.matrix, this.localToWorld()); this.mesh.render(mvp, mv); return this; }, }; }; const Portal = (() => { const { vec3 } = glMatrix; const Warp = (fromPortal = {}) => { const delta = Mat4.identity(Mat4.create()); const deltaInv = Mat4.identity(Mat4.create()); return { fromPortal, toPortal: null, delta, deltaInv, }; }; return { connectWarp(a, b) { a.toPortal = b.fromPortal; b.toPortal = a.toPortal; a.delta = Mat4.multiply(Mat4.create(), a.fromPortal.localToWorld(), b.fromPortal.worldToLocal()); b.delta = Mat4.multiply(Mat4.create(), b.fromPortal.localToWorld(), a.fromPortal.worldToLocal()); a.deltaInv = b.delta; b.deltaInv = a.delta; return this; }, connect(a, b) { this.connectWarp(a.front, b.back); this.connectWarp(b.front, a.back); return this; }, create: async (gl) => { const mesh = await Mesh.load('double_quad.obj'); const shader = await Shader(gl, '.', 'portal-shader'); const { a_position } = shader.attribute; const vao = gl.createVertexArray(); gl.bindVertexArray(vao); const buffers = createBuffers(gl, new Array(1)); setupArrayBuffer(gl, buffers[0], new Float32Array(mesh.geometries[0].data.position), 3, a_position); const portalCam = Camera(); return (self => { self.front = Warp(self); self.back = Warp(self); return self; })({ ...GameObject(gl, null), front: null, back: null, get cam() { return portalCam; }, /*Override*/ render(camera, fbo, func) { console.assert(this.euler[0] === 0); console.assert(this.euler[2] === 0); const normal = this.forward(); const camPos = Mat4.getTranslation(vec3.create(), Mat4.invert(Mat4.create(), camera.view)); const isFront = vec3.dot(vec3.subtract(vec3.create(), camPos, this.pos), normal) > 0; if (isFront) { vec3.negate(normal, normal); } const warp = isFront? this.front : this.back; const mvp = Mat4.multiply(Mat4.create(), camera.matrix, this.localToWorld()); portalCam.copy(camera); portalCam.clipOblique(vec3.add(vec3.create(), this.pos, normal.map(x => x * 0.1)), vec3.negate(vec3.create(), normal)); Mat4.multiply(portalCam.view, portalCam.view, warp.delta); shader.use(); gl.bindVertexArray(vao); const { u_mvp, u_texture } = shader.uniform; gl.uniform1i(u_texture, 0); gl.activeTexture(gl.TEXTURE0 + 0); fbo.use(); gl.uniformMatrix4fv(u_mvp, false, mvp); gl.drawArrays(gl.TRIANGLES, 0, mesh.geometries[0].data.position.length / 3); return this; }, }); }, }; })();,javascript,3d,linear-algebra,webgl2,gl-matrix,Javascript,3d,Linear Algebra,Webgl2,Gl Matrix,起初,门户看起来很正常,但当我尝试在它后面时,对象仍然会被渲染(如果我将自己定位为门户的摄影机在它们后面),但渲染方式不寻常。我不太擅长矩阵数学或线性代数,希望能得到一些帮助/见解;多谢各位

起初,门户看起来很正常,但当我尝试在它后面时,对象仍然会被渲染(如果我将自己定位为门户的摄影机在它们后面),但渲染方式不寻常。我不太擅长矩阵数学或线性代数,希望能得到一些帮助/见解;多谢各位