Search Home Members Contacts
About Us
Products
Downloads
Community
Support
Pages: [1] 2
  Print  
Author Topic: Getting started with shadow maps, help  (Read 4030 times)
tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« on: September 09, 2009, 03:34:48 PM »

Hello!

I have been trying to implementing shadows in my game for a while now without any achievement. I tried PSSM but it was to expensive for my app, I can't find Zaknafeins shadowmap to download and the others I can't get to work or I can't read the programming langugage. I have read some theory but clearly not enough yet.

What I'm looking for is a push in the right direction or maybe a fully shader with implementation tutorial at my hand Smiley

I have tried to follow some tutorials on the net but then I have lost the way when I reach DepthStencilBuffer or LightViewProjection. What are those 2 in Tv3D? How do I work with TV3D to create a shadowmap? The shaders is fine but the implementation I don't get.

I'm working with c++ or c#, c++ preffered. I would like to have Directional light.

Please give me some answers so I can get going wit this shadows(tried for xx hours nonstop now)...
« Last Edit: September 11, 2009, 09:13:51 PM by tedlin01 » Logged

Zaknafein
Customers
Community Member
*****
Posts: 2940


WWW
« Reply #1 on: September 09, 2009, 04:01:51 PM »

My implementation is there : http://www.truevision3d.com/forums/tv3d_sdk_65/landscape_shadowmapping_demo_sample-t14234.0.html
There's a download link, but it's VB.Net and it's kind of outdated. The more accepted solution is PSSM now.

My implementation differs such that it doesn't project shadows on meshes, only the landscape, and it doesn't override the rendering shader of the landscape or any mesh... so it's a bit simpler at runtime, but there's a lot of tricks to be able to achieve that.

DepthStencilBuffer, you can't access that in TV3D, you have to make your own depth rendering shader (which just outputs a distance from the camera) and use that.
LightViewProjection is just a matrix that you pass to the shadowmapping shader. I compute one in my sample, I'm sure Mietze has it somewhere too.
Logged

tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #2 on: September 09, 2009, 11:50:32 PM »

oh yeah, I don't know how to convert it to c++ but otherwise thats exactly what I want in my shadowmap, but as basic as possible to start with.

After reading http://www.riemers.net/eng/Tutorials/DirectX/Csharp/Series3/Shadow_mapping.php I was trying to create a DepthMap:
I created a landscape and created the shadereffect and added it to the landscape.
I set the parameters:

Code:
pDepthShader()->SetTechnique("ShadowMap")
pDepthShader()->SetEffectParamVector4("xLightPos", new cTV_4DVECTOR(18, 2, 5, 1)); pDepthShader()->SetEffectParamFloat("xLightPower", 0.7f); pDepthShader()->SetEffectParamFloat("xMaxDepth", 200);     pDepthShader()->SetEffectParamMatrix("xLightViewProjection", &getLightViewProjection() );
BUT all my pixels is black!? Shouldnt they fade between black and white depending on the depth?

getLightViewPorjection is calculated like this:

Code:
m_pLightCamera = m_pCameraFact->CreateCamera();
m_pLightCamera->SetPosition( 18, 2, 5 );
m_pLightCamera->SetLookAt( 0, 0, 0 );
cTV_3DMATRIX vLightView = m_pLightCamera->GetMatrix();
m_pMath->TVMatrixInverse( &vLightView, 0, &vLightView );
m_pMath->TVMatrixMultiply( &vLightViewProj, &m_pLightCamera->GetProjectionMatrix(), &vLightView );

My Shader looks like this:
Code:
struct SMapVertexToPixel
 {
     float4 Position     : POSITION;   
     float3 Position2D    : TEXCOORD0;
 };
 
 struct SMapPixelToFrame
 {
     float4 Color : COLOR0;
 };


float4x4 xWorld : WORLD;
float4x4 xWorldViewProjection : WORLDVIEWPROJ;
float4x4 xLightViewProjection;

float4 xLightPos;
float xLightPower;

