You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: articles/tutorials/advanced/2d_shaders/08_light_effect/index.md
+73-14Lines changed: 73 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,7 +20,7 @@ In the earlier days of computer graphics, forward rendering was ubiquitous. Imag
20
20
21
21
In the 2000's, the deferred rendering strategy was [introduced](https://sites.google.com/site/richgel99/the-early-history-of-deferred-shading-and-lighting) and popularized by games like [S.T.A.L.K.E.R](https://developer.nvidia.com/gpugems/gpugems2/part-ii-shading-lighting-and-shadows/chapter-9-deferred-shading-stalker). In deferred rendering, each object is drawn _once_ without _any_ lights to an off-screen texture. Then, each light is drawn on top of the off-screen texture. To make that possible, the initial rendering pass draws extra data about the scene into additional off-screen textures. Theoretically, a deferred renderer can handle more lights and objects because the work is roughly approximate to the sprites (`S`) _added_ to the lights (`L`), or `S + L`.
22
22
23
-
Deferred rendering was popular for several years. MonoGame is an adaptation of XNA, which came out in the era of deferred rendering. However, deferred renderers are not a silver bullet for performance and graphics programming. The crux of a deferred renderer is to bake data into off-screen textures, and as monitor resolutions have gotten larger and larger, the 4k resolutions making off-screen texture more expensive than before. Also, deferred renderers cannot handle transparent materials. Many big game projects use deferred rendering for _most_ of the scene, and a forward renderer for the final transparent components of the scene. As with all things, which type of rendering to use is a nuanced decision. There are new types of forward rendering strategies (see, [clustered rendering](https://github.com/DaveH355/clustered-shading), or [forward++](https://www.gdcvault.com/play/1017627/Advanced-Visual-Effects-with-DirectX) rendering) that can out perform deferred renderers. However, for our use cases, the deferred rendering technique is sufficient.
23
+
Deferred rendering was popular for several years. MonoGame is an adaptation of XNA, which came out in the era of deferred rendering. However, deferred renderers are not a silver bullet for performance and graphics programming. The crux of a deferred renderer is to bake data into off-screen textures, and as monitor resolutions have gotten larger and larger, the 4k resolutions makimakeng off-screen texture more expensive than before. Also, deferred renderers cannot handle transparent materials. Many big game projects use deferred rendering for _most_ of the scene, and a forward renderer for the final transparent components of the scene. As with all things, which type of rendering to use is a nuanced decision. There are new types of forward rendering strategies (see, [clustered rendering](https://github.com/DaveH355/clustered-shading), or [forward++](https://www.gdcvault.com/play/1017627/Advanced-Visual-Effects-with-DirectX) rendering) that can out perform deferred renderers. However, for our use cases, the deferred rendering technique is sufficient.
24
24
25
25
If you are following along with code, here is the code from the end of the [previous chapter](https://github.com/MonoGame/MonoGame.Samples/tree/3.8.4/Tutorials/2dShaders/src/07-Sprite-Vertex-Effect).
26
26
@@ -30,10 +30,15 @@ Writing a simple deferred renderer can be worked out in a few steps,
30
30
31
31
1. take the scene as we are drawing it currently, and store it in an off-screen texture. This texture is often called the diffuse texture, or color texture.
32
32
2. render the scene again, but instead of drawing the sprites normally, draw their _Normal_ maps to an off-screen texture, called the normal texture.
33
-
3. create a new off-screen texture, called the light texture, where each light is layered on-top of each other,
33
+
3. create yet another off-screen texture, called the light texture, where lights are layered ontop of each other using the normal texture,
34
34
4. finally, create a rendering to the screen based on the lighting texture and the color texture.
35
35
36
-
The second stage references a new term, called the _Normal_ Map. We will come back to this later in the chapter. For now, we will focus on the other steps.
36
+
The second stage references a new term, called the _Normal_ texture. We will come back to this later in the chapter. For now, we will focus on the other steps.
37
+
38
+
> [!TIP]
39
+
> _Texture_ vs _Map_ vs _Buffer_
40
+
>
41
+
> It is very common for people to refer to textures as _maps_ or _buffers_ in computer graphics, so if you see the terms "color map", "color texture", or "color buffer"; they very likely refer to the same thing. The terms are synonmous.
37
42
38
43
### Drawing to an off-screen texture
39
44
@@ -45,7 +50,7 @@ The second stage references a new term, called the _Normal_ Map. We will come ba
45
50
46
51
2. The `ColorBuffer` property is a [`RenderTarget2D`](xref:Microsoft.Xna.Framework.Graphics.RenderTarget2D), which is a special type of [`Texture2D`](xref:Microsoft.Xna.Framework.Graphics.Texture2D) that MonoGame can draw into. In order for MonoGame to draw anything into the `ColorBuffer`, it needs to be bound as the current render target. Add the following function to the `DeferredRenderer` class.
47
52
48
-
The `SetRenderTarget()` function instructs all future MonoGame draw operations to render into the `ColorBuffer`:
53
+
The `SetRenderTarget()` function instructs all future MonoGame draw operations to render into the `ColorBuffer`. Add this function to the `DeferredRenderer` class:
49
54
50
55
[!code-csharp[](./snippets/snippet-8-02.cs)]
51
56
@@ -184,6 +189,42 @@ The next task is to write the `pointLightEffect.fx` shader file so that the whit
184
189
185
190
> [!NOTE]
186
191
> For the sake of clarity, these screenshots show only the `LightBuffer` as full screen, that way we can focus on the distance based return value.
192
+
>
193
+
> If you want to do that too, change the `DebugDraw()` method to use the entire viewport for the `lightBorderRect`, like this:
194
+
>
195
+
> [!code-hlsl[](./snippets/snippet-8-22-2.cs)]
196
+
>
197
+
> Just do not forget to revert this change later!
198
+
199
+
200
+
> [!TIP]
201
+
> Add a pause mechanic!
202
+
>
203
+
> It can be really hard to debug the graphics stuff while the game is being played. Earlier in the series, we just added an early-return in the `GameScene`'s `Update()` method. We could do that again, or we could add a debug key to pause the game.
The light looks good! When we revert the full-screen `LightBuffer` and render the `LightBuffer` next to the `ColorBuffer`, a graphical bug will become clear. The world in the `ColorBuffer` is rotating with the vertex shader from the previous chapter, but the `LightBuffer` does not have the same effect, so the light appears broken.
Downloadthe [atlas-normal.png](./images/atlas-normal.png) texture, addittothe_DungeonSlime_'s `Content/Images` folder and include it in the mgcb content file.
>Themathtofullyexplainwhythisisrequiredisbeyondthescopeofthistutorialseries. Readabout [homogenouscoordinates](https://www.tomdalling.com/blog/modern-opengl/explaining-homogenous-coordinates-and-projective-geometry/) and the [perspective divide](https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/projection-matrix-GPU-rendering-pipeline-clipping.html)
0 commit comments