Skip to content

Commit

Permalink
fix paths for tutorial images
Browse files Browse the repository at this point in the history
  • Loading branch information
jbritain committed Nov 29, 2024
1 parent 40ec4a1 commit dd37ffc
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 26 deletions.
2 changes: 1 addition & 1 deletion src/content/docs/guides/Your First Shader/1_composite.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ color.rgb = vec3(dot(color.rgb, vec3(1.0/3.0)));

Your screen should now look like this!

![](../../../../../assets/beginner_tutorial/monochrome.webp)
![](../../../../assets/beginner_tutorial/monochrome.webp)

:::tip[Next steps]
See if you can make the screen red, or green. Using `texcoord`, can you make one half green and the other half red?
Expand Down
6 changes: 3 additions & 3 deletions src/content/docs/guides/Your First Shader/2_gbuffers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ This now gets us the correct light level. You will notice now that if you reload
### `glcolor`
Some blocks, like grass, have a tint based on their biome, provided in the form of `gl_Color`. If you look in the files for the grass block texture, it is actually grey. To demonstrate this, let's set `glcolor` to `vec4(1.0)`. Since the color is multiplied by glcolor in the fragment shader, and multiplying by 1 does nothing, this will remove the tint.

![](../../../../../assets/beginner_tutorial/notint.webp)
![](../../../../assets/beginner_tutorial/notint.webp)

Let's undo that, since having color is quite nice.

Expand Down Expand Up @@ -99,7 +99,7 @@ With those values being passed through, let's move onto the fragment shader (`gb
### `gtexture`
This is the texture atlas we mentioned earlier. It contains the textures of all the blocks onscreen, and `texcoord` tells us where in the atlas the current fragment texture is.

![](../../../../../assets/beginner_tutorial/textureatlas.webp)
![](../../../../assets/beginner_tutorial/textureatlas.webp)
This is an example of what the texture atlas looks like, however it can vary.

### `lightmap`
Expand All @@ -125,7 +125,7 @@ To do this, we can just add a new line at the end of `main`:
```glsl
color.rgb = normal;
```
![](../../../../../assets/beginner_tutorial/normals.webp)
![](../../../../assets/beginner_tutorial/normals.webp)
You can see that faces that face upwards are green. Colors are stored in the `rgba` format and vectors/coordinates in the `xyzw` format. Since both of these are stored in the same `vec4` format, this means that the `r` component represents the `x` component, and so on. Since `g` represents `y`, this means that if the face is green, then the normal must only have a value in the `y` component, and hence is facing upwards.

You'll notice some faces are black, this is where the normals are negative - you cannot have a negative color!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ Next, let's verify everything is being decoded correctly.
```glsl
color.rgb = vec3(lightmap, 0.0);
```
![](../../../../../assets/beginner_tutorial/lightmap.webp)
![](../../../../assets/beginner_tutorial/lightmap.webp)

You can see that where there is skylight, only the green component is set. However, where there is blocklight (by the torch), the color is yellow. Since red and green make yellow in RGB, we know that blocklight is stored in the red component and sunlight is stored in the green component.

```glsl
color.rgb = normal;
```
![](../../../../../assets/beginner_tutorial/normals.webp)
![](../../../../assets/beginner_tutorial/normals.webp)
Yep, that looks pretty *normal*. You'll notice that the sky is black here. This is because the `gbuffers_terrain` program does not run for the sky, so no data is stored for these pixels. We will resolve this later on.

