zoukankan      html  css  js  c++  java
  • [WebGL入门]十五,为多边形涂抹颜色(顶点颜色的指定)

    注:文章译自http://wgld.org/。原作者杉本雅広(doxas),文章中假设有我的额外说明,我会加上[lufy:]。另外。鄙人webgl研究还不够深入。一些专业词语。假设翻译有误。欢迎大家指正。



    本次的demo的执行结果

    添加顶点属性的个数

    上次,最终绘制了一个三角形。可是仅仅绘制了一个纯白色的多边形。


    这次。给多边形的顶点中加入颜色属性,基本上做的事情和上一篇文章一样,仅仅是略微添加点步骤而已。


    首先,就像曾经多次反复的那样,顶点能够包括非常多种情报(參考:顶点缓存和基础)。并且每个情报叫做一个顶点属性。

    上一篇的demo,顶点种仅仅包括了位置情报这一个顶点属性,这一次加入一个颜色的顶点属性。
    一个顶点属性。须要有一个东西和它相应,还记得吧。


    答案就是,顶点缓存(VBO)。上一篇中准备了保存位置用的VBO进行渲染,这次再准备还有一个VBO,同一时候将位置情报的VBO和颜色情报的VBO都传给顶点着色器。来给多边形着色。


    着色器代码的改动

    那么,先从着色器的代码開始看吧。
    这次,须要两个attribute变量。各自是为了接收顶点的位置和颜色。
    >顶点着色器的代码

    attribute vec3 position;
    attribute vec4 color;
    uniform   mat4 mvpMatrix;
    varying   vec4 vColor;
    
    void main(void){
        vColor = color;
        gl_Position = mvpMatrix * vec4(position, 1.0);
    }
    能够看到,一同声明了两个attribute变量。position和上次一样,没有变化,在它以下多了一个color,是为了处理顶点的颜色。
    而上一篇中没有出现的varying变量。这一次也出现了。

    就当作是复习了,再简单说一下,varying变量是顶点着色器和片段着色器之间的桥梁。看一下main函数中的代码就知道了,仅仅须要将attribute变量中的顶点的颜色直接赋值给varying变量。


    加了这个处理之后,顶点着色器中的顶点属性就能传给片段着色器了。当然。顶点着色器中不须要做不论什么处理就能将数据传给片段着色器,这也是可编辑渲染管线的长处之中的一个。
    接着,看片段着色器。
    >片段着色器的代码

    precision mediump float;
    varying vec4 vColor;
    void main(void){
        gl_FragColor = vColor;
    }
    上一篇中使用的片段着色器,直接将颜色数据代入到了中的gl_FragColor中,所以绘制出的三角形是单色的。这一次,使用从顶点着色器传来的varying类型的变量vColor,那么顶点的颜色属性就会对多边形产生影响。


    *尽管说顶点着色器和片段着色器中都使用了相同的名字的varying变量,可是事实上是两个全然不同的变量。

    >>指定准确度的precision

    这一次的片段着色器中的第一行。出现了一个陌生的precision,这个precision是用来指定数值的准确度的keyword。紧接着跟在precision后面的是准确度修饰符。
    这个修饰符有三种,简单点说就是指定准确度为上。中,下。事实上。变量中使用的小数发生变化时(也就是说。处理的数值的位数添加或是降低),依据执行的环境不同得到的结果是不太统一的。
    lowp   :准确度低
    mediump:准确度中
    highp  :准确度高
    上面的片段着色器代码中,precision后面紧接着写的是mediump float,这是说。让片段着色器中的float类型的数值的准确度都依照mediump来用。
    无论在片段着色器中有没有做什么特殊的处理。首先要将precision相关的设定写上,否则在编译着色器的时候会出错。

    这就像魔法的咒语一样,逃不掉的。


    顶点缓存相关的处理

    着色器之后。该是VBO了。这里尽管添加了一些内容,事实上仅仅是相同的东西做了两次,细致看的话,就会明确过来。跟上次基本上没什么变化吧。
    >顶点数据的矩阵的做成

    // 从数组中获取attributeLocation
    var attLocation = new Array(2);
    attLocation[0] = gl.getAttribLocation(prg, 'position');
    attLocation[1] = gl.getAttribLocation(prg, 'color');
    
    // 将元素数attribute保存到数组中
    var attStride = new Array(2);
    attStride[0] = 3;
    attStride[1] = 4;
    
    // 保存顶点的位置情报的数组
    var vertex_position = [
         0.0, 1.0, 0.0,
         1.0, 0.0, 0.0,
        -1.0, 0.0, 0.0
    ];
    
    // 保存顶点的颜色情报的数组
    var vertex_color = [
        1.0, 0.0, 0.0, 1.0,
        0.0, 1.0, 0.0, 1.0,
        0.0, 0.0, 1.0, 1.0
    ];
    上次的顶点属性仅仅有一个。所以保存顶点属性的序号的是一个纯粹的变量。这次,顶点属性有两个,所以使用了数组。而颜色是由RGBA四个元素组成的,所以颜色情报的数组长度为[顶点数 x 4]。
    将顶点数据保存到数组之后,下一步就是依据数组来生成VBO了。

    以下是代码。
    >依据顶点数据数组生成VBO

    // 生成VBO
    var position_vbo = create_vbo(vertex_position);
    var color_vbo = create_vbo(vertex_color);
    
    // VBO绑定(位置情报)
    gl.bindBuffer(gl.ARRAY_BUFFER, position_vbo);
    gl.enableVertexAttribArray(attLocation[0]);
    gl.vertexAttribPointer(attLocation[0], attStride[0], gl.FLOAT, false, 0, 0);
    
    // VBO绑定(颜色情报)
    gl.bindBuffer(gl.ARRAY_BUFFER, color_vbo);
    gl.enableVertexAttribArray(attLocation[1]);
    gl.vertexAttribPointer(attLocation[1], attStride[1], gl.FLOAT, false, 0, 0);
    生成VBO之后。进行绑定,写入数据等处理,位置情报和颜色情报都是相同的,所以是反复了两次相同的处理。有人看到这里可能会有些想法了。VBO周围的处理,能够直接做成一个函数,将数组当作參数传进来基本上就攻克了。

    总结

    以上,就是与上一篇的内容相比的变更点。

    主要就是着色器和VBO周围的处理有了些小变化。假设再给顶点添加其它新的属性的话,就依葫芦画瓢。像本次的内容一样。依照相同的步骤。再反复一遍就能够了,这样就能够给顶点自由的加入属性了。


    最后,贴出本篇文章的demo的所有代码,链接也在最后给出,大家能够參考一下。


    下次,通过操作模型变换矩阵,来绘制多个模型。


    >demo的HTML代码

    <html>
        <head>
            <title>WebGL TEST</title>
            <script src="script.js" type="text/javascript"></script>
            <script src="minMatrix.js" type="text/javascript"></script>
            
            <script id="vs" type="x-shader/x-vertex">
    attribute vec3 position;
    attribute vec4 color;
    uniform   mat4 mvpMatrix;
    varying   vec4 vColor;
    
    void main(void){
        vColor = color;
        gl_Position = mvpMatrix * vec4(position, 1.0);
    }
            </script>
            
            <script id="fs" type="x-shader/x-fragment">
    precision mediump float;
    
    varying vec4 vColor;
    
    void main(void){
        gl_FragColor = vColor;
    }
            </script>
        </head>
        <body>
            <canvas id="canvas"></canvas>
        </body>
    </html>

    >demo的javascript代码

    onload = function(){
        // canvas对象获取
        var c = document.getElementById('canvas');
        c.width = 300;
        c.height = 300;
    
        // webgl的context获取
        var gl = c.getContext('webgl') || c.getContext('experimental-webgl');
        
        // 设定canvas初始化的颜色
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        
        // 设定canvas初始化时候的深度
        gl.clearDepth(1.0);
        
        // canvas的初始化
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
        
        // 顶点着色器和片段着色器的生成
        var v_shader = create_shader('vs');
        var f_shader = create_shader('fs');
        
        // 程序对象的生成和连接
        var prg = create_program(v_shader, f_shader);
        
        // attributeLocation的获取
        var attLocation = new Array(2);
        attLocation[0] = gl.getAttribLocation(prg, 'position');
        attLocation[1] = gl.getAttribLocation(prg, 'color');
        
    	// 将元素数attribute保存到数组中
    	var attStride = new Array(2);
    	attStride[0] = 3;
    	attStride[1] = 4;
    
    	// 保存顶点的位置情报的数组
    	var vertex_position = [
    	     0.0, 1.0, 0.0,
     	    1.0, 0.0, 0.0,
    	    -1.0, 0.0, 0.0
    	];
    
    	// 保存顶点的颜色情报的数组
        var vertex_color = [
            1.0, 0.0, 0.0, 1.0,
            0.0, 1.0, 0.0, 1.0,
            0.0, 0.0, 1.0, 1.0
        ];
        
        // 生成VBO
        var position_vbo = create_vbo(vertex_position);
        var color_vbo = create_vbo(vertex_color);
        
        // VBO绑定(位置情报)
        gl.bindBuffer(gl.ARRAY_BUFFER, position_vbo);
        gl.enableVertexAttribArray(attLocation[0]);
        gl.vertexAttribPointer(attLocation[0], attStride[0], gl.FLOAT, false, 0, 0);
        
        // VBO绑定(颜色情报)
        gl.bindBuffer(gl.ARRAY_BUFFER, color_vbo);
        gl.enableVertexAttribArray(attLocation[1]);
        gl.vertexAttribPointer(attLocation[1], attStride[1], gl.FLOAT, false, 0, 0);
        
        // 使用minMatrix.js对矩阵的相关处理
        // matIV对象生成
        var m = new matIV();
        
        // 各种矩阵的生成和初始化
        var mMatrix = m.identity(m.create());
        var vMatrix = m.identity(m.create());
        var pMatrix = m.identity(m.create());
        var mvpMatrix = m.identity(m.create());
        
        // 视图变换坐标矩阵
        m.lookAt([0.0, 1.0, 3.0], [0, 0, 0], [0, 1, 0], vMatrix);
        
        // 投影坐标变换矩阵
        m.perspective(90, c.width / c.height, 0.1, 100, pMatrix);
        
        // 各矩阵想成,得到最终的坐标变换矩阵
        m.multiply(pMatrix, vMatrix, mvpMatrix);
        m.multiply(mvpMatrix, mMatrix, mvpMatrix);
        
        // uniformLocation的获取
        var uniLocation = gl.getUniformLocation(prg, 'mvpMatrix');
        
        // 向uniformLocation中传入坐标变换矩阵
        gl.uniformMatrix4fv(uniLocation, false, mvpMatrix);
        
        // 绘制模型
        gl.drawArrays(gl.TRIANGLES, 0, 3);
        
        // context的刷新
        gl.flush();
        
        // 生成着色器的函数
        function create_shader(id){
            // 用来保存着色器的变量
            var shader;
            
            // 依据id从HTML中获取指定的script标签
            var scriptElement = document.getElementById(id);
            
            // 假设指定的script标签不存在。则返回
            if(!scriptElement){return;}
            
            // 推断script标签的type属性
            switch(scriptElement.type){
                
                // 顶点着色器的时候
                case 'x-shader/x-vertex':
                    shader = gl.createShader(gl.VERTEX_SHADER);
                    break;
                    
                // 片段着色器的时候
                case 'x-shader/x-fragment':
                    shader = gl.createShader(gl.FRAGMENT_SHADER);
                    break;
                default :
                    return;
            }
            
            // 将标签中的代码分配给生成的着色器
            gl.shaderSource(shader, scriptElement.text);
            
            // 编译着色器
            gl.compileShader(shader);
            
            // 推断一下着色器是否编译成功
            if(gl.getShaderParameter(shader, gl.COMPILE_STATUS)){
                
                // 编译成功,则返回着色器
                return shader;
            }else{
                
                // 编译失败,弹出错误消息
                alert(gl.getShaderInfoLog(shader));
            }
        }
        
        // 程序对象的生成和着色器连接的函数
        function create_program(vs, fs){
            // 程序对象的生成
            var program = gl.createProgram();
            
            // 向程序对象里分配着色器
            gl.attachShader(program, vs);
            gl.attachShader(program, fs);
            
            // 将着色器连接
            gl.linkProgram(program);
            
            // 推断着色器的连接是否成功
            if(gl.getProgramParameter(program, gl.LINK_STATUS)){
            
                // 成功的话,将程序对象设置为有效
                gl.useProgram(program);
                
                // 返回程序对象
                return program;
            }else{
                
                // 假设失败,弹出错误信息
                alert(gl.getProgramInfoLog(program));
            }
        }
        
        // 生成VBO的函数
        function create_vbo(data){
            // 生成缓存对象
            var vbo = gl.createBuffer();
            
            // 绑定缓存
            gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
            
            // 向缓存中写入数据
            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW);
            
            // 将绑定的缓存设为无效
            gl.bindBuffer(gl.ARRAY_BUFFER, null);
            
            // 返回生成的VBO
            return vbo;
        }
    
    };

    给顶点加入颜色,然后绘制三角形的demo

    http://wgld.org/s/sample_003/


    转载请注明:转自lufy_legend的博客http://blog.csdn.net/lufy_legend

  • 相关阅读:
    移动端底部fixed固定定位输入框ios下不兼容
    mint-ui Picker设置指定初始值
    vue项目的mode:history模式
    更改checkbox的默认样式
    vue组件通信的几种方式
    Python运行Google App Engineer时出现的UnicodeDecodeError错误解决方案
    ActionFilterAttribute之HtmlFilter,压缩HTML代码
    MongoDB C#驱动中Query几个方法
    无需路由端口映射 花生壳6.5工程版发布
    如何让搜索引擎抓取AJAX内容?
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/7061193.html
Copyright © 2011-2022 走看看