mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 23:01:50 +00:00
- split shadowmap AABB tree into two parts. one for static and one for dynamic
- upload only the dynamic AABB subtree using glBufferSubData - change internal raytracing stack limit from 16 to 32 - update shadowmap AABB tree after R_SetupFrame for proper frame interpolation
This commit is contained in:
parent
4f4d10ce5f
commit
f10ded756e
9 changed files with 123 additions and 58 deletions
|
@ -273,7 +273,6 @@ sector_t *FGLRenderer::RenderView(player_t* player)
|
|||
fovratio = ratio;
|
||||
}
|
||||
|
||||
UpdateShadowMap();
|
||||
retsec = RenderViewpoint(r_viewpoint, player->camera, NULL, r_viewpoint.FieldOfView.Degrees, ratio, fovratio, true, true);
|
||||
}
|
||||
All.Unclock();
|
||||
|
|
|
@ -152,6 +152,8 @@ sector_t * FGLRenderer::RenderViewpoint (FRenderViewpoint &mainvp, AActor * came
|
|||
{
|
||||
R_SetupFrame (mainvp, r_viewwindow, camera);
|
||||
|
||||
UpdateShadowMap();
|
||||
|
||||
// Render (potentially) multiple views for stereo 3d
|
||||
// Fixme. The view offsetting should be done with a static table and not require setup of the entire render state for the mode.
|
||||
auto vrmode = VRMode::GetVRMode(mainview && toscreen);
|
||||
|
|
|
@ -65,7 +65,7 @@ void GLBuffer::Bind()
|
|||
}
|
||||
|
||||
|
||||
void GLBuffer::SetData(size_t size, void *data, bool staticdata)
|
||||
void GLBuffer::SetData(size_t size, const void *data, bool staticdata)
|
||||
{
|
||||
assert(nomap); // once it's mappable, it cannot be recreated anymore.
|
||||
Bind();
|
||||
|
@ -92,6 +92,12 @@ void GLBuffer::SetData(size_t size, void *data, bool staticdata)
|
|||
InvalidateBufferState();
|
||||
}
|
||||
|
||||
void GLBuffer::SetSubData(size_t offset, size_t size, const void *data)
|
||||
{
|
||||
Bind();
|
||||
glBufferSubData(mUseType, offset, size, data);
|
||||
}
|
||||
|
||||
void GLBuffer::Map()
|
||||
{
|
||||
assert(nomap == false); // do not allow mapping of static buffers. Vulkan cannot do that so it should be blocked in OpenGL, too.
|
||||
|
|
|
@ -22,7 +22,8 @@ protected:
|
|||
|
||||
GLBuffer(int usetype);
|
||||
~GLBuffer();
|
||||
void SetData(size_t size, void *data, bool staticdata) override;
|
||||
void SetData(size_t size, const void *data, bool staticdata) override;
|
||||
void SetSubData(size_t offset, size_t size, const void *data) override;
|
||||
void Map() override;
|
||||
void Unmap() override;
|
||||
void Resize(size_t newsize) override;
|
||||
|
|
|
@ -47,7 +47,8 @@ public:
|
|||
IBuffer &operator=(const IBuffer &) = delete;
|
||||
virtual ~IBuffer() = default;
|
||||
|
||||
virtual void SetData(size_t size, void *data, bool staticdata = true) = 0;
|
||||
virtual void SetData(size_t size, const void *data, bool staticdata = true) = 0;
|
||||
virtual void SetSubData(size_t offset, size_t size, const void *data) = 0;
|
||||
virtual void *Lock(unsigned int size) = 0;
|
||||
virtual void Unlock() = 0;
|
||||
virtual void Resize(size_t newsize) = 0;
|
||||
|
|
|
@ -38,35 +38,36 @@ LevelAABBTree::LevelAABBTree()
|
|||
centroids.Push((v1 + v2) * 0.5f);
|
||||
}
|
||||
|
||||
// Create a list of level lines we want to add:
|
||||
TArray<int> line_elements;
|
||||
for (unsigned int i = 0; i < level.lines.Size(); i++)
|
||||
{
|
||||
if (!level.lines[i].backsector)
|
||||
{
|
||||
#ifdef USE_POLYOBJ_SHADOWS
|
||||
if (level.lines[i].sidedef[0] && (level.lines[i].sidedef[0]->Flags & WALLF_POLYOBJ))
|
||||
polylines.Push(i);
|
||||
line_elements.Push(i);
|
||||
#else
|
||||
if (!level.lines[i].sidedef[0] || !(level.lines[i].sidedef[0]->Flags & WALLF_POLYOBJ))
|
||||
line_elements.Push(i);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// Create the static subtree
|
||||
if (!GenerateTree(¢roids[0], false))
|
||||
return;
|
||||
|
||||
// GenerateTreeNode needs a buffer where it can store line indices temporarily when sorting lines into the left and right child AABB buckets
|
||||
TArray<int> work_buffer;
|
||||
work_buffer.Resize(line_elements.Size() * 2);
|
||||
int staticroot = nodes.Size() - 1;
|
||||
|
||||
// Generate the AABB tree
|
||||
GenerateTreeNode(&line_elements[0], (int)line_elements.Size(), ¢roids[0], &work_buffer[0]);
|
||||
dynamicStartNode = nodes.Size();
|
||||
dynamicStartLine = lines.Size();
|
||||
|
||||
// Create the dynamic subtree
|
||||
if (GenerateTree(¢roids[0], true))
|
||||
{
|
||||
int dynamicroot = nodes.Size() - 1;
|
||||
|
||||
// Create a shared root node
|
||||
FVector2 aabb_min, aabb_max;
|
||||
const auto &left = nodes[staticroot];
|
||||
const auto &right = nodes[dynamicroot];
|
||||
aabb_min.X = MIN(left.aabb_left, right.aabb_left);
|
||||
aabb_min.Y = MIN(left.aabb_top, right.aabb_top);
|
||||
aabb_max.X = MAX(left.aabb_right, right.aabb_right);
|
||||
aabb_max.Y = MAX(left.aabb_bottom, right.aabb_bottom);
|
||||
nodes.Push({ aabb_min, aabb_max, staticroot, dynamicroot });
|
||||
}
|
||||
|
||||
// Add the lines referenced by the leaf nodes
|
||||
lines.Resize(level.lines.Size());
|
||||
for (unsigned int i = 0; i < level.lines.Size(); i++)
|
||||
lines.Resize(mapLines.Size());
|
||||
for (unsigned int i = 0; i < mapLines.Size(); i++)
|
||||
{
|
||||
const auto &line = level.lines[i];
|
||||
const auto &line = level.lines[mapLines[i]];
|
||||
auto &treeline = lines[i];
|
||||
|
||||
treeline.x = (float)line.v1->fX();
|
||||
|
@ -76,13 +77,46 @@ LevelAABBTree::LevelAABBTree()
|
|||
}
|
||||
}
|
||||
|
||||
bool LevelAABBTree::GenerateTree(const FVector2 *centroids, bool dynamicsubtree)
|
||||
{
|
||||
// Create a list of level lines we want to add:
|
||||
TArray<int> line_elements;
|
||||
for (unsigned int i = 0; i < level.lines.Size(); i++)
|
||||
{
|
||||
if (!level.lines[i].backsector)
|
||||
{
|
||||
bool isPolyLine = level.lines[i].sidedef[0] && (level.lines[i].sidedef[0]->Flags & WALLF_POLYOBJ);
|
||||
if (isPolyLine && dynamicsubtree)
|
||||
{
|
||||
line_elements.Push(mapLines.Size());
|
||||
mapLines.Push(i);
|
||||
}
|
||||
else if (!isPolyLine && !dynamicsubtree)
|
||||
{
|
||||
line_elements.Push(mapLines.Size());
|
||||
mapLines.Push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (line_elements.Size() == 0)
|
||||
return false;
|
||||
|
||||
// GenerateTreeNode needs a buffer where it can store line indices temporarily when sorting lines into the left and right child AABB buckets
|
||||
TArray<int> work_buffer;
|
||||
work_buffer.Resize(line_elements.Size() * 2);
|
||||
|
||||
// Generate the AABB tree
|
||||
GenerateTreeNode(&line_elements[0], (int)line_elements.Size(), centroids, &work_buffer[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LevelAABBTree::Update()
|
||||
{
|
||||
bool modified = false;
|
||||
for (unsigned int ii = 0; ii < polylines.Size(); ii++)
|
||||
for (unsigned int i = dynamicStartLine; i < mapLines.Size(); i++)
|
||||
{
|
||||
int i = polylines[ii];
|
||||
const auto &line = level.lines[i];
|
||||
const auto &line = level.lines[mapLines[i]];
|
||||
|
||||
AABBTreeLine treeline;
|
||||
treeline.x = (float)line.v1->fX();
|
||||
|
@ -95,10 +129,10 @@ bool LevelAABBTree::Update()
|
|||
TArray<int> path = FindNodePath(i, nodes.Size() - 1);
|
||||
if (path.Size())
|
||||
{
|
||||
float x1 = (float)level.lines[i].v1->fX();
|
||||
float y1 = (float)level.lines[i].v1->fY();
|
||||
float x2 = (float)level.lines[i].v2->fX();
|
||||
float y2 = (float)level.lines[i].v2->fY();
|
||||
float x1 = (float)line.v1->fX();
|
||||
float y1 = (float)line.v1->fY();
|
||||
float x2 = (float)line.v2->fX();
|
||||
float y2 = (float)line.v2->fY();
|
||||
|
||||
int nodeIndex = path[0];
|
||||
nodes[nodeIndex].aabb_left = MIN(x1, x2);
|
||||
|
@ -122,7 +156,7 @@ bool LevelAABBTree::Update()
|
|||
}
|
||||
}
|
||||
}
|
||||
return !modified;
|
||||
return modified;
|
||||
}
|
||||
|
||||
TArray<int> LevelAABBTree::FindNodePath(unsigned int line, unsigned int node)
|
||||
|
@ -165,7 +199,7 @@ double LevelAABBTree::RayTest(const DVector3 &ray_start, const DVector3 &ray_end
|
|||
double hit_fraction = 1.0;
|
||||
|
||||
// Walk the tree nodes
|
||||
int stack[16];
|
||||
int stack[32];
|
||||
int stack_pos = 1;
|
||||
stack[0] = nodes.Size() - 1; // root node is the last node in the list
|
||||
while (stack_pos > 0)
|
||||
|
@ -183,7 +217,7 @@ double LevelAABBTree::RayTest(const DVector3 &ray_start, const DVector3 &ray_end
|
|||
hit_fraction = MIN(IntersectRayLine(ray_start, ray_end, nodes[node_index].line_index, raydelta, rayd, raydist2), hit_fraction);
|
||||
stack_pos--;
|
||||
}
|
||||
else if (stack_pos == 16)
|
||||
else if (stack_pos == 32)
|
||||
{
|
||||
stack_pos--; // stack overflow - tree is too deep!
|
||||
}
|
||||
|
@ -269,15 +303,15 @@ int LevelAABBTree::GenerateTreeNode(int *lines, int num_lines, const FVector2 *c
|
|||
// Find bounding box and median of the lines
|
||||
FVector2 median = FVector2(0.0f, 0.0f);
|
||||
FVector2 aabb_min, aabb_max;
|
||||
aabb_min.X = (float)level.lines[lines[0]].v1->fX();
|
||||
aabb_min.Y = (float)level.lines[lines[0]].v1->fY();
|
||||
aabb_min.X = (float)level.lines[mapLines[lines[0]]].v1->fX();
|
||||
aabb_min.Y = (float)level.lines[mapLines[lines[0]]].v1->fY();
|
||||
aabb_max = aabb_min;
|
||||
for (int i = 0; i < num_lines; i++)
|
||||
{
|
||||
float x1 = (float)level.lines[lines[i]].v1->fX();
|
||||
float y1 = (float)level.lines[lines[i]].v1->fY();
|
||||
float x2 = (float)level.lines[lines[i]].v2->fX();
|
||||
float y2 = (float)level.lines[lines[i]].v2->fY();
|
||||
float x1 = (float)level.lines[mapLines[lines[i]]].v1->fX();
|
||||
float y1 = (float)level.lines[mapLines[lines[i]]].v1->fY();
|
||||
float x2 = (float)level.lines[mapLines[lines[i]]].v2->fX();
|
||||
float y2 = (float)level.lines[mapLines[lines[i]]].v2->fY();
|
||||
|
||||
aabb_min.X = MIN(aabb_min.X, x1);
|
||||
aabb_min.X = MIN(aabb_min.X, x2);
|
||||
|
@ -288,7 +322,7 @@ int LevelAABBTree::GenerateTreeNode(int *lines, int num_lines, const FVector2 *c
|
|||
aabb_max.Y = MAX(aabb_max.Y, y1);
|
||||
aabb_max.Y = MAX(aabb_max.Y, y2);
|
||||
|
||||
median += centroids[lines[i]];
|
||||
median += centroids[mapLines[lines[i]]];
|
||||
}
|
||||
median /= (float)num_lines;
|
||||
|
||||
|
@ -324,7 +358,7 @@ int LevelAABBTree::GenerateTreeNode(int *lines, int num_lines, const FVector2 *c
|
|||
{
|
||||
int line_index = lines[i];
|
||||
|
||||
float side = FVector3(centroids[lines[i]], 1.0f) | plane;
|
||||
float side = FVector3(centroids[mapLines[lines[i]]], 1.0f) | plane;
|
||||
if (side >= 0.0f)
|
||||
{
|
||||
work_buffer[left_count] = line_index;
|
||||
|
|
|
@ -42,18 +42,26 @@ public:
|
|||
// Constructs a tree for the current level
|
||||
LevelAABBTree();
|
||||
|
||||
// Nodes in the AABB tree. Last node is the root node.
|
||||
TArray<AABBTreeNode> nodes;
|
||||
|
||||
// Line segments for the leaf nodes in the tree.
|
||||
TArray<AABBTreeLine> lines;
|
||||
|
||||
// Shoot a ray from ray_start to ray_end and return the closest hit as a fractional value between 0 and 1. Returns 1 if no line was hit.
|
||||
double RayTest(const DVector3 &ray_start, const DVector3 &ray_end);
|
||||
|
||||
bool Update();
|
||||
|
||||
const void *Nodes() const { return nodes.Data(); }
|
||||
const void *Lines() const { return lines.Data(); }
|
||||
size_t NodesSize() const { return nodes.Size() * sizeof(AABBTreeNode); }
|
||||
size_t LinesSize() const { return lines.Size() * sizeof(AABBTreeLine); }
|
||||
|
||||
const void *DynamicNodes() const { return nodes.Data() + dynamicStartNode; }
|
||||
const void *DynamicLines() const { return lines.Data() + dynamicStartLine; }
|
||||
size_t DynamicNodesSize() const { return (nodes.Size() - dynamicStartNode) * sizeof(AABBTreeNode); }
|
||||
size_t DynamicLinesSize() const { return (lines.Size() - dynamicStartLine) * sizeof(AABBTreeLine); }
|
||||
size_t DynamicNodesOffset() const { return dynamicStartNode * sizeof(AABBTreeNode); }
|
||||
size_t DynamicLinesOffset() const { return dynamicStartLine * sizeof(AABBTreeLine); }
|
||||
|
||||
private:
|
||||
bool GenerateTree(const FVector2 *centroids, bool dynamicsubtree);
|
||||
|
||||
// Test if a ray overlaps an AABB node or not
|
||||
bool OverlapRayAABB(const DVector2 &ray_start2d, const DVector2 &ray_end2d, const AABBTreeNode &node);
|
||||
|
||||
|
@ -65,7 +73,16 @@ private:
|
|||
|
||||
TArray<int> FindNodePath(unsigned int line, unsigned int node);
|
||||
|
||||
TArray<int> polylines;
|
||||
// Nodes in the AABB tree. Last node is the root node.
|
||||
TArray<AABBTreeNode> nodes;
|
||||
|
||||
// Line segments for the leaf nodes in the tree.
|
||||
TArray<AABBTreeLine> lines;
|
||||
|
||||
int dynamicStartNode = 0;
|
||||
int dynamicStartLine = 0;
|
||||
|
||||
TArray<int> mapLines;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -155,7 +155,7 @@ bool IShadowMap::ValidateAABBTree()
|
|||
}
|
||||
|
||||
if (mAABBTree)
|
||||
return mAABBTree->Update();
|
||||
return true;
|
||||
|
||||
mAABBTree.reset(new hwrenderer::LevelAABBTree());
|
||||
return false;
|
||||
|
@ -198,11 +198,16 @@ void IShadowMap::UploadAABBTree()
|
|||
{
|
||||
if (!mNodesBuffer)
|
||||
mNodesBuffer = screen->CreateDataBuffer(2, true);
|
||||
mNodesBuffer->SetData(sizeof(hwrenderer::AABBTreeNode) * mAABBTree->nodes.Size(), &mAABBTree->nodes[0]);
|
||||
mNodesBuffer->SetData(mAABBTree->NodesSize(), mAABBTree->Nodes());
|
||||
|
||||
if (!mLinesBuffer)
|
||||
mLinesBuffer = screen->CreateDataBuffer(3, true);
|
||||
mLinesBuffer->SetData(sizeof(hwrenderer::AABBTreeLine) * mAABBTree->lines.Size(), &mAABBTree->lines[0]);
|
||||
mLinesBuffer->SetData(mAABBTree->LinesSize(), mAABBTree->Lines());
|
||||
}
|
||||
else if (mAABBTree->Update())
|
||||
{
|
||||
mNodesBuffer->SetSubData(mAABBTree->DynamicNodesOffset(), mAABBTree->DynamicNodesSize(), mAABBTree->DynamicNodes());
|
||||
mLinesBuffer->SetSubData(mAABBTree->DynamicLinesOffset(), mAABBTree->DynamicLinesSize(), mAABBTree->DynamicLines());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ float rayTest(vec2 ray_start, vec2 ray_end)
|
|||
// Walk the AABB binary tree searching for nodes touching the ray line segment's AABB box.
|
||||
// When it reaches a leaf node, use a line segment intersection test to see if we got a hit.
|
||||
|
||||
int stack[16];
|
||||
int stack[32];
|
||||
int stack_pos = 1;
|
||||
stack[0] = nodes.length() - 1;
|
||||
while (stack_pos > 0)
|
||||
|
@ -125,7 +125,7 @@ float rayTest(vec2 ray_start, vec2 ray_end)
|
|||
t = min(intersectRayLine(ray_start, ray_end, nodes[node_index].line_index, raydelta, rayd, raydist2), t);
|
||||
stack_pos--;
|
||||
}
|
||||
else if (stack_pos == 16)
|
||||
else if (stack_pos == 32)
|
||||
{
|
||||
stack_pos--; // stack overflow
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue