@@ -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