8

立方体に 6 つの異なるテクスチャを 1 つの側面に 1 つずつ使用したかったのですが、間違いが見つかりません。これが私の現在のコードです:

   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つの異なる写真でテストしようとしました. そして、正確にはcubeVertexIndexBuffersは何ですか?

4

1 に答える 1

16

まず、短い答え: コードの最後の 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しています (ここでは、一度に 1 つのテクスチャのみを使用しています)
  • 範囲外の指標を含むcubeVertexIndexBufferの代わりに使用cubeVertexIndexBuffer1

インデックスが実際に何に使用されるかについてのより良い説明については、ここですべてを繰り返したくないので、この SO の質問を参照してください。

さて、より一般的な答えに進みましょう。

異なる面に異なるテクスチャを使用するという問題を処理するには、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 つの三角形 (呼び出しの 2 番目のパラメーターである 6 つの頂点) のみを描画しますが、各呼び出しはインデックス バッファーにオフセットされるため、別の面から開始されます。(呼び出しの 4 番目のパラメーターで、バイト オフセットを示します。各インデックスは Uint16 であるため、インデックスごとに 2 バイトです。12 == "index[6] で開始") この方法では、すべてのバインディングとセットアップが 1 回だけ行われ、各描画呼び出しは、実際に必要な状態 (テクスチャ) のみを変更する必要があります。

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

于 2012-07-02T20:06:18.370 に答える