在webGL中处理多个动画2d精灵时显示不正确的纹理

时间:2013-06-01 00:04:47

标签: animation webgl textures sprite

我正在开发一个使用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四边形(每个纹理超过一个四边形)使用多个纹理事件循环,我很乐意自己做研究。

1 个答案:

答案 0 :(得分:1)

  

问题是一切都将是相同的纹理,然后一个新的精灵被实例化,一切都变成了新的纹理。

由此,我怀疑你没有在绑定之前选择正确的纹理(即使用gl.activeTexture()和正确的参数)。在onload函数中看起来很好,但在绑定sprite纹理之前不要在this.draw()函数中使用它,这可能是问题。