I'm slightly confused on how to create a simple noise function in a fragment shader if all fragment coordinates are integer therefore unable to interpolate between randomly generated values. What am I missing here? Any hint would be appreciated.
1 Answer
Perhaps this will be helpful:
Typically when I think of noise in computer graphics I also think in terms of a grid, usually the grid is 2D or 3D. (the rest of this post refers to 2D noise)
So given a 2D grid, each coordinate in the grid will have an (x,y) position. Usually the origin is (0,0) and the grid extends out in both the positive and negative directions to some limit. The limit is important because of numerical accuracy.
We can chose to use the screen coordinates as that grid, so it would have a range of something like (0,0)...(1024,768). Given an (x,y) position on that grid a noise function will always return the same value. And there are many algorithms out there to generate different kinds of noise. So long as a given noise function always returns the same value for a given input, then all will work out nicely. The code can even compute values for (x,y) locations that are not whole integer offsets in the grid using offsets, like (x,y)+(0.25,-0.25). Then take the average of those values for the fragment.
Returning the same value for a given (x,y) screen position is useful when generating new noise algorithms or tweaking an existing algorithm to get a particular pattern, beyond that it isn't that interesting.
The next alternative is to make the screen coordinates a sliding window over a larger grid. This is done by adding the current (x,y) offset for the grid to every fragment like (x,y)+(183,251). This essentially changes the origin to (183,251). And by incrementing the x and/or y coordinates of (183,251) we can slide the grid around to see different areas of the noise. Still not terribly interesting.
But how to visualize that grid as something like a height map of mountains or hills?
The trick here is to keep the idea of the grid but change how it is visualized. There are multiple ways to accomplish this, many of the shader toy examples use some form of ray tracing.
The first step to set up ray tracing is to define a camera. Usually the camera has a position and a direction. The camera position gives the current location within the noise grid, and the camera direction defines where the camera is looking.
Using the camera position, its direction, and the fragment (x,y) coordinate of the screen it is fairly easy to find a direction for a unique vector that passes through that screen coordinate, in the direction of the camera. That vector is called a ray, and it is usually normalized to make it easier to work with.
Now it is just a matter of figuring out where that ray intersects the noise grid. This is done just by stepping the ray forward from the camera position. Usually the steps are done using a fixed increment like 1.0. At each step figure out that rays (x,y) position on the noise grid, then compute the noise value for that position. The noise value is then directly used to compute a "height" at that point, and the rays position is compared with the computed height to determine if the ray is hitting, above, or below the terrain. If the ray is "above" the terrain then it is considered a miss, the ray is marched forward another step and tested again. This is done out to some limit, if nothing is hit, then a standard value like sky blue is returned. A ray that is below the terrain is usually considered a hit, but can be refined until a more accurate hit is determined. If the ray steps are to big, small terrain details can be missed, if the ray steps are to small, then algorithm will run to slowly to produce anything in real time.
This is referred to as "ray marching" since the ray is "marched" forward. But the noise, and how it is visualized is the heart of the algorithm. Coders can even use the computed noise value, along with a position for a light source to compute shading for a ray hit.
Additional rays can be sent out at small offsets from the original fragment coordinate then all the values averaged together. Atmospherics can be computed using 3D noise, and clouds can be added. The terrain height combined with another noise can be used to compute vegetation, snow, and rock colors.
When all these techniques are combined, the results can be stunning, and noise, combined with the fragment coords are what make it all tick.
Anyway, hopefully that gives a little insight into how fragment coordinates are used with noise algorithms to compute interesting scenes.
vec2
, which is floating-point. $\endgroup$