iOS, multiple lights, only one shadow map

Discussion of issues specific to mobile platforms such as iOS, Android, Symbian and Meego.
Post Reply
stoulouse
Greenskin
Posts: 116
Joined: Fri Mar 24, 2006 7:15 pm

iOS, multiple lights, only one shadow map

Post by stoulouse » Thu Jan 31, 2013 7:01 pm

hi, i' trying to debug a problem on ogre 1.8 iOS where shadow map are not correctly displayed when more than one light is used.
my use case works on mac so i think my settings are good.
after some debugging and OpenGL frame capturing i can tell that shadow maps are correctly generated at the beginning of the frame and stored in 4 textures. the first pass render my shadow receiver mesh normally, then the first shadow pass works also correctly, then all next shadow pass use the same texture id and coord than the first shadow pass. is it a know bug? i continue to debug and try to understand how it works, but if someone have a clue, i would greatly appreciate. ++samuel
0 x

stoulouse
Greenskin
Posts: 116
Joined: Fri Mar 24, 2006 7:15 pm

Re: iOS, multiple lights, only one shadow map

Post by stoulouse » Thu Jan 31, 2013 7:48 pm

while debugging this problem i've found that an other problem in entity visitRenderables, it should take care of subentity visibility flag :

Code: Select all

void Entity::visitRenderables(Renderable::Visitor* visitor, 
		bool debugRenderables)
	{
		// Visit each SubEntity
		for (SubEntityList::iterator i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i)
		{
//			if ((*i)->isVisible())
				visitor->visit(*i, 0, false);
		}
		// if manual LOD is in use, visit those too
		ushort lodi = 1;
		for (LODEntityList::iterator e = mLodEntityList.begin(); 
			e != mLodEntityList.end(); ++e, ++lodi)
		{
			
			uint nsub = (*e)->getNumSubEntities();
			for (uint s = 0; s < nsub; ++s)
			{
//				if ((*e)->getSubEntity(s)->isVisible())
					visitor->visit((*e)->getSubEntity(s), lodi, false);
			}
		}

	}
i've commented the two line i've added. correct me if i'm wrong but i think those lines should be there. otherwise, my non visible subentity of my entity would say that my entity receive shadow or is visible even if it's not the case.
0 x

stoulouse
Greenskin
Posts: 116
Joined: Fri Mar 24, 2006 7:15 pm

Re: iOS, multiple lights, only one shadow map

Post by stoulouse » Thu Jan 31, 2013 9:36 pm

i've found where the problem is coming from, SceneManager::mShadowReceiverPass is initialized but not supported technique is valid. then at the first render pass, shadows are placed in mShadowReceiverPass texture unit stage of the first pass of the unsupported technique. later in SceneManager::deriveShadowReceiverPass those lines :

Code: Select all

// handle the case where there is no fixed pipeline support
		retPass->getParent()->getParent()->compile();
        Technique* btech = retPass->getParent()->getParent()->getBestTechnique();
        if( btech )
        {
		    retPass = btech->getPass(0);
        }
create a new supported technique but then SceneManager::mShadowReceiverPass is not updated with the valid technique. i don't know yet how to solve this, keep searching...
0 x

stoulouse
Greenskin
Posts: 116
Joined: Fri Mar 24, 2006 7:15 pm

Re: iOS, multiple lights, only one shadow map

Post by stoulouse » Fri Feb 01, 2013 5:42 pm

i still cannot find a way to get around this problem. as far as i understand now, when using shadows on ios you need a shader and when using RTSS it doesn't generate a good shader for multiple lights. it's a little bit complicated and a help on how shadows work by default on ios would be great.
to bypass the two technique problem, i've created a material and set a custom shadow material :

Code: Select all

_sceneManager->setShadowTextureReceiverMaterial("Ogre/MyShadowReceiver");

Code: Select all

material Ogre/MyShadowReceiver
{
    technique
    {
	scheme ShaderGeneratorDefaultScheme
        pass
        {
            lighting off
            texture_unit
            {
				content_type shadow
                colour_op modulate
            }
        }
    }
}
but by doing this the RTSS doesn't generate a material with texture projection, so i guess i have to add code to generate a shader with texture projection when ogre ask RTSS for a compatible shader. i'm still wondering if i'm in the good direction for solving this problem... help would be very very appreciated.
0 x

stoulouse
Greenskin
Posts: 116
Joined: Fri Mar 24, 2006 7:15 pm

Re: iOS, multiple lights, only one shadow map

Post by stoulouse » Fri Feb 01, 2013 7:00 pm

more infos. it looks like RTSS is generating the correct shader with texture projection.
i don't know whats happening, i've attached a comparison of mac (RTSS not used)
Screen Shot 2013-02-01 at 19.51.02.png
mac
Screen Shot 2013-02-01 at 19.51.02.png (194.14 KiB) Viewed 1442 times
and iOS (with RTSS)
Screenshot 2013.02.01 19.53.34.jpg
ipad
Screenshot 2013.02.01 19.53.34.jpg (130.63 KiB) Viewed 1442 times
. as you can see the shadows are all rendered but the texture projection matrix on ios is always the same. to be able to see all shadows, i've modified the SceneManager::deriveShadowReceiverPass to copy texture unit states and to set mShadowTextureCustomReceiverPass and mShadowReceiverPass accordingly. like this:

Code: Select all

	// handle the case where there is no fixed pipeline support
	retPass->getParent()->getParent()->compile();
        Technique* btech = retPass->getParent()->getParent()->getBestTechnique();
        if( btech )
        {
			Pass* newPass = btech->getPass(0);
			if (newPass != retPass) {
				newPass->removeAllTextureUnitStates();
				
				Pass::TextureUnitStateIterator it = retPass->getTextureUnitStateIterator();
				while (it.hasMoreElements()) {
					TextureUnitState* tus = it.getNext();
					TextureUnitState* newTus = newPass->createTextureUnitState( tus->getName() );
					*newTus = *tus;
				}
				
				if (retPass == mShadowTextureCustomReceiverPass) {
					mShadowTextureCustomReceiverPass = newPass;
				} else if (retPass == mShadowReceiverPass) {
					mShadowReceiverPass = newPass;
				}
				
				retPass = newPass;
			}
        }
so now all shadows are rendered but texture projection are not good. i think there is a problem with RTSS and default texture shadow technique.
0 x

stoulouse
Greenskin
Posts: 116
Joined: Fri Mar 24, 2006 7:15 pm

Re: iOS, multiple lights, only one shadow map

Post by stoulouse » Sat Feb 02, 2013 5:13 pm

ok, i've finally made it working. can someone review my changes and tell me if what i'm doing is correct or not ?
first modification is in OgreSceneManager.cpp, deriveShadowReceiverPass, i've changed the last lines to copy startlight and textureunitstate to the best technique pass found. i did it because without it next stage need those parameters and they are not updated otherwise, i guess there is a better place for this or a better way to do it:

Code: Select all

		// handle the case where there is no fixed pipeline support
		retPass->getParent()->getParent()->compile();
        Technique* btech = retPass->getParent()->getParent()->getBestTechnique();
        if( btech )
        {
			Pass* newPass = btech->getPass(0);

			if (newPass != retPass) {
				newPass->setStartLight(retPass->getStartLight());
				newPass->removeAllTextureUnitStates();
				
				Pass::TextureUnitStateIterator it = retPass->getTextureUnitStateIterator();
				while (it.hasMoreElements()) {
					TextureUnitState* tus = it.getNext();
					TextureUnitState* newTus = newPass->createTextureUnitState( tus->getName() );
					*newTus = *tus;
				}
				
				retPass = newPass;				
			}
        }
next modification is in OgreSceneManager.cpp, renderModulativeTextureShadowedQueueGroupObjects, while iterating trough lights i set startlight, contenttype and texture unit texture name to the current light/shadowmap. i need to do that because later this will be used to set texture projection effect later regarding current light camera frustum and texture name:

Code: Select all

			Pass* targetPass = mShadowTextureCustomReceiverPass ?
				mShadowTextureCustomReceiverPass : mShadowReceiverPass;
			targetPass->setStartLight( l->_getIndexInFrame() );
			targetPass->getTextureUnitState(0)->setTextureName(
				mCurrentShadowTexture->getName());
			// Hook up projection frustum if fixed-function, but also need to
			// disable it explicitly for program pipeline.
			TextureUnitState* texUnit = targetPass->getTextureUnitState(0);
			texUnit->setProjectiveTexturing(!targetPass->hasVertexProgram(), cam);
			// clamp to border colour in case this is a custom material
			texUnit->setTextureAddressingMode(TextureUnitState::TAM_BORDER);
			texUnit->setTextureBorderColour(ColourValue::White);
			texUnit->setContentType(TextureUnitState::CONTENT_SHADOW);
			targetPass->getTextureUnitState(0)->setTextureName(
															   mCurrentShadowTexture->getName());
i set the texture name after setting the contenttype because using content_shadow remove the texture unit and the shadowmap is needed later.

then in OgreSceneManager.cpp, _setPass, i've changed how texture projection is set because it was checking if the pass has vertex program and the pass was not set correctly:

Code: Select all

-					pTex->setProjectiveTexturing(!pass->hasVertexProgram(), cam);
+					pTex->setProjectiveTexturing(pTex->getEffects().end() != pTex->getEffects().find(TextureUnitState::ET_PROJECTIVE_TEXTURE), cam);
finally in OgreShaderFFPTexturing.cpp, updateGpuProgramsParams, i've changed the way mTextureViewProjImageMatrix is set because it was always using the same parameter instead of the one coming from AutoParamDataSource source:

Code: Select all

void FFPTexturing::updateGpuProgramsParams(Renderable* rend, Pass* pass, const AutoParamDataSource* source, 
											  const LightList* pLightList)
{
	for (unsigned int i=0; i < mTextureUnitParamsList.size(); ++i)
	{
		TextureUnitParams* curParams = &mTextureUnitParamsList[i];

		if (curParams->mTextureViewProjImageMatrix.get() != NULL)
		{
			Matrix4 matTexViewProjImage;

			matTexViewProjImage = source->getTextureViewProjMatrix(0);

			curParams->mTextureViewProjImageMatrix->setGpuParameter(matTexViewProjImage);
		}
	}
}
i think that this patch is very dirty because i don't really understand what's going on. i works, now i can see shadowmap for each light, but i think it's not a good solution, if someone who know how RTSS and texture shadows work, it could be very nice if he can spend time to evaluate my changes.
Attachments
Screenshot 2013.02.02 16.45.35.jpg
working multiple shadows
Screenshot 2013.02.02 16.45.35.jpg (112.46 KiB) Viewed 1428 times
0 x

Post Reply