float xMaxDepth;


SMapVertexToPixel ShadowMapVertexShader( float4 inPos : POSITION)
{
    SMapVertexToPixel Output = (SMapVertexToPixel)0;
   
    float4x4 xWorldLightViewProj = mul(xWorld, xLightViewProjection);
    Output.Position = mul(inPos, xWorldLightViewProj);
    Output.Position2D = Output.Position;
   
    return Output;   
}

SMapPixelToFrame ShadowMapPixelShader(SMapVertexToPixel PSIn)
{
    SMapPixelToFrame Output = (SMapPixelToFrame)0;

    Output.Color = PSIn.Position2D.z/xMaxDepth*15;

    return Output;
}

technique ShadowMap
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 ShadowMapVertexShader();
        PixelShader = compile ps_2_0 ShadowMapPixelShader();
    }
}
Logged

tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #3 on: September 10, 2009, 04:00:53 PM »

Okey, I have gotten a bit further now. I noticed that the shader didn't work well with the CTVLandscape so I created a CTVMesh-->AddFloor instead. I have managed to write a depthmap now.

I created one CTVShader which I set for all meshes and my Floor.
This is Before the shadowmap was added:

*The Floor is black since I have just added an empty texture from the CTVTextureFactory.

Now this is how my Depthmap looks like:


Btw, this is how I calculated the LightViewMatrix.
Code:
cTV_3DMATRIX mLightView = m_pLightCamera->GetMatrix();
m_pMath->TVMatrixInverse( &mLightView, 0, &mLightView );
m_pMath->TVMatrixMultiply( &mLightViewProj, &mLightView, &m_pLightCamera->GetProjectionMatrix() );
*Appearently the multiply had to come in exact this way and not LightView first.

I then went on to render the ShadowedScene.
I added the code to the shader. This is my shader right now:
Code:
///////////////////////////////////
//////        DEPTHMAP       //////
///////////////////////////////////

struct VertexToPixel
{
    float4 Position     : POSITION;   
    float3 Position2D    : TEXCOORD0;

};

struct PixelToFrame
{
    float4 Color : COLOR0;
};

float4x4 xViewProjection : VIEWPROJ;
float4x4 xWorld : WORLD;
float4x4 xLightViewProjection;

float xMaxDepth;

VertexToPixel ShadowMapVertexShader( float4 inPos : POSITION, float4 inColor : COLOR0)
{
    VertexToPixel OUT = (VertexToPixel)0;
   
    float4x4 xLightWorldViewProjection = mul(xWorld, xLightViewProjection);

    OUT.Position = mul(inPos, xLightWorldViewProjection ); 
    OUT.Position2D = OUT.Position;

    return OUT;   
}

PixelToFrame ShadowMapPixelShader( VertexToPixel IN )
{
    PixelToFrame Output = (PixelToFrame)0;

    Output.Color = IN.Position2D.z/xMaxDepth;

    return Output;
}

technique ShadowMap
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 ShadowMapVertexShader();
        PixelShader = compile ps_2_0 ShadowMapPixelShader();
    }
}


///////////////////////////////////
//////     SHADOWEDSCENE     //////
///////////////////////////////////

float4x4 xWorldViewProjection : WORLDVIEWPROJ;

Texture xShadowMap;
sampler ShadowMapSampler = sampler_state { texture = <xShadowMap> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = clamp; AddressV = clamp;};

struct SSceneVertexToPixel
{
    float4 Position             : POSITION;
    float4 ShadowMapSamplingPos : TEXCOORD0;   
};

struct SScenePixelToFrame
{
    float4 Color : COLOR0;
};

SSceneVertexToPixel ShadowedSceneVertexShader( float4 inPos : POSITION)
{
    SSceneVertexToPixel Output = (SSceneVertexToPixel)0;
   
    float4x4 xLightWorldViewProjection = mul(xWorld, xLightViewProjection);

    Output.Position = mul(inPos, xWorldViewProjection);
    Output.ShadowMapSamplingPos = mul(inPos, xLightWorldViewProjection);
   
    return Output;   
}

