WebGL笔记(二):顶点着色

一、加载Shader

本文的Shader脚本与上一篇不同,首先做一下修改:

Vertex:

   1:  <script id="shader-vs" type="x-shader/x-vertex">  
   2:      attribute vec3 aVertexPosition;  
   3:      attribute vec4 aVertexColor;
   4:      uniform mat4 uMVMatrix;  
   5:      uniform mat4 uPMatrix; 
   6:      varying lowp vec4 vColor;
   7:      void main(void) {  
   8:          gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);  
   9:          vColor = aVertexColor;  
  10:      }  
  11:  </script> 

第2、6、9行为新增的内容。

Fragment:

   1:  <script id="shader-fs" type="x-shader/x-fragment">  
   2:      varying lowp vec4 vColor;
   3:      void main(void) {  
   4:          gl_FragColor = vColor;  
   5:      }  
   6:  </script>

第2行为新增,第4行原来为定值。

以上script中的代码主要是为了便于对比查看。还是延续上一篇的做法,本例直接将代码赋值到js变量中:

var testVertexCode = '\
    attribute vec3 aVertexPosition;\
    attribute vec4 aVertexColor;\
    uniform mat4 uMVMatrix;\
    uniform mat4 uPMatrix;\
    varying lowp vec4 vColor;\
    void main(void){\
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\
        vColor = aVertexColor;\
    }',
    testFragmentCode = '\
    varying lowp vec4 vColor;\
    void main(void){\
        gl_FragColor=vColor;\
    }';

以下为流水账:

1、创建Shader对象

var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, testVertexCode);
gl.compileShader(vertShader);
 
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, testFragmentCode);
gl.compileShader(fragShader);

2、创建Program对象并附加Shader

var program = gl.createProgram();
gl.attachShader(program, vertShader);
gl.attachShader(program, fragShader);

3、引用Program对象

gl.linkProgram(program);
gl.useProgram(program);

4、关联gl与Shader脚本中的变量

var vertexPosAttr = gl.getAttribLocation(program, 'aVertexPosition');
gl.enableVertexAttribArray(vertexPosAttr);
 
var colorPosAttr = gl.getAttribLocation(program, 'aVertexColor');
gl.enableVertexAttribArray(colorPosAttr);

上面这一步在撰写本文例子的时候又有点新的心得。getAttribLocation方法的第二个参数对应Shader脚本中已定义的变量名,自己则返回一个int值,根据名称猜测,该返回值应该是变量句柄之类的东西。enableVertexAttribArray方法应该是根据这个句柄来启用WebGL和Shader之间的某种关联关系。

二、创建定点及颜色

本例需要一组顶点数据和一组颜色数据,如下:

var vertices = [  
     1.0,   1.0,   0.0,  
    -1.0,   1.0,   0.0,  
     1.0,  -1.0,   0.0,  
    -1.0,  -1.0,   0.0
];
var colors = [  
    1.0,  1.0,  1.0,  1.0,    // white  
    1.0,  0.0,  0.0,  1.0,    // red  
    0.0,  1.0,  0.0,  1.0,    // green  
    0.0,  0.0,  1.0,  1.0     // blue  
];

下面将它们附加到gl中:

var squareVerticesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(vertexPosAttr, 3, gl.FLOAT, false, 0, 0);
 
var squareVerticesColorBuffer = gl.createBuffer();  
gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);  
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); 
gl.vertexAttribPointer(colorPosAttr, 4, gl.FLOAT, false, 0, 0); 

请注意vertexAttribPointer方法的第2个参数,单个定点(XYZ)定义为3个float值,单个色彩(RGBA)定义为4个float值,上次提到,貌似这个参数应为分组数据的个数。

三、设置位置

再赘述一下MatrixHelper对象:

function MatrixHelper(){ this.matrix = Matrix.I(4); }
MatrixHelper.prototype = {
    /* makePerspective */
    make : function(fovy, aspect, znear, zfar){
        this.ppm = makePerspective(fovy, aspect, znear, zfar);
    },
    /* multMatrix */
    mult : function(m){
        this.matrix = this.matrix.x(m);
    },
    /* mvTranslate */
    trans : function(v){
        this.mult(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());
    },
    /* setMatrixUniforms */
    set : function(gl, sProg){
        if(!!this.ppm){
              gl.uniformMatrix4fv(gl.getUniformLocation(sProg, "uPMatrix")
                , false, new Float32Array(this.ppm.flatten()));
        }
        if(!!this.matrix){
              gl.uniformMatrix4fv(gl.getUniformLocation(sProg, "uMVMatrix")
                , false, new Float32Array(this.matrix.flatten())); 
        }
    }
}

设置位置之前,需要在页头中引用MDN提供的两个包,我已上传到我的空间里:

sylvester.js

glUtils.js

