2012-07-02 13 views
5

1つのキューブに6つの異なるテクスチャを使用したいと思っていましたが、1つの側に1つの間違いが見つかりませんでした。現在のコードは次のとおりです。WebGLで複数のテクスチャを使用するには?

var texturen = new Array(); 
function initTexture(sFilename,texturen) 
{ 
    var anz = texturen.length; 
    texturen[anz] = gl.createTexture(); 
    texturen[anz].image = new Image(); 
    texturen[anz].image.onload = function()  
    { 
    gl.bindTexture(gl.TEXTURE_2D, texturen[anz]); 
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); 
    gl.texImage2D 
    (gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texturen[anz].image); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 
    gl.bindTexture(gl.TEXTURE_2D, null); 
    } 
    texturen[anz].image.src = sFilename; 
} 


var mvMatrix = mat4.create(); 
var mvMatrixStack = []; 
var pMatrix = mat4.create(); 

function mvPushMatrix() { 
    var copy = mat4.create(); 
    mat4.set(mvMatrix, copy); 
    mvMatrixStack.push(copy); 
} 

function mvPopMatrix() { 
    if (mvMatrixStack.length == 0) { 
     throw "Invalid popMatrix!"; 
    } 
    mvMatrix = mvMatrixStack.pop(); 
} 


function setMatrixUniforms() { 
    gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, pMatrix); 
    gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, mvMatrix); 
} 


function degToRad(degrees) { 
    return degrees * Math.PI/180; 
} 

var cubeVertexPositionBuffer; 
var cubeVertexTextureCoordBuffer; 
var cubeVertexIndexBuffer; 
var cubeVertexPositionBuffer1; 
var cubeVertexTextureCoordBuffer1; 
var cubeVertexIndexBuffer1; 


function initBuffers() { 
    cubeVertexPositionBuffer = gl.createBuffer(); 
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer); 
    vertices = [ 
     // Front face 
     -1.0, -1.0, 1.0, 
     1.0, -1.0, 1.0, 
     1.0, 1.0, 1.0, 
     -1.0, 1.0, 1.0, 

     // Back face 
     -1.0, -1.0, -1.0, 
     -1.0, 1.0, -1.0, 
     1.0, 1.0, -1.0, 
     1.0, -1.0, -1.0, 

     // Top face 
     -1.0, 1.0, -1.0, 
     -1.0, 1.0, 1.0, 
     1.0, 1.0, 1.0, 
     1.0, 1.0, -1.0, 
    ]; 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 
    cubeVertexPositionBuffer.itemSize = 3; 
    cubeVertexPositionBuffer.numItems = 12; 

cubeVertexPositionBuffer1 = gl.createBuffer(); 
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer1); 
    vertices = [ 
     // Bottom face 
     -1.0, -1.0, -1.0, 
     1.0, -1.0, -1.0, 
     1.0, -1.0, 1.0, 
     -1.0, -1.0, 1.0, 

     // Right face 
     1.0, -1.0, -1.0, 
     1.0, 1.0, -1.0, 
     1.0, 1.0, 1.0, 
     1.0, -1.0, 1.0, 

     // Left face 
     -1.0, -1.0, -1.0, 
     -1.0, -1.0, 1.0, 
     -1.0, 1.0, 1.0, 
     -1.0, 1.0, -1.0, 
    ]; 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 
    cubeVertexPositionBuffer1.itemSize = 3; 
    cubeVertexPositionBuffer1.numItems = 12; 


    cubeVertexTextureCoordBuffer = gl.createBuffer(); 
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer); 
    var textureCoords = [ 
     // Front face 
     0.0, 0.0, 
     1.0, 0.0, 
     1.0, 1.0, 
     0.0, 1.0, 

     // Back face 
     1.0, 0.0, 
     1.0, 1.0, 
     0.0, 1.0, 
     0.0, 0.0, 

     // Top face 
     0.0, 1.0, 
     0.0, 0.0, 
     1.0, 0.0, 
     1.0, 1.0, 
    ]; 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW); 
    cubeVertexTextureCoordBuffer.itemSize = 2; 
    cubeVertexTextureCoordBuffer.numItems = 12; 



