Jump to content



Problem with Shadows / GLSL shaders

  • You cannot reply to this topic
2 replies to this topic

#1 Brainsaw   Members   -  Reputation: 100

Like
0Likes
Like

Posted 18 February 2012 - 09:39 AM

Hello,

I have been stuck in GLSL shaders for a couple of weeks now, and I just don't get it workin (though I think I'm close to it). I am using Irrlicht as graphics engine, and I try to get some "sunlight" shadows done, for the moment just with the sun right above the scene, so I created a material that renders the depth of the scene to a texture using an orthogonal camera. The position of this camera is 500 units above the center of the visible scene.

Here are 2 images of the problem I have:


Posted Image
Posted Image

The camera position of the second image is the same as in the first, it's just pitched a little up. I put the whole shading thing online:
http://bulletbyte.de.../shadertest.zip

I don't think that it's a big problem, I just can't get my mind around it. I've been trying to fix the problem for some weeks now, and I think I'm running in circles, so I though I'd post it here. I hope someone can push me into a direction that helps. Thanks in advance.


Here is the vertex shader for the shadowmap:

struct VS_OUTPUT
{
	vec4 Position;
	vec4 Color;
};

uniform mat4 mWorldViewProj;

VS_OUTPUT vertexMain( in vec3 Position )
{
	vec4 hpos;
	VS_OUTPUT OUT;

	hpos = (mWorldViewProj * vec4( Position.x , Position.y , Position.z , 1.00000) );
	OUT.Color = hpos;
	OUT.Position = hpos;
	return OUT;
}

void main()
{
  VS_OUTPUT xlat_retVal;

  xlat_retVal = vertexMain( vec3(gl_Vertex));

  gl_Position = vec4( xlat_retVal.Position);
  gl_TexCoord[0] = vec4( xlat_retVal.Color);
}

... and the corresponding fragment shader:

uniform float MaxD;

vec4 packFloatToVec4i(const float value)
{
  const vec4 bitSh = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);
  const vec4 bitMsk = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);
  vec4 res = fract(value * bitSh);
  res -= res.xxyz * bitMsk;
  return res;
}

void main()
{
  float depth=((gl_FragCoord.z/gl_FragCoord.w)/MaxD);
  gl_FragColor = packFloatToVec4i(depth);
}

I draw the shadow map on the upper left side of the output window, and (for me) it looks reasonable. Here are the shaders that use the shadowmap:

Vertex shader:


uniform mat4 mWorldViewProj;
uniform mat4 mWorldViewProj2;
uniform mat4 mInvWorld;
uniform float MaxD;

varying vec3 normalVec;
varying vec2 texCoords;
varying float shadowDist;

void main(void)
{
		gl_Position=mWorldViewProj * gl_Vertex;
		
		vec4 shadowPos=mWorldViewProj2*gl_Vertex;
		shadowDist=shadowPos.z/MaxD;
		
		vec4 normal=vec4(gl_Normal, 0.0);
		normal=mInvWorld * normal;
		normal=normalize(normal);
		
		normalVec[0]=normal[0];
		normalVec[1]=normal[1];
		normalVec[2]=normal[2];
		
  gl_TexCoord[0]=gl_MultiTexCoord0;
		
		vec4 vecDummy=mWorldViewProj2*gl_Vertex;
		texCoords=vecDummy.xy;
  texCoords=0.5*texCoords+0.5;
}

Fragment Shader:

uniform sampler2D ColoredTextureSampler;

uniform sampler2D ShadowMapSampler;
uniform sampler2D myTexture;
uniform float fShadowMapSize;

varying vec3 normalVec;
varying vec2 texCoords;

varying float shadowDist;

float unpackFloatFromVec4i(const vec4 value)
{
  const vec4 bitSh = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);
  return(dot(value, bitSh));
}

float testShadow(vec2 smTexCoord, float realDistance) {
		float extractedDistance = unpackFloatFromVec4i(texture2D( ShadowMapSampler, vec2( smTexCoord )));
		return (extractedDistance <= realDistance) ? ( 0.5 ) : ( 0.000000 );
}

void main (void) {
		vec4 texColor=texture2D(myTexture,vec2(gl_TexCoord[0]));
		
		if (texColor.a<0.5) discard;
		
		vec3 lightVector=vec3(1,1,0);
		vec4 fogColor=vec4(0.227,0.204,0.0,1.0);
		
		float fShadow=0.0;
		for (int i=0; i<16; i++) fShadow+=testShadow(texCoords,shadowDist);
		fShadow/=16.0;
		
		gl_FragColor=mix(texColor,vec4(0.0,0.0,0.0,1.0),fShadow);
}