这两个文件会提供一个Matrix对象来简化位置状态的设置,MatrixHelper只是重新封装了一下,下面使用它设置位置:

var matrix = new MatrixHelper();
matrix.trans([0.0, 0.0, -5.0]);
matrix.make(45, 640 / 480, 0.1, 100.0);
matrix.set(gl, program);

四、绘制

gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

好了,大功告成。不出意外的话,你的屏幕上应该出现类似下图的内容:

捕获

好像有点意思了,至少比一个白方块强哈。本文与上一篇相比没有太多新东西。附代码:

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>WebGL Step 02</title>
<style type="text/css">
canvas{ background-color:#666; }
</style>
<script type="text/ecmascript" src="sylvester.js"></script>
<script type="text/ecmascript" src="glUtils.js"></script>
 
<script id="shader-vs" type="x-shader/x-vertex">  
    attribute vec3 aVertexPosition;  
    attribute vec4 aVertexColor;
    uniform mat4 uMVMatrix;  
    uniform mat4 uPMatrix; 
    varying lowp vec4 vColor;
    void main(void) {  
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);  
        vColor = aVertexColor;  
    }  
</script> 
 
<script id="shader-fs" type="x-shader/x-fragment">  
    varying lowp vec4 vColor;
    void main(void) {  
        gl_FragColor = vColor;  
    }  
</script> 
 
<script type="text/ecmascript">
function MatrixHelper(){ this.matrix = Matrix.I(4); }
MatrixHelper.prototype = {
    /* makePerspective */
    make : function(fovy, aspect, znear, zfar){
        this.ppm = makePerspective(fovy, aspect, znear, zfar);
    },
    /* multMatrix */
    mult : function(m){
        this.matrix = this.matrix.x(m);
    },
    /* mvTranslate */
    trans : function(v){
        this.mult(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());
    },
    /* setMatrixUniforms */
    set : function(gl, sProg){
        if(!!this.ppm){
              gl.uniformMatrix4fv(gl.getUniformLocation(sProg, "uPMatrix")
                , false, new Float32Array(this.ppm.flatten()));
        }
        if(!!this.matrix){
              gl.uniformMatrix4fv(gl.getUniformLocation(sProg, "uMVMatrix")
                , false, new Float32Array(this.matrix.flatten())); 
        }
    }
}
</script>
 
</head>
 
<body>
 
<canvas id="glcanvas" width="640" height="480">看来您的浏览器不支持<code>&lt;canvas&gt;</code>标记</canvas>
 
<script type="text/ecmascript">
var testVertexCode = '\
    attribute vec3 aVertexPosition;\
    attribute vec4 aVertexColor;\
    uniform mat4 uMVMatrix;\
    uniform mat4 uPMatrix;\
    varying lowp vec4 vColor;\
    void main(void){\
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);\
        vColor = aVertexColor;\
    }',
    testFragmentCode = '\
    varying lowp vec4 vColor;\
    void main(void){\
        gl_FragColor=vColor;\
    }';
    
var vertices = [  
     1.0,   1.0,   0.0,  
    -1.0,   1.0,   0.0,  
     1.0,  -1.0,   0.0,  
    -1.0,  -1.0,   0.0
];
var colors = [  
    1.0,  1.0,  1.0,  1.0,    // white  
    1.0,  0.0,  0.0,  1.0,    // red  
    0.0,  1.0,  0.0,  1.0,    // green  
    0.0,  0.0,  1.0,  1.0     // blue  
];
      
var canvas = document.getElementById('glcanvas');
var gl = canvas.getContext('experimental-webgl');
 
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, testVertexCode);
gl.compileShader(vertShader);
 
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, testFragmentCode);
gl.compileShader(fragShader);
 
var program = gl.createProgram();
gl.attachShader(program, vertShader);
gl.attachShader(program, fragShader);
 
gl.linkProgram(program);
gl.useProgram(program);
 
var vertexPosAttr = gl.getAttribLocation(program, 'aVertexPosition');
gl.enableVertexAttribArray(vertexPosAttr);
 
var colorPosAttr = gl.getAttribLocation(program, 'aVertexColor');
gl.enableVertexAttribArray(colorPosAttr);
 
var squareVerticesBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(vertexPosAttr, 3, gl.FLOAT, false, 0, 0);
 
var squareVerticesColorBuffer = gl.createBuffer();  
gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);  
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); 
gl.vertexAttribPointer(colorPosAttr, 4, gl.FLOAT, false, 0, 0); 
 
var matrix = new MatrixHelper();
matrix.trans([0.0, 0.0, -5.0]);
matrix.make(40, 640 / 480, 0.1, 100.0);
matrix.set(gl, program);
 
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
 
</script>
</body>
</html>

代码中装载Shaper脚本的script标记只是为了方便观瞻,不必纠结。

原文地址:https://www.cnblogs.com/muse/p/2269346.html