您的位置:首页 > Web前端

WebGL自学教程——WebGL示例:4. 让三角形动起来

2011-10-23 14:49 483 查看
 
4. 让三角形动起来
 

    我们需要交互。但要交互,就首先要有交互的内容。下一章我们将实现一个用键盘控制三角形旋转的例子。但在这一章,我们先作一些准备工作:让三角形无交互地不停地自我旋转;并且,稍微组织了一下代码,让数据准备代码和绘图代码独立到不同的js函数中。

    我们原先定义的三角形,在旋转时,会超出[-1.0, +1.0]这个数值范围。因此,我把三角形缩小了一半。

    加载数据的js函数为LoadData(),绘图的js函数为RenderScene()。LoadData函数返回一个整数值,0表示加载成功,其他值表示遇到了某种错误。 RenderScene函数没有返回值。以后我们会不断地完善这两个函数。

    我们使用了一个定时器,每隔一定的时间就将三角形旋转的角度加10,然后根据这个角度重新绘制整个场景(调用RenderScene)。

    在RenderScene函数中,我们根据旋转的角度计算了转换矩阵,然后把该转换矩阵传递给顶点着色器的uniform变量。在顶点着色器内部,使用接收到uniform矩阵执行顶点转换。关于3D转换、矩阵和向量计算等相关的知识,请自行找资料学习(一般介绍3D编程的书(如OpenGL、DirectX)上都会有,更专业一点,就去看数学书吧)。

    计算转换矩阵需要js文件“glMatrix-0.9.5.js”的支持。它提供了几个向量和矩阵类,并封装了一些操作。各个类及其操作的说明,可参考我整理的《函数参考:glMatrix.js》。

    整合的源码如下:

<html>

<head>

<meta http-equiv="content-type" content="text/html; charset=gb2312">

<script type="text/javascript" src="glMatrix-0.9.5.js"></script>

<script id="shader-vs" type="x-shader/x-vertex">

attribute vec3 v3Position;
uniform mat4 um4Rotate;

varying vec2 v_texCoord;

void main(void)

{

    vec4 v4pos = um4Rotate * vec4(v3Position, 1.0);

    v_texCoord = vec2((v4pos.x+1.0)/2.0, 1.0-(v4pos.y+1.0)/2.0);

    gl_Position = v4pos;

    //v_texCoord = vec2((v3Position.x+1.0)/2.0, 1.0-(v3Position.y+1.0)/2.0);

    //gl_Position = um4Rotate * vec4(v3Position, 1.0);

}

</script>

<script id="shader-fs" type="x-shader/x-fragment">

#ifdef GL_FRAGMENT_PRECISION_HIGH

    precision highp float;

#else

    precision mediump float;

#endif

uniform sampler2D s_texture;

varying vec2 v_texCoord;

void main(void)

{

    gl_FragColor = texture2D(s_texture, v_texCoord);

}

</script>

<script>

function ShaderSourceFromScript(scriptID)

{

    var shaderScript = document.getElementById(scriptID);

    if (shaderScript == null) return "";

    var sourceCode = "";

    var child = shaderScript.firstChild;

    while (child)

    {

        if (child.nodeType == child.TEXT_NODE ) sourceCode += child.textContent;

        child = child.nextSibling;

    }

    return sourceCode;

}

var webgl = null;

var vertexShaderObject = null;

var fragmentShaderObject = null;

var programObject = null;

var triangleBuffer = null;

var v3PositionIndex = 0;

var textureObject = null;

var samplerIndex = -1;
var interval = 300;

var angle = 0;

var um4RotateIndex = -1;

function LoadData()

{

    var jsArrayData = [

        0.0, 0.5, 0.0,//上顶点

        -0.5, -0.5, 0.0,//左顶点

        0.5, 0.0, 0.0];//右顶点

    triangleBuffer = webgl.createBuffer();

    webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);

    webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(jsArrayData), webgl.STATIC_DRAW);

    textureObject = webgl.createTexture();

    webgl.bindTexture(webgl.TEXTURE_2D, textureObject);

    var img = document.getElementById('myTexture');

    webgl.texImage2D(webgl.TEXTURE_2D, 0, webgl.RGB, webgl.RGB, webgl.UNSIGNED_BYTE, img);

 

    return 0;

}

