Shadertoy_ Basic introduction

Posted by frog on Sun, 23 Jan 2022 15:38:03 +0100

Official website: https://www.shadertoy.com/

1, Basic variable

uniform vec3      iResolution;   	 // Window resolution, in pixels
uniform float     iTime;        	 // The running time of the program, in seconds
uniform float     iTimeDelta;   	 // Rendering time in seconds
uniform int       iFrame;       	 // Frame rate
uniform float     iChannelTime[4];       // Channel playback time (seconds)
uniform vec3      iChannelResolution[4]; // Channel resolution (pixels)
uniform vec4      iMouse;        	 // Mouse position
uniform samplerXX iChannel0..3;          // Input channel XX = 2D/Cube
uniform vec4      iDate;          // Date (year, month, day, hour)
uniform float     iSampleRate;    // Sound sampling rate (i.e., 44100)
void mainImage(){}				  //main function

Example:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Map pixel positions to 0-1
    vec2 uv = fragCoord.xy/iResolution.xy;
    
    // Gets the pixel color of the channel 0 texture in uv
    fragColor = texture(iChannel0, uv);
    
    // Let the value of the red component change over time.
    fragColor.r = abs(sin(iTime));
}

First, let's explain in detail:
This is the main function of ShaderToy, with one in and one out parameters. The input pixel coordinate vector and the output pixel color vector. The main function is to calculate the pixel color vector according to the pixel coordinates on the screen, and simply complete the transformation or mapping from pixel coordinates to color. If the screen resolution is 800 by 600, all pixels in the 800 by 600 area are calculated. Each pixel coordinate of ShaderToy's current window is processed by this main function to determine its color, so it seems that this main program is a piece of code, but it is logically embedded in a large cycle of pixel coordinates:
UV is normalized here, UV x, uv. The values of Y are all 0 ~ 1;

When we have no texture defined in channel 0, we can see:

When we add texture material to channel 0, we can see:

2, Circle drawing

2.1 1 / 4 circle drawing

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    
    float d = length(uv);
    float c = d;
    
    fragColor = vec4(vec3(c), 1.0);
}

The length function is to find the module of the vector, that is, sqrt ((u v. X) 2 + (U v. y) 2). In fact, this is the prototype of the spatial symbolic distance Function SDF. This formula can be understood as the distance from the vector to the origin vector vec3(0,0,0); In addition, the value type of each component in the vector is generally float type, so the decimal point should be added when assigning value.

vec3 ©: Just give a value C, which means that x, y and Z of this vector are all C, that is, vec3(c,c,c).

fragColor = vec4(vec3( c ), 1.0); , This line returns a 4-dimensional vector consisting of four elements r g b a. Have a little intuitive perception of basic colors, such as vec4 (1,1,1,1.) Is white; vec4(0.,0.,0.,1.) It's black.

As can be seen from the figure, the color mapped from the screen pixel coordinate origin vec2(0,0) is black. It gradually fades to the right and upward, and white is outside the 1 / 4 ellipse. The color of the screen is white and black, as well as the transition color between them, which is determined by the same values of the three elements of the returned vector rgb.

2.2 base point translation

We can move the dot to the center of the screen by changing the value range of uv.

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    float d = length(uv);
    float c = d;
    
    fragColor = vec4(vec3(c), 1.0);
}

2.3 sharpening rounding

We shifted the origin of uv to the center. Now we can divide the color of the screen into black and white according to the specific uv coordinates and origin:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    float d = length(uv);
    float c = d;
    //sharpening 
    if(d < .3) c=1.; else c = 0.;
    
    fragColor = vec4(vec3(c), 1.0);
}


As can be seen from the figure, because the picture is not square, we draw an ellipse. Below, we adjust the scale in the x direction to make the ellipse round:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    //Adjust x-direction scale
    uv.x *= iResolution.x/iResolution.y;
    float d = length(uv);
    float c = d;
    //sharpening 
    if(d < .3) c=1.; else c = 0.;
    
    fragColor = vec4(vec3(c), 1.0);
}

2.4 edge blur

From the above figure, we can see that the edge of the circle is slightly jagged and not smooth. It is necessary to introduce the smoothing function smoothstep: understand that float d = length(uv), This can be understood as the length of the uv vector, which can be regarded as the distance to the origin. In the current case, the origin is the center of the white circle, and the distance function D is the distance from the center. Therefore, we can define a variable r to represent the radius:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    //Adjust x-direction scale
    uv.x *= iResolution.x/iResolution.y;
    float d = length(uv);
    float c = d;
    //vague
    float r = .3;
    c = smoothstep(r, r-0.02, d);
    
    fragColor = vec4(vec3(c), 1.0);
}

Circular packaging method:

//Circle drawing
float Circle(vec2 uv, vec2 p, float r, float blur) {
    float d = length(uv-p);
    float c = smoothstep(r, r-blur, d); 
    return c;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    //Adjust x-direction scale
    uv.x *= iResolution.x/iResolution.y;
 
    vec2 p = vec2(0., 0.);
    float c = Circle(uv, p, .4, .05);
    
    fragColor = vec4(vec3(c), 1.0);
}

