WebGL自學教程——WebGL樣本:4. 讓三角形動起來

來源:互聯網
上載者:User

 

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);

    那麼,你所看到的效果就是,三角形上的映像會隨著三角形一起旋轉:

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.