2012-07-02 14 views
5

Quería usar 6 texturas diferentes en un cubo, una por lado, pero no puedo encontrar el error. Aquí está mi código actual:¿Cómo usar múltiples texturas en 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); 


} 

yo sólo lo dividió en dos partes, tratando de hacer una prueba con 2 diferentes fotografías. ¿Y para qué son exactamente los cubeVertexIndexBuffers?

Respuesta

14

En primer lugar, la respuesta corta: Reemplace las últimas 10 líneas de su código con lo siguiente y creo que debería funcionar.

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

Los cambios principales son:

  • activeTexture sigue siendo TEXTURE0 (sólo está utilizando una textura a la vez aquí)
  • Usando cubeVertexIndexBuffer en lugar de cubeVertexIndexBuffer1, que contenía fuera de la indices de rango

Para una mejor explicación de en qué se utilizan realmente los índices, lo referiré a this SO question ya que prefiero no repetir todo eso aquí.

Ahora, a la respuesta más general.

Hay dos formas básicas de manejar el problema del uso de diferentes texturas en diferentes caras. El primer y más simple método es hacer exactamente lo que está haciendo aquí: renderizar el objeto en pedazos, vinculando una textura diferente para cada pieza. Aunque no es estrictamente la forma más eficaz de lograr el efecto, es la forma más común de manejarlo en aplicaciones de alto rendimiento, como los juegos, simplemente porque ofrece mucha flexibilidad, especialmente cuando los materiales son más complejos que una simple textura difusa. .

Sin embargo, hay una manera simple de mejorar el rendimiento del código como el suyo para un caso como este. Los vértices/índices no tienen que dividirse en búferes separados por textura. En su lugar podría combinarlos todos en una sola memoria intermedia y hacerlos con diferentes compensaciones de este modo:

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

¿Qué está pasando aquí es que cada llamada a drawElements sólo dibuja 2 triángulos (6 vértices, el segundo parámetro de la llamada), pero cada llamada se compensa en el buffer de índice para que comience en una cara diferente. (cuarto parámetro de la llamada, que indica un desplazamiento de bytes. Cada índice es un Uint16, por lo tanto, 2 bytes por índice. 12 == "inicio en el índice [6]") De esta forma, todo el enlace y la configuración solo se producen una vez, y cada llamada al sorteo solo tiene que cambiar el estado que es realmente necesario (la textura).

La otra forma de manejar esto, que es más rápida pero más difícil de generalizar, es vincular una matriz de texturas a un sombreador uniforme y usar otro atributo de vértice para indexar en la matriz dentro del sombreador. No voy a detallar el código para este enfoque, pero debería ser relativamente fácil de configurar una vez que se sienta cómodo con el uso del sombreador WebGL. Si tiene más preguntas sobre este enfoque específico, sería mejor preguntar en otra pregunta de SO para no sobrecargar esta.

+0

Ingresé todo lo que escribió, pero todavía no funciona:/¿Puedo enviarle el código nuevamente? :) – Applecow

+0

[nueva pregunta] (http://stackoverflow.com/questions/11306460/how-to-use-multiple-textures-on-a-cube-in-webgl) – Applecow

+0

@Toji Me gustaría saber acerca de la "matriz de texturas" que insinuó: consulte http: // stackoverflow.com/questions/19592850/how-to-bind-an-array-of-textures-to-a-webgl-shader-uniform para una nueva pregunta, por favor. Gracias – virtualnobi