## Lighting
Expand Down Expand Up @@ -90,7 +90,7 @@ color.rgb *= blocklight + skylight + ambient + sunlight;
```

Things should look something like this:
![](../../../../../assets/beginner_tutorial/lighting1.webp)
![](../../../../assets/beginner_tutorial/lighting1.webp)

## Sunlight
Now, what about that sunlight? Well, if something is facing directly towards the sun, then we want it to be fully sunlit. On the other hand, if something is facing away from the sun, we want there to be no sunlight. So, we need a function that returns 1.0 if two vectors are facing in the same direction, and 0.0 if they are facing away from each other. Happily, we can use a dot product for this.
Expand Down Expand Up @@ -120,7 +120,7 @@ vec3 sunlight = sunlightColor * clamp(dot(worldLightVector, normal), 0.0, 1.0) *

With that change, your lighting should seem a bit more realistic.

![](../../../../../assets/beginner_tutorial/lighting2.webp)
![](../../../../assets/beginner_tutorial/lighting2.webp)

## Fixing the sky
At this point, it may appear as if your Minecraft world is currently undergoing an apocalypse. This is because we are also applying lighting to the sky, despite the fact we do not have normal or lightmap data for it. So, how do we tell if a pixel is the sky or not? Well, we have access to something called the depth buffer, which tells you how far away a pixel is. If the pixel is at the maximum view distance, the depth buffer will store 1.0.
Expand All @@ -139,4 +139,4 @@ The depth is not stored in a linear format. This means that while a pixel that i
:::

Having done that, your Minecraft world should hopefully have been saved from the apocalypse.
![](../../../../../assets/beginner_tutorial/fixedsky.webp)
![](../../../../assets/beginner_tutorial/fixedsky.webp)
26 changes: 13 additions & 13 deletions src/content/docs/guides/Your First Shader/4_shadows.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ color.rgb = texture(shadowtex0, texcoord).rgb;
```

You should see something like this:
![](../../../../../assets/beginner_tutorial/shadowmap.webp)
![](../../../../assets/beginner_tutorial/shadowmap.webp)

This may not make much sense to look at, but this shows how far away the nearest thing the sun can see is.

Expand Down Expand Up @@ -131,7 +131,7 @@ vec3 sunlight = sunlightColor * dot(normal, worldLightVector) * shadow;

You should now see something like this:

![](../../../../../assets/beginner_tutorial/acne.webp)
![](../../../../assets/beginner_tutorial/acne.webp)

Now, while you can tell that things are casting shadows, a lot of surfaces seem to be in shadow when they shouldn't be, with weird patterns. This is due to something called 'shadow acne', and it occurs when something ends up casting a shadow on itself due to the lack of precision in the shadow map. We can fix this by adding something known as 'shadow bias' where we offset surfaces slightly towards the sun to prevent them casting shadows on themselves:

Expand All @@ -145,7 +145,7 @@ vec3 shadowNDCPos = shadowClipPos.xyz / shadowClipPos.w;

Your shadows should now look a lot more reasonable.

![](../../../../../assets/beginner_tutorial/basicshadows.webp)
![](../../../../assets/beginner_tutorial/basicshadows.webp)

## Making Shadows Sharper
At the moment, our shadows are extremely blocky. This is due to the limited resolution of the shadow map. We can improve things somewhat by increasing this, using the [`shadowMapResolution`](/reference/constant/shadowmapresolution) const. This constant can be defined anywhere, but just because it's a nice place to put it, we'll go back to `shadow.fsh`. Let's add the following. It should be outside the `main` function - I put mine just before my `layout` qualifier declaration.
Expand All @@ -156,7 +156,7 @@ const int shadowMapResolution = 2048;

This makes things a little bit sharper, but they still don't look great.

![](../../../../../assets/beginner_tutorial/sharpershadows.webp)
![](../../../../assets/beginner_tutorial/sharpershadows.webp)

The easy solution here would be to just increase the shadow map resolution to some very big number like 8192 (it is convention to use a power of two for your shadow map size), but this will start taking up an awful lot of video memory, causing a performance impact. Instead, we can make use of something known as 'shadow distortion'. The idea is that since stuff that is closer to us is what we can see most clearly, we want to dedicate more of the shadow map resolution to this stuff, and less of it to things that are further away.

