Introduction
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
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. gl.enableVertexAttribArray(vertexPos); }
effect
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: