问题描述
我正在尝试在WebGL 2.0中创建门户网站呈现引擎(到目前为止,我正在尝试移植此C ++项目:https://github.com/HackerPoet/NonEuclidean),并且正在尝试实现倾斜投影,以对齐对象的剪切平面。门户摄像机到各自的门户;尽管在各种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,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],euler: [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,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(),norm));
const point = Mat4.mulPoint(vec3.create(),Mat4.invert(Mat4.create(),view),[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(),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,euler: [0,scale: [1,1],mesh,forward()
{
const matrix = Mat4.fromZRotation(Mat4.create(),this.euler[2]);
Mat4.multiply(matrix,Mat4.fromXRotation(Mat4.create(),this.euler[0]));
Mat4.multiply(matrix,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,this.euler[1]));
Mat4.multiply(matrix,Mat4.fromZRotation(Mat4.create(),this.euler[2]));
Mat4.multiply(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,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(),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(),this.localToWorld());
portalCam.copy(camera);
portalCam.clipOblique(vec3.add(vec3.create(),this.pos,normal.map(x => x * 0.1)),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,mesh.geometries[0].data.position.length / 3);
return this;
},});
},};
})();
起初,门户似乎正常,但是当我尝试在门户后面进行访问时,仍会渲染对象(如果我将自己放置在门户的摄像机位于它们后面的位置),但使用的是一种不寻常的方式。我不太擅长矩阵数学或线性代数,希望能对您有所帮助。谢谢。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)