SScenePixelToFrame ShadowedScenePixelShader(SSceneVertexToPixel PSIn)
{
    SScenePixelToFrame Output = (SScenePixelToFrame)0;

    float2 ProjectedTexCoords;
    ProjectedTexCoords[0] = PSIn.ShadowMapSamplingPos.x/PSIn.ShadowMapSamplingPos.w/2.0f +0.5f;
    ProjectedTexCoords[1] = -PSIn.ShadowMapSamplingPos.y/PSIn.ShadowMapSamplingPos.w/2.0f +0.5f;
    Output.Color = tex2D(ShadowMapSampler, ProjectedTexCoords);

    return Output;
}


technique ShadowedScene
{
    pass Pass0
    {
        VertexShader = compile vs_2_0 ShadowedSceneVertexShader();
        PixelShader = compile ps_2_0 ShadowedScenePixelShader();
    }
}

.. then I made my Renderfunction like this:

Code:
// Render ShadowMap
m_pShader->SetTechnique("ShadowMap");
pRenderSurface->StartRender();
m_pScene->RenderAll(false);
pRenderSurface->EndRender();

m_pEngine->Clear(false);

// Render Shadowed Scene m_pShader->SetTechnique("ShadowedScene"); m_pShader->SetEffectParamTexture("xShadowMap", pRenderSurface->GetTexture());

m_pScene->RenderAll(false);
m_pEngine->RenderToScreen();

This is were I'm stuck now! Appearently I'm doing something wrong since I end up with this:


Accordingly to http://www.riemers.net/eng/Tutorials/DirectX/Csharp/Series3/Projective_texturing.php the picture should look something like this:


.. What I'm wondering is why my meshes is getting their original textures since I don't tell them to do so. But maybe that's happening automatically when I'm running the ShadowedScene-technique.

Any ideas what I'm doing wrong or suggestions of how to find out?

Edit: I noticed that when i comment out:
//pShader->SetEffectParamTexture("xShadowMap", pRenderSurface->GetTexture() );
There is no difference in the result! ..aint that wierd?
« Last Edit: September 10, 2009, 06:07:49 PM by tedlin01 » Logged

tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #4 on: September 11, 2009, 07:19:53 AM »

I really need your help guys :/
Logged

Lenn
Customers
Community Member
*****
Posts: 876

+/-


« Reply #5 on: September 11, 2009, 07:29:47 AM »

I haven't really looked through your code but maybe: your models have textures assigned to them within the models themselves (you can assign textures to TVM models and they will load). Perhaps that gets auto-assigned as TEXTURE0, or some other texture. Make sure you set all of the textures you are using manually by sending them to the shader.
Logged

TV3D 6.5 Community Docs - Read, use and please contribute!
tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #6 on: September 11, 2009, 07:45:23 AM »

Accually that made some difference. I'm doing some testing right now. Is it okey if i just skip the loading of the textures or must I have a texture on all the meshes? Should I have some kind of lightning or blending on them?

Should i set my rendersurface camera to the lightCamera when rendering the depthmap?
« Last Edit: September 11, 2009, 08:03:37 AM by tedlin01 » Logged

tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #7 on: September 11, 2009, 08:34:25 AM »

okey, I removed all textures from all my meshes and first then could I get a picture that looked like the one in the tutorial. In the next step I need to send in a texture for the mesh in xColoredTexture. I was wondering if I then must create one shader for each mesh since I want different textures?
« Last Edit: September 11, 2009, 09:09:26 AM by tedlin01 » Logged

Lenn
Customers
Community Member
*****
Posts: 876

+/-


« Reply #8 on: September 11, 2009, 09:06:03 AM »

No, of course not. You should go through the HLSL tutorials in the "samples for newbies" (in the announcments forum). It shows you that you can set textures in shaders from TV3D like so:

Code:

Shader.SetEffectParamTexture("textureNameInShader", TextureID)


and in your shader you need:

Code:

