我不确定如何更改解决方案以允许在webGL中使用多种形状。是否每个形状都需要多个缓冲区数组和顶点缓冲区?我目前有一个由几个变换的多维数据集构成的对象,但是现在我想添加一个基于正方形的金字塔。如果它是场景中的唯一对象,我知道如何为此设置数组缓冲区,但是我不确定如何做到这一点,以使其与其余对象协调工作。我是否还需要另一个绘图函数,因为目前使用的函数将特定的多维数据集矩阵作为输入并使用它们来构建多维数据集?这是完整的代码:
var VSHADER_SOURCE = `
attribute vec4 a_Position;
attribute vec4 a_Color;
attribute vec4 a_Normal;
uniform mat4 u_ModelMatrix;
uniform mat4 u_NormalMatrix;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjMatrix;
uniform vec3 u_LightColor;
uniform vec3 u_LightDirection; // Light direction (in the world coordinate, normalized)
varying vec4 v_Color;
uniform bool u_isLighting;
void main() {
gl_Position = u_ProjMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;
if(u_isLighting)
{
vec3 normal = normalize((u_NormalMatrix * a_Normal).xyz);
float nDotL = max(dot(normal, u_LightDirection), 0.0);
// Calculate the color due to diffuse reflection
vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;
v_Color = vec4(diffuse, a_Color.a); }
else
{
v_Color = a_Color;
}
}
`;
// Fragment shader program
var FSHADER_SOURCE = `
precision mediump float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
`;
var modelMatrix = new Matrix4(); // The model matrix
var viewMatrix = new Matrix4(); // The view matrix
var projMatrix = new Matrix4(); // The projection matrix
var g_normalMatrix = new Matrix4(); // Coordinate transformation matrix for normals
var ANGLE_STEP = 3.0; // The increments of rotation angle (degrees)
var g_xAngle = 0.0; // The rotation x angle (degrees)
var g_yAngle = 0.0; // The rotation y angle (degrees)
function main() {
// Retrieve <canvas> element
var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
var gl = getWebGLContext(canvas);
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
// Initialize shaders
if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
console.log('Failed to intialize shaders.');
return;
}
// Set clear color and enable hidden surface removal
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
// Clear color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
// Get the storage locations of uniform attributes
var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');
var u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
var u_LightDirection = gl.getUniformLocation(gl.program, 'u_LightDirection');
// Trigger using lighting or not
var u_isLighting = gl.getUniformLocation(gl.program, 'u_isLighting');
if (!u_ModelMatrix || !u_ViewMatrix || !u_NormalMatrix ||
!u_ProjMatrix || !u_LightColor || !u_LightDirection ||
!u_isLighting ) {
console.log('Failed to Get the storage locations of u_ModelMatrix, u_ViewMatrix, and/or u_ProjMatrix');
return;
}
// Set the light color (white)
gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
// Set the light direction (in the world coordinate)
var lightDirection = new Vector3([0.5, 3.0, 4.0]);
lightDirection.normalize(); // Normalize
gl.uniform3fv(u_LightDirection, lightDirection.elements);
// Calculate the view matrix and the projection matrix
viewMatrix.setLookAt(0, 0, 15, 0, 0, -100, 0, 1, 0);
projMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100);
// Pass the model, view, and projection matrix to the uniform variable respectively
gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);
document.onkeydown = function(ev){
keydown(ev, gl, u_ModelMatrix, u_NormalMatrix, u_isLighting);
};
var then = 0;
// Draw the scene repeatedly
function render(now) {
now *= 0.001; // convert to seconds
const deltaTime = now - then;
then = now;
g_yAngle = (g_yAngle + 1) % 360;
drawchair(gl, u_ModelMatrix, u_NormalMatrix, u_isLighting, deltaTime)
requestAnimationFrame(render);
}
requestAnimationFrame(render);
//draw(gl, u_ModelMatrix, u_NormalMatrix, u_isLighting);
}
//keyboard functionality
function keydown(ev, gl, u_ModelMatrix, u_NormalMatrix, u_isLighting) {
switch (ev.keyCode) {
case 40: // Up arrow key -> the positive rotation of arm1 around the y-axis
g_xAngle = (g_xAngle + ANGLE_STEP) % 360;
break;
case 38: // Down arrow key -> the negative rotation of arm1 around the y-axis
g_xAngle = (g_xAngle - ANGLE_STEP) % 360;
break;
case 39: // Right arrow key -> the positive rotation of arm1 around the y-axis
g_yAngle = (g_yAngle + ANGLE_STEP) % 360;
break;
case 37: // Left arrow key -> the negative rotation of arm1 around the y-axis
g_yAngle = (g_yAngle - ANGLE_STEP) % 360;
break;
default: return; // Skip drawing at no effective action
}
}
// square vertices
function initVertexBuffersCube(gl) {
// Create a cube
// v6----- v5
// /| /|
// v1------v0|
// | | | |
// | |v7---|-|v4
// |/ |/
// v2------v3
var vertices = new Float32Array([ // Coordinates
0.5, 0.5, 0.5, -0.5, 0.5, 0.5, -0.5,-0.5, 0.5, 0.5,-0.5, 0.5, // v0-v1-v2-v3 front
0.5, 0.5, 0.5, 0.5,-0.5, 0.5, 0.5,-0.5,-0.5, 0.5, 0.5,-0.5, // v0-v3-v4-v5 right
0.5, 0.5, 0.5, 0.5, 0.5,-0.5, -0.5, 0.5,-0.5, -0.5, 0.5, 0.5, // v0-v5-v6-v1 up
-0.5, 0.5, 0.5, -0.5, 0.5,-0.5, -0.5,-0.5,-0.5, -0.5,-0.5, 0.5, // v1-v6-v7-v2 left
-0.5,-0.5,-0.5, 0.5,-0.5,-0.5, 0.5,-0.5, 0.5, -0.5,-0.5, 0.5, // v7-v4-v3-v2 down
0.5,-0.5,-0.5, -0.5,-0.5,-0.5, -0.5, 0.5,-0.5, 0.5, 0.5,-0.5 // v4-v7-v6-v5 back
]);
//shading based on vertices
var colors = new Float32Array([ // Colors
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v1-v2-v3 front
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v3-v4-v5 right
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v0-v5-v6-v1 up
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v1-v6-v7-v2 left
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, // v7-v4-v3-v2 down
1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 // v4-v7-v6-v5 back
]);
var normals = new Float32Array([ // Normal
0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3 front
1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right
0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, // v7-v4-v3-v2 down
0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0, 0.0, 0.0,-1.0 // v4-v7-v6-v5 back
]);
// Indices of the vertices, from which things are built from triangle
// 1_________2
// | /|
// | / |
// | / |
// | / |
// |/________|
// 0 3
// A clockwise arrangement, as it were starting bottom left
var indices = new Uint8Array([
0, 1, 2, 0, 2, 3, // front
4, 5, 6, 4, 6, 7, // right
8, 9,10, 8,10,11, // up
12,13,14, 12,14,15, // left
16,17,18, 16,18,19, // down
20,21,22, 20,22,23 // back
]);
// Write the vertex property to buffers (coordinates, colors and normals)
if (!initArrayBuffer(gl, 'a_Position', vertices, 3, gl.FLOAT)) return -1;
if (!initArrayBuffer(gl, 'a_Color', colors, 3, gl.FLOAT)) return -1;
if (!initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT)) return -1;
// Write the indices to the buffer object
var indexBuffer = gl.createBuffer();
if (!indexBuffer) {
console.log('Failed to create the buffer object');
return false;
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
return indices.length;
}
function initArrayBuffer (gl, attribute, data, num, type) {
// Create a buffer object
var buffer = gl.createBuffer();
if (!buffer) {
console.log('Failed to create the buffer object');
return false;
}
// Write date into the buffer object
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
// Assign the buffer object to the attribute variable
var a_attribute = gl.getAttribLocation(gl.program, attribute);
if (a_attribute < 0) {
console.log('Failed to get the storage location of ' + attribute);
return false;
}
gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
// Enable the assignment of the buffer object to the attribute variable
gl.enableVertexAttribArray(a_attribute);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return true;
}
var g_matrixStack = []; // Array for storing a matrix
function pushMatrix(m) { // Store the specified matrix to the array
var m2 = new Matrix4(m);
g_matrixStack.push(m2);
}
function popMatrix() { // Retrieve the matrix from the array
return g_matrixStack.pop();
}
function drawchair(gl, u_ModelMatrix, u_NormalMatrix, u_isLighting) {
// Clear color and depth buffer
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.uniform1i(u_isLighting, false); // Will not apply lighting
// Calculate the view matrix and the projection matrix
modelMatrix.setTranslate(0, 0, 0); // No Translation
// Pass the model matrix to the uniform variable
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
// Draw x and y axes
gl.drawArrays(gl.LINES, 0, n);
gl.uniform1i(u_isLighting, true); // Will apply lighting
// Set the vertex coordinates and color (for the cube)
var n = initVertexBuffersCube(gl);
if (n < 0) {
console.log('Failed to set the vertex information');
return;
}
//x,y,z
// Rotate, and then translate
modelMatrix.setTranslate(0, 0, -5); // Translation (No translation is supported here)
modelMatrix.rotate(g_yAngle, 0, 1, 0); // Rotate along y axis
modelMatrix.rotate(g_xAngle, 1, 0, 0); // Rotate along x axis
// Model the chair seat
pushMatrix(modelMatrix);
modelMatrix.scale(2.0, 0.4, 2.0); // Scale
drawbox(gl, u_ModelMatrix, u_NormalMatrix, n);
modelMatrix = popMatrix();
// Model the chair back
pushMatrix(modelMatrix);
modelMatrix.translate(0, 1.20, -0.8); // Translation
modelMatrix.scale(2.0, 2.2, 0.4); // Scale
drawbox(gl, u_ModelMatrix, u_NormalMatrix, n);
modelMatrix = popMatrix();
//As if you were sitting on the chair;
//Back right leg
pushMatrix(modelMatrix);
modelMatrix.scale(0.3, 1.9, 0.3);
modelMatrix.translate(-2.6,-0.4,-2.6)
drawbox(gl, u_ModelMatrix, u_NormalMatrix, n);
modelMatrix = popMatrix();
//Back left leg
pushMatrix(modelMatrix);
modelMatrix.scale(0.3, 1.9, 0.3);
modelMatrix.translate(2.6,-0.4,-2.6)
drawbox(gl, u_ModelMatrix, u_NormalMatrix, n);
modelMatrix = popMatrix();
//Front right leg
pushMatrix(modelMatrix);
modelMatrix.scale(0.3, 1.9, 0.3);
modelMatrix.translate(-2.6,-0.4,2.6)
drawbox(gl, u_ModelMatrix, u_NormalMatrix, n);
modelMatrix = popMatrix();
//Front left leg
pushMatrix(modelMatrix);
modelMatrix.scale(0.3, 1.9, 0.3);
modelMatrix.translate(2.6,-0.4,2.6)
drawbox(gl, u_ModelMatrix, u_NormalMatrix, n);
modelMatrix = popMatrix();
}
function drawbox(gl, u_ModelMatrix, u_NormalMatrix, n) {
pushMatrix(modelMatrix);
// Pass the model matrix to the uniform variable
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
// Calculate the normal transformation matrix and pass it to u_NormalMatrix
g_normalMatrix.setInverseOf(modelMatrix); //set the normal matrix as the inverse of the current model
g_normalMatrix.transpose();
gl.uniformMatrix4fv(u_NormalMatrix, false, g_normalMatrix.elements);
// Draw the cube
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
modelMatrix = popMatrix();
}
function drawsphere(gl, u_ModelMatrix, u_NormalMatrix, n) {
pushMatrix(modelMatrix);
// Pass the model matrix to the uniform variable
gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
// Calculate the normal transformation matrix and pass it to u_NormalMatrix
g_normalMatrix.setInverseOf(modelMatrix); //set the normal matrix as the inverse of the current model
g_normalMatrix.transpose();
gl.uniformMatrix4fv(u_NormalMatrix, false, g_normalMatrix.elements);
// Draw the cube
gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
modelMatrix = popMatrix();
}
您需要为每个图形基元创建着色器等的副本。它可以很快将您的代码转换为意大利面条。
您可以通过将图形基元抽象为类并使用合成来创建复杂的形状和图形来改进代码。切换到OOP后,您将受益于拥有多个对象。