Page 1 of 1

iOS, multiple lights, only one shadow map

Posted: Thu Jan 31, 2013 7:01 pm
by stoulouse
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

Re: iOS, multiple lights, only one shadow map

Posted: Thu Jan 31, 2013 7:48 pm
by stoulouse
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.

Re: iOS, multiple lights, only one shadow map

Posted: Thu Jan 31, 2013 9:36 pm
by stoulouse
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...

Re: iOS, multiple lights, only one shadow map

Posted: Fri Feb 01, 2013 5:42 pm
by stoulouse
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.

Re: iOS, multiple lights, only one shadow map

Posted: Fri Feb 01, 2013 7:00 pm
by stoulouse
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 1440 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 1440 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.

Re: iOS, multiple lights, only one shadow map

Posted: Sat Feb 02, 2013 5:13 pm
by stoulouse
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.