我正在开发一个使用webGL的相当简单的基于2d精灵的游戏。可以翻译,缩放和旋转各个精灵。我正在使用精灵表作为纹理,然后动态修改纹理坐标以创建动画效果。只是为了让事情变得有趣,新的精灵会在飞行中实现。所有这一切都很好,当我只使用两种不同的纹理时,一切都正常渲染,但是当我尝试添加第三种纹理时,它会崩溃。我可以使用这两个纹理拥有多个精灵实例,但是一旦我尝试使用第三个纹理创建一个精灵实例,它就会出错。我是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>
注意片段着色器中的第三个条件块是如何被注释掉的。如果我包括这个,它就会破坏。好吧,代码运行,但纹理遍布整个地方。
这是在加载纹理图像后实例化sprite时运行的代码。
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”是对我正在使用的sprite对象的引用。 that.texMap是一个跟踪精灵的纹理坐标数据的对象。 that.textureIndex是每种精灵类型唯一的整数。我还将GL纹理本身的引用保存为that.texture。
这是我在sprite的每个实例的事件循环中运行的内容:
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);
};
希望这不是冗长的。我一直在网上寻找教程或处理这种情况的其他场景,我似乎无法找到任何东西。
谢谢!
编辑:所以,我知道这个问题对社区来说并不太难,但是很多人都看过我的问题并且没有人回复。这促使我做了一些自我反思,并对我的示例代码进行了长时间的努力审视。我对它进行了重组。我意识到每次sprite实例化时我都不需要制作新的纹理。相反,我在开始时加载了我需要的所有纹理。所以第二个代码块已经完全重做了。它仍然会执行许多相同的操作,但在开始时只在for循环中为每个纹理运行一次。我很乐意上传新的代码,如果有人想看看它,或者有人可以指向我在一个教程的方向,在多个2d四边形(每个纹理超过一个四边形)使用多个纹理事件循环,我很乐意自己做研究。
答案 0 :(得分:1)
问题是一切都将是相同的纹理,然后一个新的精灵被实例化,一切都变成了新的纹理。
由此,我怀疑你没有在绑定之前选择正确的纹理(即使用gl.activeTexture()和正确的参数)。在onload函数中看起来很好,但在绑定sprite纹理之前不要在this.draw()函数中使用它,这可能是问题。