gma*_*man 19 opengl opengl-es glsl
注意:我理解基本的数学.我理解perspective
各种数学库中的典型函数会产生一个矩阵,它将-zNear到-zFar的z值转换回-1到+1,但前提是结果除以w
具体的问题是GPU为你做了什么,而不是你必须自己做?
换句话说,可以说的GPU没有神奇划分gl_Position
的gl_Position.w
,并且代替你不得不做手工,如
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;
}
Run Code Online (Sandbox Code Playgroud)
由于这个原因,这个想象中的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, 255, 255,
192, 192, 192, 255,
192, 192, 192, 255,
255, 255, 255, 255,
],
});
var uniforms = {
u_diffuse: tex,
};
function render(time) {
time *= 0.001;
twgl.resizeCanvasToDisplaySize(gl.canvas);
gl.viewport(0, 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, 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);
Run Code Online (Sandbox Code Playgroud)
body { margin: 0; }
canvas { display: block; width: 100vw; height: 100vh; }
Run Code Online (Sandbox Code Playgroud)
<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, 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>
Run Code Online (Sandbox Code Playgroud)
但是,这是因为GPU实际上需要z和w是不同的,还是仅仅是GPU设计,如果我们自己进行w
划分,不同的设计可以获得所需的信息?
在提出这个问题之后,我最后写了这篇文章来说明透视插值.
der*_*ass 23
我想谈谈BDL的答案.它不仅仅是关于透视插值.它也是关于削减.gl_Position
应该提供的值的空间称为剪辑空间,这是在除以w 之前.
定义OpenGL的(默认)剪辑卷以实现
-1 <= x,y,z <= 1 (in NDC coordinates).
Run Code Online (Sandbox Code Playgroud)
但是,当您在分割之前查看此约束时,您将获得
-w <= x,y,z <= w (in clip space, with w varying per vertex)
Run Code Online (Sandbox Code Playgroud)
然而,这只是事实的一半,因为所有剪辑空间点满足这一点将在分割后满足NDC约束
w <= x,y,z <= -w (in clip space)
Run Code Online (Sandbox Code Playgroud)
这里的事情是相机后面的点将被转换到相机前面的某个地方,镜像(因为x/-1
它是相同的-x/1
).这也发生在z
坐标上.有人可能认为这是无关紧要的,因为根据典型投影矩阵的构造,相机背后的任何点都被投射到远处平面的背后(在更远的地方),因此它将位于观察体积之外在任一情况下.
但是如果你有一个原始图形,其中至少有一个点在视图体积内,并且至少有一个点在摄像机后面,你应该有一个与近平面相交的图元.然而,经过划分w
,它far
现在将与飞机相交!.因此,在划分之后,在NDC空间中进行削波很难做到正确.我尝试在此图中可视化:
(图纸是按比例绘制的,投影的深度范围比任何人通常使用的都要短得多,以更好地说明问题).
裁剪在硬件中作为固定功能阶段完成,必须在分割之前完成,因此您应该提供正确的剪辑空间坐标.
(注意:实际的GPU可能根本不会使用额外的剪辑阶段,它们实际上也可能使用无剪辑光栅化器,就像Fabian Giesen在博客文章中推测的那样.有一些算法如Olano和Greer(1997).但是,这个所有的工作都是通过直接在同质坐标中进行光栅化,所以我们仍然需要w
...)