|
tedlin01
|
 |
« 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  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
|
 |
« 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.htmlThere'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
|
 |
« 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: 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: 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: 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
|
 |
« 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. 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: /////////////////////////////////// ////// 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: // 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
|
 |
« 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
|
|
|
|
|
tedlin01
|
 |
« 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
|
 |
« 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: Shader.SetEffectParamTexture("textureNameInShader", TextureID)
and in your shader you need: 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
|
|
|
|
|
tedlin01
|
 |
« 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
|
 |
« Reply #10 on: September 11, 2009, 09:19:29 AM » |
|
Nvm, I was only supposed to add the shader to the landscape  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
|
 |
« 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=0This is hes modified code for the lightviewproj: 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: 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 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
|
 |
« 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: 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_shaders2I hope this helps you out, -Toaster
|
|
|
|
|
Logged
|
|
|
|
|
tedlin01
|
 |
« 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
|
 |
« 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
|
|
|
|
|
tedlin01
|
 |
« 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
|
|
|
|
|
tedlin01
|
 |
« 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? 
|
|
|
|
|
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. 
|
|
|
|
|
Logged
|
|
|
|
|
tedlin01
|
 |
« 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  Works perfect.
|
|
|
|
|
Logged
|
|
|
|
|