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.
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!