我正在阅读here的教程。
<script class = "WebGL">
var gl;
function initGL() {
// Get A WebGL context
var canvas = document.getElementById("canvas");
gl = getWebGLContext(canvas);
if (!gl) {
return;
}
}
var positionLocation;
var resolutionLocation;
var colorLocation;
var translationLocation;
var rotationLocation;
var translation = [50,50];
var rotation = [0, 1];
var angle = 0;
function initShaders() {
// setup GLSL program
vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");
program = createProgram(gl, [vertexShader, fragmentShader]);
gl.useProgram(program);
// look up where the vertex data needs to go.
positionLocation = gl.getAttribLocation(program, "a_position");
// lookup uniforms
resolutionLocation = gl.getUniformLocation(program, "u_resolution");
colorLocation = gl.getUniformLocation(program, "u_color");
translationLocation = gl.getUniformLocation(program, "u_translation");
rotationLocation = gl.getUniformLocation(program, "u_rotation");
// set the resolution
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
}
function initBuffers() {
// Create a buffer.
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// Set Geometry.
setGeometry(gl);
}
function setColor(red, green, blue) {
gl.uniform4f(colorLocation, red, green, blue, 1);
}
// Draw the scene.
function drawScene() {
// Clear the canvas.
gl.clear(gl.COLOR_BUFFER_BIT);
// Set the translation.
gl.uniform2fv(translationLocation, translation);
// Set the rotation.
gl.uniform2fv(rotationLocation, rotation);
// Draw the geometry.
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
// Fill the buffer with the values that define a letter 'F'.
function setGeometry(gl) {
/*Assume size1 is declared*/
var vertices = [
-size1/2, -size1/2,
-size1/2, size1/2,
size1/2, size1/2,
size1/2, size1/2,
size1/2, -size1/2,
-size1/2, -size1/2 ];
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array(vertices),
gl.STATIC_DRAW);
}
function animate() {
translation[0] += 0.01;
translation[1] += 0.01;
angle += 0.01;
rotation[0] = Math.cos(angle);
rotation[1] = Math.sin(angle);
}
function tick() {
requestAnimFrame(tick);
drawScene();
animate();
}
function start() {
initGL();
initShaders();
initBuffers();
setColor(0.2, 0.5, 0.5);
tick();
}
</script>
<!-- vertex shader -->
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
uniform vec2 u_translation;
uniform vec2 u_rotation;
void main() {
vec2 rotatedPosition = vec2(
a_position.x * u_rotation.y + a_position.y * u_rotation.x,
a_position.y * u_rotation.y - a_position.x * u_rotation.x);
// Add in the translation.
vec2 position = rotatedPosition + u_translation;
// convert the position from pixels to 0.0 to 1.0
vec2 zeroToOne = position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace, 0, 1);
}
</script>
<!-- fragment shader -->
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
uniform vec4 u_color;
void main() {
gl_FragColor = u_color;
}
</script>
我的1个形状的WebGL程序的工作原理如下:
drawScene()
:致电gl.drawArrays()
drawScene()
中tick()
,以便重复调用它。现在当我需要超过1个形状时,我是否应该使用多个对象一次填充单个缓冲区,然后使用它稍后调用drawScene()
一次绘制所有对象
的 [OR]
我是否应该从initBuffer
重复拨打drawScene()
和requestAnimFrame()
。
答案 0 :(得分:7)
在伪代码中
在初始时
抽奖时间
gl.useProgram
gl.enableVertexAttribArray
,gl.bindBuffer
和gl.vertexAttribPointer
,并使用当前着色器的属性位置。gl.uniformXXX
gl.drawArrays
或者数据被编入索引gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferOfIndicesForCurrentShape)
后跟gl.drawElements
常见优化
1)通常你不需要设置每件制服。例如,如果您使用相同着色器绘制10个形状,并且着色器采用viewMatrix或cameraMatrix,则可能viewMatrix uniform或cameraMatrix uniform对于每个形状都相同,因此只需将其设置一次。
2)您经常可以将gl.enableVertexAttribArray
的呼叫移至初始化时间。
答案 1 :(得分:2)
在一个缓冲区中拥有多个网格(并按照您的建议使用单个gl.drawArrays()
渲染)会在复杂场景中产生更好的性能,但显然此时您无法更改着色器制服(例如变换)每个网格。
如果你想让网格独立运行,你必须分别渲染每个网格。您仍然可以将所有网格保留在一个缓冲区中,以避免gl.bindBuffer()
次调用产生的一些开销,但imho对此没什么帮助,至少在简单的场景中是这样。
答案 2 :(得分:0)
为场景中的每个对象单独创建缓冲区,否则它们将无法独立移动和使用着色器效果。
但是,如果您的对象不同。从我这里得到的结果来看,我认为你只想在不同的位置上不止一次地绘制相同的形状?
你要做的就是在第一次绘制形状后,将translationLocation
统一设置在那里,使用不同的平移矩阵。这样当你再次绘制形状时,它将位于其他地方,而不是在另一个的顶部,因此你可以看到它。您可以以不同方式设置所有这些转换矩阵,然后再次调用gl.drawElements
,因为您要绘制已经在使用的相同缓冲区。