我想通过使用统一缓冲区对象和实例化渲染来绘制带有动画的多个对象。
我已经使用for循环实现了此功能,但我想一次渲染它们。
这是我的代码,当单击鼠标时,使用for循环呈现多个对象。
我正在使用四个外部库,分别是webgl-utils.js,webgl-debug.js,cuon-utils.js,cuon-matrix.js。可以在here中找到。
"use strict";
const loc_aPosition = 1;
const VSHADER_SOURCE =
`#version 300 es
layout(location=${loc_aPosition}) in vec4 aPosition;
uniform mat4 uRotMatrix;
uniform mat4 uScaleMatrix;
uniform vec2 uOffSet;
void main() {
gl_Position = aPosition * uScaleMatrix * uRotMatrix + vec4(uOffSet, 0, 0);
}`;
const FSHADER_SOURCE =
`#version 300 es
precision mediump float;
out vec4 fColor;
uniform vec4 uColor;
void main() {
fColor = uColor;
}`;
function main() {
// Retrieve <canvas> element
let canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
let gl = canvas.getContext("webgl2");
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;
}
const loc_uOffSet = gl.getUniformLocation(gl.program, 'uOffSet');
const loc_uColor = gl.getUniformLocation(gl.program, 'uColor');
const loc_uRotMatrix = gl.getUniformLocation(gl.program, 'uRotMatrix');
const loc_uScaleMatrix = gl.getUniformLocation(gl.program, 'uScaleMatrix');
if(!loc_uOffSet)
{
console.log("Failed to load uOffSet uniform variable.");
return;
}
if(!loc_uColor)
{
console.log("Failed to load uColor uniform variable.");
return;
}
if(!loc_uRotMatrix)
{
console.log("Failed to load uModelMatrix uniform variable.");
return;
}
if(!loc_uScaleMatrix)
{
console.log("Falied to load uScaleMatrix uniform variable.");
return;
}
let n = initVertexBuffers(gl);
if(n < 0)
{
console.log('Failed to set the positions of the vertices');
return;
}
// Register function (event handler) to be called on a mouse press
canvas.onmousedown = function(ev){ click(ev, gl, canvas) };
// Specify the color for clearing <canvas>
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
let tick = function()
{
animate(); // Update the rotation angle
draw(gl, loc_uRotMatrix, loc_uOffSet, loc_uColor, loc_uScaleMatrix); // Draw
requestAnimationFrame(tick, canvas); // Request that the browser calls tick
};
tick();
}
//These are the arrays for the attributes of the stars
let g_vertices = [];
let g_angles = [];
let g_colors = [];
let g_ages = [];
let g_scale = [];
const ANGLE_STEP = -60;
let g_last = Date.now();
function click(ev, gl, canvas)
{
let x = ev.clientX; // x coordinate of a mouse pointer
let y = ev.clientY; // y coordinate of a mouse pointer
let rect = ev.target.getBoundingClientRect();
x = ((x - rect.left) - canvas.width/2)/(canvas.width/2);
y = (canvas.height/2 - (y - rect.top))/(canvas.height/2);
// Store the coordinates and color
g_vertices.push([x,y]);
g_angles.push(0);
g_ages.push(Date.now());
g_scale.push(1);
let randomPos = Math.floor(Math.random() * Math.floor(3));
let rgba = [4];
let randomColor = Math.random();
for(let i = 0; i<4; i++)
{
rgba[i] = randomColor;
}
rgba[3] = 1.0;
rgba[randomPos] = Math.random();
g_colors.push(rgba);
}
//Make the BO for making stars
function initVertexBuffers(gl)
{
let vertices = new Float32Array([
0, -0.2,
-0.3, -0.4,
0.0, 0.5,
0.3, -0.4,
0.0, 0.5,
0.0, 0.3,
-0.4, 0.3,
0.4, 0.3,
0.0, 0.3,
]);
let n = 9;
//Create a buffer Object
let posBuffer = gl.createBuffer();
if(!posBuffer)
{
console.log('Failed to create the buffer object');
return;
}
//Bind the buffer object to target
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
//Write date into the buffer object
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
//Connect the assignment to a_Position variable
gl.vertexAttribPointer(loc_aPosition, 2, gl.FLOAT, false, 0, 0);
//Enable the assignment to a_Position variable
gl.enableVertexAttribArray(loc_aPosition);
return n;
}
function animate()
{
// Calculate the elapsed time
let now = Date.now();
let elapsed = now - g_last;
g_last = now;
// Update the current rotation angle (adjusted by the elapsed time)
for(let i = 0; i<g_angles.length; i++)
{
g_angles[i] = g_angles[i] + (ANGLE_STEP * elapsed) / 1000.0;
g_angles[i] %= 360;
g_scale[i] *= 0.99;
}
}
function draw(gl, loc_uModelMatrix, loc_uOffSet, loc_uColor, loc_uScaleMatrix)
{
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
let rotMatrix = new Matrix4();
let scaleMatrix = new Matrix4();
// Draw the stars
let len = g_vertices.length;
for(let i = 0; i < len; i++)
{
if((Date.now() - g_ages[i]) / 1000 > 3.5 ) // dissapear stars about 3.5 seconds after
continue;
let rgba = g_colors[i];
rotMatrix.setRotate(g_angles[i], 0, 0, 1);
scaleMatrix.setScale(g_scale[i], g_scale[i], 1);
//Set the uniform variables
gl.uniformMatrix4fv(loc_uModelMatrix, false, rotMatrix.elements);
gl.uniformMatrix4fv(loc_uScaleMatrix, false, scaleMatrix.elements);
gl.uniform2f(loc_uOffSet, g_vertices[i][0], g_vertices[i][1]);
gl.uniform4f(loc_uColor, rgba[0], rgba[1], rgba[2], rgba[3]);
gl.drawArrays(gl.TRIANGLE_FAN, 0, 9);
//Reset matrices for the next star
rotMatrix.setIdentity();
scaleMatrix.setIdentity();
}
}
这是示例图像的外观和工作方式:
我修改了上面的代码,就像这样
"use strict";
const loc_aPosition = 1;
const VSHADER_SOURCE =
`#version 300 es
layout(location=${loc_aPosition}) in vec4 aPosition;
uniform matrices
{
mat4 uScaleMat;
mat4 uRotMat;
vec2 uOffSetXY;
};
void main() {
gl_Position = aPosition * uScaleMat * uRotMat + vec4(uOffSetXY, 0, 0);
}`;
// Fragment shader program
const FSHADER_SOURCE =
`#version 300 es
uniform colors
{
vec4 uColorVec;
}
precision mediump float;
out vec4 fColor;
void main() {
fColor = uColorVec;
}`;
function main() {
// Retrieve <canvas> element
var canvas = document.getElementById('webgl');
// Get the rendering context for WebGL
var gl = canvas.getContext("webgl2");
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;
}
const loc_uOffSet = gl.getUniformLocation(gl.program, 'uOffSet');
const loc_uColor = gl.getUniformLocation(gl.program, 'uColor');
const loc_uModelMatrix = gl.getUniformLocation(gl.program, 'uModelMatrix');
const loc_uScaleMatrix = gl.getUniformLocation(gl.program, 'uScaleMatrix');
if(!loc_uOffSet)
{
console.log("Failed to load uOffSet uniform variable.");
return;
}
if(!loc_uColor)
{
console.log("Failed to load uColor uniform variable.");
return;
}
if(!loc_uModelMatrix)
{
console.log("Failed to load uModelMatrix uniform variable.");
return;
}
if(!loc_uScaleMatrix)
{
console.log("Falied to load uScaleMatrix uniform variable.");
return;
}
let matR = new Matrix4();
let matS = new Matrix4();
let offSetXY = [];
let colors = [];
let prog = gl.program
let {vao, n} = initVertexBuffers(gl);
let {vubo, cubo, matBuffer, colorBuffer} = initUBO(gl, prog, matR, matS, offSetXY, colors);
if(n < 0)
{
console.log('Failed to set the positions of the vertices');
return;
}
// Register function (event handler) to be called on a mouse press
canvas.onmousedown = function(ev){ click(ev, gl, canvas) };
// Specify the color for clearing <canvas>
gl.clearColor(0.0, 0.0, 0.0, 1.0);
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
let tick = function()
{
animate();
render(gl, prog, vao, n, g_stars, matBuffer, colorBuffer, matR, matS, offSetXY, colors, vubo, cubo)
requestAnimationFrame(tick, canvas); // Request that the browser calls tick
};
tick();
}
let g_vertices = []; // The array for the position of Triangle with mouse click
let g_angles = [];
let g_colors = [];
let g_ages = [];
let g_scale = [];
const ANGLE_STEP = -60;
const MAX_TRIANGLES = 30;
let g_last = Date.now();
let g_stars = 0;
function click(ev, gl, canvas)
{
let x = ev.clientX; // x coordinate of a mouse pointer
let y = ev.clientY; // y coordinate of a mouse pointer
let rect = ev.target.getBoundingClientRect();
x = ((x - rect.left) - canvas.width/2)/(canvas.width/2);
y = (canvas.height/2 - (y - rect.top))/(canvas.height/2);
// Store the coordinates and color
g_vertices.push([x,y]);
g_angles.push(0);
g_ages.push(Date.now());
g_scale.push(1);
g_stars++;
let randomPos = Math.floor(Math.random() * Math.floor(3));
let rgba = [4];
let randomColor = Math.random();
for(let i = 0; i<4; i++)
{
rgba[i] = randomColor;
}
rgba[3] = 1.0;
rgba[randomPos] = Math.random();
g_colors.push(rgba);
}
function initVertexBuffers(gl)
{
let vertices = new Float32Array([
0, -0.2,
-0.3, -0.4,
0.0, 0.5,
0.3, -0.4,
0.0, 0.5,
0.0, 0.3,
-0.4, 0.3,
0.4, 0.3,
0.0, 0.3,
]);
let n = 9;
//Create a buffer Object
let posBuffer = gl.createBuffer();
let vao = gl.createVertexArray();
if(!posBuffer)
{
console.log('Failed to create the buffer object');
return;
}
gl.bindVertexArray(vao);
//Bind the buffer object to target
gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
//Write date into the buffer object
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
//Connect the assignment to a_Position variable
gl.vertexAttribPointer(loc_aPosition, 2, gl.FLOAT, false, 0, 0);
//Enable the assignment to a_Position variable
gl.enableVertexAttribArray(loc_aPosition);
return {vao, n};
}
function animate()
{
// Calculate the elapsed time
let now = Date.now();
let elapsed = now - g_last;
g_last = now;
// Update the current rotation angle (adjusted by the elapsed time)
for(let i = 0; i<g_angles.length; i++)
{
g_angles[i] = g_angles[i] + (ANGLE_STEP * elapsed) / 1000.0;
g_angles[i] %= 360;
g_scale[i] *= 0.99;
}
}
function draw(gl, loc_uModelMatrix, loc_uOffSet, loc_uColor, loc_uScaleMatrix)
{
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
let rotMatrix = new Matrix4();
let scaleMatrix = new Matrix4();
// Draw the rectangle
let len = g_vertices.length;
for(let i = 0; i < len; i++)
{
if((Date.now() - g_ages[i]) / 1000 > 3.5 )
continue;
let rgba = g_colors[i];
rotMatrix.setRotate(g_angles[i], 0, 0, 1);
scaleMatrix.setScale(g_scale[i], g_scale[i], 1);
gl.uniformMatrix4fv(loc_uModelMatrix, false, rotMatrix.elements);
gl.uniformMatrix4fv(loc_uScaleMatrix, false, scaleMatrix.elements);
gl.uniform2f(loc_uOffSet, g_vertices[i][0], g_vertices[i][1]);
gl.uniform4f(loc_uColor, rgba[0], rgba[1], rgba[2], rgba[3]);
gl.drawArrays(gl.TRIANGLE_FAN, 0, 9);
rotMatrix.setIdentity();
scaleMatrix.setIdentity();
}
}
function initUBO(gl, prog, matR, matS, offSetXY, colors)
{
let vertexBinding_Matrices = 1;
let fragBinding_Colors = 2;
let vubo = gl.createBuffer();
let cubo = gl.createBuffer();
gl.bindBufferBase(gl.UNIFORM_BUFFER, vertexBinding_Matrices, vubo);
gl.bindBufferBase(gl.UNIFORM_BUFFER, fragBinding_Colors, cubo);
let idx_uniform_block1 = gl.getUniformBlockIndex(prog, 'matrices');
let idx_uniform_block2 = gl.getUniformBlockIndex(prog, 'colors');
gl.uniformBlockBinding(prog, idx_uniform_block1, vertexBinding_Matrices);
gl.uniformBlockBinding(prog, idx_uniform_block2, fragBinding_Colors);
let FSIZE = 4;
let matBuffer = new ArrayBuffer(FSIZE * 16 * 2 + FSIZE * 2);
matR.elements = new Float32Array(matBuffer, 0, 16);
matS.elements = new Float32Array(matBuffer, FSIZE * 16, 16);
offSetXY = new Float32Array(matBuffer, FSIZE * 16 * 2, 2);
gl.bindBuffer(gl.UNIFORM_BUFFER, vubo);
gl.bufferData(gl.UNIFORM_BUFFER, FSIZE * 16 * 2 + FSIZE * 2, gl.DYNAMIC_DRAW);
gl.bindBuffer(gl.UNIFORM_BUFFER, null);
let colorBuffer = new ArrayBuffer(FSIZE * 4);
colors = new Float32Array(colorBuffer, 0, 4);
gl.bindBuffer(gl.UNIFORM_BUFFER, cubo);
gl.bufferData(gl.UNIFORM_BUFFER, FSIZE * 4, gl.DYNAMIC_DRAW);
gl.bindBuffer(gl.UNIFORM_BUFFER, null);
return {vubo, cubo, matBuffer, colorBuffer};
}
function render(gl, prog, vao, n, g_stars, matBuffer, colorBuffer, matR, matS, offSetXY, colors, vubo, cubo)
{
}
仍然有很多事情可以解决这个问题...我只是想知道我是否走在正确的轨道上...
是否有使用ubos和实例渲染的示例?
p.s因为我不是英语母语人士,所以这个问题和代码都可能存在错别字...
我想通过使用均匀缓冲区objets和实例化渲染来绘制带有动画的多个对象。我已经使用for循环实现了此功能,但我想一次渲染它们。这是我的代码...
Universal Buffer Objects是设置制服的另一种方法。他们对实例化没有帮助。与使用gl.uniformXXX
相比,它们只是“潜在地”更快设置制服的一种方法。例如,如果您的着色器采用ambient
,diffuse
,specular
,shininess
作为输入,则可以制作一个包含这4种制服的制服块。然后,您可以为每种材质创建一个统一的缓冲对象,所有这四个设置,都可以使用一个WebGL功能设置不同的材质。