Expand Down Expand Up @@ -229,7 +229,7 @@ void main(){

At this point, let's write the shadow map to the screen again to check what it looks like now. We did this earlier on, so I'll not give you the code again.

![](../../../../../assets/beginner_tutorial/distortedshadowmap.webp)
![](../../../../assets/beginner_tutorial/distortedshadowmap.webp)

As expected, stuff in the middle of the shadow map has been expanded to take up more space!

Expand All @@ -248,7 +248,7 @@ vec3 shadowNDCPos = shadowClipPos.xyz / shadowClipPos.w;

Our shadows now look nice and sharp near the player!

![](../../../../../assets/beginner_tutorial/distortedshadows.webp)
![](../../../../assets/beginner_tutorial/distortedshadows.webp)

## Transparent Shadows
If you look at something like stained glass, you'll see that it casts a solid shadow. This doesn't really make sense, since (it being partially translucent) it should be letting some light through. Handily, there are a couple of extra shadowmaps we can access to help us with this.
Expand Down Expand Up @@ -309,14 +309,14 @@ with
vec3 shadow = getShadow(shadowScreenPos);
```

![](../../../../../assets/beginner_tutorial/transparentshadows.webp)
![](../../../../assets/beginner_tutorial/transparentshadows.webp)

and we now get nice colored shadows!

## Softer Shadows
The final piece of the puzzle is those nasty jagged edges on our shadows. This is called *aliasing*, and is another artifact of the limited resolution on our shadow map. If you look at real shadows, you'll also notice that they don't tend to have clean, sharp edges. Instead, they seem to have a slightly softer edge. This area at the edge of the shadow is known as the *penumbra*.

![](../../../../../assets/beginner_tutorial/penumbra.webp)
![](../../../../assets/beginner_tutorial/penumbra.webp)
[Image Source: Wikipedia](https://commons.wikimedia.org/w/index.php?curid=3675853)

What this means is that we can blur our shadows slightly, and not only will it remove the aliasing, it will also make them more physically plausible.
Expand All @@ -331,7 +331,7 @@ const bool shadowcolor0Nearest = true;

This will remove the curved edges on the shadows, making them even more jagged, but it's necessary for us to be able to correctly blur them, and also resolves some artifacts on transparent shadows you may have noticed.

![](../../../../../assets/beginner_tutorial/jaggedshadows.webp)
![](../../../../assets/beginner_tutorial/jaggedshadows.webp)

To blur our shadows, we are going to be using something known as *percentage closer filtering*. To do this, we take multiple shadow samples within an area around the position and average them. To do this, we will be using a loop. Within this loop, we will generate an offset from the shadow position, apply it in clip space, and then convert to screen space before our shadow samples.

Expand Down Expand Up @@ -390,11 +390,11 @@ vec3 shadow = getSoftShadow(shadowClipPos);
[...]
```

![](../../../../../assets/beginner_tutorial/softshadows.webp)
![](../../../../assets/beginner_tutorial/softshadows.webp)

Our shadows now have soft edges, and the aliasing artifacts are no longer visible. However, they still look a little bit pixelated. This is for two reasons. The first one is that we are using a box kernel, which means that we are sampling evenly within a square box. Ideally, a circular kernel would be used, however implementing this is left as an exercise to the reader. The second, more important reason is that we are sampling the exact same points for every pixel on screen. We can resolve this issue by randomly rotating the area we sample within for each frame. We can get a random rotation using another texture, [`noisetex`](/reference/buffers/noisetex/). Let's write `noisetex` to the screen. I'm once again leaving this up to you to do, because we've written a fair few textures to the screen at this point. Like every other texture, `noisetex` is declared with a `uniform sampler2D noisetex;`.

![](../../../../../assets/beginner_tutorial/lownoise.webp)
![](../../../../assets/beginner_tutorial/lownoise.webp)

You'll see the pixels in `noisetex` are pretty chunky. This is because it has a resolution of 64x64, and is being stretched to fit the screen. We could just increase the resolution, but to ensure we're getting a unique value for every pixel, we'll instead use a function called `texelFetch`. `texelFetch` takes in an exact pixel coordinate in a texture and returns the value there without doing any filtering. We will need to convert our `texcoord` to a pixel coordinate within the range (0-64). We can do this using another couple of uniforms, [`viewWidth`](/reference/uniforms/system#viewwidth) and [`viewHeight`](/reference/uniforms/system#viewheight) (both `float`s). We will also make use of the type `ivec2` which is like a `vec2` except it can store only integer values. Let's make another new function called `getNoise`. It will take in a vec2 texcoord and return a vec4, the lookup value from `noisetex`. We're going to access it in `getSoftShadow` so it should be placed before this function.

Expand All @@ -410,7 +410,7 @@ vec4 getNoise(vec2 coord){
`64` is the default resolution of `noisetex`. Since this value can be configured with [`noiseTextureResolution`](/reference/constants/noisetextureresolution/), if you ever change this value, you should replace the use of `64` with the uniform.
:::

![](../../../../../assets/beginner_tutorial/highnoise.webp)
![](../../../../assets/beginner_tutorial/highnoise.webp)

While the image clearly repeats, we now have unique values per pixel for the noise. We can then modify our `softShadow` function to take this into account.

Expand Down Expand Up @@ -447,6 +447,6 @@ vec3 getSoftShadow(vec4 shadowClipPos){
}
```

![](../../../../../assets/beginner_tutorial/softershadows.webp)
![](../../../../assets/beginner_tutorial/softershadows.webp)

Our shadows no longer have any visible pixels!
6 changes: 3 additions & 3 deletions src/content/docs/guides/Your First Shader/5_fog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ color.rgb = mix(color.rgb, fogColor, length(viewPos)/far);
This works because we are still using the vanilla sky. If you go on to add a custom sky, you will likely want to choose your own fog color.
:::

![](../../../../../assets/beginner_tutorial/linearfog.webp)
![](../../../../assets/beginner_tutorial/linearfog.webp)

And our terrain now nicely blends into the horizon.

Expand All @@ -87,7 +87,7 @@ This use of an exponential function for the falloff is based on a real physical

We can visualise this by plotting `f` against `distance` on a graph.

![](../../../../../assets/beginner_tutorial/foggraph.webp)
![](../../../../assets/beginner_tutorial/foggraph.webp)

As you can see, the function curves nicely to make the fog seem further away.

Expand All @@ -109,6 +109,6 @@ color.rgb = mix(color.rgb, fogColor, clamp(fogFactor, 0.0, 1.0));
Note that we clamp the value of `fogFactor` between `0` and `1`. This is because the behaviour of `mix` is undefined if it is outside this range. Since the render distance in blocks is along three axes, blocks can be more than this distance away along the diagonals, so in some cases, `dist` could be more than `1`.
:::

![](../../../../../assets/beginner_tutorial/exponentialfog.webp)
![](../../../../assets/beginner_tutorial/exponentialfog.webp)

And now our fog feels a lot more natural!
2 changes: 1 addition & 1 deletion src/content/docs/guides/Your First Shader/6_next_steps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ This is as far as we go with the tutorial, but there's plenty more that can be d

## Issues to Fix
### Transparent Entities
![](../../../../../assets/beginner_tutorial/transparententities.webp)
![](../../../../assets/beginner_tutorial/transparententities.webp)
Right now, our entities seem semitranslucent. This is because we have only written a `gbuffers_terrain` program. Entities are handled by `gbuffers_entities`, which falls back to `gbuffers_textured_lit`. Since we have not overriden this program, it doesn't write our normals or lightmap data to the buffers we need it to. An easy way to resolve this is to rename `gbuffers_terrain` to `gbuffers_textured_lit`, which most programs we care about will fall back to. For more information, see [Gbuffers](http://localhost:4321/reference/programs/gbuffers/).

### Bright Night
Expand Down

0 comments on commit dd37ffc

Please sign in to comment.