我正在开发一个使用 webGL 的相当简单的基于 2d sprite 的游戏。单个精灵可以平移、缩放和旋转。我使用精灵表作为纹理,然后动态修改纹理坐标以创建动画效果。只是为了让事情变得有趣,新的精灵会即时实例化。当我只使用两种不同的纹理时,所有这些都可以正常工作,并且一切都可以正常渲染,但是当我尝试添加第三个时它会崩溃。我可以使用这两个纹理创建多个精灵实例,但是一旦我尝试使用第三个纹理创建一个精灵实例,一切都会出错。我是 WebGL 的新手,似乎找不到涵盖事件循环内多个纹理的教程。我想我做错了即使有两个精灵,
这是我的着色器:
void main() {
// Multiply the position by the matrix.
vec2 position = (u_matrix * vec3(a_position, 1)).xy;
// convert the position from pixels to 0.0 to 1.0
vec2 zeroToOne = position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
v_texCoord = a_texCoord;
}
</script>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision mediump float;
// our texture
uniform sampler2D u_image0;
uniform sampler2D u_image1;
uniform sampler2D u_image2;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
void main() {
// Look up a color from the texture.
vec4 textureColor = texture2D(u_image0, v_texCoord);
if (textureColor.a < 0.5)
discard;
else
gl_FragColor = vec4(textureColor.rgb, textureColor.a);
vec4 textureColor1 = texture2D(u_image1, v_texCoord);
if (textureColor1.a < 0.5)
discard;
else
gl_FragColor = vec4(textureColor1.rgb, textureColor1.a);
vec4 textureColor2 = texture2D(u_image2, v_texCoord);
// if (textureColor2.a < 0.5)
// discard;
// else
// gl_FragColor = vec4(textureColor2.rgb, textureColor2.a);
}
</script>
请注意片段着色器中的第三个条件块是如何被注释掉的。如果我包括这个,它会中断。好吧,代码运行了,但是纹理到处都是。
这是我在纹理图像加载后实例化精灵时运行的代码。
image.onload = function() {
that.buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, that.buffer);
var xMin = 0;
var xMax = that.width;
var yMin = 0;
var yMax = that.height;
// setup a rectangle from 0, that.width to 0, that.height in pixels
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
xMin, yMax,
xMax, yMax,
xMin, yMin,
xMin, yMin,
xMax, yMax,
xMax, yMin]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(globalGL.positionLocation);
gl.vertexAttribPointer(globalGL.positionLocation, 2, gl.FLOAT, false, 0, 0);
// look up where the texture coordinates need to go.
that.texCoordLocation = gl.getAttribLocation(globalGL.program, "a_texCoord");
//create a texture map object and attach to that
that.texMap = new TextureMap({horizontalNum: that.texHorizontalNum, verticalNum: that.texVerticalNum});
var tex = that.texMap.getTile([0, 0]);
// provide texture coordinates for the rectangle.
that.texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, that.texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
tex.minX, tex.maxY,
tex.maxX, tex.maxY,
tex.minX, tex.minY,
tex.minX, tex.minY,
tex.maxX, tex.maxY,
tex.maxX, tex.minY]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(that.texCoordLocation);
gl.vertexAttribPointer(that.texCoordLocation, 2, gl.FLOAT, false, 0, 0);
// Create a texture.
that.texture = gl.createTexture();
that.u_imageLocation = gl.getUniformLocation(globalGL.program, "u_image" + that.textureIndex);
gl.uniform1i(that.u_imageLocation, that.textureIndex);
gl.activeTexture(gl.TEXTURE0 + that.textureIndex);
gl.bindTexture(gl.TEXTURE_2D, that.texture);
// Set the parameters so we can render any size image.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
// Upload the image into the texture.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
globalObj.agents[that.id] = that;
};
“那个”是对我正在使用的精灵对象的引用。that.texMap 是一个跟踪精灵的纹理坐标数据的对象。that.textureIndex 是每种精灵唯一的整数。我还将对 GL 纹理本身的引用保存为 that.texture。
这是我在事件循环中为每个精灵实例运行的内容:
this.draw = function() {
var tex, texCoordLocation, texCoordBuffer, i;
//This pulls up the correct texture coordinates depending on what the sprite is doing.
if (this.shooting) {
tex = this.texMap.getTile([0, 1]);
} else if ( this.moving) {
if (this.moving < 15 / this.speed) {
this.moving++;
tex = this.texMap.getTile();
} else {
this.moving = 1;
tex = this.texMap.getTile('next');
}
} else {
tex = this.texMap.getTile([0, 0]);
}
//binds the texture associated with the sprite.
gl.bindTexture(gl.TEXTURE_2D, this.texture);
//gets a reference to the textCoord attribute
texCoordLocation = gl.getAttribLocation(globalGL.program, 'a_texCoord');
//create a buffer for texture coodinates
texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
tex.minX, tex.maxY,
tex.maxX, tex.maxY,
tex.minX, tex.minY,
tex.minX, tex.minY,
tex.maxX, tex.maxY,
tex.maxX, tex.minY]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
var matrixLocation = gl.getUniformLocation(globalGL.program,'u_matrix');
//sets up arrays needed to rotate and translate the sprite
var centerTranslation = [-this.width / 2, -this.height / 2];
var decenterTranslation = [this.width / 2 , this.height / 2];
var translation = [this.x, this.y];
var angleInRadians = this.rotation;
var scale = [1, 1];
// Compute the matrices
var centerTranslationMatrix = makeTranslation(centerTranslation[0], centerTranslation[1]);
var decenterTranslationMatrix = makeTranslation(decenterTranslation[0], decenterTranslation[1]);
var translationMatrix = makeTranslation(translation[0], translation[1]);
var rotationMatrix = makeRotation(angleInRadians);
var scaleMatrix = makeScale(scale[0], scale[1]);
// Multiply the matrices.
var matrix = matrixMultiply(scaleMatrix, centerTranslationMatrix);
matrix = matrixMultiply(matrix, rotationMatrix);
matrix = matrixMultiply(matrix, decenterTranslationMatrix);
matrix = matrixMultiply(matrix, translationMatrix);
// Set the matrix.
gl.uniformMatrix3fv(matrixLocation, false, matrix);
// draw
gl.drawArrays(gl.TRIANGLES, 0, 6);
};
希望这不是冗长的。我一直在网上寻找处理这种情况的教程或其他场景,但我似乎找不到任何东西。
谢谢!
编辑:所以,我知道这个问题对社区来说并不太难,但是有不少人查看了我的问题,但没有人回应。这促使我进行一些自我反省,并仔细、长时间、认真地查看我的示例代码。
我已经对其进行了重大调整。我意识到我不需要在每次精灵被实例化时都制作新的纹理。相反,我会在开始时加载一次我需要的所有纹理。所以第二个代码块已经完全重做。它仍然做了很多相同的事情,但在开始时只为 for 循环中的每个纹理运行一次。如果有人想看一下新代码,或者如果有人可以指出一个教程的方向,我很乐意上传新代码,该教程在多个 2d 四边形(每个纹理超过一个四边形)上使用多个纹理事件循环,我很乐意自己做研究。