texture  textureNameInShader;

sampler2D TextureSample = sampler_state
{
Texture   = (textureNameInShader);
MIPFILTER = LINEAR;
MAGFILTER = LINEAR;
MINFILTER = LINEAR;
};


the mip,mag,min filter are optional, like everything else, i just wrote the way it is in those samples.
Logged

TV3D 6.5 Community Docs - Read, use and please contribute!
tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #9 on: September 11, 2009, 09:10:36 AM »

Yeah, I have been looking into those alot ^^ but I want different textures for each mesh? and all meshes is using the same shader.

As soon as I set a texture to my meshes using mesh->setTexture, everything gets messy. So the only way for me to put on a mess is by using xColoredTexture, but then I need to create a shader for each induvidual mesh, right?

Maybe there is a way I could fix this messyness that happens when I set a texture to a mesh with setTexture?
« Last Edit: September 11, 2009, 09:12:36 AM by tedlin01 » Logged

tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #10 on: September 11, 2009, 09:19:29 AM »

Nvm, I was only supposed to add the shader to the landscape Smiley

Altough I would appriciate if someone could explain how this works? How can I get a depthmap when I only have the shader to the landscape?

I mean.. When the shader runs for the landscape and checks the depth. Does it accually know about the other meshes then?
« Last Edit: September 11, 2009, 09:40:51 AM by tedlin01 » Logged

tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #11 on: September 11, 2009, 09:24:21 PM »

Okey, So since my game is an RTS I'm trying to convert this to Directional Light.
cpyburn developed a technique for just that. It's here http://www.riemers.net/Forum/index.php?var=1509&var2=0

This is hes modified code for the lightviewproj:
Code:
Matrix CreateLightViewProjectionMatrix()
        {
            // Matrix with that will rotate in points the direction of the light
            Matrix lightRotation = Matrix.CreateLookAt(Vector3.Zero,
                                                       -lightDir,
                                                       Vector3.Up);

            // Get the corners of the frustum
            Vector3[] frustumCorners = cameraFrustum.GetCorners();

            // Transform the positions of the corners into the direction of the light
            for (int i = 0; i < frustumCorners.Length; i++)
            {
                frustumCorners[i] = Vector3.Transform(frustumCorners[i], lightRotation);
            }

            // Find the smallest box around the points
            BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners);

            Vector3 boxSize = lightBox.Max - lightBox.Min;
            Vector3 halfBoxSize = boxSize * 0.5f;

            // The position of the light should be in the center of the back
            // pannel of the box.
            Vector3 lightPosition = lightBox.Min + halfBoxSize;
            lightPosition.Z = lightBox.Min.Z;

            // We need the position back in world coordinates so we transform
            // the light position by the inverse of the lights rotation
            lightPosition = Vector3.Transform(lightPosition,
                                              Matrix.Invert(lightRotation));

            // Create the view matrix for the light
            Matrix lightView = Matrix.CreateLookAt(lightPosition,
                                                   lightPosition - lightDir,
                                                   Vector3.Up);

            // Create the projection matrix for the light
            // The projection is orthographic since we are using a directional light
            Matrix lightProjection = Matrix.CreateOrthographic(boxSize.X, boxSize.Y,
                                                               -boxSize.Z, boxSize.Z);

            return lightView * lightProjection;
        }


I tried to convert to c++ with TV3D and this is the code then:

Code:
cTV_4DVECTOR * pLightCameraPosition = new cTV_4DVECTOR( -18.0f, 100.0f, -2.0f, 1.0f );

// Create LightCamera
m_pLightCamera = m_pCameraFact->CreateCamera();
m_pLightCamera->SetPosition( pLightCameraPosition->x, pLightCameraPosition->y, pLightCameraPosition->z );
m_pLightCamera->SetLookAt( 0, 0, 0 );

// Rotate the camera
cTV_3DMATRIX * pLightRotation = new cTV_3DMATRIX;
m_pMath->TVMatrixLookAt( pLightRotation, new cTV_3DVECTOR(0,0,0), &-m_pLightCamera->GetPosition(), new cTV_3DVECTOR(0, 1, 0) );

