Shader 001 - function modeling capability

0x00 starting from function

Many effects in Shader are calculated by functions. How to better understand the relationship between them. Let's see what the function is first? The definition of function can be simply described as: given A set A and applying rule f to its elements, another set B can be obtained. By reflecting the corresponding relationship between the elements in A and B into the two-dimensional rectangular coordinate system, we can get A curve about F. For example, the curve of sine function sin.

So, how to get the desired Shader effect through the function?

We all know that the Chinese translation of Shader is Shader. The function of Shader is to color every pixel in the screen. The input of a Shader program is location information, and the output is color information. Is it very similar to the mapping relationship in the function: F (position) = color.

Color of 0x01 sin

With the above expression and a little change, we can use shader to describe the color of sin. In the shader, the color is represented by a four-dimensional floating-point vector vec4, which represents (r, g, b, a) respectively, and the value range is 0.0 to 1.0. In order to show a complete sin period, you can scale and translate the sin function to make its period T = 1.0:

float f = sin(x * PI_2) / 2.0 + 0.5;

At the same time, it is also necessary to normalize the pixel coordinates of the screen to make it fall between 0.0 and 1.0. The following st calculation is a very common operation, where gl_FragCoord is the coordinate of the pixel, u_resolution is the dimension of the canvas, which can be normalized by resolution.

vec2 st = gl_FragCoord.xy / u_resolution;

Final code:

#ifdef GL_ES
precision mediump float;
#endif

#define PI_2 6.2831853

uniform vec2 u_resolution;

// Draw the curve of the corresponding relationship between y and x
float plot(float y, float x) {
    return smoothstep(x - 0.01, x, y) - smoothstep(x, x + 0.01, y);
}

void main() {
    vec2 st = gl_FragCoord.xy / u_resolution;
    float f = sin(st.x * PI_2) / 2.0 + 0.5;
    vec4 color = vec4(f);
    float p = plot(st.y, f);
    color = (1.0 - p) * color + p * vec4(0.0, 1.0, 0.0, 1.0);
    gl_FragColor = color;
}

The final results are as follows:

Carefully observe the color change from left to right and the height change of the curve. It is not difficult to find that the larger the function value, the whiter the color, that is, the closer to the white rgba (1.0, 1.0, 1.0, 1.0); The smaller the function value, the darker the color, that is, the closer it is to the black rgba (0.0, 0.0, 0.0, 0.0).

It's very easy to understand, color GL_ Each component of fragcolor is constructed according to the value of the function.

Shape of 0x02 sin

After saying the color, you might as well observe the curve change of sin. Is it very like a mountain with ups and downs? With a little modification of the above code, you can get several continuous green hills.

#ifdef GL_ES
precision mediump float;
#endif

#define PI_2 6.2831853

uniform vec2 u_resolution;
uniform float u_time;

void main() {
    vec2 st = gl_FragCoord.xy / u_resolution;
    // st.x += u_time / 2.0;
    float f = sin(st.x * PI_2 * 2.0) / 8.0 + 0.2;
    float p = 1.0 - smoothstep(f, f + 0.01, st.y);
    vec4 color = p * vec4(0.0, 1.0, 0.0, 1.0);
    // color = p * vec4(0.1, 0.3, 0.4, 1.0);
    gl_FragColor = color;
}

Several abstract green hills, although they look a little rough:

You can also cancel the comments in the above code and use U_ The time value gives the picture a little dynamic effect, so that several green hills turn into fluctuating waves.

0x04 understanding practice

This article only discusses the most basic sin function, but it is not difficult to see that sin is a powerful modeling tool. Combined with two other tools: fragment and dot, we can also use sin to draw a simple noise map.

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;

float random(vec2 st) {
    return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    float rnd = random(st);
    gl_FragColor = vec4(vec3(rnd),1.0);
}

Noise is widely used in graphics, for example, to simulate some irregular dynamic surfaces: flame, cloud, rock and so on.

In Shader, we need to deal with various function models all the time. It is the various modeling capabilities of these functions and the organic combination between them that realize a variety of Shader effects.

The ability to use these functions correctly is the basic skill of Shader. It is important to understand and practice how to use these functions.

Tags: Shader

Posted by scallywag05 on Tue, 17 May 2022 05:37:28 +0300