一、图元重启(PRIMITIVE_RESTART_FIXED_INDEX)
1.1 PRIMITIVE_RESTART_FIXED_INDEX
是webgl2新增的特性,
考虑通常的情况,当用户绘制 GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_LINE_STRIP, GL_LINE_LOOP
这些图元时,所有的绘制点按照特定的顺序被连起来,以形成一个最终的复杂图形,也就是说最终的复杂图形由多个相连的三角形或线段组成。像上面提到的情况,想要绘制分散的图形,应该怎么办?
图元重启(Primitive restart) 允许用户绘制不连续的、分散的图形。考虑使用 glDrawElements
函数,绘制时按照indices
所指定的顶点的顺序来绘制的。此时可以指定某一个值,该值表示一个重启的标志。遇到这个值的时候,WebGL不会绘制图元,而是结束上一段绘制,然后重新启动新的绘制,也就是說用后面的索引所指定的顶点来从头绘制一个图形。
举个例子:比如指定8为重启的标志,遇到8就重启。上面的是不启用图元重启的情况,即通常的情况。下面的是启用图元重启的情况,我们可以看到,从9开始,又重新从头开始绘制Triangle strip
了
1.2 在WebGL2.0的指南中,是这样描述的:
The
PRIMITIVE_RESTART_FIXED_INDEX
context state, controlled withEnable
/Disable
in OpenGL ES 3.0, is not supported in WebGL 2.0. Instead, WebGL 2.0 behaves as though this state were always enabled. This is a compatibility difference compared to WebGL 1.0.
WhendrawElements
,drawElementsInstanced
, ordrawRangeElements
processes an index, if the index's value is the maximum for the data type (255 forUNSIGNED_BYTE
indices, 65535 forUNSIGNED_SHORT
, or 4294967295 forUNSIGNED_INT
), then the vertex is not processed normally. Instead, it is as if the drawing command ended with the immediately preceding vertex, and another drawing command is immediately started with the same parameters, but only transferring the immediately following index through the end of the originally specified indices.``
大概意思就是WebGL2.0中图元重启是默认开启的,当索引值类型为UNSIGNED_BYTE
时设置索引为255,UNSIGNED_SHORT
时设置索引为65535就会自动使用图元重启
二、实例
2.1 使用gl.TRIANGLE_STRIP
绘制三角形,关键代码如下:
js
// -- Init Buffer
var vertices = new Float32Array([
-1.0, -1.0,
-1.0, 1.0,
1.0, -1.0,
1.0, 1.0
]);
var vertexPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
var num_vertices = 7;
var indices = new Uint8Array([
0, 1, 2, 3, 1, 0,3
]);
......
gl.drawElements(gl.TRIANGLE_STRIP, 7, gl.UNSIGNED_BYTE, 0);
结果应该是这样子的:
2.1.1 gl.TRIANGLE_STRIP
绘制方法
其规律是:
构建当前三角形的顶点的连接顺序依赖于要和前面已经出现过的2个顶点组成三角形的当前顶点的序号的奇偶性(如果从0开始):
如果当前顶点是奇数:
组成三角形的顶点排列顺序:T = [n-1 n-2 n].
如果当前顶点是偶数:
组成三角形的顶点排列顺序:T = [n-2 n-1 n].
以上图为例,第一个三角形,顶点v2序号是2,是偶数,则顶点排列顺序是v0,v1,v2。第二个三角形,顶点v3序号是3,是奇数,则顶点排列顺序是v2,v1,v3,第三个三角形,顶点v4序号是4,是偶数,则顶点排列顺序是v2,v3,v4,以此类推。 这个顺序是为了保证所有的三角形都是按照相同的方向绘制的,使这个三角形串能够正确形成表面的一部分。对于某些操作,维持方向是很重要的,比如剔除。
注意:顶点个数n至少要大于3,否则不能绘制任何三角形。 ------------------------------------------------
版权声明:本文为CSDN博主「没有昵称阿」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:blog.csdn.net/xiajun07061...
由此 可以看出,有了前四个索引,其实就已经绘制出来了,结果一模一样
js
//将7改为4
gl.drawElements(gl.TRIANGLE_STRIP, 4, gl.UNSIGNED_BYTE, 0);
2.2 使用图元重启
修改索引值从3改为255
js
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.18
// WebGL 2.0 behaves as though PRIMITIVE_RESTART_FIXED_INDEX were always enabled.
var MAX_UNSIGNED_SHORT = 255;
var indices = new Uint8Array([ 0, 1, 2,MAX_UNSIGNED_SHORT, 1, 0,3 ]);
这样的话就将索引进行了分割并一次性绘制出来 [0,1,2]
和[1,0,3]
结果如下:
2.3 完整代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<title>WebGL 2 Samples - draw_primitive_restart</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="info">WebGL 2 Samples - draw_primitive_restart</div>
<script id="vs" type="x-shader/x-vertex">
#version 300 es
precision highp float;
precision highp int;
layout(location = 0) in vec2 pos;
void main()
{
gl_Position = vec4(pos, 0.0, 1.0);
}
</script>
<script id="fs" type="x-shader/x-fragment">
#version 300 es
precision highp float;
precision highp int;
out vec4 color;
void main()
{
color = vec4(1.0, 0.5, 0.0, 1.0);
}
</script>
<script src="utility.js"></script>
<script>
(function () {
'use strict';
// -- Init Canvas
var canvas = document.createElement('canvas');
canvas.width = Math.min(window.innerWidth, window.innerHeight);
canvas.height = canvas.width;
document.body.appendChild(canvas);
// -- Init WebGL Context
var gl = canvas.getContext('webgl2', { antialias: false });
var isWebGL2 = !!gl;
if(!isWebGL2) {
document.getElementById('info').innerHTML = 'WebGL 2 is not available. See <a href="https://www.khronos.org/webgl/wiki/Getting_a_WebGL_Implementation">How to get a WebGL 2 implementation</a>';
return;
}
// -- Init Program
var program = createProgram(gl, getShaderSource('vs'), getShaderSource('fs'));
gl.useProgram(program);
// -- Init Buffer
var vertices = new Float32Array([
-1.0, -1.0,
-1.0, 1.0,
1.0, -1.0,
1.0, 1.0
]);
var vertexPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
// https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.18
// WebGL 2.0 behaves as though PRIMITIVE_RESTART_FIXED_INDEX were always enabled.
var MAX_UNSIGNED_SHORT = 255;
var num_vertices = 7;
var indices = new Uint8Array([
0, 1, 2, MAX_UNSIGNED_SHORT, 1, 0,3
]);
var vertexElementBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexElementBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
// -- Init Vertex Array
var vertexArray = gl.createVertexArray();
gl.bindVertexArray(vertexArray);
var vertexPosLocation = 0;
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
gl.enableVertexAttribArray(vertexPosLocation);
gl.vertexAttribPointer(vertexPosLocation, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexElementBuffer);
gl.bindVertexArray(null);
// -- Render
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.bindVertexArray(vertexArray);
gl.drawElements(gl.TRIANGLE_STRIP, 7, gl.UNSIGNED_BYTE, 0);
// -- Delete WebGL resources
gl.deleteBuffer(vertexPosBuffer);
gl.deleteBuffer(vertexElementBuffer);
gl.deleteProgram(program);
gl.deleteVertexArray(vertexArray);
})();
</script>
</body>
</html>