Примечание: Я понимаю основную математику. Я понимаю, что типичная функция perspective
в различных математических библиотеках создает матрицу, которая преобразует значения z из -zNear в -zFar обратно в -1 в +1, но только если результат делится на w
Конкретный вопрос заключается в том, что 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;
}
Что ломается в этом воображаемом 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);
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/2.x/twgl-full.min.js"></script>
<canvas id="c"></canvas>