我想在一个立方体上使用 6 种不同的纹理,每边一个,但找不到错误。这是我当前的代码:
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);
}
我只是把它分成两部分,试图用两张不同的图片进行测试。 cubeVertexIndexBuffers 到底有什么用?
最佳答案
首先,简短的回答:将代码的最后 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
(您在这里一次只使用一个纹理)- 使用
cubeVertexIndexBuffer
而不是cubeVertexIndexBuffer1
,后者包含超出范围的指标
为了更好地解释索引的实际用途,我将向您推荐 this SO question因为我不想在这里重复所有内容。
现在,进入更一般的答案。
有两种基本方法可以处理在不同面上使用不同纹理的问题。第一个也是更简单的方法就是完全按照您在此处所做的操作:将对象渲染成多个部分,为每个部分绑定(bind)不同的纹理。虽然严格来说这不是实现效果的最有效方法,但它仍然是在游戏等高性能应用程序中处理它的最常用方法,因为它提供了很大的灵 active ,尤其是当您的 Material 比简单的漫反射纹理更复杂时.
不过,对于这种情况,有一种简单的方法可以提高像您这样的代码的性能。顶点/索引不必按纹理分解为单独的缓冲区。您可以改为将它们全部组合到一个缓冲区中,并使用不同的偏移量渲染它们,如下所示:
// 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 个三 Angular 形(6 个顶点,调用的第二个参数),但每次调用都偏移到索引缓冲区中,因此它开始于一张不同的脸。 (调用的第四个参数,指示字节偏移量。每个索引都是一个 Uint16,因此每个索引 2 个字节。12 ==“从索引 [6] 开始”)这样所有绑定(bind)和设置只发生一次,并且每个绘制调用只需更改实际需要的状态(纹理)。
处理此问题的另一种方法是将一组纹理绑定(bind)到着色器统一,并使用另一个顶点属性在着色器中索引到该数组,这种方法更快但更难概括。我不打算详细介绍这种方法的代码,但是一旦您熟悉了 WebGL 着色器的使用,它应该相对容易设置。如果您对这种特定方法有进一步的疑问,最好提出不同的 SO 问题,以免使这个问题过载。
关于javascript - 如何在 WebGL 中使用多个纹理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11292599/