1

Introduction

JavaScript WebGL After drawing a surface , I thought I could try a little more complicated, but I didn't expect that there was a problem when setting the color.

Set color

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

Drawing triangle based on mainly has the following changes:

data

The color data has 4 components: R, G, B, 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 position variables were provided. For colors, additional color variables need to be provided for storage. In addition, the corresponding color needs to be output 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 varying variable of type 061cffc008bfc6, which is a way for the vertex shader to pass values to the fragment shader.

Fragment shader

The corresponding variable that the fragment shader accepts must also be declared.

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

There is a variable here, you need to use precision highp float set the floating point precision of the fragment shader. The vertex shader has a default precision that does not need to be explicitly set.

Buffer color data

The vertex position data is buffered, and the color data is also buffered.

  /**
   * 缓冲颜色数据
   * @param {*} gl WebGL 上下文
   * @param {*} shaderProgram 着色器程序
   * @param {*} colorData 颜色数据
   */
  function setColorBuffers(gl, shaderProgram, colorData) {
    // 创建空白的缓冲对象
    const buffer = gl.createBuffer();
    // 绑定目标
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    // WebGL 不支持直接使用 JavaScript 原始数组类型,需要转换
    const dataFormat = new Float32Array(colorData);
    // 初始化数据存储
    gl.bufferData(gl.ARRAY_BUFFER, dataFormat, gl.DYNAMIC_DRAW);

    // 获取对应数据索引,变量跟顶点着色器里面对应
    const vertexPos = gl.getAttribLocation(shaderProgram, "vertexColor");
    // 解析顶点数据
    gl.vertexAttribPointer(vertexPos, 4, gl.FLOAT, false, 0, 0);
    // 启用顶点属性,顶点属性默认是禁用的。
    gl.enableVertexAttribArray(vertexPos);
  }

Effect

This is exemplary , the following effects:

95-result

It is found that the color gradient is diverging. This is because the color is interpolated when it is converted to pixels during the rasterization process.

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

Dynamic customization example

This is exemplary , fragment shader major changes:

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

findMax method compares the color components of each pixel and sets the final color to the largest component. The following is the effect:

95-custom

Reference


XXHolic
363 声望1.1k 粉丝

[链接]