1

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

4

1 回答 1

1

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

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

于 2013-06-03T19:52:06.317 回答