注意:我了解基础数学.我明白,各种数学库中的典型透视函数产生一个矩阵,将z值从-zNear转换为-zFar,返回到-1到1,但只有结果除以w
具体问题是GPU为您做了什么,而不是自己做这个?
换句话说,让我们说GPU并没有通过gl_Position.w神奇地划分gl_Position,而是你手动地像
attribute vec4 position; uniform mat4 worldViewProjection; void main() { gl_Position = worldViewProjection * position; // imaginary version of GL where we must divide by W ourselves gl_Position /= gl_Position.w; }
由于这个原因,这个想象的GL有什么突破?它会工作还是有一些关于传递价值的东西,然后再分配给w,为GPU提供额外的需求信息?
请注意,如果我真的做到了纹理映射透视中断.
"use strict"; var m4 = twgl.m4; var gl = twgl.getWebGLContext(document.getElementById("c")); var programInfo = twgl.createProgramInfo(gl,["vs","fs"]); var bufferInfo = twgl.primitives.createCubeBufferInfo(gl,2); var tex = twgl.createTexture(gl,{ min: gl.NEAREST,mag: gl.NEAREST,src: [ 255,255,192,],}); var uniforms = { u_diffuse: tex,}; function render(time) { time *= 0.001; twgl.resizeCanvasToDisplaySize(gl.canvas); gl.viewport(0,gl.canvas.width,gl.canvas.height); gl.enable(gl.DEPTH_TEST); gl.enable(gl.CULL_FACE); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); var projection = m4.perspective( 30 * Math.PI / 180,gl.canvas.clientWidth / gl.canvas.clientHeight,0.5,10); var eye = [1,4,-6]; var target = [0,0]; var up = [0,1,0]; var camera = m4.lookAt(eye,target,up); var view = m4.inverse(camera); var viewProjection = m4.multiply(projection,view); var world = m4.rotationY(time); uniforms.u_worldInverseTranspose = m4.transpose(m4.inverse(world)); uniforms.u_worldViewProjection = m4.multiply(viewProjection,world); gl.useProgram(programInfo.program); twgl.setBuffersAndAttributes(gl,programInfo,bufferInfo); twgl.setUniforms(programInfo,uniforms); gl.drawElements(gl.TRIANGLES,bufferInfo.numElements,gl.UNSIGNED_SHORT,0); requestAnimationFrame(render); } requestAnimationFrame(render);
body { margin: 0; } canvas { display: block; width: 100vw; height: 100vh; }
<script id="vs" type="notjs"> uniform mat4 u_worldViewProjection; uniform mat4 u_worldInverseTranspose; attribute vec4 position; attribute vec3 normal; attribute vec2 texcoord; varying vec2 v_texcoord; varying vec3 v_normal; void main() { v_texcoord = texcoord; v_normal = (u_worldInverseTranspose * vec4(normal,0)).xyz; gl_Position = u_worldViewProjection * position; gl_Position /= gl_Position.w; } </script> <script id="fs" type="notjs"> precision mediump float; varying vec2 v_texcoord; varying vec3 v_normal; uniform sampler2D u_diffuse; void main() { vec4 diffuseColor = texture2D(u_diffuse,v_texcoord); vec3 a_normal = normalize(v_normal); float l = dot(a_normal,vec3(1,0)); gl_FragColor.rgb = diffuseColor.rgb * (l * 0.5 + 0.5); gl_FragColor.a = diffuseColor.a; } </script> <script src="https://twgljs.org/dist/2.x/twgl-full.min.js"></script> <canvas id="c"></canvas>
但是,是因为GPU实际上需要z和w是不同的,还是只是GPU设计,而不同的设计可以得到所需的信息,如果我们自己划分w?
解决方法
原因在于,不仅将gl_Position除以均匀坐标,还可以将所有其他内插变化除以.这被称为透视正确插值,其需要在插值之后(并且因此在光栅化之后)进行除法.因此,在顶点着色器中进行划分将无法正常工作.参见
this post.