mozilla
Your Search Results

    Using textures in WebGL

    現在、サンプルプログラムは回転する 3D キューブを描画します。今回はキューブの表面を単色で塗りつぶすのではなく、テクスチャをマッピングしてみましょう。

    テクスチャの読み込み

    始めに、テクスチャを読み込むコードを追加します。今回は 1 個のテクスチャを用いて、そのテクスチャをキューブの 6 面に貼り付けますが、テクスチャがいくつある場合でも同じ方法を適用できます。

    注意: テクスチャの読み込みは クロスドメインの規則 に従うことに注意することが重要です。従ってコンテンツが COLS で認可されているサイトからのみ、テクスチャを読み込むことができます。詳しくは Cross-domain textures をご覧ください。

    テクスチャを読み込むコードは以下のようになります:

    function initTextures() {
      cubeTexture = gl.createTexture();
      cubeImage = new Image();
      cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); }
      cubeImage.src = "cubetexture.png";
    }
    
    function handleTextureLoaded(image, texture) {
      gl.bindTexture(gl.TEXTURE_2D, texture);
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
      gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
      gl.generateMipmap(gl.TEXTURE_2D);
      gl.bindTexture(gl.TEXTURE_2D, null);
    }
    

    initTextures() ルーチンは GL の createTexture() 関数を呼び出して、GL のテクスチャオブジェクト cubeTexture を作成することから始まります。そして、テクスチャを画像ファイルから読み込むために Image オブジェクトを作成して、そのオブジェクトにテクスチャとして使用したい画像ファイルをロードします。handleTextureLoaded() コールバックルーチンは、画像の読み込みが完了したときに実行されます。

    実際にテクスチャを作成するために、新しいテクスチャが操作したいカレントのテクスチャであることを、gl.TEXTURE_2D にバインドすることで指定します。その後読み込んだ画像は、テクスチャとして書き込むために texImage2D() へ渡されます。

    注意: テクスチャの幅と高さのピクセル数は 2 のべき乗 (1、2、4、8、16……) であることが必要です。

    その次の 2 行はテクスチャのフィルタリングを設定しています。これは画像が拡大縮小される際に適用するフィルタの設定です。今回は、画像を拡大する場合はリニアフィルタ、縮小する場合はミップマップを使用します。ミップマップは generateMipMap() を呼び出すことで生成され、最後は null を gl.TEXTURE_2D にバインドしてテクスチャの操作を終了することで完了します。

    テクスチャを表面にマッピングする

    以上で、テクスチャの読み込みと使用する準備ができました。しかしテクスチャが使用できるようになるには、まずキューブの面の頂点にテクスチャの座標をマッピングする必要があります。これは initBuffers() にある、キューブの各面に色を設定する既存のコードの置き換えになります。

      cubeVerticesTextureCoordBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);
      
      var textureCoordinates = [
        // Front
        0.0,  0.0,
        1.0,  0.0,
        1.0,  1.0,
        0.0,  1.0,
        // Back
        0.0,  0.0,
        1.0,  0.0,
        1.0,  1.0,
        0.0,  1.0,
        // Top
        0.0,  0.0,
        1.0,  0.0,
        1.0,  1.0,
        0.0,  1.0,
        // Bottom
        0.0,  0.0,
        1.0,  0.0,
        1.0,  1.0,
        0.0,  1.0,
        // Right
        0.0,  0.0,
        1.0,  0.0,
        1.0,  1.0,
        0.0,  1.0,
        // Left
        0.0,  0.0,
        1.0,  0.0,
        1.0,  1.0,
        0.0,  1.0
      ];
    
      gl.bufferData(gl.ARRAY_BUFFER, new WebGLFloatArray(textureCoordinates),
                    gl.STATIC_DRAW);
    

    このコードは始めに各面のテクスチャの座標を収める GL のバッファを作成して、そのバッファを書き込みを行う配列としてバインドします。

    textureCoordinates 配列は、各面の各座標に対応するテクスチャの座標を定義します。テクスチャの座標の範囲は 0.0 から 1.0 であることに注意してください。テクスチャマッピングのために、テクスチャの寸法は実際の大きさに関わらず 0.0 から 1.0 の範囲に正規化されます。

    テクスチャマッピングの配列を設定したら、配列をバッファに渡すことで GL がそのデータを使用する準備が完了します。

    注意: WebKit ベースのブラウザでは、WebGLFloatArray の代わりに Float32Array を用いることが必要でしょう。

    シェーダーの更新

    シェーダープログラム (およびシェーダーを初期化するコード) も、単色に代わりテクスチャを使用するように更新する必要があります。

    始めに initShaders() で必要になる、シンプルな変更点を見てみましょう:

      textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
      gl.enableVertexAttribArray(textureCoordAttribute);
    

    これは頂点の色属性を設定するコードを、各頂点のテクスチャ座標を包含するコードに置き換えます。

    バーテックスシェーダー

    次にバーテックスシェーダーを、色のデータを取り出すものからテクスチャ座標のデータを取り出すものに置き換える必要があります。

        <script id="shader-vs" type="x-shader/x-vertex">
          attribute vec3 aVertexPosition;
          attribute vec2 aTextureCoord;
        
          uniform mat4 uMVMatrix;
          uniform mat4 uPMatrix;
          
          varying highp vec2 vTextureCoord;
        
          void main(void) {
            gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
            vTextureCoord = aTextureCoord;
          }
        </script>
    

    重要な変更点は、頂点の色を取り出すのに代わりテクスチャ座標を設定していることです。これは頂点に対応する、テクスチャ内の位置を指し示します。

    フラグメントシェーダー

    フラグメントシェーダーも同様に更新する必要があります:

        <script id="shader-fs" type="x-shader/x-fragment">
          varying highp vec2 vTextureCoord;
          
          uniform sampler2D uSampler;
          
          void main(void) {
            gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
          }
        </script>
    

    色の値をフラグメントの色に割り当てるのに代わり、フラグメントの色は、サンプラーが最適とするフラグメントの位置のテクセル (テクスチャ内のピクセル) を取り出すことで算出されます。

    テクスチャが貼り付けられたキューブの描画

    drawScene() 関数の変更点は簡単です (コードを明瞭にするために、キューブを空間中で動かすアニメーションのコードを取り除いて単に回転するようにした点は除きます)。

    色を割り当てるコードをテクスチャを割り当てるようにするためには、以下のように置き換えます:

      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
      gl.uniform1i(gl.getUniformLocation(shaderProgram, "uSampler"), 0);
    

    GL は 32 個のテクスチャレジスタを提供し、その 1 つ目が gl.TEXTURE0 です。前に読み込んだテクスチャをそのレジスタに結びつけて、そのテクスチャを使用するためにシェーダーサンプラー uSampler (シェーダープログラムにより明示されます) を設定します。

    以上で、テクスチャが貼り付けられた回転するキューブが完成します。WebGL 対応のブラウザを実行している場合は、こちらをクリックして デモを実行してみてください。

    ドキュメントのタグと貢献者

    Contributors to this page: ethertank, yyss
    最終更新者: ethertank,