// Get the Frustum points
cTV_3DVECTOR * pFrustumPoints = new cTV_3DVECTOR[8];
m_pCameraManager->getCamera()->GetFrustumPoints( pFrustumPoints );

// Transform the points to the direction of the light
for (unsigned int i = 0; i < 8; i++)
{
pFrustumPoints[i] += cTV_3DVECTOR(1.0f, 1.0f, 1.0f);
m_pMath->TVVec3TransformCoord( &pFrustumPoints[i], &pFrustumPoints[i], pLightRotation );
}

// Create BoundingBox
BBABCD * pBBABCD = new BBABCD;

for (unsigned int i = 0; i < 8; i++)
{
pBBABCD->Merge(pFrustumPoints[i]);
}

// Get BoxSize
cTV_3DVECTOR * pBoxSize = new cTV_3DVECTOR( (*pBBABCD->m_vMaximum) - (*pBBABCD->m_vMinimum) );

// Calculate half boxsize
cTV_3DVECTOR * pHalfBoxSize = new cTV_3DVECTOR( (*pBoxSize) * 0.5 );

// The position of the light should be in the center of the back
// pannel of the box.
cTV_3DVECTOR * pLightPos = new cTV_3DVECTOR( (*pBBABCD->m_vMinimum) + (*pHalfBoxSize) );
pLightPos->z = pBBABCD->m_vMinimum->z;

// We need the position back in world coordinates so we transform
// the light position by the inverse of the lights rotation
cTV_3DMATRIX * pInverseLightRotation = new cTV_3DMATRIX;
m_pMath->TVMatrixInverse( pInverseLightRotation, 0, pLightRotation );
m_pMath->TVVec3TransformCoord( pLightPos, pLightPos, pInverseLightRotation );

// Create the view matrix for the light
cTV_3DMATRIX * pLightView = new cTV_3DMATRIX;
m_pMath->TVMatrixLookAt(pLightView, pLightPos, new cTV_3DVECTOR( m_pLightCamera->GetPosition() - (*pLightPos) ), new cTV_3DVECTOR(0,1,0) );

// Create the projection matrix for the light
// The projection is orthographic since we are using a directional light

cTV_3DMATRIX * pLightProjection = MatrixOrthoLH(pBoxSize->x, pBoxSize->y, -pBoxSize->z - 20.0f, pBoxSize->z );

m_pMath->TVMatrixMultiply( &vLightViewProj, pLightView, pLightProjection );

I tried to follow the code and I didn't really see any problems with it but I guess i'm missing something. This is my renderloop:

// Render ShadowMap
            
Quote
m_pLevelManager->getShader()->SetEffectParamMatrix("xLightViewProjection", &m_pLevelManager->getLightViewProjection() );
            m_pLevelManager->getShader()->SetTechnique("ShadowMap");
            pRenderSurf->SetNewCamera(m_pLevelManager->getLightCamera() );
            pRenderSurf->StartRender();
            m_pScene->RenderAll(false);
            pRenderSurf->EndRender();

            // Render Shadowed Scene
            m_pLevelManager->getShader()->SetTechnique("ShadowedScene");
            m_pLevelManager->getShader()->SetEffectParamTexture("xShadowMap", pRenderSurf->GetTexture() );
            m_pEngine->Clear(false);
            m_pScene->RenderAll(false);
            m_pEngine->RenderToScreen();

I suspect that I might need to edit the camera for the rendersurface some how?. I also suspect that I might need to edit the shader somehow for it to work with directional instead of a pointlight.

Right now the depthmap is rendering clean white and the scene is rendering without shadows ofcourse.
Logged

Toaster
Community Member
*
Posts: 378


WWW
« Reply #12 on: September 11, 2009, 11:24:37 PM »

