Skip to content

Commit e66e148

Browse files
committed
highlighitng and snippet context for 09
1 parent 74f22b4 commit e66e148

17 files changed

+204
-100
lines changed

articles/tutorials/advanced/2d_shaders/09_shadows_effect/index.md

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ Now that we have a good understanding of the available inputs, and the goal of t
121121

122122
Every point (`S`, `D`, `F`, and `G`) needs to find `P`. To do that, the `TexCoord` can be treated as a direction from `P` to the current point, and the `ScreenSize` shader parameter can be used to find the right amount of distance to travel along that direction:
123123

124+
> [!note]
125+
> The next few snippets of shader code are psuedo code. Just follow along with the text and the full shader will be available later in the next section.
126+
124127
[!code-hlsl[](./snippets/snippet-9-02.hlsl)]
125128

126129
Next, we pack the `Color` value as the vector `(B - A)`. The `x` component of the vector can live in the `red` and `green` channels of the `Color`, and the `y` component will live in the `blue` and `alpha` channels. In the vertex shader, `B` can be derived by unpacking the `(B - A)` vector from the `COLOR` semantic and _adding_ it to the `A`. The reason we pack the _difference_ between `B` and `A` into the `Color`, and not `B` itself is due the lack of precision in the `Color` type. There are only 4 `bytes` to pack all the information, which means 2 `bytes` per `x` and `y`. Likely, the line segment will be small, so the values of `(B - A)` will fit easier into a 2 `byte` channel:
@@ -208,7 +211,7 @@ Now, we need to find a place to render the `ShadowBuffer` _per_ `PointLight` bef
208211

209212
3. And finally, call the `DrawShadows()` method right before the `GameScene` calls the `DeferredRenderer`'s `StartLightPass()` method:
210213

211-
[!code-csharp[](./snippets/snippet-9-18.cs)]
214+
[!code-csharp[](./snippets/snippet-9-18.cs?highlight=7)]
212215

213216
4. For debug visualization purposes, add this snippet at the end of the `GameScene`'s `Draw()` just so you can see the `ShaderBuffer` as we debug it:
214217

@@ -251,11 +254,11 @@ Now we have the tools to start implementing the vertex shader! Of course, anytim
251254

252255
3. And do not forget to set the technique for the vertex shader function:
253256

254-
[!code-hlsl[](./snippets/snippet-9-24.hlsl)]
257+
[!code-hlsl[](./snippets/snippet-9-24.hlsl?highlight=6)]
255258

256259
4. The last step to make sure the default vertex shader works is to pass the `MatrixTransform` and `ScreenSize` shader parameters in the `GameScene`'s `Update()` loop, next to where they are being configured for the existing `PointLightMaterial`:
257260

258-
[!code-csharp[](./snippets/snippet-9-25.cs)]
261+
[!code-csharp[](./snippets/snippet-9-25.cs?highlight=7,8)]
259262

260263
The pixel shader function for the `shadowHullEffect` needs to ignore the `input.Color` and just return a solid color:
261264

@@ -436,7 +439,7 @@ Image masking is a common task in computer graphics. There is a built-in feature
436439

437440
The stencil buffer is a part of an existing `RenderTarget`, but we need to opt into using it. In the `DeferredRenderer` class, where the `LightBuffer` is being instantiated, change the `preferredDepthFormat` to `DepthFormat.Depth24Stencil8`:
438441

439-
[!code-csharp[](./snippets/snippet-9-50.cs)]
442+
[!code-csharp[](./snippets/snippet-9-50.cs?highlight=7)]
440443

441444
The `LightBuffer` itself has `32` bits per pixel of `Color` data, _and_ an additional `32` bits of data split between the depth and stencil buffers. As the name suggests, the `Depth24Stencil8` format grants the depth buffer `24` bits of data, and the stencil buffer `8` bits of data. `8` bits are enough for a single `byte`, which means it can represent integers from `0` to `255`.
442445

