Skip to content

Commit 20a8d36

Browse files
committed
tracking 8.6; figures and workarounds
1 parent 27c111c commit 20a8d36

File tree

1 file changed

+26
-26
lines changed
  • articles/tutorials/advanced/2d_shaders/08_light_effect

1 file changed

+26
-26
lines changed

articles/tutorials/advanced/2d_shaders/08_light_effect/index.md

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -315,17 +315,13 @@ Generating normal maps is an artform. Generally, you find a _normal map picker_,
315315

316316
For this effect to work, we need an extra texture for every frame of every sprite we are drawing in the game. Given that the textures are currently coming from an atlas, the easiest thing to do will be to create a _second_ texture that shares the same layout as the first, but uses normal data instead.
317317

318-
For reference, here is the existing atlas texture.
318+
For reference, the existing texture atlas is on the left, and a version of the atlas with normal maps is on the right.
319319

320-
| ![Figure 8-17: The existing texture atlas](./images/atlas.png) |
321-
| :------------------------------------------------------------: |
322-
| **Figure 8-17: The existing texture atlas** |
320+
| ![Figure 8-17: The existing texture atlas](./images/atlas.png) | ![Figure 8-18: The normal texture atlas](./images/atlas-normal.png) |
321+
| :------------------------------------------------------------: | :-----------------------------------------------------------------: |
322+
| **Figure 8-17: The existing texture atlas** | **Figure 8-18: The normal texture atlas** |
323323

324-
And here is the atlast, but with normal data where the game sprites are instead. Download the [atlas-normal.png](./images/atlas-normal.png) texture and add it to the _DungeonSlime_'s content folder. Include it in the mgcb content file.
325-
326-
| ![Figure 8-18: The normal texture atlas](./images/atlas-normal.png) |
327-
| :-----------------------------------------------------------------: |
328-
| **Figure 8-18: The normal texture atlas** |
324+
Download the [atlas-normal.png](./images/atlas-normal.png) texture and add it to the _DungeonSlime_'s content folder. Include it in the mgcb content file.
329325

330326
Now that we have the art assets, it is time to work the normal maps into the code.
331327

@@ -374,9 +370,9 @@ Now that we have the art assets, it is time to work the normal maps into the cod
374370

375371
8. And do not forget to call the `DebugDraw()` method from the `GameScene`'s `Draw()` method. Then you will see a totally `red` `NormalBuffer`, because the shader is hard coding the value to `float4(1,0,0,1)`.
376372

377-
| ![Figure 8-19: A blank normal buffer](./images/normal-buffer-red.png) |
373+
| ![Figure 8-17: A blank normal buffer](./images/normal-buffer-red.png) |
378374
| :-------------------------------------------------------------------: |
379-
| **Figure 8-19: A blank normal buffer** |
375+
| **Figure 8-17: A blank normal buffer** |
380376

381377
To start rendering the normal values themselves, we need to load the normal texture into the `GameScene` and pass it along to the `gameEffect.fx` effect.
382378

@@ -402,9 +398,9 @@ To start rendering the normal values themselves, we need to load the normal text
402398

403399
6. Now the `NormalBuffer` is being populated with the normal data for each sprite.
404400

405-
| ![Figure 8-20: The normal map](./images/normal-buffer.png) |
401+
| ![Figure 8-18: The normal map](./images/normal-buffer.png) |
406402
| :--------------------------------------------------------: |
407-
| **Figure 8-20: The normal map** |
403+
| **Figure 8-18: The normal map** |
408404

409405
### Combing Normals with Lights
410406

@@ -426,7 +422,7 @@ When each individual light is drawn into the `LightBuffer`, it needs to use the
426422

427423
In order to override the vertex shader function, we will need to repeat the `MatrixTransform` work from the previous chapter. However, it would better to _re-use_ the work from the previous chapter so that the lights also tilt and respond to the `MatrixTransform` that the rest of the game world uses.
428424

429-
Add a reference in the `3dEffect.fxh` file in the `pointLightEffect.fx` shader:
425+
Add a reference to the `3dEffect.fxh` file in the `pointLightEffect.fx` shader:
430426

431427
[!code-hlsl[](./snippets/snippet-8-56.hlsl)]
432428

@@ -458,7 +454,9 @@ When each individual light is drawn into the `LightBuffer`, it needs to use the
458454

459455
[!code-csharp[](./snippets/snippet-8-62.cs)]
460456

461-
![8.18: The point light can access screen space](./images/light-screen.png)
457+
| ![Figure 8-19: ](./images/light-screen.png) |
458+
| :--------------------------------------------------------------------------------: |
459+
| **Figure 8-19: The point light can access screen space** |
462460

463461
11. Now, the `pointLightEffect` can use the screen space coordinates to sample the `NormalBuffer` values. To build intuition, start by just returning the values from the `NormalBuffer`.
464462

@@ -468,27 +466,29 @@ When each individual light is drawn into the `LightBuffer`, it needs to use the
468466

469467
12. Strangely, this will return a `white` box, instead of the normal data as expected.
470468

