Jump to content
  • Advertisement
Sign in to follow this  
Brainsaw

OpenGL Problem with Shadows / GLSL shaders

This topic is 2480 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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:


img1.jpg
img2.jpg

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=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;
}
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;
}

Share this post


Link to post
Share on other sites
Advertisement
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!