![]() ![]() After that, I will step through the code and explain what is happening.įloat3 DoReflectiveShadowMapping(float3 P, bool divideByW, float3 N)įloat4 textureSpacePosition = mul(lightViewProjectionTextureMatrix, float4(P, 1.0)) I will show a piece of code below that calculates the indirect shading per pixel. However, for spot and point lights you generally want to use shaped meshes with some form of culling to fill less pixels. This is because you need a full screen quad to do this and this works fine for directional lights. I recommend doing the indirect shading pass after you have done the direct shading for a particular light. This is the hard part, especially to get it right. Further than that, a non-comparison sampler that clamps with black border colors will also be necessary. You will also need the same matrix you use transform world space positions to shadow map texture space positions. These random numbers will be used to determine the coordinates of a sample. You need two random floats in the range per sample you take. This means it will avoid flickering images when every frame uses different shadows. They also recommend this to have temporal coherency. Since the algorithm is heavy in terms of performance, I thoroughly agree with the paper. The paper tells you to precalculate those numbers and store them into a buffer in order to save operations for the sampling pass. You need to bind all buffers used in the shadow pass as textures. Preparing the shading passįor the shading pass, you need to do a few things. For directional lights, this will simply look like an unshaded image. For spot lights, you multiply this by the falloff. ![]() ![]() The flux is calculated in the pixel shaders and is the albedo of the material multiplied by the light’s color. If you have normal mapping, you calculate that in the pixel shader as well. You pass the world space normal and position to the pixel shader and pass those through to the corresponding buffers. Using front face culling is a commonly used technique to avoid shadow artifacts, but this does not work with RSM. Keep in mind that you need to cull back faces instead of front faces for this technique. This means you need multiple render targets and a pixel/fragment shader to fill them. You need to store the world space positions, world space normals, and the flux. However, for RSM, you need a few extra buffers. This means you don’t even need a pixel/fragment shader for filling an SM. Traditionally, Shadow Maps (SM) are no more than a depth map. After that, I added spot light shadow maps and added support for RSM to them. Then I implemented RSM for directional lights. I had already set up a deferred renderer with shadow maps for directional lights prior to writing this article. Keep this in mind when I talk about implementation details. The shaders were written in HLSL and the renders made with DirectX 11. It also uses a lot of terminology found in DirectX 11 and 12. The architecture was set up to be multi-threading compatible and as stateless as possible. The engine I implemented this algorithm in has a cross-platform rendering architecture allowing us to create rendering techniques (like deferred shading, shadow mapping, etc.) that will theoretically work on any platform we support. You might see some harder edges and artifacts in the middle and righter image, but that can be solved by tweaking the sample kernel size, indirect light intensity, and the amount of samples taken. The last image shows the differene between the two images, thus what RSM contributed to the image. Notable differences are the brighter colors everywhere, the pink color bleeding onto the floor and the bunny, the shadow not being completely black. In the middle image you see the same image, but rendered using RSM. Whatever falls in the shadow is completely black. In the left image, you see the result of a render without RSM, using just a spot light. The images you see use the Stanford Bunny and three differently colored quads. In figure 1 you see one of the results produced by RSM. It will also cover some possible optimizations.įigure 1: From left to right: Render without Reflective Shadow Maps, render with reflective shadow maps, difference The result This post will explain how I did that and what the pitfalls were. I managed to implement a very naive version of Reflective Shadow Maps (an algorithm described in this paper). ![]()
0 Comments
Leave a Reply. |
AuthorWrite something about yourself. No need to be fancy, just an overview. ArchivesCategories |