JavaScript WebGL setting colors

Posted by sparshdharam on Tue, 04 Jan 2022 14:43:35 +0100



JavaScript WebGL draws a face Then I thought I could try something more complex. Unexpectedly, there was a problem when setting the color.

Set color

In the previous examples, a single color was set, but each vertex can have its own color information.

be based on Draw triangle There are mainly the following changes:

  • data
  • Vertex Shader
  • Fragment Shader
  • Buffer color data


Color data has four components: R, G, B and A.

  let colors = [
    1.0, 0.0, 0.0, 1.0, // red
    0.0, 1.0, 0.0, 1.0, // green
    0.0, 0.0, 1.0, 1.0, // blue

Vertex Shader

Previously, only location variables were provided. For colors, additional color variables need to be provided for storage. In addition, you also need to output the corresponding color to the next stage.

  const source = `
    attribute vec3 vertexPos;
    attribute vec4 vertexColor;

    varying vec4 vColor;
    void main(void){
      gl_Position = vec4(vertexPos, 1);
      vColor = vertexColor;

There is an additional variable of type varying, which is a way for vertex shaders to pass values to fragment shaders.

Fragment Shader

The slice shader accepts the corresponding variables and also declares them.

  const fragmentSource = `
    precision highp float;
    varying vec4 vColor;
    void main(void){
      gl_FragColor = vColor;

The variable appears here. You need to set the floating-point precision of the slice shader with precision high float. Vertex shaders have default precision and can be set without explicit.

Buffer color data

Vertex position data is buffered, and color data is buffered.

   * Buffer color data
   * @param {*} gl WebGL context
   * @param {*} shaderProgram Shader program
   * @param {*} colorData Color data
  function setColorBuffers(gl, shaderProgram, colorData) {
    // Create a blank buffer object
    const buffer = gl.createBuffer();
    // Bind target
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    // WebGL does not support the direct use of JavaScript original array types, which requires conversion
    const dataFormat = new Float32Array(colorData);
    // Initialize data store
    gl.bufferData(gl.ARRAY_BUFFER, dataFormat, gl.DYNAMIC_DRAW);

    // Get the corresponding data index, and the variable corresponds to the vertex shader
    const vertexPos = gl.getAttribLocation(shaderProgram, "vertexColor");
    // Parse vertex data
    gl.vertexAttribPointer(vertexPos, 4, gl.FLOAT, false, 0, 0);
    // Enable vertex attributes, which are disabled by default.


This is Example , the effect is as follows:

It is found that the color gradient diverges because the color is interpolated when it is transformed into pixels in the rasterization process.

In the program, only the colors of three vertices are defined, and the color of pixels between them will change with the pixel position. The difference of the same monochrome between adjacent pixels is a fixed value. If you don't want this effect, you can customize it in the slice shader.

Dynamic customization example

This is Example , the main changes of the slice shader are as follows:

  const fragmentSource = `
    precision highp float;
    varying vec4 vColor;

    int findMax(float r, float g, float b) {
        if (r > g && r > b) {
            return 0;
        if (g > r && g > b) {
            return 1;
        return 2;

    void main(void){
      float red = vColor.r;
      float green = vColor.g;
      float blue = vColor.b;
      int max = findMax(red, green, blue);
      vec4 finalColor = vColor;
      if (max == 0) {
          finalColor = vec4(1.0, 0.0, 0.0, 1.0);
      else if (max == 1) {
          finalColor = vec4(0.0, 1.0, 0.0, 1.0);
      else if (max == 2) {
          finalColor = vec4(0.0, 0.0, 1.0, 1.0);
      gl_FragColor = finalColor;

The findMax method compares the color components of each pixel and sets the final color to the largest component. Here are the effects:

Back to top

reference material

Topics: webgl