WebGL 2.0学习 绘制系列之PRIMITIVE_RESTART_FIXED_INDEX

一、图元重启(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 with Enable/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.
When drawElements, drawElementsInstanced, or drawRangeElements processes an index, if the index's value is the maximum for the data type (255 for UNSIGNED_BYTE indices, 65535 for UNSIGNED_SHORT, or 4294967295 for UNSIGNED_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>
相关推荐
学不会•17 分钟前
css数据不固定情况下,循环加不同背景颜色
前端·javascript·html
EasyNTS1 小时前
H.264/H.265播放器EasyPlayer.js视频流媒体播放器关于websocket1006的异常断连
javascript·h.265·h.264
活宝小娜3 小时前
vue不刷新浏览器更新页面的方法
前端·javascript·vue.js
程序视点3 小时前
【Vue3新工具】Pinia.js:提升开发效率,更轻量、更高效的状态管理方案!
前端·javascript·vue.js·typescript·vue·ecmascript
coldriversnow3 小时前
在Vue中,vue document.onkeydown 无效
前端·javascript·vue.js
我开心就好o3 小时前
uniapp点左上角返回键, 重复来回跳转的问题 解决方案
前端·javascript·uni-app
开心工作室_kaic4 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
刚刚好ā4 小时前
js作用域超全介绍--全局作用域、局部作用、块级作用域
前端·javascript·vue.js·vue
沉默璇年5 小时前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder5 小时前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript