WebGL 不会渲染任何东西,合适的矩阵是什么?
WebGL won't render anything, what are the proper matrices?
我正尝试从按钮开始理解和学习 WebGL 和计算机图形,这就是我开始为此开发自己的小库的原因。我花了几天时间寻找正确的答案,但我无法让它发挥作用。
我有列主矩阵,我只是想渲染基本三角形,但出于某种原因,无论我在乘以透视矩阵后做什么,我的顶点 Z 总是超出范围。
我在 space 位置 0,0,0 中设置了一个对象,顶点位置为 =
[
-0.5, -0.5, 0,
0.5, -0.5, 0,
0.5, 0.5, 0
]
我的相机设置了 60 度角 fov,纵横比 canvas.width / canvas.height
,近平面为 1/1000
,远平面为 50
。并位于 (0,0,-10)
上看着我的对象。
在渲染时我提供给我的顶点着色器:
Unifrom Matrix4 u_model
[1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1]
所以基本上是恒等矩阵
均匀矩阵4 u_view
[-1 0 0 0
0 1 0 0
0 0 -1 -10
0 0 0 1]
和统一矩阵4 u_projection
0.0003282401348280833 0 -0.3129605393123332 0
0 0.0003282401348280833 -0.3129605393123332 0
0 0 -1.0000400008000159 -0.002000040000800016
0 0 -1 0
我的矩阵模型是
[n11, n12, n13, n14
n21, n22, n23, n24,
n31, n32, n33, n34,
n41, n42, n43, n44 ]
我的透视矩阵计算:
static 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;
}
我的顶点着色器
this.vertexShaderScript =
'\r\n' +
'precision highp float;\r\n' +
'uniform mat4 u_model;\r\n' +
'uniform mat4 u_view;\r\n' +
'uniform mat4 u_projection;\r\n' +
'attribute vec3 a_position;\r\n' +
'attribute vec4 a_color;\r\n' +
'varying vec4 v_color;\r\n' +
'void main(void) {\r\n' +
' v_color = a_color;\r\n' +
' gl_Position = u_projection * u_view * u_model * vec4(a_position, 1.0);\r\n' +
'}\r\n';
和片段着色器
this.fragmentShaderScript = '\r\n' +
'precision highp float;\r\n' +
'varying vec4 v_color;\r\n' +
'void main(void) {\r\n' +
' gl_FragColor = v_color;\r\n' +
'}\r\n';
我检查了视图矩阵,尝试转置投影,用 spector js 检查了我是否将矩阵获取到着色器并且 none 它起作用了。我还检查了其他答案,但 none 对我有用。
哪个矩阵是错误的?
其余代码可以在我的github上找到:https://github.com/barteq100/webgl
你想要完成什么?
你的透视功能对我来说毫无意义。它似乎是基于 glFrustum
function from long deprecated OpenGL 2.1
你会注意到函数有 6 个参数,left、right、bottom、top、near far。你的只需要 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透视矩阵try this article。那篇文章使用了更为常见的透视数学。
无论如何,这是您的透视功能。如果我移动相机,我可以找到一个立方体,我正在以一些非常奇怪的视角在原点绘制
'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>
我正尝试从按钮开始理解和学习 WebGL 和计算机图形,这就是我开始为此开发自己的小库的原因。我花了几天时间寻找正确的答案,但我无法让它发挥作用。
我有列主矩阵,我只是想渲染基本三角形,但出于某种原因,无论我在乘以透视矩阵后做什么,我的顶点 Z 总是超出范围。
我在 space 位置 0,0,0 中设置了一个对象,顶点位置为 =
[
-0.5, -0.5, 0,
0.5, -0.5, 0,
0.5, 0.5, 0
]
我的相机设置了 60 度角 fov,纵横比 canvas.width / canvas.height
,近平面为 1/1000
,远平面为 50
。并位于 (0,0,-10)
上看着我的对象。
在渲染时我提供给我的顶点着色器:
Unifrom Matrix4 u_model
[1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1]
所以基本上是恒等矩阵
均匀矩阵4 u_view
[-1 0 0 0
0 1 0 0
0 0 -1 -10
0 0 0 1]
和统一矩阵4 u_projection
0.0003282401348280833 0 -0.3129605393123332 0
0 0.0003282401348280833 -0.3129605393123332 0
0 0 -1.0000400008000159 -0.002000040000800016
0 0 -1 0
我的矩阵模型是
[n11, n12, n13, n14
n21, n22, n23, n24,
n31, n32, n33, n34,
n41, n42, n43, n44 ]
我的透视矩阵计算:
static 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;
}
我的顶点着色器
this.vertexShaderScript =
'\r\n' +
'precision highp float;\r\n' +
'uniform mat4 u_model;\r\n' +
'uniform mat4 u_view;\r\n' +
'uniform mat4 u_projection;\r\n' +
'attribute vec3 a_position;\r\n' +
'attribute vec4 a_color;\r\n' +
'varying vec4 v_color;\r\n' +
'void main(void) {\r\n' +
' v_color = a_color;\r\n' +
' gl_Position = u_projection * u_view * u_model * vec4(a_position, 1.0);\r\n' +
'}\r\n';
和片段着色器
this.fragmentShaderScript = '\r\n' +
'precision highp float;\r\n' +
'varying vec4 v_color;\r\n' +
'void main(void) {\r\n' +
' gl_FragColor = v_color;\r\n' +
'}\r\n';
我检查了视图矩阵,尝试转置投影,用 spector js 检查了我是否将矩阵获取到着色器并且 none 它起作用了。我还检查了其他答案,但 none 对我有用。
哪个矩阵是错误的?
其余代码可以在我的github上找到:https://github.com/barteq100/webgl
你想要完成什么?
你的透视功能对我来说毫无意义。它似乎是基于 glFrustum
function from long deprecated OpenGL 2.1
你会注意到函数有 6 个参数,left、right、bottom、top、near far。你的只需要 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透视矩阵try this article。那篇文章使用了更为常见的透视数学。
无论如何,这是您的透视功能。如果我移动相机,我可以找到一个立方体,我正在以一些非常奇怪的视角在原点绘制
'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>