and, last but not least, the main .cpp file:

		#include <irrlicht.h>
		#include <CRoadMeshLoader.h>
		#include <CRandomForestNode.h>

using namespace irr;

class CShadowMapper : public video::IShaderConstantSetCallBack {
  protected:
	enum ERenderPass {
	  enPassShadow,
	  enPassFinal
	};

	IrrlichtDevice		  *m_pDevice;
	scene::ISceneManager	*m_pSmgr;
	video::ITexture		 *m_pTexture;
	video::IVideoDriver	 *m_pDrv;
	scene::ISceneNode	   *m_pRoot;
	scene::ICameraSceneNode *m_pLightCam;

	f32 m_fHeight,
		m_fShadowMapSize;
	s32 m_iDepthMaterial,
		m_iShadowMaterial;
	u32 m_iShadowMapSize;

	core::array<video::E_MATERIAL_TYPE> m_aMaterials;

	core::dimension2du m_cShadowMapDim;

	core::matrix4 m_cWorldViewProj,
				  m_cWorldViewProj2;
	core::matrix4 m_cInvWorld;
	ERenderPass m_iRenderPass;

	bool isCulled(scene::ISceneNode *pNode) {
	  if (pNode->getType()==scene::ESNT_EMPTY) return false;
						core::aabbox3d<f32> tbox=pNode->getBoundingBox();
						pNode->getAbsoluteTransformation().transformBoxEx(tbox);
						return !(tbox.intersectsWithBox(m_pLightCam->getViewFrustum()->getBoundingBox()));
	}

	void render(scene::ISceneNode *pNode) {
	  if (pNode->getType()==scene::ESNT_TERRAIN) return;

	  if (pNode->getID()!=-23 && (!isCulled(pNode) || pNode->getType()==scene::ESNT_EMPTY)) {
		for (u32 i=0; i<pNode->getMaterialCount(); i++) {
		  m_aMaterials[i]=pNode->getMaterial(i).MaterialType;
		  pNode->getMaterial(i).MaterialType=(video::E_MATERIAL_TYPE)m_iDepthMaterial;
		}
		pNode->render();
		for (u32 i=0; i<pNode->getMaterialCount(); i++) pNode->getMaterial(i).MaterialType=m_aMaterials[i];
	  }
	  else return;

	  core::list<scene::ISceneNode *> lChildren=pNode->getChildren();
	  core::list<scene::ISceneNode *>::Iterator it;

	  for (it=lChildren.begin(); it!=lChildren.end(); it++) render(*it);
	}

	u32 getMaxNumberOfMeshBuffers(scene::ISceneNode *pNode) {
	  u32 iRet=pNode->getMaterialCount();

	  for (u32 i=0; i<iRet; i++) {
		pNode->getMaterial(i).MaterialType=(video::E_MATERIAL_TYPE)m_iShadowMaterial;
		pNode->getMaterial(i).setTexture(1,m_pTexture);
	  }

	  core::list<scene::ISceneNode *> lChildren=pNode->getChildren();
	  core::list<scene::ISceneNode *>::Iterator it;

	  for (it=lChildren.begin(); it!=lChildren.end(); it++) {
		u32 i=getMaxNumberOfMeshBuffers(*it);
		if (i>iRet) iRet=i;
	  }

	  return iRet;
	}

