1 回答

TA貢獻(xiàn)1744條經(jīng)驗(yàn) 獲得超4個(gè)贊
有很多方法可以優(yōu)化繪制很多東西,但由于 yoi 剛剛開始,最重要的是通常設(shè)置緩沖區(qū)應(yīng)該發(fā)生在初始化時(shí)間,而不是渲染時(shí)間。
請(qǐng)參閱在 WebGL 中繪制多個(gè)模型
問題中的代碼是查找每個(gè)三角形的位置。它應(yīng)該將位置查找為初始時(shí)間。
該代碼還為每個(gè)三角形創(chuàng)建一個(gè)新緩沖區(qū)。創(chuàng)建一個(gè)緩沖區(qū)并使用新三角形更新它會(huì)更快,當(dāng)然最終它會(huì)耗盡內(nèi)存來(lái)創(chuàng)建新緩沖區(qū)。
const context = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
}
`;
const redFS = `
precision highp float;
void main() {
gl_FragColor = vec4(1, 0, 0, 1);
}
`;
const blueFS = `
precision highp float;
void main() {
gl_FragColor = vec4(0, 0, 1, 1);
}
`;
const blueProgram = twgl.createProgram(context, [vs, blueFS]);
const blueProgramInfo = {
program: blueProgram,
a_PositionLocation: context.getAttribLocation(blueProgram, "a_Position"),
};
const redProgram = twgl.createProgram(context, [vs, redFS]);
const redProgramInfo = {
program: redProgram,
a_PositionLocation: context.getAttribLocation(redProgram, "a_Position"),
};
const buffer = context.createBuffer();
function rand(min, max) {
return Math.random() * (max - min) + min;
}
// pre allocate
const triangleData = new Float32Array(6); // 3 vertices, 2 values per
function getTriangleGeometry() {
const x = rand(-1, 1);
const y = rand(-1, 1);
triangleData[0] = x;
triangleData[1] = y;
triangleData[2] = x + rand(-0.1, 0.1);
triangleData[3] = y + rand(-0.1, 0.1);
triangleData[4] = x + rand(-0.1, 0.1);
triangleData[5] = y + rand(-0.1, 0.1);
return triangleData;
}
function render() {
context.clear(context.COLOR_BUFFER_BIT);
for (let i = 0; i < 100; i++) {
const currentProgramInfo = i % 2 === 0 ? blueProgramInfo : redProgramInfo;
context.useProgram(currentProgramInfo.program);
const a_Position = currentProgramInfo.a_PositionLocation;
const triangleGeometry = getTriangleGeometry(); // returns Float32Array filled with randoms
context.bindBuffer(context.ARRAY_BUFFER, buffer);
context.bufferData(context.ARRAY_BUFFER, triangleGeometry, context.STATIC_DRAW);
context.enableVertexAttribArray(a_Position);
context.vertexAttribPointer(
a_Position,
2,
context.FLOAT,
false,
0,
0,
);
context.drawArrays(context.TRIANGLES, 0, 3);
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
問題中的代碼似乎使用了 2 個(gè)程序,一個(gè)繪制藍(lán)色,一個(gè)繪制紅色。讓一個(gè)帶有制服的程序來(lái)選擇顏色可能會(huì)更快。
const context = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 a_Position;
void main() {
gl_Position = a_Position;
}
`;
const fs = `
precision highp float;
uniform vec4 u_Color;
void main() {
gl_FragColor = u_Color;
}
`;
const program = twgl.createProgram(context, [vs, fs]);
const programInfo = {
program: program,
a_PositionLocation: context.getAttribLocation(program, "a_Position"),
u_ColorLocation: context.getUniformLocation(program, "u_Color"),
};
const buffer = context.createBuffer();
function rand(min, max) {
return Math.random() * (max - min) + min;
}
// pre allocate
const triangleData = new Float32Array(6); // 3 vertices, 2 values per
function getTriangleGeometry() {
const x = rand(-1, 1);
const y = rand(-1, 1);
triangleData[0] = x;
triangleData[1] = y;
triangleData[2] = x + rand(-0.1, 0.1);
triangleData[3] = y + rand(-0.1, 0.1);
triangleData[4] = x + rand(-0.1, 0.1);
triangleData[5] = y + rand(-0.1, 0.1);
return triangleData;
}
const blue = [0, 0, 1, 1];
const red = [1, 0, 0, 1];
function render() {
context.clear(context.COLOR_BUFFER_BIT);
context.useProgram(programInfo.program);
const a_Position = programInfo.a_PositionLocation;
context.bindBuffer(context.ARRAY_BUFFER, buffer);
context.enableVertexAttribArray(a_Position);
context.vertexAttribPointer(
a_Position,
2,
context.FLOAT,
false,
0,
0,
);
for (let i = 0; i < 100; i++) {
const color = i % 2 === 0 ? blue : red;
context.uniform4fv(programInfo.u_ColorLocation, color);
const triangleGeometry = getTriangleGeometry(); // returns Float32Array filled with randoms
context.bufferData(context.ARRAY_BUFFER, triangleGeometry, context.STATIC_DRAW);
context.drawArrays(context.TRIANGLES, 0, 3);
}
requestAnimationFrame(render);
}
requestAnimationFrame(render);
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
如果在初始化時(shí)將所有三角形放在一個(gè)緩沖區(qū)中,并且在初始化時(shí)將每個(gè)三角形的頂點(diǎn)顏色放在緩沖區(qū)中,然后在渲染時(shí)使用單個(gè)繪制調(diào)用繪制它們,速度會(huì)明顯更快。如果您想要每幀隨機(jī)三角形,那么在初始化時(shí)創(chuàng)建一個(gè)緩沖區(qū),在單個(gè)緩沖區(qū)中填充 N 個(gè)隨機(jī)三角形,然后在一次繪制調(diào)用中將它們?nèi)坷L制出來(lái),仍然會(huì)更快。
const context = document.querySelector('canvas').getContext('webgl');
const vs = `
attribute vec4 a_Position;
attribute vec4 a_Color;
varying vec4 v_Color;
void main() {
gl_Position = a_Position;
v_Color = a_Color;
}
`;
const fs = `
precision highp float;
varying vec4 v_Color;
void main() {
gl_FragColor = v_Color;
}
`;
const program = twgl.createProgram(context, [vs, fs]);
const programInfo = {
program: program,
a_PositionLocation: context.getAttribLocation(program, "a_Position"),
a_ColorLocation: context.getAttribLocation(program, "a_Color"),
u_ColorLocation: context.getUniformLocation(program, "u_Color"),
};
const positionBuffer = context.createBuffer();
const colorBuffer = context.createBuffer();
function rand(min, max) {
return Math.random() * (max - min) + min;
}
const numTriangles = 1000;
const positionData = new Float32Array(numTriangles * 3 * 2);
const colorData = new Float32Array(numTriangles * 3 * 4);
const blue = [0, 0, 1, 1];
const red = [1, 0, 0, 1];
// the color data does not change so fill it out at init time
for (let i = 0; i < numTriangles; ++i) {
const offset = i * 4;
colorData.set(i % 2 === 0 ? blue : red, offset);
}
context.bindBuffer(context.ARRAY_BUFFER, colorBuffer);
context.bufferData(context.ARRAY_BUFFER, colorData, context.STATIC_DRAW);
function getTriangleGeometry() {
for (let i = 0; i < numTriangles; ++i) {
const offset = i * 3 * 2; // 3 verts per tri, 2 values per ver
const x = rand(-1, 1);
const y = rand(-1, 1);
positionData[offset ] = x;
positionData[offset + 1] = y;
positionData[offset + 2] = x + rand(-0.1, 0.1);
positionData[offset + 3] = y + rand(-0.1, 0.1);
positionData[offset + 4] = x + rand(-0.1, 0.1);
positionData[offset + 5] = y + rand(-0.1, 0.1);
}
return positionData;
}
function render() {
context.clear(context.COLOR_BUFFER_BIT);
context.useProgram(programInfo.program);
const a_Position = programInfo.a_PositionLocation;
context.bindBuffer(context.ARRAY_BUFFER, positionBuffer);
const triangleGeometry = getTriangleGeometry(); // returns Float32Array filled with randoms
context.bufferData(context.ARRAY_BUFFER, triangleGeometry, context.DYNAMIC_DRAW);
context.enableVertexAttribArray(a_Position);
context.vertexAttribPointer(
a_Position,
2,
context.FLOAT,
false,
0,
0,
);
const a_Color = programInfo.a_ColorLocation;
context.bindBuffer(context.ARRAY_BUFFER, colorBuffer);
context.enableVertexAttribArray(a_Color);
context.vertexAttribPointer(
a_Color,
4,
context.FLOAT,
false,
0,
0,
);
context.drawArrays(context.TRIANGLES, 0, numTriangles * 3);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>
<canvas></canvas>
像上面那樣在每一幀中繪制一堆隨機(jī)三角形可以說(shuō)是一個(gè)例外。大多數(shù) WebGL 應(yīng)用程序繪制在建模包中創(chuàng)建的 3D 模型,因此更常見的是在初始化時(shí)將數(shù)據(jù)放入緩沖區(qū)一次(如立方體、球體、汽車、人、樹的數(shù)據(jù)),然后在渲染時(shí)繪制它。
另請(qǐng)注意,GPU 只能繪制這么多像素,因此如果您的三角形很大(如整個(gè)屏幕的大?。?,您將只能繪制 10 到幾百個(gè))。1920x1080 的屏幕約為 2 百萬(wàn)像素。所以每個(gè)全屏三角形也將是大約 200 萬(wàn)像素。繪制其中的 1000 個(gè)是 2000 * 200 萬(wàn)或 40 億像素。每秒 60 幀 2400 億像素。中高端 GPU 每秒只能繪制 100 億幀,這是理論上的最大值,因此它最多只能以每秒 2 幀的速度進(jìn)行繪制。
大多數(shù) 3D 應(yīng)用程序繪制的場(chǎng)景中,大多數(shù)三角形都很遠(yuǎn)且很小。他們還使用深度緩沖區(qū)并從前到后繪制不透明對(duì)象,這樣后面的像素就不會(huì)被繪制。
添加回答
舉報(bào)