To be first

Today I see the sky high and crisp, a hundred miles without clouds, great joy. Everyday things to ShaderToy for fun, with LeetCode. Although often into its heard, but never know its so also. Friends say, how can you be so confused and energetic? The fun is not popular, answer it.

ShaderToy – a ShaderToy

As a “giant” who often dives in ShaderToy, I can’t help but wonder how wonderful the world of graphics is when I see the works of all the giant guys in the community. There’s nothing you can’t imagine, nothing they can’t handle. In particular, with all of the above effects, you can imagine that you can achieve amazing results without using models, just using pure mathematics. For the obsession of me, is completely unable to extricate themselves. In order to get more people into the pit, I decided to share some of the shader functions THAT I play regularly, along with the post-processing effects. Let more friends for graphics community vitality to add a little spray.

The preparatory work

I hope you know enough about the basics of WebGL, the grammar basics of GLSL, and the mildewy high school math to wipe it off with dishwashing liquid. Play the game when the dish is clean. You can browse at WebGL Basics.

The show of the titans

Ray tracing

Cyberpunk

Pattern noise

The official start of the

The concept of directed distance field SDF

For some basic shapes, such as circles, rectangles, spacers, or the combination of relatively complex geometric surface graphics. In fact, they are essentially SDF or the realization of the distance field, and here, we are mainly talking about the plane 2D distance field. Therefore, half of our modeling function has and only has the calculation of the component of one dimension. As for the transformation involving higher dimensions, it may be the transition transformation from high dimensions to two dimensions.

Basic graphics

Derivation of rectangle

If a basketball court is 100 meters by 100 meters, and there is a 30 * 30 square area, starting at (10,10), we can simply think of it as the following legend.

If you are any pixel in this region, how can you tell if you are in the middle of this white region? For those of us who are smart, let’s assume that the coordinates of any point are P=(x,y), P=(x,y), and the whole region is MMM. If we define the white region, we can understand the following

For any ∀ P (x, y) ∈ M \ forall P (x, y) \ M ∀ in P (x, y) ∈ M, 10 < = x < = 40 studying < = y < < = = 40 10 x < = 40 \ cap 10 < = y < = 4010 < < = = x 40 studying 10 < = y < = 40

That seems to be all right, so let’s convert 10 down, and we have this code and this effect.

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv =  fragCoord/iResolution.xy;
    uv.x /= iResolution.y/iResolution.x;
    uv.y = 1. -uv.y;
    
    
    if(uv.x >= 0.1 && uv.y >= 0.1 && uv.x <= 0.4 && uv.y <= 0.4){
        fragColor = vec4(1..1..1..1.);
    }else{
         fragColor = vec4(0..0..0..1.0);
    }

    // Output to screen
   
}
Copy the code

But from the GPU’s point of view, this code can still be optimized. Because GPU is not good at logical judgment operation. Let’s see if we can do this without judgment? The answer, of course, is yes. Here we introduce the first styling function of GLSLstep

Step () function

Definition of the step() function, which returns 0.0 if x < edge, and 1.0 otherwise

GenType step (genType edge, genType x), genType step (float edge, genType x)

We use the first overloaded function to define the left edge

float left = step(0.1,uv.x);
Copy the code

Define the right edge

float right = step(uv.x,0.4);
Copy the code

Define the top boundary

float top = step(0.1,uv.y);
Copy the code

Define the boundary of the base

float bottom = step(uv.y,0.4);
Copy the code

And then put it together

float pixelValue = top + right + left + bottom;
```glsl
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv =  fragCoord/iResolution.xy;
    uv.x /= iResolution.y/iResolution.x;
    uv.y = 1. -uv.y;
    
    float left = step(0.1,uv.x);
    float right = step(uv.x,0.4);
    float top = step(0.1,uv.y);
    float bottom = step(uv.y,0.4);
    float pixelValue = top * right * left * bottom;
    fragColor = vec4(vec3(pixelValue),1.0);

    // Output to screen
   
}
Copy the code

Of course, that’s okay, too.

Circular derivation idea

In the same way, we already knew in high school that the analytic formula for a circle (x2+y2)= R2 (x^2 +y ^2) =r ^2 (x2+y2)= R2, so we could just write this code

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv =  fragCoord/iResolution.xy;
    uv.x /= iResolution.y/iResolution.x;
    uv.y = 1. -uv.y;
    
      // Center (0.4, 0.4)
      uv -= vec2(40.);
      if(uv.x * uv.x + uv.y * uv.y <= .05){
      
          fragColor = vec4(vec3(1.),1.0);
      }else{
          fragColor = vec4(vec3(0.),1.0);
      }
    
    // Output to screen
   
}
Copy the code

Maybe you’ve seen if, and we think about circles in terms of distance fields, and you’ll see that any point that is less than or equal to the radius from the center of the circle is inside the circle.

Short () function

float distance (genType p0, genType p1)

Calculate the distance between the vectors P0 and P1

GLSL has a built-in distance() function to help us solve these kinds of problems, so here’s the code

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv =  fragCoord/iResolution.xy;
    uv.x /= iResolution.y/iResolution.x;
    uv.y = 1. -uv.y;
    
      
 
     
     // Center of the circle (0.3, 0.3) r = 0.2
     float result = step(distance(uv,vec2(3..3.)),2.);
          fragColor = vec4(vec3(result ),1.0);

    
    // Output to screen
   
}
Copy the code

Combination of encapsulation

If we wrap the above rectangle and circle code into a function, we can combine some graphics to display

float Circle(vec2 uv,vec2 center,float r){
  float result = step(distance(uv,center),r);
  return result;     
}
float Rect(vec2 uv,vec2 startPoint, float w,float h){
    float left = step(startPoint.x,uv.x);
    float right = step(uv.x,startPoint.x + w);
    float top = step(startPoint.y ,uv.y);
    float bottom = step(uv.y,startPoint.y + h);
    float pixelValue = top * right * left * bottom;
    return pixelValue;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv =  fragCoord/iResolution.xy;
    uv.x /= iResolution.y/iResolution.x;
    uv.y = 1. -uv.y;
    
    float circleA = Circle(uv,vec2(2..2.),1.);
    float circleB = Circle(uv,vec2(7... 5),2.);
    float circleC = Circle(uv,vec2(2... 5),.05);
    
    float rectA = Rect(uv,vec2(2..2.),2..0.2);
    float rectB = Rect(uv,vec2(31... 5),1..0.2);
    float rectC = Rect(uv,vec2(2... 5),1..0.2);
    
    float result = circleA + circleB + circleC;
    
    result += rectA + rectB + rectC;
    
    fragColor = vec4(vec3(result),1.0);
    
    
    // Output to screen
   
}
Copy the code

Color mask

We finally added a color mask directly based on the UV coordinates as the color value

    fragColor = vec4(vec3(result)* vec3(uv,1.0),1.0);
Copy the code

Add the shadertoy built-in time variable

 fragColor = vec4(vec3(result)*cos(iTime+uv.xyx+vec3(0.2.4)),1.0);
Copy the code

Perfect ~ ~

To Be Continued

Today’s share is over here, the next issue we introduce some more fun modeling functions and modeling methods