  public:
	CShadowMapper(IrrlichtDevice *pDevice, u32 iShadowMapSize, f32 fHeight, scene::ISceneNode *pRoot=NULL) {
	  //Get the standard Irrlicht instances
	  m_pDevice=pDevice;
	  m_pSmgr  =pDevice->getSceneManager();
	  m_pDrv   =pDevice->getVideoDriver();
	  m_pRoot  =pRoot==NULL?m_pSmgr->getRootSceneNode():pRoot;

	  //calculate the view frustrum of the current camera
	  const scene::SViewFrustum *cFrustrum=m_pSmgr->getActiveCamera()->getViewFrustum();
	  core::vector3df vLeftUp=cFrustrum->getFarLeftUp(),
					  vRightDown=cFrustrum->getFarRightDown();

	  //initialize some members
	  m_fHeight=fHeight;
	  m_iShadowMapSize=iShadowMapSize;
	  m_cShadowMapDim=core::dimension2du(m_iShadowMapSize,m_iShadowMapSize);
	  m_fShadowMapSize=(f32)m_iShadowMapSize;
	  m_pTexture=pDevice->getVideoDriver()->addRenderTargetTexture(m_cShadowMapDim,"ShadowMap");
	  m_iRenderPass=enPassFinal;

	  //Initialize the Lightcam
	  m_pLightCam=m_pSmgr->addCameraSceneNode();
	  core::matrix4 cProjMat;
	  f32 size=vLeftUp.X; if (size<0.0f) size=-size;
	  cProjMat.buildProjectionMatrixOrthoLH(size,size,10,2.0f*m_fHeight);
	  m_pLightCam->setProjectionMatrix(cProjMat,true);
	  m_pLightCam->setPosition(core::vector3df(3000,200,3000));

	  //Compile the shaders
	  video::IGPUProgrammingServices *pGpu=m_pDrv->getGPUProgrammingServices();

	  printf("**** compiling pass 1 shaders (fHeight=%.2f)...\n",fHeight);
	  m_iDepthMaterial=pGpu->addHighLevelShaderMaterialFromFiles("../../shaders/SSM_ShadowPass1V.glsl","main",video::EVST_VS_2_0,
																 "../../shaders/SSM_ShadowPass1P.glsl","main",video::EPST_PS_2_0,
																 this,video::EMT_SOLID);

	  printf("**** compiling pass 2 shaders...\n");
	  m_iShadowMaterial=pGpu->addHighLevelShaderMaterialFromFiles("../../shaders/SSM_ShadowPass2V.glsl","main",video::EVST_VS_2_0,
																  "../../shaders/SSM_ShadowPass2P.glsl","main",video::EPST_PS_2_0,
																  this,video::EMT_SOLID);
	  printf("**** Ready.\n");

	  u32 iNumberOfTextures=getMaxNumberOfMeshBuffers(m_pRoot);
	  for (u32 i=0; i<iNumberOfTextures; i++) m_aMaterials.push_back(video::EMT_SOLID);
	}

	void update() {
	  //Activate Lightcam
	  scene::ICameraSceneNode *pActiveCamera=m_pSmgr->getActiveCamera();
	  m_pSmgr->setActiveCamera(m_pLightCam);

	  //Calculate new position and target of the lightcam
	  core::vector3df vPos=pActiveCamera->getPosition(),
					  vTgt=vPos-pActiveCamera->getTarget();

	  vTgt.normalize();
	  vPos-=750.0f*vTgt;
	  if (vPos.Y<0.0f) vPos.Y=0.0f;
	  m_pLightCam->setTarget(vPos);
	  vPos.Y+=m_fHeight;
	  m_pLightCam->setPosition(vPos);
	  m_pLightCam->setUpVector(-vTgt);

	  //Render the shadowmap
	  m_iRenderPass=enPassShadow;
	  m_pDrv->setRenderTarget(m_pTexture);

	  core::recti cRect=core::recti(0,0,m_cShadowMapDim.Width,m_cShadowMapDim.Height);
	  m_pDrv->draw2DRectangle(video::SColor(0xFF,0xFF,0xFF,0xFF),cRect);

	  m_pDrv->setTransform(video::ETS_VIEW	  ,m_pLightCam->getViewMatrix	  ());
	  m_pDrv->setTransform(video::ETS_PROJECTION,m_pLightCam->getProjectionMatrix());
	  m_pLightCam->render();
	  render(m_pRoot);

	  //restore the active camera
	  m_pSmgr->setActiveCamera(pActiveCamera);
	  m_pDrv->setRenderTarget(video::ERT_FRAME_BUFFER);
	  m_iRenderPass=enPassFinal;
	}

	virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userData) {
	  switch (m_iRenderPass) {
		case enPassShadow:
		  m_cWorldViewProj =m_pDrv->getTransform(video::ETS_PROJECTION);
		  m_cWorldViewProj*=m_pDrv->getTransform(video::ETS_VIEW);
		  m_cWorldViewProj*=m_pDrv->getTransform(video::ETS_WORLD);

		  services->setVertexShaderConstant("mWorldViewProj",m_cWorldViewProj.pointer(), 16);

		  services->setPixelShaderConstant("MaxD",&m_fHeight,1);
		  break;

		case enPassFinal: {
			m_cInvWorld=m_pDrv->getTransform(video::ETS_WORLD);
			m_cInvWorld.makeInverse();

			services->setVertexShaderConstant("mInvWorld", m_cInvWorld.pointer(), 16);

			m_cWorldViewProj =m_pDrv->getTransform(video::ETS_PROJECTION);
			m_cWorldViewProj*=m_pDrv->getTransform(video::ETS_VIEW);
			m_cWorldViewProj*=m_pDrv->getTransform(video::ETS_WORLD);

			services->setVertexShaderConstant("mWorldViewProj", m_cWorldViewProj.pointer(), 16);

			core::matrix4 dummy=m_pLightCam->getViewMatrix();
			dummy.makeInverse();

			m_cWorldViewProj2 =m_pLightCam->getProjectionMatrix();
			m_cWorldViewProj2*=m_pLightCam->getViewMatrix();
			m_cWorldViewProj2*=m_pDrv ->getTransform(video::ETS_WORLD);
			services->setVertexShaderConstant("mWorldViewProj2", m_cWorldViewProj2.pointer(), 16);

			core::matrix4 world = m_pDrv->getTransform(video::ETS_WORLD);
			world = world.getTransposed();

			services->setVertexShaderConstant("mTransWorld",world.pointer(), 16);

			s32 var0=0;
			services->setPixelShaderConstant("ColoredTextureSampler", (f32 *)(&var0), 1);

			services->setPixelShaderConstant("fShadowMapSize",&m_fShadowMapSize,1);

			f32 MaxD=m_fHeight;
			services->setVertexShaderConstant("MaxD",&MaxD,1);

			s32 var2=1;
			services->setPixelShaderConstant("ShadowMapSampler",(f32 *)&var2,1);
		  }
		  break;
	  }
	}

	video::ITexture *getDepthMap() { return m_pTexture; }
};