Hmm I'm if the Light matrix code there is right or not i'm not too great with the maths stuff. Make sure your shader is outputting the correct data. to test this I would position the camera at a default place where it can view some meshes and the landscape. Then draw the depth buffer to the screen. You should in theory see red meshes although it depends on what type of depth output you are doing though as some are colorized and stuff. All in all if your depth map is white this is bad.

For each mesh that casts shadows you have to apply the depth shader to it. However you can disable the shader on that mesh by doing something like: Mesh.SetShader(null); For using multiple textures you have to do:

Code:
texture  textureNameInShader : TEXTURE0;

sampler2D TextureSample = sampler_state
{
Texture   = (textureNameInShader);
MIPFILTER = LINEAR;
MAGFILTER = LINEAR;
MINFILTER = LINEAR;
};

TEXTURE0 specifies the first texture layer on your mesh to  be used automatically. You don't have to send the texture at all cause this is done via Semantics. To see a list of Semantics that you can use you can go here:
http://wiki.truevision3d.com/tutorialsarticlesandexamples/programming_hlsl_shaders2

I hope this helps you out,
-Toaster
Logged

Visit my site at: Unknown Abstraction
tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #13 on: September 12, 2009, 06:31:58 AM »

thanks for the help. I chose to go ahead with another approach. Since It was working with my point light I just moved it very far away to look like a sun. I don't know if it's a good approach but my FPS is good and with some guassian blur on it, it will look perfect for my top-down view. I also got it working for a landscape but I have a little bit the sematics for the textures didnt work for it. I had to set them manually. I have 4 chunks atm.

Also is there anyway I can work with these chunks? For me to get the right texture coordinates I have to check which chunk i'm on in the shader and modify the texturecoords, otherwise I will get the same texture on each chunk.
Logged

ZaPPZion
Moderator
Community Member
*****
Posts: 554


« Reply #14 on: September 13, 2009, 09:33:44 AM »

for a sun, you should go for a directional light with according shadowmapping, because for a pointlight you'll render 6 directions instead of just 1 (iirc)
Logged

Check out my website: www.bartkuipers.com
tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #15 on: September 13, 2009, 10:00:04 AM »

Damn.. I spent like 120 hours now and I don't even know if I'm close to the results I want.. Can someone just give it to me maybe? xD

What I want is Directional Shadows. They should have some kind of blur so that it looks nice. And it should be quick to render so I don't get lag-spikes everytime I Render.
The meshes should also be shadowed by other meshes.

Every tutorial I look into is in XNA and DirectX and is using techniques and method that aint avaible for T3D. XNA Shadowmap sample is for example using VertexPositionTexture.
« Last Edit: September 13, 2009, 10:12:15 AM by tedlin01 » Logged

Lenn
Customers
Community Member
*****
Posts: 876

+/-


« Reply #16 on: September 13, 2009, 03:49:48 PM »

What's wrong with Zak's solution?
Logged

TV3D 6.5 Community Docs - Read, use and please contribute!
tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #17 on: September 13, 2009, 04:13:16 PM »

its VB. I use c++ and it's way to complitated for me to convert :/
Maybe zaknafein kan write a language-independant tutorial? Smiley
Logged

Lenn
Customers
Community Member
*****
Posts: 876

+/-


« Reply #18 on: September 13, 2009, 05:18:22 PM »

It is much simpler to convert from VB than to write a new one from scratch.
All of the TV3D function names are the same.
Even I could do it and I don't know C++.
Come on, you should try a little harder. Wink
Logged

TV3D 6.5 Community Docs - Read, use and please contribute!
tedlin01
Customers
Community Member
*****
Posts: 140


WWW
« Reply #19 on: September 13, 2009, 09:39:36 PM »

hehe. just got up the paste of the conversion when suddenly my email dinged. Whats that? the c++ conversion from Norb. I guess I'm lucky Smiley Works perfect.
Logged

Pages: [1] 2
  Print  
 
Jump to:  

Powered by SMF 1.1.3 | SMF © 2006-2007, Simple Machines LLC
Seo4Smf v0.2 © Webmaster's Talks