Skip to content

Commit e0ed87d

Browse files
committed
preparation for cascades: separate rendering into 4 tasks
1 parent 6e407b9 commit e0ed87d

File tree

3 files changed

+164
-127
lines changed

3 files changed

+164
-127
lines changed

data/cage/shaders/engine/fragment.glsl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ float egacShadowedIntensity(UniShadowedLight uni)
6565
{
6666
case CAGE_SHADER_OPTIONVALUE_LIGHTDIRECTIONALSHADOW:
6767
case CAGE_SHADER_OPTIONVALUE_LIGHTSPOTSHADOW:
68-
intensity = sampleShadowMap2dArrayFast(texShadows2d[shadowmapSamplerIndex], shadowPos, cascade);
68+
intensity = sampleShadowMap2d(texShadows2d[shadowmapSamplerIndex], shadowPos, cascade);
6969
break;
7070
case CAGE_SHADER_OPTIONVALUE_LIGHTPOINTSHADOW:
7171
intensity = sampleShadowMapCube(texShadowsCube[shadowmapSamplerIndex], shadowPos);

data/cage/shaders/functions/sampleShadowMap.glsl

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,7 @@
22
$include poissonDisk4.glsl
33
$include randomAngle.glsl
44

5-
float sampleShadowMap2dFast(sampler2D texShadow2d, vec3 shadowPos)
6-
{
7-
return float(texture(texShadow2d, shadowPos.xy).x > shadowPos.z);
8-
}
9-
10-
float sampleShadowMap2d(sampler2D texShadow2d, vec3 shadowPos)
11-
{
12-
vec2 radius = 0.8 / textureSize(texShadow2d, 0).xy;
13-
float visibility = 0.0;
14-
for (int i = 0; i < 4; i++)
15-
{
16-
float ra = randomAngle(12000.0, shadowPos);
17-
mat2 rot = mat2(cos(ra), sin(ra), -sin(ra), cos(ra));
18-
vec2 samp = rot * poissonDisk4[i] * radius;
19-
visibility += float(texture(texShadow2d, shadowPos.xy + samp).x > shadowPos.z);
20-
}
21-
visibility /= 4.0;
22-
return visibility;
23-
}
24-
25-
float sampleShadowMap2dArrayFast(sampler2DArray texShadow2d, vec3 shadowPos, int cascade)
26-
{
27-
return float(texture(texShadow2d, vec3(shadowPos.xy, float(cascade))).x > shadowPos.z);
28-
}
29-
30-
float sampleShadowMap2dArray(sampler2DArray texShadow2d, vec3 shadowPos, int cascade)
5+
float sampleShadowMap2d(sampler2DArray texShadow2d, vec3 shadowPos, int cascade)
316
{
327
vec2 radius = 0.8 / textureSize(texShadow2d, 0).xy;
338
float visibility = 0.0;

sources/libengine/graphics/renderPipeline.cpp

Lines changed: 162 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ namespace cage
188188

189189
struct CameraData : private Noncopyable
190190
{
191-
std::map<Entity *, Holder<struct RenderPipelineImpl>> shadowmaps;
191+
std::vector<Holder<struct RenderPipelineImpl>> shadowmaps;
192192
uint32 lightsCount = 0;
193193
uint32 shadowedLightsCount = 0;
194194
};
@@ -199,6 +199,7 @@ namespace cage
199199
Holder<ProvisionalTexture> shadowTexture;
200200
LightComponent lightComponent;
201201
ShadowmapComponent shadowmapComponent;
202+
uint32 cascade = 0;
202203
};
203204

204205
struct RenderPipelineImpl : public RenderPipelineConfig
@@ -1052,42 +1053,6 @@ namespace cage
10521053
renderQueue->universalUniformStruct(uni, CAGE_SHADER_UNIBLOCK_PROJECTION);
10531054
}
10541055

1055-
void taskShadowmap()
1056-
{
1057-
CAGE_ASSERT(!data);
1058-
CAGE_ASSERT(shadowmap);
1059-
1060-
renderQueue = newRenderQueue(name, provisionalGraphics);
1061-
const auto graphicsDebugScope = renderQueue->namedScope("shadowmap");
1062-
1063-
for (uint32 cascade = 0; cascade < CAGE_SHADER_MAX_SHADOWMAPSCASCADES; cascade++)
1064-
{
1065-
FrameBufferHandle renderTarget = provisionalGraphics->frameBufferDraw("renderTarget");
1066-
renderQueue->bind(renderTarget);
1067-
renderQueue->clearFrameBuffer(renderTarget);
1068-
renderQueue->depthTexture(renderTarget, shadowmap->shadowTexture, cascade);
1069-
renderQueue->activeAttachments(renderTarget, 0);
1070-
renderQueue->checkFrameBuffer(renderTarget);
1071-
renderQueue->viewport(Vec2i(), resolution);
1072-
renderQueue->colorWrite(false);
1073-
renderQueue->clear(false, true);
1074-
renderQueue->checkGlErrorDebug();
1075-
1076-
prepareProjection();
1077-
prepareEntities();
1078-
orderRenderData();
1079-
1080-
{
1081-
const auto graphicsDebugScope = renderQueue->namedScope("shadowmap pass");
1082-
renderPass(RenderModeEnum::Shadowmap);
1083-
}
1084-
1085-
renderQueue->resetFrameBuffer();
1086-
renderQueue->resetAllTextures();
1087-
renderQueue->checkGlErrorDebug();
1088-
}
1089-
}
1090-
10911056
void prepareCameraLights()
10921057
{
10931058
ProfilingScope profiling("prepare lights");
@@ -1120,10 +1085,12 @@ namespace cage
11201085
std::vector<UniShadowedLight> shadows;
11211086
uint32 tex2dCount = 0, texCubeCount = 0;
11221087
shadows.reserve(CAGE_SHADER_MAX_SHADOWMAPSCUBE + CAGE_SHADER_MAX_SHADOWMAPS2D);
1123-
for (auto &[e, sh_] : data->shadowmaps)
1088+
for (auto &sh_ : data->shadowmaps)
11241089
{
11251090
CAGE_ASSERT(sh_->shadowmap);
11261091
ShadowmapData &sh = *sh_->shadowmap;
1092+
if (sh.cascade != 0)
1093+
continue;
11271094
if (sh.lightComponent.lightType == LightTypeEnum::Point)
11281095
{
11291096
if (texCubeCount == CAGE_SHADER_MAX_SHADOWMAPSCUBE)
@@ -1375,66 +1342,6 @@ namespace cage
13751342
}
13761343
}
13771344

1378-
Holder<AsyncTask> prepareShadowmap(Entity *e, const LightComponent &lc, const ShadowmapComponent &sc)
1379-
{
1380-
CAGE_ASSERT(e->id() != 0); // lights with shadowmap may not be anonymous
1381-
1382-
Holder<RenderPipelineImpl> data = systemMemory().createHolder<RenderPipelineImpl>(this);
1383-
this->data->shadowmaps[e] = data.share();
1384-
1385-
data->name = Stringizer() + name + "_shadowmap_" + e->id();
1386-
data->shadowmap = ShadowmapData();
1387-
ShadowmapData &shadowmap = *data->shadowmap;
1388-
shadowmap.lightComponent = lc;
1389-
shadowmap.shadowmapComponent = sc;
1390-
data->resolution = Vec2i(sc.resolution);
1391-
data->model = modelTransform(e);
1392-
data->transform = Transform(Vec3(data->model * Vec4(0, 0, 0, 1)));
1393-
data->view = inverse(data->model);
1394-
data->projection = [&]()
1395-
{
1396-
switch (lc.lightType)
1397-
{
1398-
case LightTypeEnum::Directional:
1399-
return orthographicProjection(-sc.directionalWorldSize, sc.directionalWorldSize, -sc.directionalWorldSize, sc.directionalWorldSize, -sc.directionalWorldSize, sc.directionalWorldSize);
1400-
case LightTypeEnum::Spot:
1401-
return perspectiveProjection(lc.spotAngle, 1, lc.minDistance, lc.maxDistance);
1402-
case LightTypeEnum::Point:
1403-
return perspectiveProjection(Degs(90), 1, lc.minDistance, lc.maxDistance);
1404-
default:
1405-
CAGE_THROW_CRITICAL(Exception, "invalid light type");
1406-
}
1407-
}();
1408-
data->viewProj = data->projection * data->view;
1409-
data->frustum = Frustum(data->viewProj);
1410-
static constexpr Mat4 bias = Mat4(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0.5, 0, 0.5, 0.5, 0.5, 1);
1411-
shadowmap.shadowUni.shadowMat[0] = bias * data->viewProj;
1412-
1413-
{
1414-
const String name = Stringizer() + data->name + "_" + data->resolution;
1415-
shadowmap.shadowTexture = provisionalGraphics->texture(name, shadowmap.lightComponent.lightType == LightTypeEnum::Point ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D_ARRAY,
1416-
[resolution = data->resolution, lightType = shadowmap.lightComponent.lightType](Texture *t)
1417-
{
1418-
if (lightType == LightTypeEnum::Point)
1419-
t->initialize(Vec3i(resolution, 1), 1, GL_DEPTH_COMPONENT16);
1420-
else
1421-
t->initialize(Vec3i(resolution, CAGE_SHADER_MAX_SHADOWMAPSCASCADES), 1, GL_DEPTH_COMPONENT24);
1422-
t->filters(GL_LINEAR, GL_LINEAR, 16);
1423-
t->wraps(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
1424-
});
1425-
}
1426-
1427-
{
1428-
UniShadowedLight &uni = shadowmap.shadowUni;
1429-
(UniLight &)uni = initializeLightUni(data->model, lc, e->getOrDefault<ColorComponent>(), transform.position);
1430-
uni.shadowParams[2] = shadowmap.shadowmapComponent.normalOffsetScale;
1431-
uni.shadowParams[3] = shadowmap.shadowmapComponent.shadowFactor;
1432-
uni.params[0] += 1; // shadowed light type
1433-
}
1434-
1435-
return tasksRunAsync<RenderPipelineImpl>("render shadowmap task", [](RenderPipelineImpl &impl, uint32) { impl.taskShadowmap(); }, std::move(data));
1436-
}
1437-
14381345
Holder<RenderQueue> prepareCamera()
14391346
{
14401347
CAGE_ASSERT(!name.empty());
@@ -1447,7 +1354,7 @@ namespace cage
14471354
{
14481355
if (failedMask(e))
14491356
return;
1450-
tasks.push_back(prepareShadowmap(e, lc, sc));
1357+
prepareShadowmap(tasks, e, lc, sc);
14511358
},
14521359
+scene, false);
14531360
tasks.push_back(tasksRunAsync("render camera task", Delegate<void(uint32)>().bind<RenderPipelineImpl, &RenderPipelineImpl::taskCamera>(this)));
@@ -1472,11 +1379,166 @@ namespace cage
14721379

14731380
// ensure that shadowmaps are rendered before the camera
14741381
for (auto &shm : data->shadowmaps)
1475-
queue->enqueue(std::move(shm.second->renderQueue));
1382+
queue->enqueue(std::move(shm->renderQueue));
14761383

14771384
queue->enqueue(std::move(renderQueue));
14781385
return queue;
14791386
}
1387+
1388+
void taskShadowmap()
1389+
{
1390+
CAGE_ASSERT(!data);
1391+
CAGE_ASSERT(shadowmap);
1392+
1393+
renderQueue = newRenderQueue(name, provisionalGraphics);
1394+
const auto graphicsDebugScope = renderQueue->namedScope("shadowmap");
1395+
1396+
FrameBufferHandle renderTarget = provisionalGraphics->frameBufferDraw("renderTarget");
1397+
renderQueue->bind(renderTarget);
1398+
renderQueue->clearFrameBuffer(renderTarget);
1399+
renderQueue->depthTexture(renderTarget, shadowmap->shadowTexture, shadowmap->cascade);
1400+
renderQueue->activeAttachments(renderTarget, 0);
1401+
renderQueue->checkFrameBuffer(renderTarget);
1402+
renderQueue->viewport(Vec2i(), resolution);
1403+
renderQueue->colorWrite(false);
1404+
renderQueue->clear(false, true);
1405+
renderQueue->checkGlErrorDebug();
1406+
1407+
prepareProjection();
1408+
prepareEntities();
1409+
orderRenderData();
1410+
1411+
{
1412+
const auto graphicsDebugScope = renderQueue->namedScope("shadowmap pass");
1413+
renderPass(RenderModeEnum::Shadowmap);
1414+
}
1415+
1416+
renderQueue->resetFrameBuffer();
1417+
renderQueue->resetAllTextures();
1418+
renderQueue->checkGlErrorDebug();
1419+
}
1420+
1421+
Holder<RenderPipelineImpl> initializeShadowmapCommon(Entity *e, const LightComponent &lc, const ShadowmapComponent &sc)
1422+
{
1423+
CAGE_ASSERT(e->id() != 0); // lights with shadowmap may not be anonymous
1424+
1425+
Holder<RenderPipelineImpl> data = systemMemory().createHolder<RenderPipelineImpl>(this);
1426+
this->data->shadowmaps.push_back(data.share());
1427+
1428+
data->name = Stringizer() + name + "_shadowmap_" + e->id();
1429+
data->shadowmap = ShadowmapData();
1430+
ShadowmapData &shadowmap = *data->shadowmap;
1431+
shadowmap.lightComponent = lc;
1432+
shadowmap.shadowmapComponent = sc;
1433+
data->resolution = Vec2i(sc.resolution);
1434+
data->model = modelTransform(e);
1435+
data->transform = Transform(Vec3(data->model * Vec4(0, 0, 0, 1)));
1436+
1437+
{
1438+
UniShadowedLight &uni = shadowmap.shadowUni;
1439+
(UniLight &)uni = initializeLightUni(data->model, lc, e->getOrDefault<ColorComponent>(), transform.position);
1440+
uni.shadowParams[2] = sc.normalOffsetScale;
1441+
uni.shadowParams[3] = sc.shadowFactor;
1442+
uni.params[0] += 1; // shadowed light type
1443+
}
1444+
1445+
return data;
1446+
}
1447+
1448+
void finalizeShadowmapCascade()
1449+
{
1450+
CAGE_ASSERT(shadowmap->lightComponent.lightType == LightTypeEnum::Directional);
1451+
1452+
// todo modify for individual cascades
1453+
view = inverse(model);
1454+
1455+
{
1456+
const auto sc = shadowmap->shadowmapComponent;
1457+
projection = orthographicProjection(-sc.directionalWorldSize, sc.directionalWorldSize, -sc.directionalWorldSize, sc.directionalWorldSize, -sc.directionalWorldSize, sc.directionalWorldSize);
1458+
}
1459+
1460+
viewProj = projection * view;
1461+
frustum = Frustum(viewProj);
1462+
static constexpr Mat4 bias = Mat4(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0.5, 0, 0.5, 0.5, 0.5, 1);
1463+
shadowmap->shadowUni.shadowMat[shadowmap->cascade] = bias * viewProj;
1464+
}
1465+
1466+
void finalizeShadowmapSingle()
1467+
{
1468+
CAGE_ASSERT(shadowmap->cascade == 0);
1469+
1470+
view = inverse(model);
1471+
1472+
projection = [&]()
1473+
{
1474+
const auto lc = shadowmap->lightComponent;
1475+
switch (lc.lightType)
1476+
{
1477+
case LightTypeEnum::Spot:
1478+
return perspectiveProjection(lc.spotAngle, 1, lc.minDistance, lc.maxDistance);
1479+
case LightTypeEnum::Point:
1480+
return perspectiveProjection(Degs(90), 1, lc.minDistance, lc.maxDistance);
1481+
case LightTypeEnum::Directional:
1482+
default:
1483+
CAGE_THROW_CRITICAL(Exception, "invalid light type");
1484+
}
1485+
}();
1486+
1487+
viewProj = projection * view;
1488+
frustum = Frustum(viewProj);
1489+
static constexpr Mat4 bias = Mat4(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 0.5, 0, 0.5, 0.5, 0.5, 1);
1490+
shadowmap->shadowUni.shadowMat[shadowmap->cascade] = bias * viewProj;
1491+
}
1492+
1493+
void prepareShadowmap(std::vector<Holder<AsyncTask>> &outputTasks, Entity *e, const LightComponent &lc, const ShadowmapComponent &sc)
1494+
{
1495+
switch (lc.lightType)
1496+
{
1497+
case LightTypeEnum::Directional:
1498+
{
1499+
Holder<ProvisionalTexture> tex;
1500+
{
1501+
const String name = Stringizer() + this->name + "_shadowmap_" + e->id() + "_cascades_" + resolution;
1502+
tex = provisionalGraphics->texture(name, GL_TEXTURE_2D_ARRAY,
1503+
[resolution = sc.resolution](Texture *t)
1504+
{
1505+
t->initialize(Vec3i(resolution, resolution, CAGE_SHADER_MAX_SHADOWMAPSCASCADES), 1, GL_DEPTH_COMPONENT24);
1506+
t->filters(GL_LINEAR, GL_LINEAR, 16);
1507+
t->wraps(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
1508+
});
1509+
}
1510+
for (uint32 cascade = 0; cascade < CAGE_SHADER_MAX_SHADOWMAPSCASCADES; cascade++)
1511+
{
1512+
auto data = initializeShadowmapCommon(e, lc, sc);
1513+
data->shadowmap->cascade = cascade;
1514+
data->shadowmap->shadowTexture = tex.share();
1515+
data->finalizeShadowmapCascade();
1516+
outputTasks.push_back(tasksRunAsync<RenderPipelineImpl>("render shadowmap cascade", [](RenderPipelineImpl &impl, uint32) { impl.taskShadowmap(); }, std::move(data)));
1517+
}
1518+
break;
1519+
}
1520+
case LightTypeEnum::Spot:
1521+
case LightTypeEnum::Point:
1522+
{
1523+
auto data = initializeShadowmapCommon(e, lc, sc);
1524+
data->finalizeShadowmapSingle();
1525+
{
1526+
const String name = Stringizer() + data->name + "_" + resolution;
1527+
data->shadowmap->shadowTexture = provisionalGraphics->texture(name, data->shadowmap->lightComponent.lightType == LightTypeEnum::Point ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D_ARRAY,
1528+
[resolution = data->resolution, internalFormat = data->shadowmap->lightComponent.lightType == LightTypeEnum::Point ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT24](Texture *t)
1529+
{
1530+
t->initialize(Vec3i(resolution, 1), 1, internalFormat);
1531+
t->filters(GL_LINEAR, GL_LINEAR, 16);
1532+
t->wraps(GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE);
1533+
});
1534+
}
1535+
outputTasks.push_back(tasksRunAsync<RenderPipelineImpl>("render shadowmap single", [](RenderPipelineImpl &impl, uint32) { impl.taskShadowmap(); }, std::move(data)));
1536+
break;
1537+
}
1538+
default:
1539+
CAGE_THROW_CRITICAL(Exception, "invalid light type");
1540+
}
1541+
}
14801542
};
14811543
}
14821544

0 commit comments

Comments
 (0)