int main() {
  core::dimension2du cWindowSize=core::dimension2du(1280,1024);

		IrrlichtDevice *pDevice=createDevice(video::EDT_OPENGL,cWindowSize,32,false,false,false,0);

		pDevice->setWindowCaption(L"Hello World! - Irrlicht Engine Demo");

		video::IVideoDriver  *pDrv   =pDevice->getVideoDriver();
		scene::ISceneManager *pSmgr  =pDevice->getSceneManager();
		gui::IGUIEnvironment *pGuienv=pDevice->getGUIEnvironment();

		CRandomForestFactory *pForest=new CRandomForestFactory(pSmgr);
		pSmgr->registerSceneNodeFactory(pForest);

		CRoadMeshLoader *pRoad=new CRoadMeshLoader(pDevice);
		pSmgr->addExternalMeshLoader(pRoad);

		pSmgr->loadScene("../../data/irrodecar.xml");

  scene::ICameraSceneNode *pFpsCam=pSmgr->addCameraSceneNodeFPS();
  pFpsCam->setNearValue(10.0f);
  pFpsCam->setFarValue(1500.0f);

  pFpsCam->setPosition(core::vector3df(6525.0f,390.0f,7550.0f));
  pFpsCam->setTarget(core::vector3df(-2000.0f,-750.0f,2450.0f));

  u32 iShadowSize=2048;

  CShadowMapper *pShadow=new CShadowMapper(pDevice,iShadowSize,500.0f,pSmgr->getSceneNodeFromName("worldNode"));
  video::ITexture *pDepth=pShadow->getDepthMap();

  s32 iLastFPS=-1;
  while(pDevice->run()) {
	pSmgr->setActiveCamera(pFpsCam);

				pDrv->beginScene(true,true,video::SColor(0,200,200,200));
				pShadow->update();
				pSmgr->drawAll();
				pDrv->draw2DImage(pDepth,core::rect<s32>(0,0,384,384),core::rect<s32>(0,0,iShadowSize,iShadowSize));
				pGuienv->drawAll();

				pDrv->endScene();

	s32 iFps=pDrv->getFPS();

	  if (iLastFPS!=iFps) {
	  core::stringw str = L"Shadow Mapping [";
	  str+=pDrv->getName();
	  str+="] FPS:";
	  str+=iFps;

	  pDevice->setWindowCaption(str.c_str());
	  iLastFPS=iFps;
	}
		}

		pDevice->drop();

		return 0;
}


Ad:

#2 dpadam450   Members   -  Reputation: 184

Like
0Likes
Like

Posted 18 February 2012 - 01:26 PM

No idea what I'm looking at. I see a shadow in the first image (what is wrong with it). The second image you don't show the ground so I can't see what is wrong.
http://www.ultimategamedevelopment.com - My game development DVD tutorials. Learn to make complete 2D/3D games step by step.

http://www.youtube.c...ev?feature=mhee - Follow my video blog on making a 3D flight sim game.

#3 NimrodPSI   Members   -  Reputation: 123

Like
0Likes
Like

Posted 24 February 2012 - 10:09 PM

I'm thinking the issue is that blue checkered rectangle. If the 'sun' position is directly above the scene then the whole thing should be in shadow, not just the bottom quarter. Then in the second image the view angle is higher, but the exact same shadow is now farther up the rectangle. My assumption is you're using the wrong coordinates for your shadow calculation so it's taking the 'cameras' movement/view into account, as can happen with lighting.






We are working on generating results for this topic
PARTNERS