如何使用WebGL渲染2D Sprite?

时间:2014-10-05 14:12:14

标签: opengl opengl-es html5-canvas dart webgl

我正在努力使用Dart和WebGL将2D Sprite渲染到Canvas。我在网上找到很少的例子;大多数都是3D,或包含大量的意大利面条代码,没有真正解释他们正在做什么。我试图做一个渲染精灵的最简单的事情。

到目前为止,我已设法在画布上渲染绿色方块(两个三角形)。我挣扎的那一点,是如何将它从绿色方块改为使用我的纹理(纹理加载和绑定正确,我相信)。我认为这需要更改着色器(采用纹理合作而不是颜色)以及传递与缓冲区中顶点相关的纹理坐标。

此代码also exists in a Gist

注意:这只是一次性的样本;大多数代码都存在于构造函数中;我现在对代码的整洁程度不太感兴趣;当我在屏幕上看到一个精灵时,我可以整理一下!

注意:我对使用第三方库不感兴趣;我这样做是为了学习WebGL!

<!DOCTYPE html>
<html>
  <head>
    <title>MySecondGame</title>
  </head>
  <body>
    <canvas width="1024" height="768"></canvas>

    <div style="display: none;">
      <img id="img-player" src="assets/player.png" />
    </div>

    <script id="vertex" type="x-shader">
      attribute vec2 aVertexPosition;

      void main() {
        gl_Position = vec4(aVertexPosition, 0.0, 1.0);
      }
    </script>
    <script id="fragment" type="x-shader">
      #ifdef GL_ES
      precision highp float;
      #endif

      uniform vec4 uColor;

      void main() {
        gl_FragColor = uColor;
      }
    </script>

    <script type="application/dart">
      import 'dart:async';
      import 'dart:html';
      import 'dart:math';
      import 'dart:typed_data';
      import 'dart:web_gl';

      Game game;

      main() {
        game = new Game(document.querySelector('canvas'));
      }

      class Game {
        RenderingContext _gl;
        Buffer vbuffer;
        int numItems;
        Texture playerTexture;
        double elapsedTime;
        double fadeAmount;

        Game(CanvasElement canvas) {
          _gl = canvas.getContext3d();
          playerTexture = _gl.createTexture();
          _gl.bindTexture(TEXTURE_2D, playerTexture);
          _gl.texImage2DUntyped(TEXTURE_2D, 0, RGBA, RGBA, UNSIGNED_BYTE, document.querySelector('#img-player'));
          _gl.texParameteri(TEXTURE_2D, TEXTURE_MAG_FILTER, NEAREST);
          _gl.texParameteri(TEXTURE_2D, TEXTURE_MIN_FILTER, LINEAR_MIPMAP_NEAREST);
          _gl.generateMipmap(TEXTURE_2D);
          _gl.bindTexture(TEXTURE_2D, null);

          var vsScript = document.querySelector('#vertex');
          var vs = _gl.createShader(VERTEX_SHADER);
          _gl.shaderSource(vs, vsScript.text);
          _gl.compileShader(vs);

          var fsScript = document.querySelector('#fragment');
          var fs = _gl.createShader(FRAGMENT_SHADER);
          _gl.shaderSource(fs, fsScript.text);
          _gl.compileShader(fs);

          var program = _gl.createProgram();
          _gl.attachShader(program, vs);
          _gl.attachShader(program, fs);
          _gl.linkProgram(program);

          if (!_gl.getShaderParameter(vs, COMPILE_STATUS))
            print(_gl.getShaderInfoLog(vs));

          if (!_gl.getShaderParameter(fs, COMPILE_STATUS))
            print(_gl.getShaderInfoLog(fs));

          if (!_gl.getProgramParameter(program, LINK_STATUS))
            print(_gl.getProgramInfoLog(program));

          var aspect = canvas.width / canvas.height;
          var vertices = new Float32List.fromList([
            -0.5, 0.5 * aspect, 0.5, 0.5 * aspect,  0.5, -0.5 * aspect,  // Triangle 1
            -0.5, 0.5 * aspect, 0.5,-0.5 * aspect, -0.5, -0.5 * aspect   // Triangle 2
          ]);

          vbuffer = _gl.createBuffer();
          _gl.bindBuffer(ARRAY_BUFFER, vbuffer);                                       
          _gl.bufferData(ARRAY_BUFFER, vertices, STATIC_DRAW);
          numItems = vertices.length ~/ 2;

          _gl.useProgram(program);

          var uColor = _gl.getUniformLocation(program, "uColor");
          _gl.uniform4fv(uColor, new Float32List.fromList([0.0, 0.3, 0.0, 1.0]));

          var aVertexPosition = _gl.getAttribLocation(program, "aVertexPosition");
          _gl.enableVertexAttribArray(aVertexPosition);
          _gl.vertexAttribPointer(aVertexPosition, 2, FLOAT, false, 0, 0);

          window.animationFrame.then(_gameLoop);
        }

        _gameLoop(num time) {
          elapsedTime = time;
          _update();
          _render();
          window.animationFrame.then(_gameLoop);
        }

        _update() {
          // Use sine curve for fading. Sine is -1-1, so tweak to be 0 - 1.
          fadeAmount = (sin(elapsedTime/1000) / 2) + 0.5;
        }

        _render() {
          // Set colour for clearing to.
          _gl.clearColor(fadeAmount, 1 - fadeAmount, 0.0, 1.0);
          // Clear.
          _gl.clear(RenderingContext.COLOR_BUFFER_BIT);

          _gl.bindTexture(TEXTURE_2D, playerTexture);
          _gl.drawArrays(TRIANGLES, 0, numItems);
          _gl.bindTexture(TEXTURE_2D, null);
        }
      }
    </script>
    <script src="packages/browser/dart.js"></script>
  </body>
