`

webGL——3

 
阅读更多
今天下班比较早,早早吃完饭,开始我们的第二课,给三角形和正方形涂上颜色。
本人声明:这是我学习webGL 的笔记,仅供参考,有不当之处,请多多指教!
现对上一课做个总结:
   (1)使用具有"x-shader/x-vertex"和"x-shader/x-fragment"类型的script标签定义了顶点渲染器和片段渲染器;
   (2)在initGL函数中初始化了一个WebGL的上下文;
   (3)使用getShader和initShaders函数装载渲染器到一个WebGL对象中;
   (4)定义了模型矩阵以及操作该矩阵的函数loadIdentity、multMatrix和mvTranslate;
   (5)定义了投影矩阵pMatrix和一个操作该矩阵的函数perspective;
   (6)定义了setMatrixUniforms函数用于将模型视图矩阵和投影矩阵,以便渲染器根据initBuffers加载场景缓存区;
   (7)定义场景绘制函数drawScene;
   (8)定义webGLStart函数在网页起始位置设置webGL的环境;
   (9)最后用body的onload事件调用webGLStart函数
本节课,我们依然沿用这个编程思路,对代码作少许改动,为图形填上颜色。
在上节课代码的基础上我们做如下变化(红色为添加代码):
    (1)顶点渲染器代码:
   
<script id="shader-vs" type="x-shader/x-vertex">
    attribute vec3 aVertexPosition;//顶点位置变化属性
   [color=red] attribute vec4 aVertexColor;//顶点颜色变化属性[/color]

    uniform mat4 uMVMatrix;//同一变量 模型矩阵
    uniform mat4 uPMatrix;//同一变量 投影矩阵

    [color=red]varying vec4 vColor;//可变颜色 输出值[/color]

    void main(void) {
        gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
       [color=red] vColor = aVertexColor;[/color]
    }
    </script>

    (2)片段渲染器(像素渲染器):
   
 <script id="shader-fs" type="x-shader/x-fragment">
    precision mediump float;

    [color=red]varying vec4 vColor;[/color]

    void main(void) {
        [color=red]gl_FragColor = vColor;//此处 由上一课的直接赋值变为接受顶点渲染器的输出值vColor[/color]
    }

    (3)initShaders()函数:
   
 [color=red]shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");//这是关于我们如何针对每个顶点获得一个传入到顶点渲染器属性引用的处理 -----------渲染器绑定颜色变化矩阵
        gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute);//转化为数组[/color]

    (4)initBuffers函数:
    
triangleVertexPositionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
        var vertices = [
             0.0,  1.0,  0.0,
            -1.0, -1.0,  0.0,
             1.0, -1.0,  0.0
        ];
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        triangleVertexPositionBuffer.itemSize = 3;
        triangleVertexPositionBuffer.numItems = 3;
        [color=red]//设置三角形颜色缓存
        triangleVertexColorBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);
        var colors = [
            1.0, 0.0, 0.0, 1.0,
            0.0, 1.0, 0.0, 1.0,
            0.0, 0.0, 1.0, 1.0
        ];
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
        triangleVertexColorBuffer.itemSize = 4;
        triangleVertexColorBuffer.numItems = 3;[/color]

        
        squareVertexPositionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
        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
        ];
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
        squareVertexPositionBuffer.itemSize = 3;
        squareVertexPositionBuffer.numItems = 4;
        
        [color=red]//设置正方形颜色矩阵
        squareVertexColorBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);
        colors = [];
        for (var i=0; i < 4; i++) {
            colors = colors.concat([0.5, 0.5, 1.0, 1.0]);
        }
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
        squareVertexColorBuffer.itemSize = 4;
        squareVertexColorBuffer.numItems = 4;[/color]

    
     (5)drawSence函数:
       gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

        mat4.perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0, pMatrix);

        mat4.identity(mvMatrix);

        mat4.translate(mvMatrix, [-1.5, 0.0, -7.0]);
        gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
        gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

        gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);//绑定三角形颜色缓存
        gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, triangleVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);


        setMatrixUniforms();
        gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems);

        mat4.translate(mvMatrix, [3.0, 0.0, 0.0]);
        gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer);
        gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

        gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexColorBuffer);//绑定正方形颜色缓存
        gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, squareVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0);


        setMatrixUniforms();
        gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems);


至此,我么针对上一课的代码的改动已经完成,结果是:我们的三角形和正方形都有了渐变的颜色而且是光滑的!如下图:

在此,需要补充以下几点:
     (1)shader的几个变量:
       1.uniform变量
uniform变量是外部application程序传递给(vertex和fragment)shader的变量。因此它是application通过函数glUniform**()函数赋值的。在(vertex和fragment)shader程序内部,uniform变量就像是C语言里面的常量(const ),它不能被shader程序修改。(shader只能用,不能改)

如果uniform变量在vertex和fragment两者之间声明方式完全一样,则它可以在vertex和fragment共享使用。(相当于一个被vertex和fragment shader共享的全局变量)

uniform变量一般用来表示:变换矩阵,材质,光照参数和颜色等信息。

以下是例子:

uniform mat4 viewProjMatrix; //投影+视图矩阵
uniform mat4 viewMatrix; //视图矩阵
uniform vec3 lightPosition; //光源位置


       2.attribute变量
attribute变量是只能在vertex shader中使用的变量。(它不能在fragment shader中声明attribute变量,也不能被fragment shader中使用)

一般用attribute变量来表示一些顶点的数据,如:顶点坐标,法线,纹理坐标,顶点颜色等。

在application中,一般用函数glBindAttribLocation()来绑定每个attribute变量的位置,然后用函数glVertexAttribPointer()为每个attribute变量赋值。

以下是例子:

uniform mat4 u_matViewProjection;
attribute vec4 a_position;
attribute vec2 a_texCoord0;
varying vec2 v_texCoord;
void main(void)
{
gl_Position = u_matViewProjection * a_position;
v_texCoord = a_texCoord0;
}


        3.varying变量
varying变量是vertex和fragment shader之间做数据传递用的。一般vertex shader修改varying变量的值,然后fragment shader使用该varying变量的值。因此varying变量在vertex和fragment shader二者之间的声明必须是一致的。application不能使用此变量。

以下是例子:

// Vertex shader
uniform mat4 u_matViewProjection;
attribute vec4 a_position;
attribute vec2 a_texCoord0;
varying vec2 v_texCoord; // Varying in vertex shader
void main(void)
{
gl_Position = u_matViewProjection * a_position;
v_texCoord = a_texCoord0;
}


// Fragment shader
precision mediump float;
varying vec2 v_texCoord; // Varying in fragment shader
uniform sampler2D s_baseMap;
uniform sampler2D s_lightMap;
void main()
{
vec4 baseColor;
vec4 lightColor;
baseColor = texture2D(s_baseMap, v_texCoord);
lightColor = texture2D(s_lightMap, v_texCoord);
gl_FragColor = baseColor * (lightColor + 0.25);
}
      (2)shader渲染器的渲染过程,如下图:

      此图,显示了显卡渲染图形的过程,每次调用像drawArrays这样的函数,WebGL都要处理先前以属性(如第一课中用于顶点的缓冲区)和统一变量(其用于投影矩阵和模型视图矩阵)的形式提交给它的数据,并将其传入到顶点渲染器。



对每个顶点调用一次顶点渲染器,每次都为该顶点设置合适的属性。同时,将统一变量传入到顶点渲染器。但是,统一变量正如它们的名字,在调用的过程并不发生改变。顶点渲染器用第一课中提到的这个数据来工作,它使用投影和模型视图矩阵以便顶点能根据当前的模型视图状态来将其置入场景中和在场景中移动,并将结果放入varying variables中。它也能输出一些varying variables。其中一个比较特殊的是gl_Position,它是必须的,它包含了渲染器完成顶点着色以后的顶点坐标。

一旦顶点渲染器完成其工作,WebGL就会从这些可变变量中将三维图像转化为二维图像,接着它在图像中为每一个像素调用一次片段渲染器。(由于这个原因,在一些三维图像系统中片段渲染器被认作为像素渲染器。)当然,这意味着片段渲染器用于那些没有顶点的像素——即,顶点结束的像素之间的像素。对于组成三角形的顶点位置,WebGL将通过线性插值的方法在两个顶点间填充一些像素。线性插值处理填充了组成可见三角形的顶点分隔的空间。片段渲染器的作用是返回每一个插值点的颜色,它在gl_FragColor可变变量中返回这个颜色值。

一旦片段渲染器处理完成,WebGL对其结果稍作混合,再将其放入帧缓冲区(frame buffer),此即屏幕上最终显示的东西。

很明显,这一课最重要的就是要教会你如何通过所有运行在片段渲染器上的JavaScript代码给顶点着色,我们不会从一个顶点到另一个顶点来直接获取。

我们所采用的方法是基于如下事实:我们能从顶点渲染器中传出可变变量(而不是位置信息),然后我们可以在片段渲染器中重新获得它们。因此,我们把颜色信息传入到顶点渲染器,然后顶点渲染器直接将该信息置入一个可以在片段渲染器中获得的可变变量中。

这种方法很方便地为我们提供了颜色的渐变,且不花费任何代价。当在顶点间生成片段时,除了位置信息,所有顶点渲染器设置的可变变量都是线性插值的。顶点间的线性颜色插值为我们提供了平滑渐变,就像你在图中的三角形看到的那样。


最后,希望你能在上一课代码的基础上,改出本课的效果,祝君好运!
    
  • 大小: 7.5 KB
  • 大小: 40.2 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics