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>
相关推荐
everyStudy44 分钟前
前端五种排序
前端·算法·排序算法
甜兒.2 小时前
鸿蒙小技巧
前端·华为·typescript·harmonyos
她似晚风般温柔7894 小时前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app
Jiaberrr5 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy6 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
城南云小白6 小时前
web基础+http协议+httpd详细配置
前端·网络协议·http
前端小趴菜、6 小时前
Web Worker 简单使用
前端
web_learning_3216 小时前
信息收集常用指令
前端·搜索引擎
Ylucius6 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
tabzzz6 小时前
Webpack 概念速通:从入门到掌握构建工具的精髓
前端·webpack