当前位置:网站首页>Opengl/webgl shader development getting started guide

Opengl/webgl shader development getting started guide

2022-07-08 02:15:00 Brain in new VAT

Learning to write graphics shaders is learning to use GPU The power of , Its thousands of cores all run in parallel . This is a kind of programming that requires different ways of thinking , But its huge potential is worth the initial investment .

Almost every modern graphic simulation you see is done in some way GPU Written code provides support , From the tip AAA Realistic lighting effect in the game to 2D Post treatment effect and fluid simulation .
 Insert picture description here

Minecraft A scene in , Before and after applying some shaders .

1、 The purpose of this guide

Shader programming sometimes becomes a mysterious dark magic , And often misunderstood . There are many code examples that show you how to create incredible effects , But little or no explanation was provided . This guide aims to bridge this gap . I will pay more attention to the basics of writing and understanding shader code , So you can easily adjust 、 Compose or write your own code from scratch !

This is a general guide , So what you learn here will apply to anything that can run shaders .

2、 What is a shader ?

Shaders are just programs that run in the graphics pipeline and tell the computer how to render each pixel . These programs are called shaders , Because they are usually used to control lighting and shadows effect , But there is no reason why they cannot deal with other special effects .

Shaders are written in a special shading language . Never mind , You don't have to go out and learn a new language ; We will use GLSL(OpenGL Coloring language ), It's kind of like C Language . There are many coloring languages for different platforms , But because they are applicable in GPU Up operation , So they are very similar .

Be careful : This article focuses on fragment shaders . If you are curious about other types of shaders , Can be in OpenGL Wiki Read about the phases in the graphics pipeline on .

3、 Let's get started !

We will use... In this tutorial ShaderToy. This allows you to start programming the colorator directly in the browser , Without any setup !ShaderToy Use WebGL Rendering , So you need a browser that can support this function . Creating an account is optional , But it's very convenient for saving code .

Be careful : At the time of writing ,ShaderToy In the testing phase . Some small ones UI/ Grammatical details may vary slightly .

single click New Shader after , You should see the following :

 Insert picture description here

If you are not logged in , Your interface may be slightly different .
The small black arrow at the bottom is where you click to compile the code .

4、 What happened? ?

I will explain how shaders work in one sentence . are you ready ? Start !

The only purpose of the shader is to return four numbers :r、g、b and a.

This is what it has done or can do . The function you see in front of you runs for each pixel on the screen . It returns these four color values , This becomes the color of the pixel . This is the so-called pixel shader ( Sometimes called Fragment Shader ).

Consider this , Let's try to turn the screen into pure red .rgba( Red 、 green 、 Blue and “alpha”, Define transparency ) Value from 0 To 1, So what we need to do is return r,g,b,a = 1,0,0,1.ShaderToy Expect the final pixel color to be stored in fragColor.

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    fragColor = vec4(1.0,0.0,0.0,1.0);
}

Congratulations ! This is your first working shader !

Challenge : Can you change it to pure gray ?

vec4 Just a data type , So we can declare colors as variables , As shown below :

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec4 solidRed = vec4(1.0,0.0,0.0,1.0);
    fragColor = solidRed;
}

however , This is not very exciting . We have the ability to run code in parallel on hundreds of thousands of pixels , And we set them all to the same color .

Let's try to render a gradient on the screen . ok , If you don't know something about the pixels we are affecting , For example, its position on the screen , There is nothing we can do …

5、 Shader input

Pixel shaders pass some variables For your use . The most useful thing for us is fragCoord, It saves pixels x and y( as well as z, If you are in the 3D Work in China ) coordinate . Let's try to turn all pixels on the left half of the screen black , Turn all pixels on the right half red :

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 xy = fragCoord.xy; //We obtain our coordinates for the current pixel
    vec4 solidRed = vec4(0,0.0,0.0,1.0);//This is actually black right now
    if(xy.x > 300.0){//Arbitrary number, we don't know how big our screen is!
        solidRed.r = 1.0;//Set its red component to 1.0
    }
    fragColor = solidRed;
}

Be careful : For any , You can go through 、 And or through obj.x、obj.y、obj.z、obj.w or obj.r 、obj.g 、obj.b 、obj.a visit vec4 Its components . They are equivalent ; This is just a convenient way of naming , To make your code more readable , So that others can see obj.r when , They will understand obj Represents a color .

Do you see the problem in the code above ? Try clicking the full screen button in the lower right corner of the preview window .

The ratio of the red screen will vary according to the size of the screen . To make sure half of the screen is red , We need to know how big the screen is . Screen size is not a built-in variable like pixel position , Because it is usually set up by the programmer who builds the application . under these circumstances , Setting the screen size is ShaderToy Developer .

If something is not a built-in variable , You can transfer this information from CPU( Your main program ) Send to GPU( Your shader ).ShaderToy Dealt with this problem for us . You can Shader Inputs Tab to see all the variables passed to the shader . In this way from CPU Pass on to GPU The variables in the GLSL called Uniform.

 Insert picture description here

Let's adjust the code above to get the center of the screen correctly . We need to use shader input iResolution:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 xy = fragCoord.xy; //We obtain our coordinates for the current pixel
    xy.x = xy.x / iResolution.x; //We divide the coordinates by the screen size
    xy.y = xy.y / iResolution.y;
    // Now x is 0 for the leftmost pixel, and 1 for the rightmost pixel
    vec4 solidRed = vec4(0,0.0,0.0,1.0); //This is actually black right now
    if(xy.x > 0.5){
        solidRed.r = 1.0; //Set its red component to 1.0
    }
    fragColor = solidRed;
}

If you try to enlarge the preview window this time , The color should still perfectly divide the screen in two .

6、 From split to gradient

It should be easy to turn it into a gradient . Our color values range from 0 To 1, Coordinates are also from 0 To 1.

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 xy = fragCoord.xy; //We obtain our coordinates for the current pixel
    xy.x = xy.x / iResolution.x; //We divide the coordinates by the screen size
    xy.y = xy.y / iResolution.y;
    // Now x is 0 for the leftmost pixel, and 1 for the rightmost pixel
    vec4 solidRed = vec4(0,0.0,0.0,1.0); //This is actually black right now
     solidRed.r = xy.x; //Set its red component to the normalized x value
    fragColor = solidRed;
}

look !

Challenge : Can you turn it into a vertical gradient ? The diagonal ? Gradient with multiple colors ?

If you play enough , You can see that there are coordinates in the upper left corner (0,1), instead of (0,0). It's important to remember that .

7、 The plot

It's fun to play with colors , But if we want to do something impressive , Our shader must be able to take input from the image and change it . In this way , We can make a shader that affects the whole game screen ( For example, underwater fluid effect or color correction ), Or only some objects are affected in some way according to the input ( For example, realistic lighting system ).

If we program on a common platform , You need to put the image ( Or texture ) As Uniform Send to GPU, Just like sending screen resolution .ShaderToy Solved this problem for us . There are four input channels at the bottom :

 Insert picture description here

ShaderToy Four input channels of
single click iChannel0 And choose any texture you like ( Images ).

After completion , You now have an image being passed to the shader . however , There is a question : No, DrawImage() function . please remember , The only thing a pixel shader can do is change the color of each pixel .

So if we can only return one color , How do we paint textures on the screen ? We need to map the current pixel of the shader to the corresponding pixel on the texture in some way :
 Insert picture description here

according to (0,0) Position on the screen , You may need to flip y Axis to map the texture correctly . At the time of writing ,ShaderToy Updated , Its origin is at the upper left , So there is no need to flip anything .

We can do that by using texture(textureData,coordinates) Function to do this , This function combines texture data with (x, y) Coordinate pairs as input , And take the texture color at these coordinates as a return vec4.

You can match the coordinates to the screen in any way you like . You can paint the entire texture on a quarter of the screen ( By skipping pixels , Effectively shrink it ) Or paint only part of the texture .

Because we just want to view the image , So we will match pixels 1:1:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 xy = fragCoord.xy / iResolution.xy;//Condensing this into one line
    vec4 texColor = texture(iChannel0,xy);//Get the pixel at xy from iChannel0
    fragColor = texColor;//Set the screen pixel to that color
}

such , We have the first picture !

 Insert picture description here

Now we have extracted data from texture correctly , You can operate it at will ! You can stretch it and scale it , Or play with its color .

Let's try to modify it with a gradient , Similar to what we did above :

texColor.b = xy.x;

 Insert picture description here

Congratulations , You just made your first post-processing effect !

Challenge : Can you write a shader that turns an image into black and white ?

Please note that , Even if it is a still image , What you see in front of you also happens in real time . You can see it for yourself by replacing still images with videos : Click again iChannel0 Enter and select one of the videos .

8、 Add some actions

up to now , All our effects are static . By using ShaderToy Input provided to us , We can do more interesting things .iGlobalTime Is an increasing variable ; We can use it as a seed to make periodic effects . Let's try to play with colors :

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 xy = fragCoord.xy / iResolution.xy; // Condensing this into one line
    vec4 texColor = texture(iChannel0,xy); // Get the pixel at xy from iChannel0
       texColor.r *= abs(sin(iGlobalTime));
    texColor.g *= abs(cos(iGlobalTime));
    texColor.b *= abs(sin(iGlobalTime) * cos(iGlobalTime));
    fragColor = texColor; // Set the screen pixel to that color
}

GLSL Sine and cosine functions are built in , And many other useful functions , For example, get the length of a vector or the distance between two vectors . Color should not be negative , So we make sure to use abs Function to get the absolute value .

Challenge : You can make a shader , Change the image back and forth from black and white to full color ?

9、 Conclusion

Although you may be used to stepping through the code and printing out the values of everything to see what happened , But this is impossible when writing shaders . You may find some platform specific debugging tools , But usually the best way is to set the value being tested to the graph you can see .

These are just the basics of using shaders , But familiarity with these basics will enable you to do more . Browse ShaderToy Effect on , See if you can understand or copy some of these effects !

One thing I didn't mention in this tutorial is Vertex Shaders . They are still written in the same language , Except that they run on every vertex instead of every pixel , They return a position and a color . Vertex shaders are usually responsible for putting 3D The scene is projected onto the screen ( Something built into most graphics pipelines ). Pixel shaders are responsible for many of the advanced effects we see , This is why we pay attention .

The final challenge : Can you write a shader to remove ShaderToy The green screen in the previous video , And add another video as the background in the first video ?


Link to the original text : Novice guide to shader development — BimAnt

原网站

版权声明
本文为[Brain in new VAT]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/189/202207080037232511.html