function RenderScene()

{

    webgl.clearColor(0.0, 0.0, 0.0, 1.0);

    webgl.clear(webgl.COLOR_BUFFER_BIT);

    webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);

    webgl.enableVertexAttribArray(v3PositionIndex);

    webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false, 0, 0);

    webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_MIN_FILTER, webgl.NEAREST);

    webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_MAG_FILTER, webgl.NEAREST);

    webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_S, webgl.CLAMP_TO_EDGE);

    webgl.texParameteri(webgl.TEXTURE_2D, webgl.TEXTURE_WRAP_T, webgl.CLAMP_TO_EDGE);

    webgl.activeTexture(webgl.TEXTURE0);

    webgl.bindTexture(webgl.TEXTURE_2D, textureObject);

    webgl.uniform1i(samplerIndex, 0);

 

    var m4Rotate = mat4.create();

    mat4.identity(m4Rotate);

    mat4.rotateZ(m4Rotate, angle*Math.PI/180);

    webgl.uniformMatrix4fv(um4RotateIndex, false, m4Rotate);

    webgl.drawArrays(webgl.TRIANGLES, 0, 3);

}

function RotateTriangle()

{

 angle += 10;

 if(angle >= 360) angle -= 360;

 

 RenderScene();

}

function Init()

{

    var myCanvasObject = document.getElementById('myCanvas');

    webgl = myCanvasObject.getContext("experimental-webgl");

    webgl.viewport(0, 0, myCanvasObject.clientWidth, myCanvasObject.clientHeight);

    vertexShaderObject = webgl.createShader(webgl.VERTEX_SHADER);

    fragmentShaderObject = webgl.createShader(webgl.FRAGMENT_SHADER);

    webgl.shaderSource(vertexShaderObject, ShaderSourceFromScript("shader-vs"));

    webgl.shaderSource(fragmentShaderObject, ShaderSourceFromScript("shader-fs"));

    webgl.compileShader(vertexShaderObject);

    webgl.compileShader(fragmentShaderObject);

    if(!webgl.getShaderParameter(vertexShaderObject, webgl.COMPILE_STATUS)){alert(webgl.getShaderInfoLog(vertexShaderObject));return;}

    if(!webgl.getShaderParameter(fragmentShaderObject, webgl.COMPILE_STATUS)){alert(webgl.getShaderInfoLog(fragmentShaderObject));return;}

    programObject = webgl.createProgram();

    webgl.attachShader(programObject, vertexShaderObject);

    webgl.attachShader(programObject, fragmentShaderObject);

    webgl.bindAttribLocation(programObject, v3PositionIndex, "v3Position");

    webgl.linkProgram(programObject);

    if(!webgl.getProgramParameter(programObject, webgl.LINK_STATUS)){alert(webgl.getProgramInfoLog(programObject));return;}

    samplerIndex = webgl.getUniformLocation(programObject, "s_texture");

    um4RotateIndex = webgl.getUniformLocation(programObject, "um4Rotate");

    webgl.useProgram(programObject);

    if(LoadData() != 0){alert("error:LoadData()!");return;}

    window.setInterval("RotateTriangle()", interval);

}

</script>

</head>

<body onload='Init()'>

<canvas id="myCanvas" style="border:1px solid red;" width='600px' height='450px'></canvas>

<img id="myTexture" src='texture.bmp'>

</body>

</html>

    运行结果如下:



    它们的效果是,贴在三角形上图片看起来并不会跟着三角形一起旋转;即是说,在任何时刻,三角形看起来总是起到一个透明的作用,将其所在区域的图片的内容显示出来。如果你把顶点着色器中的这三行注释掉:

        vec4 v4pos = um4Rotate * vec4(v3Position, 1.0);

        v_texCoord = vec2((v4pos.x+1.0)/2.0, 1.0-(v4pos.y+1.0)/2.0);

        gl_Position = v4pos;

    而把下面的这两行取消注释:

        //v_texCoord = vec2((v3Position.x+1.0)/2.0, 1.0-(v3Position.y+1.0)/2.0);

        //gl_Position = um4Rotate * vec4(v3Position, 1.0);

    那么,你所看到的效果就是,三角形上的图像会随着三角形一起旋转:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息