</html>

(也用opengl标记,因为我相信WebGL / OpenGL的解决方案可能相同。

1 个答案:

答案 0 :(得分:1)

好的,设法使这项工作。你可以see the full diff in a gist here

我可能错了;但似乎我期望在我设置缓冲区时将数据设置在缓冲区中;但我无法找到任何方式来说明哪个数据是针对哪个缓冲区的。我将代码分成了一些设置代码:

vbuffer = _gl.createBuffer();
_gl.bindBuffer(ARRAY_BUFFER, vbuffer);
_gl.bufferData(ARRAY_BUFFER, vertices, STATIC_DRAW);
numItems = vertices.length ~/ 2;

tbuffer = _gl.createBuffer();
_gl.bindBuffer(ARRAY_BUFFER, tbuffer);                                       
_gl.bufferData(ARRAY_BUFFER, textureCoords, STATIC_DRAW);

aVertexPosition = _gl.getAttribLocation(program, "aVertexPosition");
_gl.enableVertexAttribArray(aVertexPosition);

aTextureCoord = _gl.getAttribLocation(program, "aTextureCoord");
_gl.enableVertexAttribArray(aTextureCoord);

uSampler = _gl.getUniformLocation(program, "uSampler");

和一些渲染代码:

_gl.bindBuffer(ARRAY_BUFFER, vbuffer);
_gl.vertexAttribPointer(aVertexPosition, 2, FLOAT, false, 0, 0);

_gl.bindBuffer(ARRAY_BUFFER, tbuffer);
_gl.vertexAttribPointer(aTextureCoord, 2, FLOAT, false, 0, 0);

_gl.bindTexture(TEXTURE_2D, playerTexture);
_gl.uniform1i(uSampler, 0);

_gl.drawArrays(TRIANGLES, 0, numItems);

我不完全确定这是否正确(感觉就像我每帧都发送相同的顶点和textureCoord),但它正在工作。

I MADE A GAME!!!!111