为什么 GL 为您将 `gl_Position` 除以 W 而不是让您自己做? [英] Why does GL divide `gl_Position` by W for you rather than letting you do it yourself?

查看:24
本文介绍了为什么 GL 为您将 `gl_Position` 除以 W 而不是让您自己做?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:我了解基本的数学.我知道各种数学库中典型的 perspective 函数会生成一个矩阵,该矩阵将 z 值从 -zNear 转换为 -zFar 回 -1 到 +1,但前提是结果除以 w

Note: I understand the basic math. I understand that the typical perspective function in various math libraries produces a matrix that converts z values from -zNear to -zFar back into -1 to +1 but only if the result is divided by w

具体问题是 GPU 为您执行此操作而不是您必须自己执行此操作可以获得什么?

The specific question is what is gained by the GPU doing this for you rather than you having to do it yourself?

换句话说,假设 GPU 没有将 gl_Position 神奇地除以 gl_Position.w 而是您必须像在

In other words, lets say the GPU did not magically divide gl_Position by gl_Position.w and that instead you had to do it manually as in

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 提供额外所需的信息?

What breaks in this imaginary GL because of this? Would it work or is there something about passing in the value before it's been divided by w that provides extra needed info to the GPU?

请注意,如果我真的这样做,纹理映射透视会中断.

Note that if I actually do it the texture mapping perspective breaks.

"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);

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, 0));
  gl_FragColor.rgb = diffuseColor.rgb * (l * 0.5 + 0.5);
  gl_FragColor.a = diffuseColor.a;
}
  </script>
  <script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
  <canvas id="c"></canvas>

但是,这是因为 GPU 实际上需要 z 和 w 不同,还是仅仅是 GPU 设计,如果我们将 w 分开,不同的设计可以得出它需要的信息?

But, is that because the GPU actually needs z and w to be different or is it just GPU design and a different design could derive the info it needed if we did the w divide ourselves?

问完这个问题后,我写了这篇文章透视插值.

After asking this question I ended up writing this article that illustrates the perspective interpolation.

推荐答案

原因是,不仅 gl_Position 被齐次坐标分割,而且所有其他插值变量也被分割.这称为透视校正插值,它要求除法在插值之后(因此在光栅化之后).所以在顶点着色器中进行划分根本行不通.另请参阅这篇文章.

The reason is, that not only gl_Position gets divided by the homogeneous coordinate, but also all other interpolated varyings. This is called perspective correct interpolation which requires the division to be after the interpolation (and thus after the rasterization). So doing the division in the vertex shader would simply not work. See also this post.

这篇关于为什么 GL 为您将 `gl_Position` 除以 W 而不是让您自己做?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