cubeVertexTextureCoordBuffer1 = gl.createBuffer(); 
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexTextureCoordBuffer1); 
    var textureCoords = [ 
    // Bottom face 
     1.0, 1.0, 
     0.0, 1.0, 
     0.0, 0.0, 
     1.0, 0.0, 

     // Right face 
     1.0, 0.0, 
     1.0, 1.0, 
     0.0, 1.0, 
     0.0, 0.0, 

     // Left face 
     0.0, 0.0, 
     1.0, 0.0, 
     1.0, 1.0, 
     0.0, 1.0, 
    ]; 
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW); 
    cubeVertexTextureCoordBuffer1.itemSize = 2; 
    cubeVertexTextureCoordBuffer1.numItems = 12; 

cubeVertexIndexBuffer = gl.createBuffer(); 
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); 
    var cubeVertexIndices = [ 
     0, 1, 2,  0, 2, 3, // Front face 
     4, 5, 6,  4, 6, 7, // Back face 
     8, 9, 10,  8, 10, 11, // Top face 
    ]; 
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW); 
    cubeVertexIndexBuffer.itemSize = 1; 
    cubeVertexIndexBuffer.numItems = 18; 

cubeVertexIndexBuffer1 = gl.createBuffer(); 
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer1); 
    var cubeVertexIndices = [ 
     12, 13, 14, 12, 14, 15, // Bottom face 
     16, 17, 18, 16, 18, 19, // Right face 
     20, 21, 22, 20, 22, 23 // Left face 
    ]; 
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW); 
    cubeVertexIndexBuffer1.itemSize = 1; 
    cubeVertexIndexBuffer1.numItems = 18; 



} 


var xRot = 0; 
var yRot = 0; 
var zRot = 0; 

function drawScene() { 
    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, [0.0, 0.0, -5.0]); 

    mat4.rotate(mvMatrix, degToRad(xRot), [1, 0, 0]); 
    mat4.rotate(mvMatrix, degToRad(yRot), [0, 1, 0]); 
    mat4.rotate(mvMatrix, degToRad(zRot), [0, 0, 0]); 
    setMatrixUniforms(); 

gl.activeTexture(gl.TEXTURE0); 
gl.bindTexture(gl.TEXTURE_2D, texturen[0]); 
gl.vertexAttribPointer 
(textureCoordAttribute, cubeVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0); 
    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer); 
    gl.vertexAttribPointer 
    (shaderProgram.vertexPositionAttribute,cubeVertexPositionBuffer.itemSize, 
    gl.FLOAT, false, 0, 0); 

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); 

    gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0); 


gl.activeTexture(gl.TEXTURE1); 
gl.bindTexture(gl.TEXTURE_2D, texturen[1]); 
gl.vertexAttribPointer 
(textureCoordAttribute, cubeVertexTextureCoordBuffer1.itemSize, gl.FLOAT, false, 0, 0); 
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer1); 
gl.vertexAttribPointer 
(shaderProgram.vertexPositionAttribute,cubeVertexPositionBuffer1.itemSize, 
    gl.FLOAT, false, 0, 0); 


    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer1); 

    gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer1.numItems, gl.UNSIGNED_SHORT, 0); 


} 

私はちょうど2つの部分に分けて、2つの写真でテストしようとしました。また、キューブVirtexIndexBuffersは正確に何ですか?

答えて

14

まず、短い答え:あなたのコードの最後の10行を次のものに置き換えてください。うまくいくはずです。

gl.activeTexture(gl.TEXTURE0); 
gl.bindTexture(gl.TEXTURE_2D, texturen[1]); 
gl.vertexAttribPointer(textureCoordAttribute, cubeVertexTextureCoordBuffer1.itemSize, gl.FLOAT, false, 0, 0); 
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer1); 
gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute,cubeVertexPositionBuffer1.itemSize, gl.FLOAT, false, 0, 0); 

gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); 
gl.drawElements(gl.TRIANGLES, cubeVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0); 

主な変更は以下のとおりです。

  • activeTextureはまだTEXTURE0でアウトオブ含まれ、代わりにcubeVertexIndexBuffer1cubeVertexIndexBufferを使用して
  • (あなたはここでしか一度に一つのテクスチャを使用しています)範囲の指標

インデックスが実際にどのように使用されているかの詳細な説明については、0を参照してください私はむしろすべてここでそれを繰り返すことはないでしょう。

ここでは、より一般的な回答にします。

異なる顔で異なるテクスチャを使用する際の問題を処理するには、基本的に2つの方法があります。最初の簡単な方法は、あなたがここでやっていることを正確に行うことです。オブジェクトをピース単位でレンダリングし、ピースごとに異なるテクスチャをバインドします。厳密には効果を達成する最も効率的な方法ではありませんが、ゲームなどの高性能アプリケーションでそれを処理する最も一般的な方法です。これは、特に材料が単純な拡散テクスチャよりも複雑な場合には、 。

このようなケースでは、あなたのようなコードのパフォーマンスを向上させる簡単な方法があります。頂点/インデックスは、テクスチャごとに別々のバッファに分割する必要はありません。代わりに、単一のバッファにそれらのすべてを組み合わせて、そのような異なるオフセットでそれらをレンダリングすることができます:

// On Init 
var vertBuffer = gl.createBuffer(); 
gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer); 
var vertices = [ 
    // Vertex values for all 6 faces 
]; 
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 

var indexBuffer = gl.createBuffer(); 
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); 
var indices = [ 
    // Index values for all 6 faces 
]; 
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW); 

// On Draw 
// Setup the shader and uniforms and all that jazz 

gl.bindBuffer(gl.ARRAY_BUFFER, vertBuffer); 
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); 
gl.vertexAttribPointer(// Blah blah blah...); 

// Draw face 0 
gl.bindTexture(gl.TEXTURE_2D, texture[0]); 
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0); 

// Draw face 1 
gl.bindTexture(gl.TEXTURE_2D, texture[1]); 
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 12); 

// Draw face 2 
gl.bindTexture(gl.TEXTURE_2D, texture[2]); 
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 24); 

// .. And so on to face 5 
// Draw face 2 
gl.bindTexture(gl.TEXTURE_2D, texture[5]); 
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 60); 

ここで何が起こっているdrawElementsへの各呼び出しは唯一の2つの三角形(6つの頂点、コールの2番目のパラメータを描くということです)、各呼び出しはインデックスバッファにオフセットされているため、別の面で開始されます。 (呼び出しの4番目のパラメータで、バイトオフセットを示します。各インデックスはUint16なので、インデックスごとに2バイトです12 == "start on index [6]")このようにしてバインドとセットアップはすべて一度だけ行われ、それぞれの描画呼び出しは、実際に必要な状態(テクスチャ)を変更するだけで済みます。

これを処理するもう1つの方法は、高速化は困難ですが一般化するのは、テクスチャの配列をシェーダユニフォームにバインドし、別の頂点属性を使用してシェーダ内の配列にインデックスを付けることです。このアプローチのコードを詳しく説明するつもりはありませんが、WebGLシェーダの使用に慣れたら、設定するのは比較的簡単です。この具体的なアプローチについてさらに質問がある場合は、これを過負荷にしないように、異なるSOの質問で尋ねるのが最善です。

+0

あなたが書いたすべてを入力しましたが、それでも動作しません。/もう一度コードを送ってもいいですか? :) – Applecow

+0

[新しい質問](http://stackoverflow.com/questions/11306460/how-to-use-multiple-textures-on-a-cube-in-webgl) – Applecow

+0

@Tojiについて知りたいあなたがヒントした「テクスチャの配列」 - http:// stackoverflowを見てください。com/questions/19592850 /新しい質問のためのhow-to-bind-array-of-textures-to-a-webgl-shader-uniformを参照してください。ありがとう – virtualnobi