1. 程式人生 > >【WebGL初學系列之四】紋理三角

【WebGL初學系列之四】紋理三角

 前面已經給三角形添加了顏色,為了讓其更加豐富多彩,我們這裡繼續向它新增紋理圖片。在實際的應用當中,紋理的新增也比直接繪製顏色要多得多,因為新增紋理就可以讓很多形狀看起來更加逼真了,好吧,廢話少說了,還是接著寫。

一:新增紋理

   首先來看,我們要給三角形新增紋理,所以我們必須要先建立紋理。建立紋理首先得建立一個WebGL的紋理物件,然後將要顯示的紋理繫結到紋理物件中。這裡建立一個紋理的物件使用WebGL的createTexture()函式進行建立嗎,返回一個紋理物件,緊接著用bindTexture將紋理物件進行繫結,最後,將資料拷貝到紋理。這裡使用的WebGL API為 void texImage2D(GLenum target, GLint level, GLenum internalformat,GLenum format, GLenum type, HTMLImageElement image),具體函式的引數細節這裡不多說了,可以去查查API。此函式的作用是將記憶體中的圖片資料拷貝到紋理儲存器中。程式碼如下:

                //建立一個紋理物件區間
                textObj = webgl.createTexture();
                //繫結文理物件
                webgl.bindTexture(webgl.TEXTURE_2D, textObj);
                //獲得html中的原始圖片
                var img = document.getElementById("texImg");
                //將圖片資料拷貝到紋理中
                webgl.texImage2D(webgl.TEXTURE_2D, 0, webgl.RGB, webgl.RGB, webgl.UNSIGNED_BYTE, img);

二:渲染紋理

    接下來,就是需要看紋理是如何使用和渲染出來的。
    來看看,Shader程式如何編寫。要將三角形繪製紋理,首先我們得對片段著色器進行處理,片段著色器中新增一個Uniform變數對紋理物件進行訪問。通過uniform變數對其進行訪問,需要知道uniform變數的關聯索引。uniform變數管理索引由程式在連結時自動生成,我們通過getUniformLocation函式進行獲取其索引。
    sampleTexIndex = canvas.getUniformLocation(shaderProgramObject, "sTexture");
    三角形要繪製紋理的位置當然由定點著色器決定,所以需要一個定點著色器算好後,通過varying變數傳入片段著色器。但是紋理和渲染又不同,紋理座標是左上角是(0,0)點右下角是(1, 1)點。設紋理座標為(x1,y1),渲染座標為(x2,y2),計算公式如下:
    x1= (x2 + 1.0)/2.0;
    y1= 1.0 - (y2 + 1.0)/2.0;
    所以,最後著色器的程式碼如下

       <script id="shader-vs" type="x-shader/x-vertex">
            attribute vec3 v3Position;
            varying vec2 vTexCood;
            void main()
            {
                vTexCood = vec2((v3Position.x+1.0)/2.0, 1.0-(v3Position.y+1.0)/2.0);
                gl_Position = 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
            varying vec2 vTexCood;
            uniform sampler2D sTexture;
            void main()
            {
                gl_FragColor = texture2D(sTexture, vTexCood);
               // gl_FragColor = vec4(1.0,1.0,1.0, 1.0);
            }
        </script> 

    影象資料在紋理儲存器中,在使用之前,要給其打上一個標示符。在片段著色器中通過整個紋理標識進行訪問。當上標識之前必須啟用標識。紋理單元為TEXTURE0,TEXTURE1,TEXTURE2...等等。紋理單元的數量還是有一定的限制,必須在getParameter(MAX_TEXTURE_IMAGE_UNITS)的返回值範圍之內。
                //啟用紋理標示0
                webgl.activeTexture(webgl.TEXTURE0);
                webgl.bindTexture(webgl.texImage2D, textObj);
                webgl.uniform1i(sampleTexIndex, 0);
 
三:完整程式碼 最後,給出完整程式碼
  <html>
 <head>
        <script type="text/javascript" src="../Js/InitWebGL.js"></script>
        <script id="shader-vs" type="x-shader/x-vertex">
            attribute vec3 v3Position;
            varying vec2 vTexCood;
            void main()
            {
                vTexCood = vec2((v3Position.x+1.0)/2.0, 1.0-(v3Position.y+1.0)/2.0);
                gl_Position = 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
            varying vec2 vTexCood;
            uniform sampler2D sTexture;
            void main()
            {
                gl_FragColor = texture2D(sTexture, vTexCood);
               // gl_FragColor = vec4(1.0,1.0,1.0, 1.0);
            }
        </script>
 
        <script>
            var v3PositionIndex = 0;
            var sampleTexIndex = -1;
            var triangleBuffer = null;
            var triangleBuffer = null;
            var textObj = null;
 
            function initData(webgl)
            {
                //頂點座標
                var jsArrayData = [
                     0.0, 1.0, 0.0,
                    -1.0, 0.0, -1.0,
                     1.0, 0.0, 0.0
                ]
 
                //建立一個webgl能夠訪問的緩衝
                triangleBuffer = webgl.createBuffer();
                //繫結buffer
                webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);
                //將js資料拷貝到buffer上
                webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(jsArrayData), webgl.STATIC_DRAW);
 
                //建立一個紋理物件區間
                textObj = webgl.createTexture();
                //繫結文理物件
                webgl.bindTexture(webgl.TEXTURE_2D, textObj);
                //獲得html中的原始圖片
                var img = document.getElementById("texImg");
                //將圖片資料拷貝到紋理中
                webgl.texImage2D(webgl.TEXTURE_2D, 0, webgl.RGB, webgl.RGB, webgl.UNSIGNED_BYTE, img);
 
            }
 
            function renderScene(webgl)
            {
                //清空螢幕
                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);
 
                //啟用紋理標示0
                webgl.activeTexture(webgl.TEXTURE0);
                webgl.bindTexture(webgl.texImage2D, textObj);
                webgl.uniform1i(sampleTexIndex, 0);
 
                //繪製資料
                webgl.drawArrays(webgl.TRIANGLES, 0, 3);
            }
 
            function init()
            {
                //獲取webgl canvas
                var canvas = initCanvas("webglCanvas");
 
                //初始化shader程式
                var bind1 = [v3PositionIndex, "v3Position"];
                var bindData = new Array();
                bindData.push(bind1);
                var shaderProgramObject = initShaders(canvas, "shader-vs", "shader-fs", bindData);
 
                //獲取Uniform變數在連結時生成的索引
                sampleTexIndex = canvas.getUniformLocation(shaderProgramObject, "sTexture");
                canvas.useProgram(shaderProgramObject);
 
                //初始化頂點資料
                initData(canvas);
 
                //渲染場景
                renderScene(canvas);
            }
        </script>
 </head>
 <body onload ="init()">
  <canvas id="webglCanvas" style="border:1px solid red" width="600" height="600"></canvas>
        <img id = "texImg" src="../Img/1.jpg" width="600" height="600"><img/>
 </body>
</html>>
四:效果展示