WebGL绘制不同颜色的多个形状

时间:2016-09-28 22:13:25

标签: javascript html5 webgl fragment-shader

我目前正在学习WebGL和Javascript。一项任务要求我使用WebGL创建多个形状,并且它们都是不同的颜色,但是,我无法弄清楚如何设置它以使每个形状都具有它自己的颜色。



// HelloTriangle.js (c) 2012 matsuda
// Vertex shader program
var VSHADER_SOURCE =
  'attribute vec4 a_Position;\n' +
  'void main() {\n' +
  '  gl_Position = a_Position;\n' +
  '}\n';
 
// Fragment shader program
var FSHADER_SOURCE =
  'precision mediump float;\n' +
  'uniform vec4 u_FragColor;\n' +
  'void main() {\n' +
  '  gl_FragColor = u_FragColor;\n' +
  '}\n';
 
function main() {
  // Retrieve <canvas> element
  var canvas = document.getElementById('webgl');
 
  // Get the rendering context for WebGL
  var gl = getWebGLContext(canvas);
  if (!gl) {
    console.log('Failed to get the rendering context for WebGL');
    return;
  }
 
  // Initialize shaders
  if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
    console.log('Failed to intialize shaders.');
    return;
  }
 
  // Write the positions of vertices to a vertex shader
  var n = initVertexBuffers(gl);
  if (n < 0) {
    console.log('Failed to set the positions of the vertices');
    return;
  }
 
  // Specify the color for clearing <canvas>
  gl.clearColor(0, 0, 0, 1);
 
  // Clear <canvas>
  gl.clear(gl.COLOR_BUFFER_BIT);
 
  // Draw the rectangle
  gl.drawArrays(gl.TRIANGLES, 0, 3); // Triangle One
  gl.drawArrays(gl.TRIANGLES, 3, 3); // Triangle Two
  gl.drawArrays(gl.TRIANGLE_FAN, 6, 6); // Triangle Fan
}
 
function randColor() // Assign Random color values
{
    setR = Math.random();
    setG = Math.random();
    setB = Math.random();
}
 
function initVertexBuffers(gl) {
  var vertices = new Float32Array([
    0.1,   0.1,   -0.1,  -0.1,   0.1,  -0.1,  // First Triangle
    0.15,  0.25,   0.1,   0.2,  -0.1,   0.2,  // Second Triangle
    0.75,  0.65,   0.35,  0.25,  0.65,  0.55,
    0.65,  0.25,   0.35,  0.45,  0.25,  0.15  // Triangle Fan
  ]);
  var n = 6; // The number of vertices
 
  // Create a buffer object
  var vertexBuffer = gl.createBuffer();
  if (!vertexBuffer) {
    console.log('Failed to create the buffer object');
    return -1;
  }
 
  // Bind the buffer object to target
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  // Write date into the buffer object
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
 
  var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  if (a_Position < 0) {
    console.log('Failed to get the storage location of a_Position');
    return -1;
  }
 
  // Get the storage location of u_FragColor
  var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
  if (!u_FragColor) {
    console.log('Failed to get the storage location of u_FragColor');
    return;
  }
 
  //Pass color of point to u_FragColor
  randColor();
  gl.uniform4f(u_FragColor, setR, setG, setB, 1.0);
 
  // Assign the buffer object to a_Position variable
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
 
  // Enable the assignment to a_Position variable
  gl.enableVertexAttribArray(a_Position);
 
  return n;
}
&#13;
<canvas id="webgl" width="400" height="400">
  Please use a browser that supports "canvas"
</canvas>

<script src="../lib/webgl-utils.js"></script>
<script src="../lib/webgl-debug.js"></script>
<script src="../lib/cuon-utils.js"></script>
&#13;
&#13;
&#13;

我很确定我应该修改的代码如下:

//Pass color of point to u_FragColor
randColor();
gl.uniform4f(u_FragColor, setR, setG, setB, 1.0);

然而,我无法弄清楚如何制作它以便为我试图绘制的每个形状存储一个值。我认为通过在每次绘制之前随机改变颜色,这将解决它,但事实并非如此。任何有关这方面的见解将不胜感激。

谢谢。

1 个答案:

答案 0 :(得分:1)

你尝试了什么?该代码存在很多问题,并且尝试运行它会出错。

首先关闭initShaders会返回gl.program上的着色器,这是没有意义的。 WebGL应用程序通常有多个着色器程序。相反,您希望initShaders返回一个程序,以便您可以执行

之类的操作
var program1 = initShaders(gl, vertex1ShaderSource, fragment1ShaderSource);
var program2 = initShaders(gl, vertex2ShaderSource, fragment2ShaderSource);
var program3 = initShaders(gl, vertex3ShaderSource, fragment3ShaderSource);
..etc...

接下来initVertexBuffers引用一个名为program的变量,但不存在这样的变量。

initVertexBuffers正在设置制服,但您想在开始绘制之前设置制服,而不是在初始化顶点时设置。

initVertexBuffers也在查找属性和统一位置并检查错误。一方面,检查这些类型的错误本身并不错,但这会使您的代码更难以以其他方式进行调试。在大多数WebGL程序中,如果您没有出现错误但屏幕上没有显示任何错误,则首先要做的是让片段着色器返回纯色

precision mediump float;
uniform vec4 u_FragColor;
void main() {
  //gl_FragColor = u_FragColor;
  gl_FragColor = vec4(1, 0, 0, 1); // return red
}

当您这样做时,WebGL将优化未提供的u_FragColor,并且您检查到您获得u_FragColor位置的代码将无法调试您的着色器。

我建议reading some other tutorials on WebGL

要绘制相同形状的多个副本,过程通常是

在初始时

 set up program
 look up attribute locations and uniform locations
 setup vertices for shape

抽奖时间

 setup attributes for shape
 gl.useProgram(program for shape)
 for each instance of shape
   set uniforms
     set a matrix uniform to position and orient the shape
     set a color uniform for the color
   drawArrays/drawElements

要绘制多个不同的形状,过程通常是

在初始时

 set up programs
 look up attribute locations and uniform locations
 for each shape
   setup vertices for shape

抽奖时间

 for each shape
   gl.useProgram(program for shape) (if different from last shape)
   setup attributes for shape (if different from last shape)
   set uniforms
     set a matrix uniform to position and orient the shape
     set a color uniform for the color
   drawArrays/drawElements

关于定位和定向形状的矩阵see this article