1

私は、webGL を使用するかなり単純な 2D スプライト ベースのゲームに取り組んでいます。個々のスプライトは、移動、スケーリング、および回転できます。スプライト シートをテクスチャとして使用し、その場でテクスチャ座標を変更してアニメーション効果を作成しています。興味深いことに、新しいスプライトはその場でインスタンス化されます。これらはすべて正常に機能し、2 つの異なるテクスチャのみを使用している場合はすべて適切にレンダリングされますが、3 つ目を追加しようとするとうまくいきません。2 つのテクスチャを使用してスプライトの複数のインスタンスを作成できますが、3 番目のテクスチャを使用してスプライトのインスタンスを作成しようとすると、すべてがうまくいきません。私は WebGL が初めてで、イベント ループ内の複数のテクスチャをカバーするチュートリアルが見つからないようです。2つのスプライトでも間違っていたと思いますが、

ここに私のシェーダーがあります:

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>

フラグメント シェーダーの 3 番目の条件付きブロックがコメント アウトされていることに注意してください。これを含めると、壊れます。コードは実行されますが、テクスチャはいたるところにあります。

これは、テクスチャ イメージがロードされた後、スプライトがインスタンス化されるときに実行するコードです。

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);
};

うまくいけば、これは冗長ではありません。私は、この種の状況を回避するためのチュートリアルやその他のシナリオを探して Web のいたるところにいましたが、何も見つからないようです。

ありがとう!

編集: この問題がコミュニティにとってそれほど難しくないことはわかっていますが、かなりの数の人々が私の質問を閲覧し、誰も回答していません。これにより、少し内省し、サンプル コードをよく、長く、よく見てみるようになりました。

大幅に作り直しました。スプライトがインスタンス化されるたびに新しいテクスチャを作成する必要がないことに気付きました。代わりに、必要なすべてのテクスチャを最初に 1 回ロードします。そのため、2 番目のコード ブロックは完全に作り直されました。それはまだ多くの同じことを行いますが、最初の for ループでテクスチャごとに 1 回だけ実行します。誰かがそれを見たい場合、または誰かが複数の 2D クワッド (テクスチャごとに複数のクワッド) で複数のテクスチャを使用するチュートリアルの方向性を教えてくれれば、新しいコードをアップロードできれば幸いです。イベントループ、私は自分で調査を喜んで行います.

4

1 に答える 1