WebGL绘制rect&图像到一个着色器

时间:2014-09-17 20:52:50

标签: javascript webgl

尝试做一些基本的webgl,我有两个"游戏对象"。一个简单的精灵和一个矩形。基本上我想要做的是绘制精灵图像,然后绘制一个具有指定颜色的矩形。

两个对象都有pos向量,宽度和高度。精灵有一个图像对象,矩形有一个颜色对象,其rgb值为0到1.

对不起所有代码,但这是我的绘制方法:

draw: function () {
  this.resize();
  var delta = this.getDeltaTime();

  gl.viewport(0, 0, gl.canvas.clientWidth, gl.canvas.clientHeight);
  gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

  var shaderProgram = this.shader.shaderProgram;

  var matrixLocation = gl.getUniformLocation(shaderProgram, "uMatrix");

  for (var i = 0; i < this.objects.length; i++) {
    var planePositionBuffer = gl.createBuffer();
    mat3.identity(this.mvMatrix);
    gl.bindBuffer(gl.ARRAY_BUFFER, planePositionBuffer);
    var object = this.objects[i];

    var x1 = object.pos.x;
    var y1 = object.pos.y;
    var x2 = object.pos.x + object.width;
    var y2 = object.pos.y + object.height;

    var vertices = [
      x1, y1,
      x2, y1,
      x1, y2,
      x1, y2,
      x2, y1,
      x2, y2
    ];

    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0);

    var textureBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, textureBuffer);

    var textureCoords;
    if (object.image) {
      var dw = (object.width / object.image.image.width);
      var dh = 1.0 - (object.height / object.image.image.height);
      textureCoords = [
        0.0, 1.0,
        dw, 1.0,
        0.0, dh,
        0.0, dh,
        dw, 1.0,
        dw, dh
      ];

      gl.activeTexture(gl.TEXTURE0);
      gl.bindTexture(gl.TEXTURE_2D, this.objects[i].image);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW);
      gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
    }


    mat3.multiply(this.mvMatrix, this.mvMatrix, [
      2 / gl.canvas.clientWidth, 0, 0,
      0, -2 / gl.canvas.clientHeight, 0,
      -1, 1, 1
    ]);

    gl.uniformMatrix3fv(matrixLocation, false, this.mvMatrix);

    gl.uniform1i(shaderProgram.samplerUniform, 0);

    var colorLocation = gl.getUniformLocation(shaderProgram, "uColor");
    if (object.color) {
      var color = object.color;
      gl.uniform4f(colorLocation, color.r, color.g, color.b, 1);
    }
    else {
      gl.uniform4f(colorLocation, 1.0, 1.0, 1.0, 1);
    }

    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 6);
  }

  requestAnimationFrame(this.draw.bind(this));
}

基本上我正在做的是将位置坐标放在一起以绘制图像/ rect的位置。

然后我检查对象是否有图像。如果是,则根据图像尺寸的子图形宽度计算纹理坐标。并绑定纹理。

然后在下面,如果对象没有颜色,我将均匀颜色设置为白色。如果对象确实有颜色,则从中设置制服。

现在假设在我的列表中,图像精灵是第一个,矩形是第二个,首先是针对图像调用bindTexture。这样就可以进行抽奖。 OpenGL是一个状态机,因此图像首先绘制,保持绑定,然后再次绘制矩形坐标。它只使用我在矩形中保存的绿色。

所以我的主要问题是:是否有正确的方法来清除它?或者是否有办法仅在某些情况下对顶点绘制颜色,在另一种情况下是否有纹理?

这是我的着色器:

<script id="shader-fs" type="x-shader/x-fragment">
  precision mediump float;

  varying vec2 vTextureCoord;
  uniform sampler2D uSampler;
  uniform vec4 uColor;

  void main(void) {
    gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)) * uColor;
  }
</script>

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

  uniform mat3 uMatrix;
  varying vec2 vTextureCoord;

  void main() {
    gl_Position = vec4((uMatrix * vec3(aVertexPosition, 1)).xy, 0, 1);
    vTextureCoord = aTextureCoord;
  }
</script>

非常简单。使用统一矩阵在我的代码中通过剪辑坐标获得屏幕坐标。

2 个答案:

答案 0 :(得分:1)

使用单个着色器使用纹理或颜色绘制的典型方法是将您不使用的那个设置为白色和乘法或黑色并添加。我喜欢白色和倍增,这是你已经拥有的。

所以,当你想用一个纹理

绘制时
var whiteColor = [1, 1, 1, 1];

gl.bindTexture(gl.TEXTURE_2D, textureWithImageInIt);
gl.uniform4fv(uColorLocation, whiteColor);

当你想用一种颜色绘制时,会绑定一个1x1像素的白色纹理

在初始时

var white1PixelTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, white1PixelTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE,
              new Uint8Array([255,255,255,255]));

抽奖时间

gl.bindTexture(gl.TEXTURE_2D, white1PixelTexture);
gl.uniform4fv(uColorLocation, someColor);  

这是有效的,因为white = 11 * something = something所以texture * 1 = texture1 * color = color;

它还可以让您为简单效果着色纹理。将颜色设置为红色[1, 0.4, 0.4, 1],您将获得纹理的红色版本。随着时间的推移调整alpha [1, 0, 0, lerpColorOverTime],您可以淡出纹理。

答案 1 :(得分:0)

是的,有一种正确的方法,只需在您完成纹理时解开纹理:

 gl.activeTexture(gl.TEXTURE0);
 gl.bindTexture(gl.TEXTURE_2D, null);