3, Rectangle drawing

We can mainly use smoothstep to divide the two directions of uv to form a rectangular area:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    //Adjust x-direction scale
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    
    float mask=smoothstep(-.2,.2,uv.x);
    
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}

From the operation, we can see that the filter band is from - 0.2 to 0.2, which is divided into two colors on both sides;

Next, we can encapsulate this part. The available parameters are uv variable, start position, end position and blur size:

float Band(float t,float start,float end,float blur)
{
    float stepL =smoothstep(start-blur,start+blur,t);
    float stepR =smoothstep(end+blur,end-blur,t);
    return stepL*stepR;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    //Adjust x-direction scale
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    
    float mask=Band(uv.x,-.2,.2,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}

The following effects can be seen during operation:

Next, we process the v direction of uv and encapsulate it into a square method:

float Band(float t,float start,float end,float blur)
{
    float step1 =smoothstep(start-blur,start+blur,t);
    float step2 =smoothstep(end+blur,end-blur,t);
    return step1*step2;
}

float Rect(vec2 uv,float left,float right,float bottom,float top,float blur)
{
    float band1=Band(uv.x,left,right,blur);
    float band2=Band(uv.y,bottom,top,blur);
    return band1*band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    //Adjust x-direction scale
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    
    float mask=Rect(uv,-.2,.2,-.2,.2,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}



You can also try different parameters to achieve polygon effect:

4, Wavy line drawing

4.1 foundation drawing

First, we need to draw a rectangle, and then adjust the parameters in the previous part as follows (you can also adjust the UV scale):

Before completing the wave, let's first look at the equation to be used as follows:

Next, we reflect in the code:

float Band(float t,float start,float end,float blur)
{
    float step1 =smoothstep(start-blur,start+blur,t);
    float step2 =smoothstep(end+blur,end-blur,t);
    return step1*step2;
}

float Rect(vec2 uv,float left,float right,float bottom,float top,float blur)
{
    float band1=Band(uv.x,left,right,blur);
    float band2=Band(uv.y,bottom,top,blur);
    return band1*band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    //Adjust x-direction scale
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    float x=uv.x;
    float m=-(x-.5)*(x+.5);
    float y=uv.y+m;

    float mask=Rect(vec2(x,y),-.5,.5,-.05,.05,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}

After operation, it can be seen as follows:

Next, we can use more functions to express:

It is reflected in the code as follows:

float Band(float t,float start,float end,float blur)
{
    float step1 =smoothstep(start-blur,start+blur,t);
    float step2 =smoothstep(end+blur,end-blur,t);
    return step1*step2;
}

float Rect(vec2 uv,float left,float right,float bottom,float top,float blur)
{
    float band1=Band(uv.x,left,right,blur);
    float band2=Band(uv.y,bottom,top,blur);
    return band1*band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    //Adjust x-direction scale
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    float x=uv.x;
    float m=-(x-.5)*(x+.5);
    m=m*m*4.;
    float y=uv.y-m;

    float mask=Rect(vec2(x,y),-.5,.5,-.05,.05,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}


Operation visible:

We can also use sinusoidal functions for rectangles:

float Band(float t,float start,float end,float blur)
{
    float step1 =smoothstep(start-blur,start+blur,t);
    float step2 =smoothstep(end+blur,end-blur,t);
    return step1*step2;
}

float Rect(vec2 uv,float left,float right,float bottom,float top,float blur)
{
    float band1=Band(uv.x,left,right,blur);
    float band2=Band(uv.y,bottom,top,blur);
    return band1*band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    //Adjust x-direction scale
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    float x=uv.x;
    float m=sin(x*8.)*.2;
    float y=uv.y-m;

    float mask=Rect(vec2(x,y),-.5,.5,-.05,.05,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}

4.2 dynamic rendering

Next, we use a time variable on the sinusoidal function to achieve the dynamic effect:

float Band(float t,float start,float end,float blur)
{
    float step1 =smoothstep(start-blur,start+blur,t);
    float step2 =smoothstep(end+blur,end-blur,t);
    return step1*step2;
}

float Rect(vec2 uv,float left,float right,float bottom,float top,float blur)
{
    float band1=Band(uv.x,left,right,blur);
    float band2=Band(uv.y,bottom,top,blur);
    return band1*band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// Map pixel positions to 0-1
    vec2 uv = fragCoord/iResolution.xy;
    // Base point translation
    uv-=0.5;
    //Adjust x-direction scale
    uv.x *= iResolution.x/iResolution.y;
 
    float t=iTime;
    
    vec3 color=vec3(0.);
    float x=uv.x;
    float m=sin(t+x*8.)*.2;
    float y=uv.y-m;

    float mask=Rect(vec2(x,y),-.5,.5,-.05,.05,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}