OGRECave/ogre-next

Shadow artifacts with point light and transparency

jwwalker opened this issue · 3 comments

System Information

  • Ogre Version: master branch commit [68a8cc7]
  • Operating System / Platform: macOS 13.6.7
  • RenderSystem: Metal
  • GPU: Radeon Pro 560X

Detailed description

When using a point light and an object that uses transparent mode, you see shadows where you shouldn't.

To reproduce, start with the ShadowMapFromCode sample, but add the line

#include <OgreHlmsPbsDatablock.h>

and replace this method:

    void ShadowMapFromCodeGameState::createScene01()
    {
        Ogre::SceneManager *sceneManager = mGraphicsSystem->getSceneManager();

        Ogre::v1::MeshPtr planeMeshV1 = Ogre::v1::MeshManager::getSingleton().createPlane(
            "Plane v1", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
            Ogre::Plane( Ogre::Vector3::UNIT_Y, 1.0f ), 50.0f, 50.0f, 1, 1, true, 1, 4.0f, 4.0f,
            Ogre::Vector3::UNIT_Z, Ogre::v1::HardwareBuffer::HBU_STATIC,
            Ogre::v1::HardwareBuffer::HBU_STATIC );

        Ogre::MeshPtr planeMesh = Ogre::MeshManager::getSingleton().createByImportingV1(
            "Plane", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, planeMeshV1.get(), true,
            true, true );

        {
            Ogre::Item *item = sceneManager->createItem( planeMesh, Ogre::SCENE_DYNAMIC );
            Ogre::SceneNode *sceneNode = sceneManager->getRootSceneNode( Ogre::SCENE_DYNAMIC )
                                             ->createChildSceneNode( Ogre::SCENE_DYNAMIC );
            sceneNode->setPosition( 0, -1, 0 );
            sceneNode->attachObject( item );
        }

        float armsLength = 2.5f;

        for( int i = 0; i < 4; ++i )
        {
            for( int j = 0; j < 4; ++j )
            {
                Ogre::Item *item = sceneManager->createItem(
                    "Cube_d.mesh", Ogre::ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME,
                    Ogre::SCENE_DYNAMIC );
				Ogre::SubItem* subItem = item->getSubItem( 0 );
				Ogre::HlmsDatablock* block = subItem->getDatablock();
				Ogre::HlmsPbsDatablock* pbsBlock = dynamic_cast<Ogre::HlmsPbsDatablock*>( block );
				if (pbsBlock != nullptr)
				{
					pbsBlock->setTransparency( 1.0f );
				}

                const size_t idx = static_cast<size_t>( i * 4 + j );

                mSceneNode[idx] = sceneManager->getRootSceneNode( Ogre::SCENE_DYNAMIC )
                                      ->createChildSceneNode( Ogre::SCENE_DYNAMIC );

                mSceneNode[idx]->setPosition( ( float( i ) - 1.5f ) * armsLength, 2.0f,
                                              ( float( j ) - 1.5f ) * armsLength );
                mSceneNode[idx]->setScale( 0.65f, 0.65f, 0.65f );

                mSceneNode[idx]->roll( Ogre::Radian( (Ogre::Real)idx ) );

                mSceneNode[idx]->attachObject( item );
            }
        }

        Ogre::SceneNode *rootNode = sceneManager->getRootSceneNode();

        Ogre::Light *light = sceneManager->createLight();
        Ogre::SceneNode *lightNode = rootNode->createChildSceneNode();
        lightNode->attachObject( light );
        light->setPowerScale( 1.0f );
        light->setType( Ogre::Light::LT_DIRECTIONAL );
        light->setDirection( Ogre::Vector3( -1, -1, -1 ).normalisedCopy() );
        light->setVisible( false );

        mLightNodes[0] = lightNode;

        light = sceneManager->createLight();
        lightNode = rootNode->createChildSceneNode();
        lightNode->attachObject( light );
        light->setDiffuseColour( 0.8f, 0.4f, 0.2f );  // Warm
        light->setSpecularColour( 0.8f, 0.4f, 0.2f );
        light->setPowerScale( Ogre::Math::PI );
        light->setType( Ogre::Light::LT_SPOTLIGHT );
        lightNode->setPosition( -10.0f, 10.0f, 10.0f );
        light->setDirection( Ogre::Vector3( 1, -1, -1 ).normalisedCopy() );
        light->setAttenuationBasedOnRadius( 10.0f, 0.01f );
        light->setVisible( false );

        mLightNodes[1] = lightNode;

        light = sceneManager->createLight();
        lightNode = rootNode->createChildSceneNode();
        lightNode->attachObject( light );
        light->setDiffuseColour( 0.2f, 0.4f, 0.8f );  // Cold
        light->setSpecularColour( 0.2f, 0.4f, 0.8f );
        light->setPowerScale( Ogre::Math::PI );
        light->setType( Ogre::Light::LT_SPOTLIGHT );
        lightNode->setPosition( 10.0f, 10.0f, -10.0f );
        light->setDirection( Ogre::Vector3( -1, -1, 1 ).normalisedCopy() );
        light->setAttenuationBasedOnRadius( 10.0f, 0.01f );
        light->setVisible( false );

        mLightNodes[2] = lightNode;

#ifdef USE_STATIC_BRANCHING_FOR_SHADOWMAP_LIGHTS
        light = sceneManager->createLight();
        lightNode = rootNode->createChildSceneNode();
        lightNode->attachObject( light );
        light->setDiffuseColour( 0.8f, 0.0f, 0.0f );  // Red
        light->setSpecularColour( 0.8f, 0.0f, 0.0f );
        light->setPowerScale( Ogre::Math::PI );
        light->setType( Ogre::Light::LT_POINT );
        lightNode->setPosition( -10.0f, -10.0f, 10.0f );
        // light->setDirection( Ogre::Vector3( 1, -1, -1 ).normalisedCopy() );
        light->setAttenuationBasedOnRadius( 10.0f, 0.01f );
        light->setVisible( false );

        mLightNodes[3] = lightNode;

        light = sceneManager->createLight();
        lightNode = rootNode->createChildSceneNode();
        lightNode->attachObject( light );
        light->setDiffuseColour( 1.0f, 0.8f, 0.0f );  // Green
        light->setSpecularColour( 0.0f, 0.8f, 0.0f );
        light->setPowerScale( Ogre::Math::PI );
        light->setType( Ogre::Light::LT_POINT );
        lightNode->setPosition( -10.0f, 0.0f, 10.0f );
        // light->setDirection( Ogre::Vector3( -1, -1, 1 ).normalisedCopy() );
        light->setAttenuationBasedOnRadius( 10.0f, 0.01f );

        mLightNodes[4] = lightNode;
#endif

        mCameraController = new CameraController( mGraphicsSystem, false );

        createShadowMapDebugOverlays();

#if !OGRE_NO_JSON
        // For ESM, setup the filter settings (radius and gaussian deviation).
        // It controls how blurry the shadows will look.
        Ogre::HlmsManager *hlmsManager = Ogre::Root::getSingleton().getHlmsManager();
        Ogre::HlmsCompute *hlmsCompute = hlmsManager->getComputeHlms();

        Ogre::uint8 kernelRadius = 8;
        float gaussianDeviationFactor = 0.5f;
        Ogre::uint16 K = 80;
        Ogre::HlmsComputeJob *job = 0;

        // Setup compute shader filter (faster for large kernels; but
        // beware of mobile hardware where compute shaders are slow)
        // For reference large kernels means kernelRadius > 2 (approx)
        job = hlmsCompute->findComputeJob( "ESM/GaussianLogFilterH" );
        MiscUtils::setGaussianLogFilterParams( job, kernelRadius, gaussianDeviationFactor, K );
        job = hlmsCompute->findComputeJob( "ESM/GaussianLogFilterV" );
        MiscUtils::setGaussianLogFilterParams( job, kernelRadius, gaussianDeviationFactor, K );

        // Setup pixel shader filter (faster for small kernels, also to use as a fallback
        // on GPUs that don't support compute shaders, or where compute shaders are slow).
        MiscUtils::setGaussianLogFilterParams( "ESM/GaussianLogFilterH", kernelRadius,
                                               gaussianDeviationFactor, K );
        MiscUtils::setGaussianLogFilterParams( "ESM/GaussianLogFilterV", kernelRadius,
                                               gaussianDeviationFactor, K );
#endif

        TutorialGameState::createScene01();
    }

In this modified version, I have turned off all the lights except one point light, whose position I have moved, and I have called setTransparency on the cubes.

Here's a screen shot. Given that the light is to the left of the cubes, there is no reason that the front left cube should have shadows on it. And if you comment out the setTransparency line, it won't.

Screenshot 2024-07-25 at 9 27 17 AM

I can reproduce the bug under Windows with both the Vulkan and Direct3D render systems.

Further experimentation shows that if you have an opaque mesh casting a shadow on a translucent object, it looks OK. Whereas if a translucent object casts a shadow, it may cast a shadow on itself as well as on something else.

Fixed!

Thanks for the report!