diff --git a/src/graphics/stkmesh.hpp b/src/graphics/stkmesh.hpp index f4c246419..569331b96 100644 --- a/src/graphics/stkmesh.hpp +++ b/src/graphics/stkmesh.hpp @@ -63,12 +63,22 @@ core::vector3df getWindDir(); class STKMeshCommon { +protected: + bool m_culledForPlayerCam; + bool m_culledForShadowCam[4]; + bool m_culledForRSMCam; public: PtrVector MeshSolidMaterial[MAT_COUNT]; PtrVector TransparentMesh[TM_COUNT]; virtual void update() = 0; virtual bool glow() const = 0; virtual bool isImmediateDraw() const { return false; } + bool isCulledForPlayerCam() const { return m_culledForPlayerCam; } + void setCulledForPlayerCam(bool v) { m_culledForPlayerCam = v; } + bool isCulledForShadowCam(unsigned cascade) const { return m_culledForShadowCam[cascade]; } + void setCulledForShadowCam(unsigned cascade, bool v) { m_culledForShadowCam[cascade] = v; } + bool isCulledForRSMCam() const { return m_culledForRSMCam; } + void setCulledForRSMCam(bool v) { m_culledForRSMCam = v; } }; template diff --git a/src/graphics/stkscenemanager.cpp b/src/graphics/stkscenemanager.cpp index b1b9c8679..57721bf20 100644 --- a/src/graphics/stkscenemanager.cpp +++ b/src/graphics/stkscenemanager.cpp @@ -17,28 +17,23 @@ #include "utils/profiler.hpp" #include #include +#include static void FillInstances_impl(std::vector > InstanceList, InstanceData * InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, - size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &PolyCount) + size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &PolyCount, std::function cull_func) { // Should never be empty GLMesh *mesh = InstanceList.front().first; - - DrawElementsIndirectCommand &CurrentCommand = CommandBuffer[CommandBufferOffset++]; - CurrentCommand.baseVertex = mesh->vaoBaseVertex; - CurrentCommand.count = mesh->IndexCount; - CurrentCommand.firstIndex = mesh->vaoOffset / 2; - CurrentCommand.baseInstance = InstanceBufferOffset; - CurrentCommand.instanceCount = InstanceList.size(); - - PolyCount += InstanceList.size() * mesh->IndexCount / 3; + size_t InitialOffset = InstanceBufferOffset; for (unsigned i = 0; i < InstanceList.size(); i++) { auto &Tp = InstanceList[i]; - InstanceData &Instance = InstanceBuffer[InstanceBufferOffset++]; scene::ISceneNode *node = Tp.second; + if (cull_func(node)) + continue; + InstanceData &Instance = InstanceBuffer[InstanceBufferOffset++]; const core::matrix4 &mat = node->getAbsoluteTransformation(); const core::vector3df &Origin = mat.getTranslation(); const core::vector3df &Orientation = mat.getRotationDegrees(); @@ -55,26 +50,31 @@ FillInstances_impl(std::vector > Instan Instance.Texture = mesh->TextureHandles[0]; Instance.SecondTexture = mesh->TextureHandles[1]; } -} - - -static void -FillInstancesGlow_impl(std::vector > InstanceList, GlowInstanceData * InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, -size_t &InstanceBufferOffset, size_t &CommandBufferOffset) -{ - // Should never be empty - GLMesh *mesh = InstanceList.front().first; DrawElementsIndirectCommand &CurrentCommand = CommandBuffer[CommandBufferOffset++]; CurrentCommand.baseVertex = mesh->vaoBaseVertex; CurrentCommand.count = mesh->IndexCount; CurrentCommand.firstIndex = mesh->vaoOffset / 2; - CurrentCommand.baseInstance = InstanceBufferOffset; - CurrentCommand.instanceCount = InstanceList.size(); + CurrentCommand.baseInstance = InitialOffset; + CurrentCommand.instanceCount = InstanceBufferOffset - InitialOffset; + + PolyCount += (InstanceBufferOffset - InitialOffset) * mesh->IndexCount / 3; +} + + +static void +FillInstancesGlow_impl(std::vector > InstanceList, GlowInstanceData * InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, + size_t &InstanceBufferOffset, size_t &CommandBufferOffset, std::function cull_func) +{ + // Should never be empty + GLMesh *mesh = InstanceList.front().first; + size_t InitialOffset = InstanceBufferOffset; for (unsigned i = 0; i < InstanceList.size(); i++) { STKMeshSceneNode *node = dynamic_cast(InstanceList[i].second); + if (cull_func(node)) + continue; GlowInstanceData &Instance = InstanceBuffer[InstanceBufferOffset++]; const core::matrix4 &mat = node->getAbsoluteTransformation(); const core::vector3df &Origin = mat.getTranslation(); @@ -91,17 +91,25 @@ size_t &InstanceBufferOffset, size_t &CommandBufferOffset) Instance.Scale.Y = Scale.Y; Instance.Scale.Z = Scale.Z; } + + DrawElementsIndirectCommand &CurrentCommand = CommandBuffer[CommandBufferOffset++]; + CurrentCommand.baseVertex = mesh->vaoBaseVertex; + CurrentCommand.count = mesh->IndexCount; + CurrentCommand.firstIndex = mesh->vaoOffset / 2; + CurrentCommand.baseInstance = InitialOffset; + CurrentCommand.instanceCount = InstanceBufferOffset - InitialOffset; } static void FillInstances(const std::unordered_map > > &GatheredGLMesh, std::vector &InstancedList, - InstanceData *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &Polycount) + InstanceData *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &Polycount, + std::function cull_func) { auto It = GatheredGLMesh.begin(), E = GatheredGLMesh.end(); for (; It != E; ++It) { - FillInstances_impl(It->second, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, Polycount); + FillInstances_impl(It->second, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, Polycount, cull_func); if (!UserConfigParams::m_azdo) InstancedList.push_back(It->second.front().first); } @@ -109,13 +117,14 @@ void FillInstances(const std::unordered_map > > &GatheredGLMesh, std::vector &InstancedList, - InstanceData *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, const core::vector3df &dir, size_t &PolyCount) + InstanceData *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, const core::vector3df &dir, size_t &PolyCount, + std::function cull_func) { auto It = GatheredGLMesh.begin(), E = GatheredGLMesh.end(); SunLightProvider * const cb = (SunLightProvider *)irr_driver->getCallback(ES_SUNLIGHT); for (; It != E; ++It) { - FillInstances_impl(It->second, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, PolyCount); + FillInstances_impl(It->second, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, PolyCount, cull_func); if (!UserConfigParams::m_azdo) InstancedList.push_back(It->second.front().first); } @@ -142,37 +151,27 @@ bool isBoxInFrontOfPlane(const core::plane3df &plane, const core::vector3df edge static bool isCulled(const scene::ICameraSceneNode *cam, const scene::ISceneNode *node) { - // can be seen by a bounding box ? - if (node->getAutomaticCulling() & scene::EAC_BOX) - { - core::aabbox3d tbox = node->getBoundingBox(); - node->getAbsoluteTransformation().transformBoxEx(tbox); - return !(tbox.intersectsWithBox(cam->getViewFrustum()->getBoundingBox())); - } - - // can be seen by cam pyramid planes ? - if (node->getAutomaticCulling() & scene::EAC_FRUSTUM_BOX) - { - scene::SViewFrustum frust = *cam->getViewFrustum(); - - //transform the frustum to the node's current absolute transformation - core::matrix4 invTrans(node->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE); - //invTrans.makeInverse(); - frust.transform(invTrans); - - core::vector3df edges[8]; - node->getBoundingBox().getEdges(edges); - - for (s32 i = 0; i < scene::SViewFrustum::VF_PLANE_COUNT; ++i) - if (isBoxInFrontOfPlane(frust.planes[i], edges)) - return true; + if (!node->getAutomaticCulling()) return false; - } + + scene::SViewFrustum frust = *cam->getViewFrustum(); + + //transform the frustum to the node's current absolute transformation + core::matrix4 invTrans(node->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE); + //invTrans.makeInverse(); + frust.transform(invTrans); + + core::vector3df edges[8]; + node->getBoundingBox().getEdges(edges); + + for (s32 i = 0; i < scene::SViewFrustum::VF_PLANE_COUNT; ++i) + if (isBoxInFrontOfPlane(frust.planes[i], edges)) + return true; return false; } static void -handleSTKCommon(scene::ISceneNode *Node, std::vector *ImmediateDraw, bool IsCulledForSolid, bool IsCulledForShadow[4], bool IsCulledForRSM) +handleSTKCommon(scene::ISceneNode *Node, std::vector *ImmediateDraw) { STKMeshCommon *node = dynamic_cast(Node); if (!node) @@ -187,47 +186,19 @@ handleSTKCommon(scene::ISceneNode *Node, std::vector *Immed for (unsigned Mat = 0; Mat < MAT_COUNT; ++Mat) { GLMesh *mesh; - if (!IsCulledForSolid) + if (irr_driver->hasARB_draw_indirect()) { - if (irr_driver->hasARB_draw_indirect()) + for_in(mesh, node->MeshSolidMaterial[Mat]) { - for_in(mesh, node->MeshSolidMaterial[Mat]) - { - if (node->glow()) - MeshForGlowPass[mesh->mb].emplace_back(mesh, node); - - - if (Mat != MAT_SPLATTING && mesh->TextureMatrix.isIdentity()) - MeshForSolidPass[Mat][mesh->mb].emplace_back(mesh, Node); - else - { - core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; - ModelMatrix.getInverse(InvModelMatrix); - switch (Mat) - { - case MAT_DEFAULT: - ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; - case MAT_ALPHA_REF: - ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; - case MAT_UNLIT: - ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; - case MAT_SPLATTING: - ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix); - break; - } - } - } - } - else - { - core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; - ModelMatrix.getInverse(InvModelMatrix); - - for_in(mesh, node->MeshSolidMaterial[Mat]) + if (node->glow()) + MeshForGlowPass[mesh->mb].emplace_back(mesh, node); + + if (Mat != MAT_SPLATTING && mesh->TextureMatrix.isIdentity()) + MeshForSolidPass[Mat][mesh->mb].emplace_back(mesh, Node); + else { + core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; + ModelMatrix.getInverse(InvModelMatrix); switch (Mat) { case MAT_DEFAULT: @@ -236,93 +207,60 @@ handleSTKCommon(scene::ISceneNode *Node, std::vector *Immed case MAT_ALPHA_REF: ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); break; - case MAT_NORMAL_MAP: - ListMatNormalMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; - case MAT_DETAIL: - ListMatDetails::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; case MAT_UNLIT: ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); break; - case MAT_SPHEREMAP: - ListMatSphereMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; case MAT_SPLATTING: ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix); break; - case MAT_GRASS: - ListMatGrass::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir); - break; } } } } + else + { + core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; + ModelMatrix.getInverse(InvModelMatrix); + + for_in(mesh, node->MeshSolidMaterial[Mat]) + { + switch (Mat) + { + case MAT_DEFAULT: + ListMatDefault::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_ALPHA_REF: + ListMatAlphaRef::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_NORMAL_MAP: + ListMatNormalMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_DETAIL: + ListMatDetails::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_UNLIT: + ListMatUnlit::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPHEREMAP: + ListMatSphereMap::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPLATTING: + ListMatSplatting::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix); + break; + case MAT_GRASS: + ListMatGrass::getInstance()->SolidPass.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir); + break; + } + } + } if (!UserConfigParams::m_shadows) return; for (unsigned cascade = 0; cascade < 4; ++cascade) - { - if (!IsCulledForShadow[cascade]) - { - if (irr_driver->hasARB_draw_indirect()) - { - for_in(mesh, node->MeshSolidMaterial[Mat]) - MeshForShadowPass[cascade][Mat][mesh->mb].emplace_back(mesh, Node); - } - else - { - core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; - ModelMatrix.getInverse(InvModelMatrix); - - for_in(mesh, node->MeshSolidMaterial[Mat]) - { - switch (Mat) - { - case MAT_DEFAULT: - ListMatDefault::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; - case MAT_ALPHA_REF: - ListMatAlphaRef::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; - case MAT_NORMAL_MAP: - ListMatNormalMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; - case MAT_DETAIL: - ListMatDetails::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; - case MAT_UNLIT: - ListMatUnlit::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; - case MAT_SPHEREMAP: - ListMatSphereMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); - break; - case MAT_SPLATTING: - ListMatSplatting::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix); - break; - case MAT_GRASS: - ListMatGrass::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir); - } - } - } - } - } - if (!UserConfigParams::m_gi) - return; - if (!IsCulledForRSM) { if (irr_driver->hasARB_draw_indirect()) { for_in(mesh, node->MeshSolidMaterial[Mat]) - { - if (Mat != MAT_SPLATTING) - MeshForRSMPass[Mat][mesh->mb].emplace_back(mesh, Node); - else - { - core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; - ModelMatrix.getInverse(InvModelMatrix); - ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix); - } - } + MeshForShadowPass[cascade][Mat][mesh->mb].emplace_back(mesh, Node); } else { @@ -334,76 +272,122 @@ handleSTKCommon(scene::ISceneNode *Node, std::vector *Immed switch (Mat) { case MAT_DEFAULT: - ListMatDefault::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + ListMatDefault::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); break; case MAT_ALPHA_REF: - ListMatAlphaRef::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + ListMatAlphaRef::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); break; case MAT_NORMAL_MAP: - ListMatNormalMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + ListMatNormalMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); break; case MAT_DETAIL: - ListMatDetails::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + ListMatDetails::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); break; case MAT_UNLIT: - ListMatUnlit::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + ListMatUnlit::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); break; case MAT_SPHEREMAP: - ListMatSphereMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + ListMatSphereMap::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); break; case MAT_SPLATTING: - ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix); + ListMatSplatting::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix); break; case MAT_GRASS: - ListMatGrass::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir); - break; + ListMatGrass::getInstance()->Shadows[cascade].emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir); } } } } + if (!UserConfigParams::m_gi) + return; + if (irr_driver->hasARB_draw_indirect()) + { + for_in(mesh, node->MeshSolidMaterial[Mat]) + if (Mat != MAT_SPLATTING) + MeshForRSMPass[Mat][mesh->mb].emplace_back(mesh, Node); + else + { + core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; + ModelMatrix.getInverse(InvModelMatrix); + ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix); + } + } + else + { + core::matrix4 ModelMatrix = Node->getAbsoluteTransformation(), InvModelMatrix; + ModelMatrix.getInverse(InvModelMatrix); + + for_in(mesh, node->MeshSolidMaterial[Mat]) + { + switch (Mat) + { + case MAT_DEFAULT: + ListMatDefault::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_ALPHA_REF: + ListMatAlphaRef::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_NORMAL_MAP: + ListMatNormalMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_DETAIL: + ListMatDetails::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_UNLIT: + ListMatUnlit::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPHEREMAP: + ListMatSphereMap::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, mesh->TextureMatrix); + break; + case MAT_SPLATTING: + ListMatSplatting::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix); + break; + case MAT_GRASS: + ListMatGrass::getInstance()->RSM.emplace_back(mesh, ModelMatrix, InvModelMatrix, windDir); + break; + } + } + } } // Transparent - if (!IsCulledForSolid) + GLMesh *mesh; + if (World::getWorld() && World::getWorld()->isFogEnabled()) { - GLMesh *mesh; - if (World::getWorld() && World::getWorld()->isFogEnabled()) - { - const Track * const track = World::getWorld()->getTrack(); + const Track * const track = World::getWorld()->getTrack(); - // Todo : put everything in a ubo - const float fogmax = track->getFogMax(); - const float startH = track->getFogStartHeight(); - const float endH = track->getFogEndHeight(); - const float start = track->getFogStart(); - const float end = track->getFogEnd(); - const video::SColor tmpcol = track->getFogColor(); + // Todo : put everything in a ubo + const float fogmax = track->getFogMax(); + const float startH = track->getFogStartHeight(); + const float endH = track->getFogEndHeight(); + const float start = track->getFogStart(); + const float end = track->getFogEnd(); + const video::SColor tmpcol = track->getFogColor(); - video::SColorf col(tmpcol.getRed() / 255.0f, - tmpcol.getGreen() / 255.0f, - tmpcol.getBlue() / 255.0f); + video::SColorf col(tmpcol.getRed() / 255.0f, + tmpcol.getGreen() / 255.0f, + tmpcol.getBlue() / 255.0f); - for_in(mesh, node->TransparentMesh[TM_DEFAULT]) - pushVector(ListBlendTransparentFog::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, - fogmax, startH, endH, start, end, col); - for_in(mesh, node->TransparentMesh[TM_ADDITIVE]) - pushVector(ListAdditiveTransparentFog::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, - fogmax, startH, endH, start, end, col); - } - else - { - for_in(mesh, node->TransparentMesh[TM_DEFAULT]) - pushVector(ListBlendTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix); - for_in(mesh, node->TransparentMesh[TM_ADDITIVE]) - pushVector(ListAdditiveTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix); - } - for_in(mesh, node->TransparentMesh[TM_DISPLACEMENT]) - pushVector(ListDisplacement::getInstance(), mesh, Node->getAbsoluteTransformation()); + for_in(mesh, node->TransparentMesh[TM_DEFAULT]) + pushVector(ListBlendTransparentFog::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, + fogmax, startH, endH, start, end, col); + for_in(mesh, node->TransparentMesh[TM_ADDITIVE]) + pushVector(ListAdditiveTransparentFog::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix, + fogmax, startH, endH, start, end, col); } + else + { + for_in(mesh, node->TransparentMesh[TM_DEFAULT]) + pushVector(ListBlendTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix); + for_in(mesh, node->TransparentMesh[TM_ADDITIVE]) + pushVector(ListAdditiveTransparent::getInstance(), mesh, Node->getAbsoluteTransformation(), mesh->TextureMatrix); + } + for_in(mesh, node->TransparentMesh[TM_DISPLACEMENT]) + pushVector(ListDisplacement::getInstance(), mesh, Node->getAbsoluteTransformation()); } static void parseSceneManager(core::list List, std::vector *ImmediateDraw, - scene::ICameraSceneNode* cam, scene::ICameraSceneNode *shadowCams[4], scene::ICameraSceneNode *RSM_cam) + scene::ICameraSceneNode* cam) { core::list::Iterator I = List.begin(), E = List.end(); for (; I != E; ++I) @@ -414,27 +398,16 @@ parseSceneManager(core::list List, std::vectorupdateAbsolutePosition(); - bool IsCulledForSolid = isCulled(cam, *I); - - bool IsCulledForShadow[4]; - for (unsigned i = 0; i < 4; ++i) - IsCulledForShadow[i] = isCulled(shadowCams[i], *I); - - bool IsCulledForRSM = isCulled(RSM_cam, *I); - - if (!IsCulledForSolid) + if (ParticleSystemProxy *node = dynamic_cast(*I)) { - if (ParticleSystemProxy *node = dynamic_cast(*I)) - { - if (node->update()) - ParticlesList::getInstance()->push_back(node); - continue; - } + if (!isCulled(cam, *I) && node->update()) + ParticlesList::getInstance()->push_back(node); + continue; } - handleSTKCommon(*I, ImmediateDraw, IsCulledForSolid, IsCulledForShadow, IsCulledForRSM); + handleSTKCommon(*I, ImmediateDraw); - parseSceneManager((*I)->getChildren(), ImmediateDraw, cam, shadowCams, RSM_cam); + parseSceneManager((*I)->getChildren(), ImmediateDraw, cam); } } @@ -442,9 +415,10 @@ template static void GenDrawCalls(unsigned cascade, std::vector &InstancedList, InstanceData *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, size_t &PolyCount) { + std::function shadowculling = [&](const scene::ISceneNode *nd) {return dynamic_cast(nd)->isCulledForShadowCam(cascade); }; if (irr_driver->hasARB_draw_indirect()) ShadowPassCmd::getInstance()->Offset[cascade][Mat] = CommandBufferOffset; // Store command buffer offset - FillInstances(MeshForShadowPass[cascade][Mat], InstancedList, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, PolyCount); + FillInstances(MeshForShadowPass[cascade][Mat], InstancedList, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, PolyCount, shadowculling); if (UserConfigParams::m_azdo) ShadowPassCmd::getInstance()->Size[cascade][Mat] = CommandBufferOffset - ShadowPassCmd::getInstance()->Offset[cascade][Mat]; } @@ -453,9 +427,10 @@ template static void GenDrawCallsGrass(unsigned cascade, std::vector &InstancedList, InstanceData *InstanceBuffer, DrawElementsIndirectCommand *CommandBuffer, size_t &InstanceBufferOffset, size_t &CommandBufferOffset, const core::vector3df &dir, size_t &PolyCount) { + std::function shadowculling = [&](const scene::ISceneNode *nd) {return dynamic_cast(nd)->isCulledForShadowCam(cascade); }; if (irr_driver->hasARB_draw_indirect()) ShadowPassCmd::getInstance()->Offset[cascade][Mat] = CommandBufferOffset; // Store command buffer offset - FillInstancesGrass(MeshForShadowPass[cascade][Mat], InstancedList, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, dir, PolyCount); + FillInstancesGrass(MeshForShadowPass[cascade][Mat], InstancedList, InstanceBuffer, CommandBuffer, InstanceBufferOffset, CommandBufferOffset, dir, PolyCount, shadowculling); if (UserConfigParams::m_azdo) ShadowPassCmd::getInstance()->Size[cascade][Mat] = CommandBufferOffset - ShadowPassCmd::getInstance()->Offset[cascade][Mat]; } @@ -493,7 +468,20 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode) DeferredUpdate.clear(); core::list List = m_scene_manager->getRootSceneNode()->getChildren(); - parseSceneManager(List, ImmediateDrawList::getInstance(), camnode, m_shadow_camnodes, m_suncam); + parseSceneManager(List, ImmediateDrawList::getInstance(), camnode); + +#pragma omp parallel for + for (int i = 0; i < (int)DeferredUpdate.size(); i++) + { + scene::ISceneNode *node = dynamic_cast(DeferredUpdate[i]); + DeferredUpdate[i]->setCulledForPlayerCam(isCulled(camnode, node)); + DeferredUpdate[i]->setCulledForRSMCam(isCulled(m_suncam, node)); + DeferredUpdate[i]->setCulledForShadowCam(0, isCulled(m_shadow_camnodes[0], node)); + DeferredUpdate[i]->setCulledForShadowCam(1, isCulled(m_shadow_camnodes[1], node)); + DeferredUpdate[i]->setCulledForShadowCam(2, isCulled(m_shadow_camnodes[2], node)); + DeferredUpdate[i]->setCulledForShadowCam(3, isCulled(m_shadow_camnodes[3], node)); + } + // Add a 1 s timeout if (!m_sync) m_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); @@ -553,6 +541,8 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode) size_t SolidPoly = 0, ShadowPoly = 0, MiscPoly = 0; PROFILER_PUSH_CPU_MARKER("- Draw Command upload", 0xFF, 0x0, 0xFF); + + auto playercamculling = [](const scene::ISceneNode *nd) {return dynamic_cast(nd)->isCulledForPlayerCam(); }; #pragma omp parallel sections { #pragma omp section @@ -566,34 +556,35 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode) CmdBuffer = (DrawElementsIndirectCommand*)glMapBufferRange(GL_DRAW_INDIRECT_BUFFER, 0, 10000 * sizeof(DrawElementsIndirectCommand), GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | GL_MAP_INVALIDATE_BUFFER_BIT); } + // Default Material SolidPassCmd::getInstance()->Offset[MAT_DEFAULT] = current_cmd; - FillInstances(MeshForSolidPass[MAT_DEFAULT], ListInstancedMatDefault::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly); + FillInstances(MeshForSolidPass[MAT_DEFAULT], ListInstancedMatDefault::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); SolidPassCmd::getInstance()->Size[MAT_DEFAULT] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_DEFAULT]; // Alpha Ref SolidPassCmd::getInstance()->Offset[MAT_ALPHA_REF] = current_cmd; - FillInstances(MeshForSolidPass[MAT_ALPHA_REF], ListInstancedMatAlphaRef::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly); + FillInstances(MeshForSolidPass[MAT_ALPHA_REF], ListInstancedMatAlphaRef::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); SolidPassCmd::getInstance()->Size[MAT_ALPHA_REF] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_ALPHA_REF]; // Unlit SolidPassCmd::getInstance()->Offset[MAT_UNLIT] = current_cmd; - FillInstances(MeshForSolidPass[MAT_UNLIT], ListInstancedMatUnlit::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly); + FillInstances(MeshForSolidPass[MAT_UNLIT], ListInstancedMatUnlit::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); SolidPassCmd::getInstance()->Size[MAT_UNLIT] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_UNLIT]; // Spheremap SolidPassCmd::getInstance()->Offset[MAT_SPHEREMAP] = current_cmd; - FillInstances(MeshForSolidPass[MAT_SPHEREMAP], ListInstancedMatSphereMap::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly); + FillInstances(MeshForSolidPass[MAT_SPHEREMAP], ListInstancedMatSphereMap::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); SolidPassCmd::getInstance()->Size[MAT_SPHEREMAP] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_SPHEREMAP]; // Detail SolidPassCmd::getInstance()->Offset[MAT_DETAIL] = current_cmd; - FillInstances(MeshForSolidPass[MAT_DETAIL], ListInstancedMatDetails::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly); + FillInstances(MeshForSolidPass[MAT_DETAIL], ListInstancedMatDetails::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); SolidPassCmd::getInstance()->Size[MAT_DETAIL] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_DETAIL]; // Normal Map SolidPassCmd::getInstance()->Offset[MAT_NORMAL_MAP] = current_cmd; - FillInstances(MeshForSolidPass[MAT_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly); + FillInstances(MeshForSolidPass[MAT_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, SolidPoly, playercamculling); SolidPassCmd::getInstance()->Size[MAT_NORMAL_MAP] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_NORMAL_MAP]; // Grass SolidPassCmd::getInstance()->Offset[MAT_GRASS] = current_cmd; - FillInstancesGrass(MeshForSolidPass[MAT_GRASS], ListInstancedMatGrass::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, windDir, SolidPoly); + FillInstancesGrass(MeshForSolidPass[MAT_GRASS], ListInstancedMatGrass::getInstance()->SolidPass, InstanceBuffer, CmdBuffer, offset, current_cmd, windDir, SolidPoly, playercamculling); SolidPassCmd::getInstance()->Size[MAT_GRASS] = current_cmd - SolidPassCmd::getInstance()->Offset[MAT_GRASS]; if (!irr_driver->hasBufferStorageExtension()) @@ -621,7 +612,7 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode) auto It = MeshForGlowPass.begin(), E = MeshForGlowPass.end(); for (; It != E; ++It) { - FillInstancesGlow_impl(It->second, GlowInstanceBuffer, GlowCmdBuffer, offset, current_cmd); + FillInstancesGlow_impl(It->second, GlowInstanceBuffer, GlowCmdBuffer, offset, current_cmd, playercamculling); if (!UserConfigParams::m_azdo) ListInstancedGlow::getInstance()->push_back(It->second.front().first); } @@ -673,6 +664,7 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode) } #pragma omp section { + auto rsmcamculling = [](const scene::ISceneNode *nd) {return dynamic_cast(nd)->isCulledForRSMCam(); }; size_t offset = 0, current_cmd = 0; if (!irr_driver->hasBufferStorageExtension()) { @@ -684,23 +676,23 @@ void IrrDriver::PrepareDrawCalls(scene::ICameraSceneNode *camnode) // Default Material RSMPassCmd::getInstance()->Offset[MAT_DEFAULT] = current_cmd; - FillInstances(MeshForRSMPass[MAT_DEFAULT], ListInstancedMatDefault::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly); + FillInstances(MeshForRSMPass[MAT_DEFAULT], ListInstancedMatDefault::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling); RSMPassCmd::getInstance()->Size[MAT_DEFAULT] = current_cmd - RSMPassCmd::getInstance()->Offset[MAT_DEFAULT]; // Alpha Ref RSMPassCmd::getInstance()->Offset[MAT_ALPHA_REF] = current_cmd; - FillInstances(MeshForRSMPass[MAT_ALPHA_REF], ListInstancedMatAlphaRef::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly); + FillInstances(MeshForRSMPass[MAT_ALPHA_REF], ListInstancedMatAlphaRef::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling); RSMPassCmd::getInstance()->Size[MAT_ALPHA_REF] = current_cmd - RSMPassCmd::getInstance()->Offset[MAT_ALPHA_REF]; // Unlit RSMPassCmd::getInstance()->Offset[MAT_UNLIT] = current_cmd; - FillInstances(MeshForRSMPass[MAT_UNLIT], ListInstancedMatUnlit::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly); + FillInstances(MeshForRSMPass[MAT_UNLIT], ListInstancedMatUnlit::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling); RSMPassCmd::getInstance()->Size[MAT_UNLIT] = current_cmd - RSMPassCmd::getInstance()->Offset[MAT_UNLIT]; // Detail RSMPassCmd::getInstance()->Offset[MAT_DETAIL] = current_cmd; - FillInstances(MeshForRSMPass[MAT_DETAIL], ListInstancedMatDetails::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly); + FillInstances(MeshForRSMPass[MAT_DETAIL], ListInstancedMatDetails::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling); RSMPassCmd::getInstance()->Size[MAT_DETAIL] = current_cmd - RSMPassCmd::getInstance()->Offset[MAT_DETAIL]; // Normal Map RSMPassCmd::getInstance()->Offset[MAT_NORMAL_MAP] = current_cmd; - FillInstances(MeshForRSMPass[MAT_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly); + FillInstances(MeshForRSMPass[MAT_NORMAL_MAP], ListInstancedMatNormalMap::getInstance()->RSM, RSMInstanceBuffer, RSMCmdBuffer, offset, current_cmd, MiscPoly, rsmcamculling); RSMPassCmd::getInstance()->Size[MAT_NORMAL_MAP] = current_cmd - RSMPassCmd::getInstance()->Offset[MAT_NORMAL_MAP]; if (!irr_driver->hasBufferStorageExtension())