OpenGL 是按内部或外部查看器的顺序排列的吗?
Are OpenGL ordered as viewed by an internal or external viewer?
我编写了一个显示旋转立方体的 WebGL 程序。从 外侧 看,索引按逆时针顺序排列。然而,当我决定启用剔除面孔时,我理解为“正面”的面孔被剔除,立方体似乎被挖空了。我可以通过告诉 WebGL 剔除“正面”面孔来解决这个问题。
我声明立方体的顶点位置、纹理坐标和索引如下:image or text.
我的问题是:我是否应该在 形状内按逆时针顺序声明点?如果不是,为什么我使用的索引是倒着的?
下面是这个程序(已经是最小可复现的例子)
const cubeVertexPositions = [
// Front
-1, 1, -1,
-1, -1, -1,
1, -1, -1,
1, 1, -1,
// Back
1, 1, 1,
1, -1, 1,
-1, -1, 1,
-1, 1, 1,
// Left
-1, 1, 1,
-1, -1, 1,
-1, -1, -1,
-1, 1, -1,
// Right
1, 1, -1,
1, -1, -1,
1, -1, 1,
1, 1, 1,
// Top
-1, 1, 1,
-1, 1, -1,
1, 1, -1,
1, 1, 1,
// Bottom
-1, -1, -1,
-1, -1, 1,
1, -1, 1,
1, -1, -1
];
const cubeTextureCoordinates = [
// Front
0, 1,
0, 0,
1, 0,
1, 1,
// Back
0, 1,
0, 0,
1, 0,
1, 1,
// Left
0, 1,
0, 0,
1, 0,
1, 1,
// Right
0, 1,
0, 0,
1, 0,
1, 1,
// Bottom
0, 1,
0, 0,
1, 0,
1, 1,
// Top
0, 1,
0, 0,
1, 0,
1, 1
];
const cubeIndices = [
// Front
0, 1, 2,
2, 3, 0,
// Back
4, 5, 6,
6, 7, 4,
// Left
8, 9, 10,
10, 11, 8,
// Right
12, 13, 14,
14, 15, 12,
// Top
16, 17, 18,
18, 19, 16,
// Bottom
20, 21, 22,
22, 23, 20
];
// Vertex shader source code.
const vertexShaderSrc = `#version 300 es
in vec4 a_position;
in vec2 a_texcoord;
out vec2 v_texcoord;
uniform mat4 u_matrix;
void main() {
gl_Position = u_matrix * a_position;
v_texcoord = a_texcoord;
}`;
// Fragment shader source code.
const fragmentShaderSrc = `#version 300 es
precision highp float;
in vec2 v_texcoord;
uniform sampler2D u_texture;
out vec4 outColor;
void main() {
outColor = texture(u_texture, v_texcoord);
}`;
// Variables for controlling the cube.
let cubeTranslation = new Vector(0, 0, 0);
let cubeRotation = new Vector(0, 0, 0);
let cubeAngularVelocity = new Vector(0, 1, 0);
let cubeScale = new Vector(1, 1, 1);
let cubeHue = new Vector(1, 1, 1, 1);
let fov = 60;
let near = 1;
let far = 200;
let lookAt = cubeTranslation;
let cameraTranslaton = new Vector(0, 0, 5);
// Initialization instructions.
onload = () => {
// Find the canvas and WebGL2 context.
const canvas = document.querySelector('#canvas');
const gl = canvas.getContext('webgl2');
// Create a WebGL2 program using the vertex and fragment shader source code above.
const programInfo = new ProgramInfo(gl, new ShaderInfo(gl, gl.VERTEX_SHADER, vertexShaderSrc), new ShaderInfo(gl, gl.FRAGMENT_SHADER, fragmentShaderSrc));
// Cube vertex positions buffer.
const cubeVerticesBufferInfo = new BufferInfo(gl, new Float32Array(cubeVertexPositions));
// Cube texture coordinates buffer.
const cubeTexcoordsBufferInfo = new BufferInfo(gl, new Float32Array(cubeTextureCoordinates));
// Vertex Array Object for the cube.
const vao = new VAOInfo(gl, programInfo);
vao.addAttribute(new AttributeInfo('a_position', cubeVerticesBufferInfo));
vao.addAttribute(new AttributeInfo('a_texcoord', cubeTexcoordsBufferInfo, 2));
vao.setIndices(new Uint8Array(cubeIndices));
// A simple texture to show the edges of the cube.
const outlineTextureInfo = new TextureInfo(gl);
outlineTextureInfo.setColor(new Uint8Array([255, 0, 255, 255])); // Temporary color while image is loading.
outlineTextureInfo.loadImage(imageBase64);
// Render time instructions.
const render = (time) => {
requestAnimationFrame(render);
// Set global state.
UmbraGL.resizeCanvasToDisplaySize(canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
// gl.cullFace(gl.FRONT); // Uncomment this line to fix the cube.
// Animate.
cubeRotation.operate(cubeAngularVelocity);
// Draw.
gl.useProgram(programInfo.program);
programInfo.uniforms['u_matrix'].setter([...new Matrix()
.perspective(fov, gl.canvas.clientWidth / gl.canvas.clientHeight, near, far)
.multiply(new Matrix().lookAt(cameraTranslaton, lookAt).invert())
.translate(...cubeTranslation)
.rotate(...cubeRotation)
]);
programInfo.uniforms['u_texture'].setter(outlineTextureInfo.texture);
vao.draw();
};
requestAnimationFrame(render);
};
// Base64 version of the image. This is at the bottom so that it doesn't get in the way of the rest of the code.
const imageBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAIAAADwf7zUAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0VaRFpExCFDdbIgKuIoVSyChdJWaNXB5NIvaNKQtLg4Cq4FBz8Wqw4uzro6uAqC4AeIm5uToouU+L+k0CLGg+N+vLv3uHsHCM0KU82eCUDVakYqHhOzuVXR/wofQhjAIIISM/VEejED1/F1Dw9f76I8y/3cnyOo5E0GeETiOaYbNeIN4pnNms55nzjMSpJCfE48btAFiR+5Ljv8xrlos8Azw0YmNU8cJhaLXSx3MSsZKvE0cURRNcoXsg4rnLc4q5U6a9+TvzCQ11bSXKc5gjiWkEASImTUUUYFNURp1UgxkaL9mIt/2PYnySWTqwxGjgVUoUKy/eB/8LtbszA16SQFYoDvxbI+RgH/LtBqWNb3sWW1TgDvM3CldfzVJjD7SXqjo0WOgP5t4OK6o8l7wOUOMPSkS4ZkS16aQqEAvJ/RN+WA0C3Qt+b01t7H6QOQoa6Wb4CDQ2CsSNnrLu/u7e7t3zPt/n4ASt1ylxIM+ngAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQflBRMRGRZyIYKeAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAEaJJREFUeNrt2bERwDAIBMHHZUvF4yIU2CN2S/iIGxIAAGCMStLdhgAAgOvtvR8rAADAHAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQACYAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAACAc5Wkuw0BAAD3X/9VPgAAADCIAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAASACQAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAMA3AbDWsgIAAEwJABMAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAJgAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAAAAAAPAfLyiBENdcBN3eAAAAAElFTkSuQmCC';
body {
margin: 0;
}
canvas#canvas {
width: 100%;
height: 100%;
}
<script src="https://unpkg.com/umbra-math@1.0.0/index.js"></script>
<script src="https://unpkg.com/umbra-gl@1.0.0/index.js"></script>
<canvas id="canvas"></canvas>
您说“从外面看,索引是逆时针排列的。”
不,他们不是。第一个三角形的索引是 0, 1, 2,顶点是 (-1, 1, -1), (-1, -1, -1), (1, -1, -1).
0
y +
^ | \
| | \
| +-----+
1 2
----> x
在右手系统 (Right-hand rule) 中,z 轴指向视图。因此这是背面的三角形。
当你从后面看三角形时,你可以清楚地看到缠绕顺序是顺时针的
0
+
/ |
/ |
+-----+
2 1
我编写了一个显示旋转立方体的 WebGL 程序。从 外侧 看,索引按逆时针顺序排列。然而,当我决定启用剔除面孔时,我理解为“正面”的面孔被剔除,立方体似乎被挖空了。我可以通过告诉 WebGL 剔除“正面”面孔来解决这个问题。
我声明立方体的顶点位置、纹理坐标和索引如下:image or text.
我的问题是:我是否应该在 形状内按逆时针顺序声明点?如果不是,为什么我使用的索引是倒着的?
下面是这个程序(已经是最小可复现的例子)
const cubeVertexPositions = [
// Front
-1, 1, -1,
-1, -1, -1,
1, -1, -1,
1, 1, -1,
// Back
1, 1, 1,
1, -1, 1,
-1, -1, 1,
-1, 1, 1,
// Left
-1, 1, 1,
-1, -1, 1,
-1, -1, -1,
-1, 1, -1,
// Right
1, 1, -1,
1, -1, -1,
1, -1, 1,
1, 1, 1,
// Top
-1, 1, 1,
-1, 1, -1,
1, 1, -1,
1, 1, 1,
// Bottom
-1, -1, -1,
-1, -1, 1,
1, -1, 1,
1, -1, -1
];
const cubeTextureCoordinates = [
// Front
0, 1,
0, 0,
1, 0,
1, 1,
// Back
0, 1,
0, 0,
1, 0,
1, 1,
// Left
0, 1,
0, 0,
1, 0,
1, 1,
// Right
0, 1,
0, 0,
1, 0,
1, 1,
// Bottom
0, 1,
0, 0,
1, 0,
1, 1,
// Top
0, 1,
0, 0,
1, 0,
1, 1
];
const cubeIndices = [
// Front
0, 1, 2,
2, 3, 0,
// Back
4, 5, 6,
6, 7, 4,
// Left
8, 9, 10,
10, 11, 8,
// Right
12, 13, 14,
14, 15, 12,
// Top
16, 17, 18,
18, 19, 16,
// Bottom
20, 21, 22,
22, 23, 20
];
// Vertex shader source code.
const vertexShaderSrc = `#version 300 es
in vec4 a_position;
in vec2 a_texcoord;
out vec2 v_texcoord;
uniform mat4 u_matrix;
void main() {
gl_Position = u_matrix * a_position;
v_texcoord = a_texcoord;
}`;
// Fragment shader source code.
const fragmentShaderSrc = `#version 300 es
precision highp float;
in vec2 v_texcoord;
uniform sampler2D u_texture;
out vec4 outColor;
void main() {
outColor = texture(u_texture, v_texcoord);
}`;
// Variables for controlling the cube.
let cubeTranslation = new Vector(0, 0, 0);
let cubeRotation = new Vector(0, 0, 0);
let cubeAngularVelocity = new Vector(0, 1, 0);
let cubeScale = new Vector(1, 1, 1);
let cubeHue = new Vector(1, 1, 1, 1);
let fov = 60;
let near = 1;
let far = 200;
let lookAt = cubeTranslation;
let cameraTranslaton = new Vector(0, 0, 5);
// Initialization instructions.
onload = () => {
// Find the canvas and WebGL2 context.
const canvas = document.querySelector('#canvas');
const gl = canvas.getContext('webgl2');
// Create a WebGL2 program using the vertex and fragment shader source code above.
const programInfo = new ProgramInfo(gl, new ShaderInfo(gl, gl.VERTEX_SHADER, vertexShaderSrc), new ShaderInfo(gl, gl.FRAGMENT_SHADER, fragmentShaderSrc));
// Cube vertex positions buffer.
const cubeVerticesBufferInfo = new BufferInfo(gl, new Float32Array(cubeVertexPositions));
// Cube texture coordinates buffer.
const cubeTexcoordsBufferInfo = new BufferInfo(gl, new Float32Array(cubeTextureCoordinates));
// Vertex Array Object for the cube.
const vao = new VAOInfo(gl, programInfo);
vao.addAttribute(new AttributeInfo('a_position', cubeVerticesBufferInfo));
vao.addAttribute(new AttributeInfo('a_texcoord', cubeTexcoordsBufferInfo, 2));
vao.setIndices(new Uint8Array(cubeIndices));
// A simple texture to show the edges of the cube.
const outlineTextureInfo = new TextureInfo(gl);
outlineTextureInfo.setColor(new Uint8Array([255, 0, 255, 255])); // Temporary color while image is loading.
outlineTextureInfo.loadImage(imageBase64);
// Render time instructions.
const render = (time) => {
requestAnimationFrame(render);
// Set global state.
UmbraGL.resizeCanvasToDisplaySize(canvas);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
// gl.cullFace(gl.FRONT); // Uncomment this line to fix the cube.
// Animate.
cubeRotation.operate(cubeAngularVelocity);
// Draw.
gl.useProgram(programInfo.program);
programInfo.uniforms['u_matrix'].setter([...new Matrix()
.perspective(fov, gl.canvas.clientWidth / gl.canvas.clientHeight, near, far)
.multiply(new Matrix().lookAt(cameraTranslaton, lookAt).invert())
.translate(...cubeTranslation)
.rotate(...cubeRotation)
]);
programInfo.uniforms['u_texture'].setter(outlineTextureInfo.texture);
vao.draw();
};
requestAnimationFrame(render);
};
// Base64 version of the image. This is at the bottom so that it doesn't get in the way of the rest of the code.
const imageBase64 = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABAAAAAQACAIAAADwf7zUAAABhWlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw0AcxV9TS0VaRFpExCFDdbIgKuIoVSyChdJWaNXB5NIvaNKQtLg4Cq4FBz8Wqw4uzro6uAqC4AeIm5uToouU+L+k0CLGg+N+vLv3uHsHCM0KU82eCUDVakYqHhOzuVXR/wofQhjAIIISM/VEejED1/F1Dw9f76I8y/3cnyOo5E0GeETiOaYbNeIN4pnNms55nzjMSpJCfE48btAFiR+5Ljv8xrlos8Azw0YmNU8cJhaLXSx3MSsZKvE0cURRNcoXsg4rnLc4q5U6a9+TvzCQ11bSXKc5gjiWkEASImTUUUYFNURp1UgxkaL9mIt/2PYnySWTqwxGjgVUoUKy/eB/8LtbszA16SQFYoDvxbI+RgH/LtBqWNb3sWW1TgDvM3CldfzVJjD7SXqjo0WOgP5t4OK6o8l7wOUOMPSkS4ZkS16aQqEAvJ/RN+WA0C3Qt+b01t7H6QOQoa6Wb4CDQ2CsSNnrLu/u7e7t3zPt/n4ASt1ylxIM+ngAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQflBRMRGRZyIYKeAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAAEaJJREFUeNrt2bERwDAIBMHHZUvF4yIU2CN2S/iIGxIAAGCMStLdhgAAgOvtvR8rAADAHAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQACYAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAACAc5Wkuw0BAAD3X/9VPgAAADCIAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAASACQAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAMA3AbDWsgIAAEwJABMAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAJgAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAAAgAAABAAAAAAAIAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAAAQAAAAgAAAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAIAAAAQAAAAAACAAAAEAAAAIAAAAAABAAAACAAAAAAAQAAAAgAAABAAAAAAAIAAAAEAAAAIAAAAAABAAAACAAAAEAAAAAAAgAAABAAAACAAAAAAAQAAAAgAAAAAAEAAAACAAAAEAAAAIAAAAAABAAAAAAAAPAfLyiBENdcBN3eAAAAAElFTkSuQmCC';
body {
margin: 0;
}
canvas#canvas {
width: 100%;
height: 100%;
}
<script src="https://unpkg.com/umbra-math@1.0.0/index.js"></script>
<script src="https://unpkg.com/umbra-gl@1.0.0/index.js"></script>
<canvas id="canvas"></canvas>
您说“从外面看,索引是逆时针排列的。”
不,他们不是。第一个三角形的索引是 0, 1, 2,顶点是 (-1, 1, -1), (-1, -1, -1), (1, -1, -1).
0
y +
^ | \
| | \
| +-----+
1 2
----> x
在右手系统 (Right-hand rule) 中,z 轴指向视图。因此这是背面的三角形。
当你从后面看三角形时,你可以清楚地看到缠绕顺序是顺时针的
0
+
/ |
/ |
+-----+
2 1