mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 15:22:16 +00:00
Document the algorithm used for generating the 1D shadow maps
This commit is contained in:
parent
d09c3ad305
commit
b281a697ce
2 changed files with 49 additions and 0 deletions
|
@ -32,6 +32,39 @@
|
|||
#include "gl/shaders/gl_shadowmapshader.h"
|
||||
#include "r_state.h"
|
||||
|
||||
/*
|
||||
The 1D shadow maps are stored in a 1024x1024 texture as float depth values (R32F).
|
||||
|
||||
Each line in the texture is assigned to a single light. For example, to grab depth values for light 20
|
||||
the fragment shader (main.fp) needs to sample from row 20. That is, the V texture coordinate needs
|
||||
to be 20.5/1024.
|
||||
|
||||
mLightToShadowmap is a hash map storing which line each ADynamicLight is assigned to. The public
|
||||
ShadowMapIndex function allows the main rendering to find the index and upload that along with the
|
||||
normal light data. From there, the main.fp shader can sample from the shadow map texture, which
|
||||
is currently always bound to texture unit 16.
|
||||
|
||||
The texel row for each light is split into four parts. One for each direction, like a cube texture,
|
||||
but then only in 2D where this reduces itself to a square. When main.fp samples from the shadow map
|
||||
it first decides in which direction the fragment is (relative to the light), like cubemap sampling does
|
||||
for 3D, but once again just for the 2D case.
|
||||
|
||||
Texels 0-255 is Y positive, 256-511 is X positive, 512-767 is Y negative and 768-1023 is X negative.
|
||||
|
||||
Generating the shadow map itself is done by FShadowMap::Update(). The shadow map texture's FBO is
|
||||
bound and then a screen quad is drawn to make a fragment shader cover all texels. For each fragment
|
||||
it shoots a ray and collects the distance to what it hit.
|
||||
|
||||
The shadowmap.fp shader knows which light and texel it is processing by mapping gl_FragCoord.y back
|
||||
to the light index, and it knows which direction to ray trace by looking at gl_FragCoord.x. For
|
||||
example, if gl_FragCoord.y is 20.5, then it knows its processing light 20, and if gl_FragCoord.x is
|
||||
127.5, then it knows we are shooting straight ahead for the Y positive direction.
|
||||
|
||||
Ray testing is done by uploading two GPU storage buffers - one holding AABB tree nodes, and one with
|
||||
the line segments at the leaf nodes of the tree. The fragment shader then performs a test same way
|
||||
as on the CPU, except everything uses indexes as pointers are not allowed in GLSL.
|
||||
*/
|
||||
|
||||
void FShadowMap::Update()
|
||||
{
|
||||
UploadAABBTree();
|
||||
|
|
|
@ -13,27 +13,43 @@ public:
|
|||
FShadowMap() { }
|
||||
~FShadowMap() { Clear(); }
|
||||
|
||||
// Release resources
|
||||
void Clear();
|
||||
|
||||
// Update shadow map texture
|
||||
void Update();
|
||||
|
||||
// Return the assigned shadow map index for a given light
|
||||
int ShadowMapIndex(ADynamicLight *light) { return mLightToShadowmap[light]; }
|
||||
|
||||
// Test if a world position is in shadow relative to the specified light and returns false if it is
|
||||
bool ShadowTest(ADynamicLight *light, const DVector3 &pos);
|
||||
|
||||
private:
|
||||
// Upload the AABB-tree to the GPU
|
||||
void UploadAABBTree();
|
||||
|
||||
// Upload light list to the GPU
|
||||
void UploadLights();
|
||||
|
||||
// OpenGL storage buffer with the list of lights in the shadow map texture
|
||||
int mLightList = 0;
|
||||
|
||||
// Working buffer for creating the list of lights. Stored here to avoid allocating memory each frame
|
||||
TArray<float> mLights;
|
||||
|
||||
// The assigned shadow map index for each light
|
||||
TMap<ADynamicLight*, int> mLightToShadowmap;
|
||||
|
||||
// OpenGL storage buffers for the AABB tree
|
||||
int mNodesBuffer = 0;
|
||||
int mLinesBuffer = 0;
|
||||
|
||||
// Used to detect when a level change requires the AABB tree to be regenerated
|
||||
int mLastNumNodes = 0;
|
||||
int mLastNumSegs = 0;
|
||||
|
||||
// AABB-tree of the level, used for ray tests
|
||||
std::unique_ptr<LevelAABBTree> mAABBTree;
|
||||
|
||||
FShadowMap(const FShadowMap &) = delete;
|
||||
|
|
Loading…
Reference in a new issue