Skip to main content

uniform Variables and Fragment Shader_WebGL Notes 4

Free2015-12-24#JS#WebGL#WebGL uniform#webgl uniform变量#webgl设置颜色#webgl修改颜色

By passing values to the fragment shader through attribute variables, we can dynamically modify the point's color

Preface

In the previous note, we passed the coordinate information of the mouse click location to the vertex shader through attribute variables, achieving the effect of drawing a point wherever you click, but all drawn points are the same color. If we want to dynamically set the point's color, we need uniform variables, because attribute variables can only be used in vertex shaders, while color information is in the fragment shader

I. uniform Variables and attribute Variables

uniform and attribute are similar, both are storage qualifiers, main differences as follows:

  • attribute

Can only be used in vertex shaders, used to represent per-vertex data (this value is different in each vertex), such as the previously used attribute vec4 a_Position

  • uniform

Can be used in vertex shaders, also can be used in fragment shaders, used to represent uniform, unchanging data (this value is the same in each vertex), such as uniform Sampler2D u_Sampler that will be used in texture mapping later, and the uniform vec4 u_FragColor we're about to use

P.S. uniform and attribute have other differences, and there's another storage qualifier called varying, these contents will all be expanded in GLSL ES syntax notes

II. Setting Point Color

Similar to setting coordinates, first declare uniform variable to receive color data, then pass in color values, draw it out

1. Fragment Shader

The shading process is in the fragment shader, we need to modify the fragment shader source program:

// Fragment shader source program
//!!! Need to declare floating point precision, otherwise error No precision specified for (float) 
var fsSrc = 'precision mediump float;' +
    'uniform vec4 u_FragColor;' +
    'void main() {' +
    'gl_FragColor = u_FragColor;' + // Set color
'}';

Usage is completely consistent with attribute variables, but need to pay special attention to one point: need to declare floating point precision, otherwise fragment shader will fail to compile, and report the following error:

ERROR: 0:1: '' : No precision specified for (float)

2. Setting Color

Similar to gl.getAttribLocation and gl.vertexAttrib3f, here we use gl.getUniformLocation and gl.uniform4f:

// Set color
// Get uniform variable's storage location
var u_FragColor = gl.getUniformLocation(glUtil.program, 'u_FragColor');
var color = item.color;
// Pass color values to uniform variable
gl.uniform4f(u_FragColor, color.r, color.g, color.b, color.a);

Note color values rgba are all 0.0~1.0, values not in this range will be automatically truncated to 0.0 or 1.0, but no error

3. Drawing Multiple Points

Here it's directly implemented by looping gl.drawArrays(gl.POINTS, 0, 1);, the method is not scientific but can achieve the effect, more scientific method needs to cooperate with buffer, this is the content of the next note, we haven't unlocked it yet

var arrPos = [];
webgl.addEventListener('click', function(e) {
    // Transform coordinates
    var x = (e.offsetX - webgl.width / 2) / (webgl.width / 2);
    var y = (webgl.height / 2 - e.offsetY) / (webgl.height / 2);
    console.log(x, y);
    // Random color
    var color = {
        r: Math.random(),
        g: Math.random(),
        b: Math.random(),
        a: Math.random()
    };
    // Record coordinates, color
    arrPos.push({
        x: x,
        y: y,
        color: color
    });

    // Clear canvas
    gl.clear(gl.COLOR_BUFFER_BIT);
    // Draw points at all recorded coordinates
    arrPos.forEach(function(item) {
        // 2. Assign values to attribute variable
        // Get attribute variable's storage location
        var a_Position = gl.getAttribLocation(glUtil.program, 'a_Position');
        if (a_Position < 0) {
            console.log('Failed to get the storage location of a_Position');
            return;
        }
        // Pass vertex position to attribute variable
        gl.vertexAttrib3f(a_Position, item.x, item.y, 0.0);

        // Set color
        // Get uniform variable's storage location
        var u_FragColor = gl.getUniformLocation(glUtil.program, 'u_FragColor');
        var color = item.color;
        // Pass color values to uniform variable
        gl.uniform4f(u_FragColor, color.r, color.g, color.b, color.a);

        // Draw point
        gl.drawArrays(gl.POINTS, 0, 1);
    });
});

Nothing new, just a crude loop, the only issue needing attention is the clear before the loop, the previous note mentioned this issue: after drawing completes, the color buffer will be reset, its content will be lost. From the effect perspective, clear is setting black background before each drawing, if there's no clear, the background will become transparent (vec4(0.0, 0.0, 0.0, 0.0))

III. DEMO

For the complete example containing the above code, please see: http://www.ayqy.net//temp/webgl/uniform/index.html

IV. Summary

We have already achieved the effect of clicking points to create a brilliant starry sky, not considering performance, implementing this way is still good, because the buffer introduced in the next note looks more troublesome, but there are still benefits, with buffer we can pass a set of data at once, later drawing triangles, coloring triangles, applying textures will all be very convenient

Looping draw a point after all is not a long-term solution, can't use one point at a time to piece together triangles, not to mention there are also 3D models, buffer is still very necessary

Reference Materials

  • "WebGL Programming Guide"

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment