diff --git a/changes.txt b/changes.txt index 1e862545..62be9e55 100644 --- a/changes.txt +++ b/changes.txt @@ -1,6 +1,7 @@ -------------------------- Changes in 1.9 (not yet released) +- Add options for transparency node sorting algorithm - CImageWriterPNG now also supports the writeImageToFile param to allow setting compressing level. 0 stays default, 1-10 for range increasing compression level. - Add io::IUserData which can be set in SMaterial to make it easer passing additional material values to shaders - Add lens shift support for the camera and the perspective projection functions diff --git a/include/ISceneManager.h b/include/ISceneManager.h index fab9a7ed..60c325d5 100644 --- a/include/ISceneManager.h +++ b/include/ISceneManager.h @@ -97,7 +97,32 @@ namespace scene //! Drawn after transparent effect nodes. For custom gui's. Unsorted (in order nodes registered themselves). ESNRP_GUI = 128 + }; + //! Enumeration for sorting transparent nodes + /** Sorting used for nodes with ESNRP_TRANSPARENT or ESNRP_AUTOMATIC+transparency. + Also used for ESNRP_TRANSPARENT_EFFECT nodes (in an independent array) + Transparent nodes are always drawn back to front based on distance to camera. + This enum controls which points are used for the distance. */ + enum E_TRANSPARENT_NODE_SORTING + { + //! Don't sort, but draw in the order in which nodes registered themselves for rendering + //! By default this is the order in which nodes are in the scenegraph + //! Which can be used to do some custom sorting via scene-graph (mainly useful if you only have to that once) + ETNS_NONE, + + //! Distance from node origin to camera + ETNS_ORIGIN, + + //! Distance from node center to camera + ETNS_CENTER, + + //! Distance from the nearest of the 2 transformed bounding-box extend corners to camera + ETNS_BBOX_EXTENTS, + + //! Default sorting Irrlicht uses currently + //! This may change in the future + ETNS_DEFAULT = ETNS_CENTER }; class IAnimatedMesh; @@ -1676,6 +1701,12 @@ namespace scene //! Set current render pass. virtual void setCurrentRenderPass(E_SCENE_NODE_RENDER_PASS nextPass) =0; + //! Get current node sorting algorithm used for transparent nodes + virtual E_TRANSPARENT_NODE_SORTING getTransparentNodeSorting() const = 0; + + //! Set the node sorting algorithm used for transparent nodes + virtual void setTransparentNodeSorting(E_TRANSPARENT_NODE_SORTING sorting) = 0; + //! Get an instance of a geometry creator. /** The geometry creator provides some helper methods to create various types of basic geometry. This can be useful for custom scene nodes. */ diff --git a/source/Irrlicht/CSceneManager.cpp b/source/Irrlicht/CSceneManager.cpp index 93dd9199..ef789190 100644 --- a/source/Irrlicht/CSceneManager.cpp +++ b/source/Irrlicht/CSceneManager.cpp @@ -230,6 +230,8 @@ CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, // root node's scene manager SceneManager = this; + setTransparentNodeSorting(ETNS_DEFAULT); + if (Driver) Driver->grab(); @@ -1362,14 +1364,14 @@ u32 CSceneManager::registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDE case ESNRP_TRANSPARENT: if (!isCulled(node)) { - TransparentNodeList.push_back(TransparentNodeEntry(node, camWorldPos)); + TransparentNodeList.push_back(TransparentNodeEntry(node, funcTransparentNodeDistance(node, camWorldPos))); taken = 1; } break; case ESNRP_TRANSPARENT_EFFECT: if (!isCulled(node)) { - TransparentEffectNodeList.push_back(TransparentNodeEntry(node, camWorldPos)); + TransparentEffectNodeList.push_back(TransparentNodeEntry(node, funcTransparentNodeDistance(node, camWorldPos))); taken = 1; } break; @@ -1384,7 +1386,7 @@ u32 CSceneManager::registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDE if (Driver->needsTransparentRenderPass(node->getMaterial(i))) { // register as transparent node - TransparentNodeEntry e(node, camWorldPos); + TransparentNodeEntry e(node, funcTransparentNodeDistance(node, camWorldPos)); TransparentNodeList.push_back(e); taken = 1; break; @@ -1664,7 +1666,8 @@ void CSceneManager::drawAll() CurrentRenderPass = ESNRP_TRANSPARENT; Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); - TransparentNodeList.sort(); // sort by distance from camera + if ( TransparentNodeSorting != ETNS_NONE ) + TransparentNodeList.sort(); // sort by distance from camera if (LightManager) { LightManager->OnRenderPassPreRender(CurrentRenderPass); @@ -1698,7 +1701,8 @@ void CSceneManager::drawAll() CurrentRenderPass = ESNRP_TRANSPARENT_EFFECT; Driver->getOverrideMaterial().Enabled = ((Driver->getOverrideMaterial().EnablePasses & CurrentRenderPass) != 0); - TransparentEffectNodeList.sort(); // sort by distance from camera + if ( TransparentNodeSorting != ETNS_NONE ) + TransparentEffectNodeList.sort(); // sort by distance from camera if (LightManager) { @@ -2191,6 +2195,70 @@ E_SCENE_NODE_RENDER_PASS CSceneManager::getSceneNodeRenderPass() const return CurrentRenderPass; } +// Not sorting this later +static f32 transparentSortingNone(const ISceneNode* node, const core::vector3df& camera) +{ + return 0.f; +} + +// Distance from node origin to camera +static f32 transparentSortingByOrigin(const ISceneNode* node, const core::vector3df& camera) +{ + return node->getAbsolutePosition().getDistanceFromSQ(camera); +} + +// Distance from node center to camera +static f32 transparentSortingByCenter(const ISceneNode* node, const core::vector3df& camera) +{ + core::vector3df center = node->getBoundingBox().getCenter(); + const core::matrix4& absMat = node->getAbsoluteTransformation(); + absMat.rotateVect(center); + return (absMat.getTranslation()+center).getDistanceFromSQ(camera); +} + +/* +const core::aabbox3d box = Node->getTransformedBoundingBox(); +Distance = core::min_(camera.getDistanceFromSQ(box.MinEdge), camera.getDistanceFromSQ(box.MaxEdge)); +*/ +static f32 transparentSortingBBoxExtents(const ISceneNode* node, const core::vector3df& camera) +{ + const core::aabbox3d& box = node->getBoundingBox(); + const f32* m = node->getAbsoluteTransformation().pointer(); + + f32 p[4]; + p[0] = camera.X - (box.MinEdge.X * m[0] + box.MinEdge.Y * m[4] + box.MinEdge.Z * m[8] + m[12]); + p[1] = camera.Y - (box.MinEdge.X * m[1] + box.MinEdge.Y * m[5] + box.MinEdge.Z * m[9] + m[13]); + p[2] = camera.Z - (box.MinEdge.X * m[2] + box.MinEdge.Y * m[6] + box.MinEdge.Z * m[10] + m[14]); + f32 l0 = (p[0] * p[0]) + (p[1] * p[1]) + (p[2] * p[2]); + + p[0] = camera.X - (box.MaxEdge.X * m[0] + box.MaxEdge.Y * m[4] + box.MaxEdge.Z * m[8] + m[12]); + p[1] = camera.Y - (box.MaxEdge.X * m[1] + box.MaxEdge.Y * m[5] + box.MaxEdge.Z * m[9] + m[13]); + p[2] = camera.Z - (box.MaxEdge.X * m[2] + box.MaxEdge.Y * m[6] + box.MaxEdge.Z * m[10] + m[14]); + f32 l1 = (p[0] * p[0]) + (p[1] * p[1]) + (p[2] * p[2]); + return core::min_(l0, l1); +} + +void CSceneManager::setTransparentNodeSorting(E_TRANSPARENT_NODE_SORTING sorting) +{ + TransparentNodeSorting = sorting; + switch ( TransparentNodeSorting ) + { + case ETNS_NONE: + funcTransparentNodeDistance = transparentSortingNone; + break; + case ETNS_ORIGIN: + funcTransparentNodeDistance = transparentSortingByOrigin; + break; + case ETNS_CENTER: + funcTransparentNodeDistance = transparentSortingByCenter; + break; + case ETNS_BBOX_EXTENTS: + funcTransparentNodeDistance = transparentSortingBBoxExtents; + break; + default: + break; + } +} //! Returns an interface to the mesh cache which is shared between all existing scene managers. IMeshCache* CSceneManager::getMeshCache() diff --git a/source/Irrlicht/CSceneManager.h b/source/Irrlicht/CSceneManager.h index 8d3e83be..3bf83be2 100644 --- a/source/Irrlicht/CSceneManager.h +++ b/source/Irrlicht/CSceneManager.h @@ -445,6 +445,16 @@ namespace scene //! Returns current render pass. virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const IRR_OVERRIDE; + //! Get current node sorting algorithm used for transparent nodes + virtual E_TRANSPARENT_NODE_SORTING getTransparentNodeSorting() const IRR_OVERRIDE + { + return TransparentNodeSorting; + } + + //! Set the node sorting algorithm used for transparent nodes + virtual void setTransparentNodeSorting(E_TRANSPARENT_NODE_SORTING sorting) IRR_OVERRIDE; + + //! Creates a new scene manager. virtual ISceneManager* createNewSceneManager(bool cloneContent) IRR_OVERRIDE; @@ -567,37 +577,13 @@ namespace scene void* TextureValue; }; - /* - const core::aabbox3d box = Node->getTransformedBoundingBox(); - Distance = core::min_(camera.getDistanceFromSQ(box.MinEdge), camera.getDistanceFromSQ(box.MaxEdge)); - */ - static inline f32 estimatedSphereDistance(const ISceneNode* node, const core::vector3df& camera) - { - const core::aabbox3d& box = node->getBoundingBox(); - const f32* m = node->getAbsoluteTransformation().pointer(); - - f32 p[4]; - p[0] = camera.X - (box.MinEdge.X * m[0] + box.MinEdge.Y * m[4] + box.MinEdge.Z * m[8] + m[12]); - p[1] = camera.Y - (box.MinEdge.X * m[1] + box.MinEdge.Y * m[5] + box.MinEdge.Z * m[9] + m[13]); - p[2] = camera.Z - (box.MinEdge.X * m[2] + box.MinEdge.Y * m[6] + box.MinEdge.Z * m[10] + m[14]); - f32 l0 = (p[0] * p[0]) + (p[1] * p[1]) + (p[2] * p[2]); - - p[0] = camera.X - (box.MaxEdge.X * m[0] + box.MaxEdge.Y * m[4] + box.MaxEdge.Z * m[8] + m[12]); - p[1] = camera.Y - (box.MaxEdge.X * m[1] + box.MaxEdge.Y * m[5] + box.MaxEdge.Z * m[9] + m[13]); - p[2] = camera.Z - (box.MaxEdge.X * m[2] + box.MaxEdge.Y * m[6] + box.MaxEdge.Z * m[10] + m[14]); - f32 l1 = (p[0] * p[0]) + (p[1] * p[1]) + (p[2] * p[2]); - return core::min_(l0, l1); - } - - //! sort on distance (center) to camera + //! Sort on distance to camera + //! Larger distances drawn first struct TransparentNodeEntry { - TransparentNodeEntry(ISceneNode* n, const core::vector3df& camera) - : Node(n) - { - //Distance = Node->getAbsoluteTransformation().getTranslation().getDistanceFromSQ(camera); - Distance = estimatedSphereDistance(n, camera); - } + TransparentNodeEntry(ISceneNode* n, const f32 distance) + : Node(n), Distance(distance) + {} bool operator < (const TransparentNodeEntry& other) const { @@ -682,6 +668,12 @@ namespace scene E_SCENE_NODE_RENDER_PASS CurrentRenderPass; + //! Algorithm used to sort transparent nodes + E_TRANSPARENT_NODE_SORTING TransparentNodeSorting; + //! Pointer to the actual algorithm to get the distance + // (Could be we have to pass more parameters for better results, like view normal) + f32 (*funcTransparentNodeDistance)(const ISceneNode* node, const core::vector3df& camera); + //! An optional callbacks manager to allow the user app finer control //! over the scene lighting and rendering. ILightManager* LightManager; diff --git a/tests/tests-last-passed-at.txt b/tests/tests-last-passed-at.txt index 7a936a53..61976c19 100644 --- a/tests/tests-last-passed-at.txt +++ b/tests/tests-last-passed-at.txt @@ -1,4 +1,4 @@ Tests finished. 72 tests of 72 passed. Compiled as DEBUG -Test suite pass at GMT Mon Nov 13 14:43:47 2023 +Test suite pass at GMT Wed Nov 22 14:39:17 2023