diff --git a/changes.txt b/changes.txt index 7b1d0dbe..2dd72643 100644 --- a/changes.txt +++ b/changes.txt @@ -1,5 +1,7 @@ -------------------------- Changes in 1.9 (not yet released) +- Fix bug that AnimatedMeshSceneNode ignored ReadOnlyMaterials flag when checking materials for transparent render passes. +- Unify checks if materials should use transparent render pass with new IVideoDriver::needsTransparentRenderPass function. - Material.ZWriteEnable is now of type E_ZWRITE instead of bool. This allows now setting materials to always "on" independent of material type and transparency. This breaks compiling. To have old values replace false with EZW_OFF and true with EWZ_AUTO. - Materials EMT_REFLECTION_2_LAYER and EMT_TRANSPARENT_REFLECTION_2_LAYER on OpenGL are now same as in D3D9. Before GL used a sphere-map for those instead of reflection. diff --git a/include/IVideoDriver.h b/include/IVideoDriver.h index c49c7428..dea34a3a 100644 --- a/include/IVideoDriver.h +++ b/include/IVideoDriver.h @@ -1317,7 +1317,7 @@ namespace video the E_MATERIAL_TYPE enum or a value which was returned by addMaterialRenderer(). \return Pointer to material renderer or null if not existing. */ - virtual IMaterialRenderer* getMaterialRenderer(u32 idx) =0; + virtual IMaterialRenderer* getMaterialRenderer(u32 idx) const = 0; //! Get amount of currently available material renderers. /** \return Amount of currently available material renderers. */ @@ -1523,6 +1523,9 @@ namespace video //! Check if the driver supports creating textures with the given color format /** \return True if the format is available, false if not. */ virtual bool queryTextureFormat(ECOLOR_FORMAT format) const = 0; + + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const = 0; }; } // end namespace video diff --git a/include/SMaterial.h b/include/SMaterial.h index 90f5c671..3661f7ee 100644 --- a/include/SMaterial.h +++ b/include/SMaterial.h @@ -475,7 +475,7 @@ namespace video //! Store the blend factors /** textureBlendFunc/textureBlendFuncSeparate functions should be used to write properly blending factors to this parameter. If you use EMT_ONETEXTURE_BLEND - type for this material, this field should be equal to MaterialTypeParam. */ + type for this material, this field should be equal to MaterialTypeParams. */ f32 BlendFactor; //! DEPRECATED. Will be removed after Irrlicht 1.9. Please use PolygonOffsetDepthBias instead. @@ -779,14 +779,9 @@ namespace video inline bool operator==(const SMaterial& b) const { return !(b!=*this); } - bool isTransparent() const + //! Check if material needs alpha blending + bool isAlphaBlendOperation() const { - if ( MaterialType==EMT_TRANSPARENT_ADD_COLOR || - MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL || - MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA || - MaterialType==EMT_TRANSPARENT_REFLECTION_2_LAYER ) - return true; - if (BlendOperation != EBO_NONE && BlendFactor != 0.f) { E_BLEND_FACTOR srcRGBFact = EBF_ZERO; @@ -804,6 +799,19 @@ namespace video return true; } } + return false; + } + + //! Check for some fixed-function transparent types. Still used internally, but might be deprecated soon. + //! You probably should not use this anymore, IVideoDriver::needsTransparentRenderPass is more useful in most situations + //! as it asks the material renders directly what they do with the material. + bool isTransparent() const + { + if ( MaterialType==EMT_TRANSPARENT_ADD_COLOR || + MaterialType==EMT_TRANSPARENT_ALPHA_CHANNEL || + MaterialType==EMT_TRANSPARENT_VERTEX_ALPHA || + MaterialType==EMT_TRANSPARENT_REFLECTION_2_LAYER ) + return true; return false; } diff --git a/source/Irrlicht/CAnimatedMeshSceneNode.cpp b/source/Irrlicht/CAnimatedMeshSceneNode.cpp index d8c8491d..fb992b49 100644 --- a/source/Irrlicht/CAnimatedMeshSceneNode.cpp +++ b/source/Irrlicht/CAnimatedMeshSceneNode.cpp @@ -149,7 +149,7 @@ void CAnimatedMeshSceneNode::buildFrameNr(u32 timeMs) void CAnimatedMeshSceneNode::OnRegisterSceneNode() { - if (IsVisible) + if (IsVisible && Mesh) { // because this node supports rendering of mixed mode meshes consisting of // transparent and solid material at the same time, we need to go through all @@ -163,12 +163,12 @@ void CAnimatedMeshSceneNode::OnRegisterSceneNode() int solidCount = 0; // count transparent and solid materials in this scene node - for (u32 i=0; igetMeshBufferCount() : Materials.size(); + for (u32 i=0; igetMaterialRenderer(Materials[i].MaterialType); + const video::SMaterial& material = ReadOnlyMaterials ? Mesh->getMeshBuffer(i)->getMaterial() : Materials[i]; - if ((rnd && rnd->isTransparent()) || Materials[i].isTransparent()) + if ( driver->needsTransparentRenderPass(Materials[i]) ) ++transparentCount; else ++solidCount; @@ -274,7 +274,7 @@ void CAnimatedMeshSceneNode::render() return; - bool isTransparentPass = + const bool isTransparentPass = SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; ++PassCount; @@ -329,8 +329,7 @@ void CAnimatedMeshSceneNode::render() { for (u32 i=0; igetMeshBufferCount(); ++i) { - video::IMaterialRenderer* rnd = driver->getMaterialRenderer(Materials[i].MaterialType); - bool transparent = (rnd && rnd->isTransparent()); + const bool transparent = driver->needsTransparentRenderPass(Materials[i]); // only render transparent buffer if this is the transparent render pass // and solid only in solid pass diff --git a/source/Irrlicht/CD3D9Driver.cpp b/source/Irrlicht/CD3D9Driver.cpp index e337c23a..03a45864 100644 --- a/source/Irrlicht/CD3D9Driver.cpp +++ b/source/Irrlicht/CD3D9Driver.cpp @@ -3580,6 +3580,11 @@ bool CD3D9Driver::queryTextureFormat(ECOLOR_FORMAT format) const return getD3DFormatFromColorFormat(format) != D3DFMT_UNKNOWN; } +bool CD3D9Driver::needsTransparentRenderPass(const irr::video::SMaterial& material) const +{ + return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation(); +} + u32 CD3D9Driver::getD3DBlend(E_BLEND_FACTOR factor) const { u32 r = 0; diff --git a/source/Irrlicht/CD3D9Driver.h b/source/Irrlicht/CD3D9Driver.h index b42d39e4..2ceed2ea 100644 --- a/source/Irrlicht/CD3D9Driver.h +++ b/source/Irrlicht/CD3D9Driver.h @@ -300,6 +300,9 @@ namespace video //! Check if the driver supports creating textures with the given color format virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_; + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + //! Get the current color format of the color buffer /** \return Color format of the color buffer as D3D color value. */ D3DFORMAT getD3DColorFormat() const; diff --git a/source/Irrlicht/CMeshSceneNode.cpp b/source/Irrlicht/CMeshSceneNode.cpp index def77d43..108711a4 100644 --- a/source/Irrlicht/CMeshSceneNode.cpp +++ b/source/Irrlicht/CMeshSceneNode.cpp @@ -52,7 +52,7 @@ CMeshSceneNode::~CMeshSceneNode() //! frame void CMeshSceneNode::OnRegisterSceneNode() { - if (IsVisible) + if (IsVisible && Mesh) { // because this node supports rendering of mixed mode meshes consisting of // transparent and solid material at the same time, we need to go through all @@ -66,41 +66,18 @@ void CMeshSceneNode::OnRegisterSceneNode() int solidCount = 0; // count transparent and solid materials in this scene node - if (ReadOnlyMaterials && Mesh) + const u32 numMaterials = ReadOnlyMaterials ? Mesh->getMeshBufferCount() : Materials.size(); + for (u32 i=0; igetMeshBuffer(i)->getMaterial() : Materials[i]; - for (u32 i=0; igetMeshBufferCount(); ++i) - { - scene::IMeshBuffer* mb = Mesh->getMeshBuffer(i); - video::IMaterialRenderer* rnd = mb ? driver->getMaterialRenderer(mb->getMaterial().MaterialType) : 0; + if ( driver->needsTransparentRenderPass(Materials[i]) ) + ++transparentCount; + else + ++solidCount; - if (rnd && rnd->isTransparent()) - ++transparentCount; - else - ++solidCount; - - if (solidCount && transparentCount) - break; - } - } - else - { - // count copied materials - - for (u32 i=0; igetMaterialRenderer(Materials[i].MaterialType); - - if ((rnd && rnd->isTransparent()) || Materials[i].isTransparent()) - ++transparentCount; - else - ++solidCount; - - if (solidCount && transparentCount) - break; - } + if (solidCount && transparentCount) + break; } // register according to material types counted @@ -124,7 +101,7 @@ void CMeshSceneNode::render() if (!Mesh || !driver) return; - bool isTransparentPass = + const bool isTransparentPass = SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; ++PassCount; @@ -165,8 +142,7 @@ void CMeshSceneNode::render() { const video::SMaterial& material = ReadOnlyMaterials ? mb->getMaterial() : Materials[i]; - video::IMaterialRenderer* rnd = driver->getMaterialRenderer(material.MaterialType); - bool transparent = (rnd && rnd->isTransparent()); + const bool transparent = driver->needsTransparentRenderPass(material); // only render transparent buffer if this is the transparent render pass // and solid only in solid pass diff --git a/source/Irrlicht/CNullDriver.cpp b/source/Irrlicht/CNullDriver.cpp index 06a7f97c..3c4d745c 100644 --- a/source/Irrlicht/CNullDriver.cpp +++ b/source/Irrlicht/CNullDriver.cpp @@ -2325,7 +2325,7 @@ void CNullDriver::deleteMaterialRenders() //! Returns pointer to material renderer or null -IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx) +IMaterialRenderer* CNullDriver::getMaterialRenderer(u32 idx) const { if ( idx < MaterialRenderers.size() ) return MaterialRenderers[idx].Renderer; @@ -2749,6 +2749,22 @@ core::dimension2du CNullDriver::getMaxTextureSize() const return core::dimension2du(0x10000,0x10000); // maybe large enough } +bool CNullDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const +{ + // TODO: I suspect it would be nice if the material had an enum for further control. + // Especially it probably makes sense to allow disabling transparent render pass as soon as material.ZWriteEnable is on. + // But then we might want an enum for the renderpass in material instead of just a transparency flag in material - and that's more work. + // Or we could at least set return false when material.ZWriteEnable is EZW_ON? Still considering that... + // Be careful - this function is deeply connected to getWriteZBuffer as transparent render passes are usually about rendering with + // zwrite disabled and getWriteZBuffer calls this function. + + video::IMaterialRenderer* rnd = getMaterialRenderer(material.MaterialType); + if (rnd && rnd->isTransparent()) + return true; + + return false; +} + //! Color conversion convenience function /** Convert an image (as array of pixels) from source to destination diff --git a/source/Irrlicht/CNullDriver.h b/source/Irrlicht/CNullDriver.h index ec2e095f..fa4d7279 100644 --- a/source/Irrlicht/CNullDriver.h +++ b/source/Irrlicht/CNullDriver.h @@ -533,7 +533,7 @@ namespace video s32 userData=0) _IRR_OVERRIDE_; //! Returns pointer to material renderer or null - virtual IMaterialRenderer* getMaterialRenderer(u32 idx) _IRR_OVERRIDE_; + virtual IMaterialRenderer* getMaterialRenderer(u32 idx) const _IRR_OVERRIDE_; //! Returns amount of currently available material renderers. virtual u32 getMaterialRendererCount() const _IRR_OVERRIDE_; @@ -667,6 +667,9 @@ namespace video //! Returns the maximum texture size supported. virtual core::dimension2du getMaxTextureSize() const _IRR_OVERRIDE_; + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + //! Color conversion convenience function /** Convert an image (as array of pixels) from source to destination array, thereby converting the color format. The pixel size is @@ -743,14 +746,14 @@ namespace video return (f32) getAverage ( p[(y * pitch) + x] ); } - inline bool getWriteZBuffer(const SMaterial&material) const + inline bool getWriteZBuffer(const SMaterial& material) const { switch ( material.ZWriteEnable ) { case video::EZW_OFF: return false; case video::EZW_AUTO: - return AllowZWriteOnTransparent || !material.isTransparent(); + return AllowZWriteOnTransparent || ! needsTransparentRenderPass(material); case video::EZW_ON: return true; } diff --git a/source/Irrlicht/COctreeSceneNode.cpp b/source/Irrlicht/COctreeSceneNode.cpp index c58fe390..16df1199 100644 --- a/source/Irrlicht/COctreeSceneNode.cpp +++ b/source/Irrlicht/COctreeSceneNode.cpp @@ -79,10 +79,7 @@ void COctreeSceneNode::OnRegisterSceneNode() // count transparent and solid materials in this scene node for (u32 i=0; igetMaterialRenderer(Materials[i].MaterialType); - - if ((rnd && rnd->isTransparent()) || Materials[i].isTransparent()) + if (driver->needsTransparentRenderPass(Materials[i])) ++transparentCount; else ++solidCount; @@ -145,7 +142,7 @@ void COctreeSceneNode::render() if (!camera) return; - bool isTransparentPass = + const bool isTransparentPass = SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; ++PassCount; @@ -188,8 +185,7 @@ void COctreeSceneNode::render() if ( 0 == d[i].CurrentSize ) continue; - const video::IMaterialRenderer* const rnd = driver->getMaterialRenderer(Materials[i].MaterialType); - const bool transparent = (rnd && rnd->isTransparent()); + const bool transparent = driver->needsTransparentRenderPass(Materials[i]); // only render transparent buffer if this is the transparent render pass // and solid only in solid pass diff --git a/source/Irrlicht/COpenGLDriver.cpp b/source/Irrlicht/COpenGLDriver.cpp index b69a832f..8d233c2c 100644 --- a/source/Irrlicht/COpenGLDriver.cpp +++ b/source/Irrlicht/COpenGLDriver.cpp @@ -3617,6 +3617,11 @@ bool COpenGLDriver::queryTextureFormat(ECOLOR_FORMAT format) const return getColorFormatParameters(format, dummyInternalFormat, dummyPixelFormat, dummyPixelType, &dummyConverter); } +bool COpenGLDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const +{ + return CNullDriver::needsTransparentRenderPass(material) || material.isAlphaBlendOperation(); +} + //! Only used by the internal engine. Used to notify the driver that //! the window was resized. void COpenGLDriver::OnResize(const core::dimension2d& size) diff --git a/source/Irrlicht/COpenGLDriver.h b/source/Irrlicht/COpenGLDriver.h index 071d188d..46a6ebbc 100644 --- a/source/Irrlicht/COpenGLDriver.h +++ b/source/Irrlicht/COpenGLDriver.h @@ -382,6 +382,9 @@ namespace video //! Check if the driver supports creating textures with the given color format virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_; + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + //! Convert E_PRIMITIVE_TYPE to OpenGL equivalent GLenum primitiveTypeToGL(scene::E_PRIMITIVE_TYPE type) const; diff --git a/source/Irrlicht/CSceneManager.cpp b/source/Irrlicht/CSceneManager.cpp index 4e42634f..0d1f7c9d 100644 --- a/source/Irrlicht/CSceneManager.cpp +++ b/source/Irrlicht/CSceneManager.cpp @@ -1377,9 +1377,7 @@ u32 CSceneManager::registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDE taken = 0; for (u32 i=0; igetMaterialRenderer(node->getMaterial(i).MaterialType); - if ((rnd && rnd->isTransparent()) || node->getMaterial(i).isTransparent()) + if (Driver->needsTransparentRenderPass(node->getMaterial(i))) { // register as transparent node TransparentNodeEntry e(node, camWorldPos); diff --git a/source/Irrlicht/CSoftwareDriver2.cpp b/source/Irrlicht/CSoftwareDriver2.cpp index 10a85e2e..43548107 100644 --- a/source/Irrlicht/CSoftwareDriver2.cpp +++ b/source/Irrlicht/CSoftwareDriver2.cpp @@ -178,7 +178,7 @@ void CBurningVideoDriver::setCurrentShader() bool zMaterialTest = Material.org.ZBuffer != ECFN_DISABLED && Material.org.ZWriteEnable != video::EZW_OFF && - getWriteZBuffer(Material.org); + ( AllowZWriteOnTransparent || !Material.org.isTransparent() ); EBurningFFShader shader = zMaterialTest ? ETR_TEXTURE_GOURAUD : ETR_TEXTURE_GOURAUD_NOZ; @@ -2381,6 +2381,11 @@ bool CBurningVideoDriver::queryTextureFormat(ECOLOR_FORMAT format) const return format == BURNINGSHADER_COLOR_FORMAT; } +bool CBurningVideoDriver::needsTransparentRenderPass(const irr::video::SMaterial& material) const +{ + return CNullDriver::needsTransparentRenderPass(material) || material.isTransparent(); +} + } // end namespace video } // end namespace irr diff --git a/source/Irrlicht/CSoftwareDriver2.h b/source/Irrlicht/CSoftwareDriver2.h index c9017306..3e9d2aaf 100644 --- a/source/Irrlicht/CSoftwareDriver2.h +++ b/source/Irrlicht/CSoftwareDriver2.h @@ -164,6 +164,9 @@ namespace video //! Check if the driver supports creating textures with the given color format virtual bool queryTextureFormat(ECOLOR_FORMAT format) const _IRR_OVERRIDE_; + //! Used by some SceneNodes to check if a material should be rendered in the transparent render pass + virtual bool needsTransparentRenderPass(const irr::video::SMaterial& material) const _IRR_OVERRIDE_; + IDepthBuffer * getDepthBuffer () { return DepthBuffer; } IStencilBuffer * getStencilBuffer () { return StencilBuffer; } diff --git a/tests/tests-last-passed-at.txt b/tests/tests-last-passed-at.txt index a62cf4c8..d47378ad 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 Thu Jan 02 15:17:55 2020 +Test suite pass at GMT Fri Jan 03 10:49:15 2020