Чего вы пытаетесь достичь?
Ваша функция перспективы не имеет смысла для меня.Похоже, что она основана на функции glFrustum
из давно устаревшего OpenGL 2.1
Вы заметите, что функция принимает 6 аргументов: влево, вправо, внизу, сверху, близко к дальнему.Ваш занимает всего 4, а цифры, которые вы вводите, кажутся бессмыслицей.Почему l
означает левый код с -4?Как вы думаете, почему r
должно быть fov * aspect
?
Тогда вы не показали код, который устанавливает ваши матрицы, поэтому мы не знаем, как вы его передаете.Матрицы WebGL (и OpenGL), как ожидается, будут основными строками.Или, другими словами, матрица перевода будет указана следующим образом в JavaScript
const translationMatrix = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 1, 1, 0,
x, y, z, 1,
];
Спецификация OpenGL называет каждую строку этой матрицы столбцом, но по стандартам компьютерного языка они являются строками.См. https://webglfundamentals.org/webgl/lessons/webgl-matrix-vs-math.html
Если вы хотите изучить перспективные матрицы WebGL , попробуйте эту статью .Эта статья использует гораздо более распространенную перспективную математику.
В любом случае, вот ваша перспективная функция.Если я переместлю камеру, то найду куб, который рисую в начале координат с какой-то очень странной перспективой
'use strict';
/* global twgl, m4, requestAnimationFrame, document */
class Matrix4 { }
function perspective(fov, aspect, near, far) {
const r = fov * aspect;
const l = -4;
const t = r;
const b = l;
const matrix = new Matrix4();
matrix.n11 = (2 * near) / (r - l);
matrix.n12 = 0;
matrix.n13 = (r+l)/(r-l);
matrix.n14 = 0;
matrix.n21 = 0;
matrix.n22 = (2 * near) / (t - b);
matrix.n23 = (t+b)/(t-b);
matrix.n24 = 0;
matrix.n31 = 0;
matrix.n32 = 0;
matrix.n33 = (near + far) / (near - far);
matrix.n34 = (2 * near * far) / (near - far);
matrix.n41 = 0;
matrix.n42 = 0;
matrix.n43 = -1;
matrix.n44 = 0;
return matrix;
}
function toMat(m) {
return [
m.n11, m.n21, m.n31, m.n41,
m.n12, m.n22, m.n32, m.n42,
m.n13, m.n23, m.n33, m.n43,
m.n14, m.n24, m.n34, m.n44,
];
}
const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texcoord;
uniform mat4 projection;
uniform mat4 modelView;
varying vec3 v_normal;
varying vec2 v_texcoord;
void main() {
gl_Position = projection * modelView * position;
v_normal = mat3(modelView) * normal;
v_texcoord = texcoord;
}
`;
const fs = `
precision highp float;
varying vec3 v_normal;
varying vec2 v_texcoord;
varying float v_modelId;
void main() {
vec3 lightDirection = normalize(vec3(1, 2, -3)); // arbitrary light direction
float l = dot(lightDirection, normalize(v_normal)) * .5 + .5;
gl_FragColor = vec4(vec3(0,1,0) * l, 1);
}
`;
// compile shader, link, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// make some vertex data
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 1);
function render(time) {
time *= 0.001; // seconds
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
const fov = Math.PI * 0.25;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const near = 0.1;
const far = 100;
const projection = toMat(perspective(fov, aspect, near, far));
const camera = m4.translation([0, 0, 1]);
const view = m4.inverse(camera);
let modelView = m4.rotateY(view, time);
gl.useProgram(programInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
// calls gl.activeTexture, gl.bindTexture, gl.uniformXXX
twgl.setUniforms(programInfo, {
projection,
modelView,
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
Если я изменю функцию перспективы на что-то более традиционное, то после перемещения камеры я получу нечто более нормальное
'use strict';
/* global twgl, m4, requestAnimationFrame, document */
class Matrix4 { }
function perspective(fov, aspect, near, far) {
const f = Math.tan(Math.PI * 0.5 - 0.5 * fov);
const rangeInv = 1.0 / (near - far);
const matrix = new Matrix4();
matrix.n11 = f / aspect;
matrix.n12 = 0;
matrix.n13 = 0;
matrix.n14 = 0;
matrix.n21 = 0;
matrix.n22 = f;
matrix.n23 = 0;
matrix.n24 = 0;
matrix.n31 = 0;
matrix.n32 = 0;
matrix.n33 = (near + far) * rangeInv;
matrix.n34 = near * far * rangeInv * 2;
matrix.n41 = 0;
matrix.n42 = 0;
matrix.n43 = -1;
matrix.n44 = 0;
return matrix;
}
function toMat(m) {
return [
m.n11, m.n21, m.n31, m.n41,
m.n12, m.n22, m.n32, m.n42,
m.n13, m.n23, m.n33, m.n43,
m.n14, m.n24, m.n34, m.n44,
];
}
const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texcoord;
uniform mat4 projection;
uniform mat4 modelView;
varying vec3 v_normal;
varying vec2 v_texcoord;
void main() {
gl_Position = projection * modelView * position;
v_normal = mat3(modelView) * normal;
v_texcoord = texcoord;
}
`;
const fs = `
precision highp float;
varying vec3 v_normal;
varying vec2 v_texcoord;
varying float v_modelId;
void main() {
vec3 lightDirection = normalize(vec3(1, 2, -3)); // arbitrary light direction
float l = dot(lightDirection, normalize(v_normal)) * .5 + .5;
gl_FragColor = vec4(vec3(0,1,0) * l, 1);
}
`;
// compile shader, link, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// make some vertex data
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 1);
function render(time) {
time *= 0.001; // seconds
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
const fov = Math.PI * 0.25;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const near = 0.1;
const far = 100;
const projection = toMat(perspective(fov, aspect, near, far));
const camera = m4.translation([0, 0, 3]);
const view = m4.inverse(camera);
let modelView = m4.rotateY(view, time);
gl.useProgram(programInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
// calls gl.activeTexture, gl.bindTexture, gl.uniformXXX
twgl.setUniforms(programInfo, {
projection,
modelView,
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>
Если вы хотите сохранить ту же перспективную математику (т. Е. Использовать матрицу из glFrustum
, указанную выше), то это нужные вам значениядля l
, r
, t
, b
const t = near * Math.tan(0.5 * fov);
const b = -t;
const r = t * aspect;
const l = -r;
'use strict';
/* global twgl, m4, requestAnimationFrame, document */
class Matrix4 { }
function perspective(fov, aspect, near, far) {
const t = near * Math.tan(0.5 * fov);
const b = -t;
const r = t * aspect;
const l = -r;
const matrix = new Matrix4();
matrix.n11 = (2 * near) / (r - l);
matrix.n12 = 0;
matrix.n13 = (r+l)/(r-l);
matrix.n14 = 0;
matrix.n21 = 0;
matrix.n22 = (2 * near) / (t - b);
matrix.n23 = (t+b)/(t-b);
matrix.n24 = 0;
matrix.n31 = 0;
matrix.n32 = 0;
matrix.n33 = (near + far) / (near - far);
matrix.n34 = (2 * near * far) / (near - far);
matrix.n41 = 0;
matrix.n42 = 0;
matrix.n43 = -1;
matrix.n44 = 0;
return matrix;
}
function toMat(m) {
return [
m.n11, m.n21, m.n31, m.n41,
m.n12, m.n22, m.n32, m.n42,
m.n13, m.n23, m.n33, m.n43,
m.n14, m.n24, m.n34, m.n44,
];
}
const m4 = twgl.m4;
const gl = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 position;
attribute vec3 normal;
attribute vec2 texcoord;
uniform mat4 projection;
uniform mat4 modelView;
varying vec3 v_normal;
varying vec2 v_texcoord;
void main() {
gl_Position = projection * modelView * position;
v_normal = mat3(modelView) * normal;
v_texcoord = texcoord;
}
`;
const fs = `
precision highp float;
varying vec3 v_normal;
varying vec2 v_texcoord;
varying float v_modelId;
void main() {
vec3 lightDirection = normalize(vec3(1, 2, -3)); // arbitrary light direction
float l = dot(lightDirection, normalize(v_normal)) * .5 + .5;
gl_FragColor = vec4(vec3(0,1,0) * l, 1);
}
`;
// compile shader, link, look up locations
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
// make some vertex data
const bufferInfo = twgl.primitives.createCubeBufferInfo(gl, 1);
function render(time) {
time *= 0.001; // seconds
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
const fov = Math.PI * 0.25;
const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;
const near = 0.1;
const far = 100;
const projection = toMat(perspective(fov, aspect, near, far));
const camera = m4.translation([0, 0, 3]);
const view = m4.inverse(camera);
let modelView = m4.rotateY(view, time);
gl.useProgram(programInfo.program);
// calls gl.bindBuffer, gl.enableVertexAttribArray, gl.vertexAttribPointer
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
// calls gl.activeTexture, gl.bindTexture, gl.uniformXXX
twgl.setUniforms(programInfo, {
projection,
modelView,
});
// calls gl.drawArrays or gl.drawElements
twgl.drawBufferInfo(gl, bufferInfo);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
canvas { border: 1px solid black; }
<script src="https://twgljs.org/dist/4.x/twgl-full.min.js"></script>
<canvas></canvas>