471-
| ![Figure 8-21: A white box instead of the normal data?](./images/light-broken.png) |
469+
| ![Figure 8-20: A white box instead of the normal data?](./images/light-broken.png) |
472470
| :--------------------------------------------------------------------------------: |
473-
| **Figure 8-21: A white box instead of the normal data?** |
471+
| **Figure 8-20: A white box instead of the normal data?** |
474472

475473
This happens because of a misunderstanding between the shader compiler and `SpriteBatch`. _Most_ of the time when `SpriteBatch` is being used, there is a single `Texture` and `Sampler` being used to draw a sprite to the screen. The `SpriteBatch`'s draw function passes the given `Texture2D` to the shader by setting it in the `GraphicsDevice.Textures` array [directly](https://github.com/MonoGame/MonoGame/blob/develop/MonoGame.Framework/Graphics/SpriteBatcher.cs#L212). The texture is not being passed _by name_, it is being passed by _index_. In the lighting case, the `SpriteBatch` is being drawn with the `Core.Pixel` texture (a white 1x1 image we generated in the earlier chapters).
476474

477475
However, the shader compiler will aggressively optimize away data that isn't being used in the shader. The current `pointLightEffect.fx` does not _use_ the default texture or sampler that `SpriteBatch` expects by default. The default texture is _removed_ from the shader during compilation, because it isn't used anywhere and has no effect. The only texture that is left is the `NormalBuffer`, which now becomes the first indexable texture.
478476

479477
Despite passing the `NormalBuffer` texture to the named `NormalTexture` `Texture2D` parameter in the shader before calling `SpriteBatch.Draw()`, the `SpriteBatch` code itself then overwrites whatever is in texture slot `0` with the texture passed to the `Draw()` call, the white pixel.
480478

481-
There are two workarounds. If performance is not _critical_, you could add back in a throw-away read from the main `SpriteTextureSampler` , and use the resulting color _somehow_ in the computation for the final result of the shader. However, this is useless work, and will likely confuse anyone who looks at the shader in the future. The other workaround is to pass the `NormalBuffer` to the `Draw()` function directly, and not bother sending it as a shader parameter at all.
479+
There are two workarounds.
480+
1. Modify the shader code to read data from the main `SpriteTextureSampler` and use the resulting color _somehow_ in the computation fro the final result of the shader. For example, You could multiple the color by a very small constant, like `.00001`, and then add the product to the final color. It would have no perceivable effect, but the shader compiler wouldn't be optimize the sampler away. Hoewver, this is useless and silly work. Worse, it will likely confuse anyone who looks at the shader in the future.
481+
2. The better approach is to pass the `NormalBuffer` to the `Draw()` function directly, and not bother sending it as a shader parameter at all.
482482

483483
Change the `PointLight.Draw()` method to pass the `normalBuffer` to the `SpriteBatch.Draw()` method _instead_ of passing it in as a parameter to the `PointLightMaterial`. Here is the new `PointLight.Draw()` method:
484484

485485
[!code-csharp[](./snippets/snippet-8-64.cs)]
486486

487487
And now the normal map is being rendered where the light exists.
488488

489-
| ![Figure 8-22: The light shows the normal map entirely](./images/light-normal.png) |
489+
| ![Figure 8-21: The light shows the normal map entirely](./images/light-normal.png) |
490490
| :--------------------------------------------------------------------------------: |
491-
| **Figure 8-22: The light shows the normal map entirely** |
491+
| **Figure 8-21: The light shows the normal map entirely** |
492492

493493
Now it is time to _use_ the normal data in conjunction with the light direction to decide how much light each pixel should receive.
494494

@@ -500,15 +500,15 @@ Now it is time to _use_ the normal data in conjunction with the light direction
500500

501501
[!code-hlsl[](./snippets/snippet-8-66.hlsl)]
502502

503-
| ![Figure 8-23: The light with the normal](./images/light-with-normal.png) |
503+
| ![Figure 8-22: The light with the normal](./images/light-with-normal.png) |
504504
| :-----------------------------------------------------------------------: |
505-
| **Figure 8-23: The light with the normal** |
505+
| **Figure 8-22: The light with the normal** |
506506

507507
To drive the effect for a moment, this gif shows the normal effect being blended in. Notice how the wings on the bat shade differently based on their position towards the light as the normal effect is brought in.
508508

509-
| ![Figure 8-24: The lighting on the bat with normals](./gifs/normals.gif) |
509+
| ![Figure 8-23: The lighting on the bat with normals](./gifs/normals.gif) |
510510
| :----------------------------------------------------------------------: |
511-
| **Figure 8-24: The lighting on the bat with normals** |
511+
| **Figure 8-23: The lighting on the bat with normals** |
512512

513513
### Gameplay
514514

@@ -530,9 +530,9 @@ Now that we have lights rendering in the game, it is time to hook a few more up
530530

531531
And now when the game runs, it looks like this.
532532

533-
| ![Figure 8-25: The final results](./gifs/final.gif) |
533+
| ![Figure 8-24: The final results](./gifs/final.gif) |
534534
| :-------------------------------------------------: |
535-
| **Figure 8-25: The final results** |
535+
| **Figure 8-24: The final results** |
536536

537537
## Conclusion
538538

0 commit comments

Comments
 (0)