@@ -494,7 +497,7 @@ Instead of writing the shadow hulls as _color_ into the color portion of the `Li
494497

495498
3. The `_stencilWrite` variable is a declarative structure that tells MonoGame how the stencil buffer should be used during a `SpriteBatch` draw call. The next step is to actually pass the `_stencilWrite` declaration into the `SpriteBatch`'s `Draw()` call when the shadow hulls are being rendered:
496499

497-
[!code-csharp[](./snippets/snippet-9-58.cs)]
500+
[!code-csharp[](./snippets/snippet-9-58.cs?highlight=2)]
498501

499502
Unfortunately, there is not a good way to visualize the state of the stencil buffer, so if you run the game, it is hard to tell if the stencil buffer contains any data. Instead, we will try and _use_ the stencil buffer's data when the point lights are drawn. The point lights will not interact with the stencil buffer in the same way the shadow hulls did.
500503

@@ -508,13 +511,14 @@ Unfortunately, there is not a good way to visualize the state of the stencil buf
508511

509512
3. And now pass the new `_stencilTest` state to the `SpriteBatch` `Draw()` call that draws the point lights:
510513

511-
[!code-csharp[](./snippets/snippet-9-61.cs)]
514+
[!code-csharp[](./snippets/snippet-9-61.cs?highlight=2)]
512515

513516
The shadows look _better_, but something is still broken. It looks eerily similar to the previous iteration before passing the `_stencilTest` and `_stencilWrite` declarations to `SpriteBatch`...
514517

515518
| ![Figure 9-19: The shadows still look funky](./images/stencil_blend.png) |
516519
| :----------------------------------------------------------------------: |
517520
| **Figure 9-19: The shadows still look funky** |
521+
518522
This happens because the shadow hulls are _still_ being drawn as colors into the `LightBuffer`. The shadow hull shader is rendering a black pixel, so those black pixels are drawing on top of the `LightBuffer` 's previous point lights. To solve this, we need to create a custom `BlendState` that ignores all color channel writes.
519523

520524
1. Create a new class variable in the `DeferredRenderer`:
@@ -532,7 +536,7 @@ This happens because the shadow hulls are _still_ being drawn as colors into the
532536

533537
3. Finally, pas it to the shadow hull `SpriteBatch` call:
534538

535-
[!code-csharp[](./snippets/snippet-9-64.cs)]
539+
[!code-csharp[](./snippets/snippet-9-64.cs?highlight=4)]
536540

537541
Now the shadows look closer, but there is one final issue.
538542

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
1-
ShadowHullMaterial = SharedContent.WatchMaterial("effects/shadowHullEffect");
2-
ShadowHullMaterial.IsDebugVisible = true;
1+
protected override void LoadContent()
2+
{
3+
base.LoadContent();
4+
5+
// ...
6+
7+
ShadowHullMaterial = SharedContent.WatchMaterial("effects/shadowHullEffect");
8+
ShadowHullMaterial.IsDebugVisible = true;
9+
10+
// ...
11+
}
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,8 @@
1-
ShadowHullMaterial.Update();
1+
protected override void Update(GameTime gameTime)
2+
{
3+
// ...
4+
5+
ShadowHullMaterial.Update();
6+
7+
// ...
8+
}
Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,13 @@
1-
// render the shadow buffers
2-
PointLight.DrawShadows(_lights, _shadowCasters);
1+
public override void Draw(GameTime gameTime)
2+
{
3+
// ...
4+
Core.SpriteBatch.End();
5+
6+
// render the shadow buffers
7+
PointLight.DrawShadows(_lights, _shadowCasters);
8+
9+
// start rendering the lights
10+
_deferredRenderer.StartLightPhase();
11+
12+
// ...
13+
}
Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1-
Core.SpriteBatch.Begin();
2-
Core.SpriteBatch.Draw(_lights[0].ShadowBuffer, Vector2.Zero, Color.White);
3-
Core.SpriteBatch.End();
1+
public override void Draw(GameTime gameTime)
2+
{
3+
// ...
4+
5+
Core.SpriteBatch.Begin();
6+
Core.SpriteBatch.Draw(_lights[0].ShadowBuffer, Vector2.Zero, Color.White);
7+
Core.SpriteBatch.End();
8+
}
Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
1-
foreach (var caster in shadowCasters)
2-
{
3-
var posA = caster.A;
4-
var aToB = (caster.B - caster.A) / screenSize;
5-
var packed = PackVector2_SNorm(aToB);
6-
Core.SpriteBatch.Draw(Core.Pixel, posA, packed);
1+
public void DrawShadowBuffer(List<ShadowCaster> shadowCasters)
2+
{
3+
/// ...
4+
5+
foreach (var caster in shadowCasters)
6+
{
7+
var posA = caster.A;
8+
var aToB = (caster.B - caster.A) / screenSize;
9+
var packed = PackVector2_SNorm(aToB);
10+
Core.SpriteBatch.Draw(Core.Pixel, posA, packed);
11+
}
12+
13+
// ...
714
}
Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,11 @@
1-
Core.ShadowHullMaterial.SetParameter("MatrixTransform", matrixTransform);
2-
Core.ShadowHullMaterial.SetParameter("ScreenSize", new Vector2(Core.GraphicsDevice.Viewport.Width, Core.GraphicsDevice.Viewport.Height));
1+
public override void Update(GameTime gameTime)
2+
{
3+
// ...
4+
5+
var matrixTransform = _camera.CalculateMatrixTransform();
6+
7+
Core.ShadowHullMaterial.SetParameter("MatrixTransform", matrixTransform);
8+
Core.ShadowHullMaterial.SetParameter("ScreenSize", new Vector2(Core.GraphicsDevice.Viewport.Width, Core.GraphicsDevice.Viewport.Height));
9+
10+
// ...
11+
}
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
public void DrawShadowBuffer(List<ShadowCaster> shadowCasters)
2-
{
3-
Core.GraphicsDevice.SetRenderTarget(ShadowBuffer);
1+
public void DrawShadowBuffer(List<ShadowCaster> shadowCasters)
2+
{
3+
Core.GraphicsDevice.SetRenderTarget(ShadowBuffer);
44
// clear the shadow buffer to white to start
55
Core.GraphicsDevice.Clear(Color.White);
6+
67
// ...
8+
}
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1-
// simple shadow caster
2-
_shadowCasters.Add(ShadowCaster.SimplePolygon(_slime.GetBounds().Location, radius: 50, sides: 6));
1+
private void InitializeLights()
2+
{
3+
// ...
4+
5+
// simple shadow caster
6+
_shadowCasters.Add(ShadowCaster.SimplePolygon(_slime.GetBounds().Location, radius: 50, sides: 6));
7+
}
Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
1-
foreach (var caster in shadowCasters)
1+
public void DrawShadowBuffer(List<ShadowCaster> shadowCasters)
22
{
3-
for (var i = 0; i < caster.Points.Count; i++)
3+
/// ...
4+
5+
foreach (var caster in shadowCasters)
46
{
5-
var a = caster.Position + caster.Points[i];
6-
var b = caster.Position + caster.Points[(i + 1) % caster.Points.Count];
7+
for (var i = 0; i < caster.Points.Count; i++)
8+
{
9+
var a = caster.Position + caster.Points[i];
10+
var b = caster.Position + caster.Points[(i + 1) % caster.Points.Count];
711

8-
var aToB = (b - a) / screenSize;
9-
var packed = PackVector2_SNorm(aToB);
10-
Core.SpriteBatch.Draw(Core.Pixel, a, packed);
12+
var aToB = (b - a) / screenSize;
13+
var packed = PackVector2_SNorm(aToB);
14+
Core.SpriteBatch.Draw(Core.Pixel, a, packed);
15+
}
1116
}
17+
18+
// ...
1219
}

0 commit comments

Comments
 (0)