| Topic: Directional lights?
|
|
 | Directional lights? | |  |
| Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 10/10/2008 at 19:38:33
| | | Hi Riemer and community! I've followed the series all the way through series 4 and managed to go much farther on from there thanks to the great teaching of these tutorials. However, I now want to get shadow mapping into my scene using a directional light. I can't figure out how I would create either a view matrix or projection matrix for the directional light, can anyone enlighten me as to how this might be done? | |
|
| | | | | | Poster | : riemer | | Posts | : 1392 | | Country | : Belgium | | City | : Antwerp |
| | | | Posted by riemer on 11/10/2008 at 03:41:52
| | You would need to set up an orthogonal projection matrix, using Matrix.CreateOrthogonal, and use this as projection matrices for your lights.
If you get things working, could you post some code? | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 11/10/2008 at 16:57:00
| | Okay, now that makes sense. Now the next problem I'm having is finding which area of the screen to map, does this have something to do with finding which areas are in the camera's viewing frustum?
Of course! :) It could take some time though, knowing my schedule... | |
|
| | | | | | Poster | : radulph | | Posts | : 225 | | Country | : germany | | City | : hamburg |
| | | | Posted by radulph on 12/10/2008 at 04:03:46
| | I actually implemented shadow mapping in my terrain too.
Your aim should be to keep the view frustum of your light source as small as possible in order to get the best quality.
You could compute the center of your camera VF, move far enough in opposite light direction and let the camera look at this center.
Now choose the height and width of your lights VF just so that the VF of the camera fits in.
This way you don't need to render your whole terrain into the shadow map, but only the visible parts (namly the ones inside the camera's VF).
That means, that you also should make the VF of the camera as small as possible (eg, not to choose 10000 for the far clipping plane distance)
I didn't get too far with all this and my shadows lack quality. If you manage to generate optimal view matrices for your light sources, so that nearly the whole shadow map is covered and only very little black space left - and - the quality still is insufficient, then you might go for perspective shadow maps (where objects closer to the viewer get more space in the shadow map).
When using orthographic projection, remember, that the width and height parameters are given in world space units.
Greets.
| |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 12/10/2008 at 12:00:20
| | Thank you very much, this is all starting to come together now! Unfortunately, I need a far clip distance of at least 10000 for the project I am currently working on. I'm thinking I might test shortening only the light view frustum far clip instead of the overall camera view frustum, would this work?
Also, I'm thinking that I could render two shadow maps, one closer up with better resolution and one for farther away objects. Is there any information out there on doing this? | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 12/10/2008 at 21:02:24
| | | I'm having another problem unfortunately. I tried to implement it and got a shadow map working. However, when I rendered the shadow scene step both of my models came out purely purple. What can I do to get rid of this? | |
|
| | | | | | Poster | : radulph | | Posts | : 225 | | Country | : germany | | City | : hamburg |
| | | | Posted by radulph on 13/10/2008 at 11:05:54
| | Well you are a programmer, arent you? ;)
So everything you need, lies in your hands, or at least direct in front of you. If you manage to create one shadow map for your terrain (is that, what you are doing?), it should be no problem to implement 2.
However, suggesting that you would like to render a terrain, I have an advise for you:
Use a shadow map for near objects. Compute it as discussed in earlierer posts, just act as if the far clipping plane wouldn't be that far away.
If you can abandon small and distant objects (eg trees, houses) to cast shadows and only need the terrain to self shadow, you can use John Snyeders way:
By intelligent sampling of the height map in the shader, he is able to compute a horizon map for a 512x512 terrain in real time.
To compute the horizon angle of an arbitary point of the terrain, you need to sample the height map from this point in all directions.
To determine if an arbitary point is in shadow (by the terrain itself), however, you need to sample the height map only in one direction (namly opposite light dir). This was you should be able to speed up the algorithm very much and use it for much bigger terrains.
greets.
http://research.microsoft.com/~johnsny/
"Fast Soft Self-Shadowing on Dynamic Height Fields" | |
|
| | | | | | Poster | : radulph | | Posts | : 225 | | Country | : germany | | City | : hamburg |
| | | | Posted by radulph on 13/10/2008 at 11:11:13
| | sry, didn't see your other post. What do you mean exactly? When you apply your shadow map to your final scene, your models don't get colored, but rather are purely purple?
hm...
what about the rest of your scene? | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 13/10/2008 at 21:46:12
| | Well, right now, I'm actually not testing on my terrain, but rather two models, a cube and a sphere. Would you recommend I test it on my terrain first? I have the sphere positioned so that it will cast a shadow on the cube.
I'll make sure to keep the view distance short then.
I'd much rather ues John Snyeder's technique for terrain. :) However I am in need of shadow mapping for models as well. Thank you for pointing me to that though!
Yes, purely purple. I added a bit of code in the effect file and it only changed it to dark blue, so something is wrong.
My sample view and projection matrices are:
view = Matrix.CreateLookAt(new Vector3(5, 4, 5), Vector3.Zero, Vector3.One);
projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 1, 0.1f, 1000.0f);
Vector3 viewcenter = (Vector3.Zero - new Vector3(5, 4, 5)) / 2;
Vector3 viewposition = Vector3.Zero - (new Vector3(0.5f, -1f, -0.5f) * 5);
lightview = Matrix.CreateLookAt(viewposition, Vector3.Zero, Vector3.One);
lightprojection = Matrix.CreateOrthographic(10, 10, 1f, 50.0f);
Should I be calculating the light's view and projection differently? Both models show up in the shadow map, for some reason I can't get the shadow map to be applied in the scene without it turning dark blue or purple! | |
|
| | | | | | Poster | : radulph | | Posts | : 225 | | Country | : germany | | City | : hamburg |
| | | | Posted by radulph on 14/10/2008 at 04:36:27
| | Shadow mapping is a general purpose algorithm to compute shadws and works on every 3d geometry (even simulated one via parallax mapping etc). So don't worry about your models.
What I meant, was to abandon distant models to cast shadows and be satsified with terrain self shadowing only. (Not so for near models)
Can you save your shadow map and show it in order to see, if it looks correctly? | |
|
| | | | | | Poster | : radulph | | Posts | : 225 | | Country | : germany | | City | : hamburg |
| | | | Posted by radulph on 14/10/2008 at 04:40:26
| | Plus: (This forum really needs an edit funciton :) )
To determine if your light's view and projection matrices are correct, just replace your camera matrix by them to see if you capture the whole scene.
Greets. | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 14/10/2008 at 12:05:21
| | Okay, I'll continue with my simple scene for now then.
I did, and it renders something although I don't know if it is correct. I can't quite seem to imagine how it would turn out so the second I got the grayish sphere and cube to turn up I figured it was good.
Is there something I could be doing in my draw method that could be incorrect? For drawing the shadow map, for instance, should I clear the background black instead of white? I don't have access to my code at the moment (forgot to put it on the flash drive :) ) so I can't test this out, I'll let you know if I get it working before you reply. | |
|
| | | | | | Poster | : radulph | | Posts | : 225 | | Country | : germany | | City | : hamburg |
| | | | Posted by radulph on 14/10/2008 at 12:45:34
| | | An image of your shadow map really would help ;) | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 15/10/2008 at 21:48:23
| | Thank you for all your help, I managed to figure out the problem and my shadows now display. :) However (as expected) I'm having some problems again.
The least of my worries is the small artifacts along the cube edges farthest from the light direction (I could have a screenshot later, but I'm going to implement PCF or VSM in this and the artifacts might disappear).
My biggest concern is that my directional light looks like a point light casting a shadow. It fades the farther from the light direction it gets. I don't know why this is happening, I tried resizing the projection matrix, changed the view position, and neither worked. I'd be grateful for further help. | |
|
| | | | | | Poster | : radulph | | Posts | : 225 | | Country | : germany | | City | : hamburg |
| | | | Posted by radulph on 16/10/2008 at 05:53:29
| | Well you make trouble shooting really hard, not providing the community with screenshots or detailed informations :)
I'm curious to know, what the error was...
Since you use an orthographic projection matrix, your light source shouldn't show the characteristics of a point light - are you sure?
Try to render your scene from the top with an orthogaphic projection too and check whether the conturs of your shadow are parallel or not.
Greets. | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 16/10/2008 at 13:32:49
| | Forgive me, sometimes I am separated from my code. :) Here is a screenshot.

It's sort of embarrassing as it's a dummy problem. :) I was setting my models' world matrices to Matrix.Identity when I rendered the shadow map instead of what I said their world's to previously.
When I render it from the top it seems fine, but when I set the light direction to (-.5f, -1f, .5f) as it is now it fades away.
Thank you for your continued help! | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 16/10/2008 at 13:34:41
| | | Do I have to post my image on a website for it to upload on this forum? I have not uploaded an image before and I saw that it did not show... | |
|
| | | | | | Poster | : cpyburn | | Posts | : 29 | | Country | : UnitedStats | | City | : Memphis |
| | | | Posted by cpyburn on 16/10/2008 at 16:06:22
| | 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;
} | |
|
| | | | | | Poster | : radulph | | Posts | : 225 | | Country | : germany | | City | : hamburg |
| | | | Posted by radulph on 16/10/2008 at 18:00:12
| | Hi cpyburn,
thank you for your code - seems to generate some quality matrices, I defenatly will give it a try (my shadows are cruel :) )
Have you also tried to compute, how to turn the "light camera" (I mean choosing up vectors different then (0, 1, 0)) in order to reduce unused space in the shadow map even further? (This is for example neccessary, when the light comes from a small angle)
Let me know.
To Irish-Koder: I really can't imagine the shadow to fade, as you use an orthographic position - don't you? But I believe you.
You have to upload your image somewhere and post the link. Let us have a look at it ;)
BTW: Congratrulations on your progress.
| |
|
| | | | | | Poster | : radulph | | Posts | : 225 | | Country | : germany | | City | : hamburg |
| | | | Posted by radulph on 16/10/2008 at 18:10:46
| | | sry should be projection not position, also some posts earlier should be assuming not suggesting :) | |
|
| | | | | | Poster | : cpyburn | | Posts | : 29 | | Country | : UnitedStats | | City | : Memphis |
| | | | Posted by cpyburn on 16/10/2008 at 22:14:54
| | | the light camera is just a lookat matrix, you should be able to turn it how ever you want and still get a shadowmap. I also use a 2048 shadowmap for better quality. | |
|
| | | | | | Poster | : cpyburn | | Posts | : 29 | | Country | : UnitedStats | | City | : Memphis |
| | | | Posted by cpyburn on 17/10/2008 at 09:11:06
| | i have recreated remiers tutorial using 2048 shadow map and the CreateLightViewProjectionMatrix(). It looks pretty dang good. Here is a screen shot.
http://c1.ac-images.myspacecdn.com/images02/2/l_4fce867a06e144549082a7750a744368.jpg
| |
|
| | | | | | Poster | : cpyburn | | Posts | : 29 | | Country | : UnitedStats | | City | : Memphis |
| | | | Posted by cpyburn on 17/10/2008 at 09:26:31
| | I went ahead and took one more screen shot, more realistic, with the light position 1000f up in the z direction so that you could see the resolution.
http://c2.ac-images.myspacecdn.com/images02/8/l_4995400a02cc4c7c8be672858a5ddff5.jpg
| |
|
| | | | | | Poster | : radulph | | Posts | : 225 | | Country | : germany | | City | : hamburg |
| | | | Posted by radulph on 17/10/2008 at 10:45:18
| | How can you generate that big shadow maps?
I seem to get an error, whenever setting up a render target, whos resolutions is bigger than the current screen resolution.
Greets. | |
|
| | | | | | Poster | : cpyburn | | Posts | : 29 | | Country | : UnitedStats | | City | : Memphis |
| | | | Posted by cpyburn on 17/10/2008 at 10:48:06
| | | You need to use the depthstencilbuffer | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 19/10/2008 at 19:53:26
| | To Radulph: Guess what? It works now, and this time I have no clue why! I was playing around in a new project with the same thing, and this time for some reason there is no fade!
I uploaded an image of my simple test this time too. :) Here is the link to the page:
http://img407.imageshack.us/my.php?image=dirshadow03kn9.jpg
To cpyburn: Very good looking shadows, I must say! I tried out your method, however it didn't turn out at all as I wanted it too. I'm still just using the original Riemer's method, do I need to make some changes? For instance, I don't do any work regarding depth stencil buffers. | |
|
| | | | | | Poster | : cpyburn | | Posts | : 29 | | Country | : UnitedStats | | City | : Memphis |
| | | | Posted by cpyburn on 20/10/2008 at 09:03:30
| | | I will post the code tomorrow on how to use depthstencil buffer. | |
|
| | | | | | Poster | : cpyburn | | Posts | : 29 | | Country | : UnitedStats | | City | : Memphis |
| | | | Posted by cpyburn on 20/10/2008 at 09:15:36
| | i meant to say if you plan on making a game then you will most definately need to change how you code shadows. Riemers tutorial is directional light like headlights, a sun is a orthographic light, and a candle is a point light which needs a cube map.
Orthographic light gives you this effect.
http://c4.ac-images.myspacecdn.com/images02/35/l_1a100d4068c14c2a8e160804d33a097f.jpg
Which adds amazing results to a game. Here is what it looks like without.
http://c4.ac-images.myspacecdn.com/images02/4/l_820ff0d799f44ec6ade25697221bb7c7.jpg | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 20/10/2008 at 20:54:17
| | That would be great if you could. :)
Those are great shadows. What kind of speed do you get rendering them? I saw a different example with 2048 shadow maps and the quality was not near as good.
My current scene renders from handmade matrices, I'm going to give your method another attempt though. :D Hopefully it works out this time, I think I know why it didn't the first time.
Thank you for your help! | |
|
| | | | | | Poster | : cpyburn | | Posts | : 29 | | Country | : UnitedStats | | City | : Memphis |
| | | | Posted by cpyburn on 21/10/2008 at 11:09:47
| | this is with the sun REALLY HIGH, move the lightpos around a little bit for fun. good luck to you all.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace XNAseries3
{
public class Game1 : Microsoft.Xna.Framework.Game
{
struct MyOwnVertexFormat
{
private Vector3 position;
private Vector2 texCoord;
private Vector3 normal;
public MyOwnVertexFormat(Vector3 position, Vector2 texCoord, Vector3 normal)
{
this.position = position;
this.texCoord = texCoord;
this.normal = normal;
}
public static VertexElement[] VertexElements =
{
new VertexElement(0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0),
new VertexElement(0, sizeof(float)*3, VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0),
new VertexElement(0, sizeof(float)*5, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0),
};
public static int SizeInBytes = sizeof(float) * (3 + 2 + 3);
}
GraphicsDeviceManager graphics;
GraphicsDevice device;
Effect effect;
Matrix viewMatrix;
Matrix projectionMatrix;
VertexBuffer vertexBuffer;
VertexDeclaration vertexDeclaration;
Vector3 cameraPosition;
Texture2D streetTexture;
Model lamppostModel;
Texture2D[] lamppostTextures;
Model carModel;
Texture2D[] carTextures;
Texture2D carLight;
Vector3 lightPos;
float lightPower;
float ambientPower;
Matrix lightsViewProjectionMatrix;
// The size of the shadow map
// The larger the size the more detail we will have for our entire scene
const int shadowMapWidthHeight = 2048;
RenderTarget2D renderTarget;
Texture2D shadowMap;
DepthStencilBuffer shadowDepthBuffer;
BoundingFrustum cameraFrustum = new BoundingFrustum(Matrix.Identity);
KeyboardState currentKeyboardState;
GamePadState currentGamePadState;
float rotateDude = 0.0f;
Vector3 cameraForward = new Vector3(0, 2, -12);
Vector3[] lamppostPositions = new Vector3[2];
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
graphics.PreferredBackBufferWidth = 500;
graphics.PreferredBackBufferHeight = 500;
graphics.IsFullScreen = false;
graphics.ApplyChanges();
Window.Title = "Recreate";
base.Initialize();
}
protected override void LoadContent()
{
device = GraphicsDevice;
effect = Content.Load<Effect>("PreshaderShadowEffects");
streetTexture = Content.Load<Texture2D>("streettexture");
carLight = Content.Load<Texture2D>("carlight");
//carModel = Content.Load<Model>("carmesh/car");
//lamppostModel = Content.Load<Model>("lamppost");
carModel = LoadModel("carmesh/car", out carTextures);
lamppostModel = LoadModel("lamppost", out lamppostTextures);
SetUpVertices();
SetUpCamera();
//PresentationParameters pp = device.PresentationParameters;
//renderTarget = new RenderTarget2D(device, pp.BackBufferWidth, pp.BackBufferHeight, 1, SurfaceFormat.Single);
// Create new floating point render target
renderTarget = new RenderTarget2D(graphics.GraphicsDevice,
shadowMapWidthHeight,
shadowMapWidthHeight,
1, SurfaceFormat.Single);
// Create depth buffer to use when rendering to the shadow map
shadowDepthBuffer = new DepthStencilBuffer(graphics.GraphicsDevice,
shadowMapWidthHeight,
shadowMapWidthHeight,
DepthFormat.Depth24);
}
private Model LoadModel(string assetName, out Texture2D[] textures)
{
Model newModel = Content.Load<Model>(assetName);
textures = new Texture2D[7];
int i = 0;
foreach (ModelMesh mesh in newModel.Meshes)
{
foreach (BasicEffect currentEffect in mesh.Effects)
{
textures[i++] = currentEffect.Texture;
}
foreach (ModelMeshPart meshPart in mesh.MeshParts)
{
meshPart.Effect = effect.Clone(device);
}
}
return newModel;
}
private void SetUpVertices()
{
MyOwnVertexFormat[] vertices = new MyOwnVertexFormat[18];
vertices[0] = new MyOwnVertexFormat(new Vector3(-20, 0, 10), new Vector2(-0.25f, 25.0f), new Vector3(0, 1, 0));
vertices[1] = new MyOwnVertexFormat(new Vector3(-20, 0, -100), new Vector2(-0.25f, 0.0f), new Vector3(0, 1, 0));
vertices[2] = new MyOwnVertexFormat(new Vector3(2, 0, 10), new Vector2(0.25f, 25.0f), new Vector3(0, 1, 0));
vertices[3] = new MyOwnVertexFormat(new Vector3(2, 0, -100), new Vector2(0.25f, 0.0f), new Vector3(0, 1, 0));
vertices[4] = new MyOwnVertexFormat(new Vector3(2, 0, 10), new Vector2(0.25f, 25.0f), new Vector3(-1, 0, 0));
vertices[5] = new MyOwnVertexFormat(new Vector3(2, 0, -100), new Vector2(0.25f, 0.0f), new Vector3(-1, 0, 0));
vertices[6] = new MyOwnVertexFormat(new Vector3(2, 1, 10), new Vector2(0.375f, 25.0f), new Vector3(-1, 0, 0));
vertices[7] = new MyOwnVertexFormat(new Vector3(2, 1, -100), new Vector2(0.375f, 0.0f), new Vector3(-1, 0, 0));
vertices[8] = new MyOwnVertexFormat(new Vector3(2, 1, 10), new Vector2(0.375f, 25.0f), new Vector3(0, 1, 0));
vertices[9] = new MyOwnVertexFormat(new Vector3(2, 1, -100), new Vector2(0.375f, 0.0f), new Vector3(0, 1, 0));
vertices[10] = new MyOwnVertexFormat(new Vector3(3, 1, 10), new Vector2(0.5f, 25.0f), new Vector3(0, 1, 0));
vertices[11] = new MyOwnVertexFormat(new Vector3(3, 1, -100), new Vector2(0.5f, 0.0f), new Vector3(0, 1, 0));
vertices[12] = new MyOwnVertexFormat(new Vector3(13, 1, 10), new Vector2(0.75f, 25.0f), new Vector3(0, 1, 0));
vertices[13] = new MyOwnVertexFormat(new Vector3(13, 1, -100), new Vector2(0.75f, 0.0f), new Vector3(0, 1, 0));
vertices[14] = new MyOwnVertexFormat(new Vector3(13, 1, 10), new Vector2(0.75f, 25.0f), new Vector3(-1, 0, 0));
vertices[15] = new MyOwnVertexFormat(new Vector3(13, 1, -100), new Vector2(0.75f, 0.0f), new Vector3(-1, 0, 0));
vertices[16] = new MyOwnVertexFormat(new Vector3(13, 21, 10), new Vector2(1.25f, 25.0f), new Vector3(-1, 0, 0));
vertices[17] = new MyOwnVertexFormat(new Vector3(13, 21, -100), new Vector2(1.25f, 0.0f), new Vector3(-1, 0, 0));
vertexBuffer = new VertexBuffer(device, vertices.Length * MyOwnVertexFormat.SizeInBytes, BufferUsage.WriteOnly);
vertexBuffer.SetData(vertices);
vertexDeclaration = new VertexDeclaration(device, MyOwnVertexFormat.VertexElements);
}
private void SetUpCamera()
{
cameraPosition = new Vector3(-25, 13, 18);
viewMatrix = Matrix.CreateLookAt(cameraPosition, cameraForward, new Vector3(0, 1, 0));
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 1.0f, 100.0f);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
HandleInput(gameTime);
UpdateCamera(gameTime);
UpdateLightData();
base.Update(gameTime);
}
private void UpdateLightData()
{
ambientPower = 0.5f;
lightPos = new Vector3(-18, 100, -2);
//lightPos = new Vector3(lightPos.X, lightPos.Y - 10f, lightPos.Z);
lightPower = 2.0f;
//Matrix lightsView = Matrix.CreateLookAt(lightPos, Vector3.Down, Vector3.Up);
//Matrix lightsProjection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, 1f, 1f, 1000f);
//lightsViewProjectionMatrix = lightsView * lightsProjection;
lightsViewProjectionMatrix = CreateLightViewProjectionMatrix();
lamppostPositions[0] = new Vector3(3f, 11.5f, -35f);
lamppostPositions[1] = new Vector3(3f, 11.5f, -5f);
}
protected override void Draw(GameTime gameTime)
{
// Set our render target to our floating point render target
device.SetRenderTarget(0, renderTarget);
// Save the current stencil buffer
DepthStencilBuffer oldDepthBuffer = device.DepthStencilBuffer;
// Set the graphics device to use the shadow depth stencil buffer
device.DepthStencilBuffer = shadowDepthBuffer;
// Clear the render target to white or all 1's
// We set the clear to white since that represents the
// furthest the object could be away
device.Clear(Color.White);
DrawScene("ShadowMap");
Matrix car1Matrix = Matrix.CreateScale(4f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateTranslation(-3, 0, -15);
DrawModel(carModel, carTextures, car1Matrix, "ShadowMap");
//Matrix car2Matrix = Matrix.CreateScale(4f) * Matrix.CreateRotationY(MathHelper.Pi * 5.0f / 8.0f) * Matrix.CreateTranslation(-28, 0, -1.9f);
//DrawModel(carModel, carTextures, car2Matrix, "ShadowMap");
Matrix lamp1Matrix = Matrix.CreateScale(0.05f) * Matrix.CreateTranslation(4.0f, 1, -35);
DrawModel(lamppostModel, carTextures, lamp1Matrix, "ShadowMap");
Matrix lamp2Matrix = Matrix.CreateScale(0.05f) * Matrix.CreateTranslation(4.0f, 1, -5);
DrawModel(lamppostModel, carTextures, lamp2Matrix, "ShadowMap");
// Set render target back to the back buffer
device.SetRenderTarget(0, null);
// Reset the depth buffer
device.DepthStencilBuffer = oldDepthBuffer;
// Return the shadow map as a texture
shadowMap = renderTarget.GetTexture();
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
DrawScene("ShadowedScene");
DrawModel(carModel, carTextures, car1Matrix, "ShadowedScene");
//DrawModel(carModel, carTextures, car2Matrix, "ShadowedScene");
DrawModel(lamppostModel, carTextures, lamp1Matrix, "ShadowedScene");
DrawModel(lamppostModel, carTextures, lamp2Matrix, "ShadowedScene");
using (SpriteBatch sprite = new SpriteBatch(device))
{
sprite.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate,
SaveStateMode.SaveState);
sprite.Draw(shadowMap, new Rectangle(0, 0, 128, 128), Color.White);
sprite.End();
}
base.Draw(gameTime);
}
private void DrawScene(string technique)
{
effect.CurrentTechnique = effect.Techniques[technique];
effect.Parameters["xCamerasViewProjection"].SetValue(viewMatrix * projectionMatrix);
effect.Parameters["xLightsViewProjection"].SetValue(lightsViewProjectionMatrix);
effect.Parameters["xWorld"].SetValue(Matrix.Identity);
effect.Parameters["xTexture"].SetValue(streetTexture);
effect.Parameters["xLightPos"].SetValue(lightPos);
effect.Parameters["xLightPower"].SetValue(lightPower);
effect.Parameters["xAmbient"].SetValue(ambientPower);
effect.Parameters["xShadowMap"].SetValue(shadowMap);
effect.Begin();
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Begin();
device.VertexDeclaration = vertexDeclaration;
device.Vertices[0].SetSource(vertexBuffer, 0, MyOwnVertexFormat.SizeInBytes);
device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 18);
pass.End();
}
effect.End();
}
private void DrawModel(Model model, Texture2D[] textures, Matrix wMatrix, string technique)
{
Matrix[] modelTransforms = new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(modelTransforms);
int i = 0;
foreach (ModelMesh mesh in model.Meshes)
{
foreach (Effect currentEffect in mesh.Effects)
{
Matrix worldMatrix = modelTransforms[mesh.ParentBone.Index] * wMatrix;
currentEffect.CurrentTechnique = currentEffect.Techniques[technique];
currentEffect.Parameters["xCamerasViewProjection"].SetValue(viewMatrix * projectionMatrix);
currentEffect.Parameters["xLightsViewProjection"].SetValue(lightsViewProjectionMatrix);
currentEffect.Parameters["xWorld"].SetValue(worldMatrix);
currentEffect.Parameters["xTexture"].SetValue(textures[i++]);
currentEffect.Parameters["xLightPos"].SetValue(lightPos);
currentEffect.Parameters["xLightPower"].SetValue(lightPower);
currentEffect.Parameters["xAmbient"].SetValue(ambientPower);
currentEffect.Parameters["xShadowMap"].SetValue(shadowMap);
}
mesh.Draw();
}
}
Matrix CreateLightViewProjectionMatrix()
{
// Matrix with that will rotate in points the direction of the light
Matrix lightRotation = Matrix.CreateLookAt(Vector3.Zero,
-lightPos,
Vector3.Up);
// Get the corners of the frustum
cameraFrustum.Matrix = viewMatrix * projectionMatrix;
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] += new Vector3(1f, 1f, 1f);
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 - lightPos,
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 - 20f, boxSize.Z);
return lightView * lightProjection;
}
#region Handle Input
/// <summary>
/// Handles input for quitting the game.
/// </summary>
void HandleInput(GameTime gameTime)
{
float time = (float)gameTime.ElapsedGameTime.TotalMilliseconds;
currentKeyboardState = Keyboard.GetState();
currentGamePadState = GamePad.GetState(PlayerIndex.One);
if (currentKeyboardState.IsKeyDown(Keys.Q))
rotateDude -= time * 0.2f;
if (currentKeyboardState.IsKeyDown(Keys.E))
rotateDude += time * 0.2f;
// Check for exit.
if (currentKeyboardState.IsKeyDown(Keys.Escape) ||
currentGamePadState.Buttons.Back == ButtonState.Pressed)
{
Exit();
}
}
/// <summary>
/// Handles input for moving the camera.
/// </summary>
void UpdateCamera(GameTime gameTime)
{
float time = (float)gameTime.ElapsedGameTime.TotalMilliseconds;
// Check for input to rotate the camera.
float pitch = -currentGamePadState.ThumbSticks.Right.Y * time * 0.001f;
float turn = -currentGamePadState.ThumbSticks.Right.X * time * 0.001f;
if (currentKeyboardState.IsKeyDown(Keys.Up))
pitch += time * 0.001f;
if (currentKeyboardState.IsKeyDown(Keys.Down))
pitch -= time * 0.001f;
if (currentKeyboardState.IsKeyDown(Keys.Left))
turn += time * 0.001f;
if (currentKeyboardState.IsKeyDown(Keys.Right))
turn -= time * 0.001f;
Vector3 cameraRight = Vector3.Cross(Vector3.Up, cameraForward);
Vector3 flatFront = Vector3.Cross(cameraRight, Vector3.Up);
Matrix pitchMatrix = Matrix.CreateFromAxisAngle(cameraRight, pitch);
Matrix turnMatrix = Matrix.CreateFromAxisAngle(Vector3.Up, turn);
Vector3 tiltedFront = Vector3.TransformNormal(cameraForward, pitchMatrix *
turnMatrix);
// Check angle so we cant flip over
if (Vector3.Dot(tiltedFront, flatFront) > 0.001f)
{
cameraForward = Vector3.Normalize(tiltedFront);
}
// Check for input to move the camera around.
if (currentKeyboardState.IsKeyDown(Keys.W))
cameraPosition += cameraForward * time * 0.1f;
if (currentKeyboardState.IsKeyDown(Keys.S))
cameraPosition -= cameraForward * time * 0.1f;
if (currentKeyboardState.IsKeyDown(Keys.A))
cameraPosition += cameraRight * time * 0.1f;
if (currentKeyboardState.IsKeyDown(Keys.D))
cameraPosition -= cameraRight * time * 0.1f;
cameraPosition += cameraForward *
currentGamePadState.ThumbSticks.Left.Y * time * 0.1f;
cameraPosition -= cameraRight *
currentGamePadState.ThumbSticks.Left.X * time * 0.1f;
if (currentGamePadState.Buttons.RightStick == ButtonState.Pressed ||
currentKeyboardState.IsKeyDown(Keys.R))
{
cameraPosition = new Vector3(0, 50, 50);
cameraForward = new Vector3(0, 0, -1);
}
cameraForward.Normalize();
// Create the new view matrix
viewMatrix = Matrix.CreateLookAt(cameraPosition,
cameraPosition + cameraForward,
Vector3.Up);
// Set the new frustum value
cameraFrustum.Matrix = viewMatrix * projectionMatrix;
}
#endregion
}
}
| |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 21/10/2008 at 19:30:17
| | | Alright, I got your method working! :) The resolution is still not that great, I'm only able to set my view's farplane to 50 to actually get shadows. When my object moves it will occasionally flicker at the bottom of the shadow, and my resolution is not at all comparable to yours. I'll tweak it some more and see if I can't get rid of the artifacts, but I may have to just go to VSM to get rid of it. | |
|
| | | | | | Poster | : cpyburn | | Posts | : 29 | | Country | : UnitedStats | | City | : Memphis |
| | | | Posted by cpyburn on 22/10/2008 at 08:28:21
| | you have to realize this, step outside the box and look at your scene from the lights view. And then think to yourself if I only have 2048 pixels as a resolution then the smaller I make my projection matrix (smaller farplane), the way better of a shadow I will get, because you are storing less shadow data in a high resolution texture. you only have 2048x2048 pixels, each pixel will hold a part of a shadow. If you see that the bigger the scene gets, the 2048 pixels doesnt change so where will you store the extra shadow information for the bigger scene? you wont, you cant, its impossible... the bigger your scene gets, the more pixels of information you need to store (far plane increasing) to keep the same awesome looking shadow. hope that makes since, because now I am going to explain to you how to get better shadows.
think about this, your scene is 1000f far plane long, you only need awesome shadows in the first 10f, you need decent shadows in the next 100f, you need ok shadows in the next 240f, then you really dont care about the remaining 650, you just need it to appear that there is a shadow in this range. the reason you dont care is because you really cant see that far, you can, but you cant make out the resolution of the shadows. so if its a little blocky, you will never notice. this is called cascading shadow mapping. its pretty complex and took me about a week to grasp but hopefully my explaination will decrease your learning curve.
so now what? well rendering 4 2048 shadow maps is just to much and will bottle neck your game, at least mine anyways. i dropped mine down to 1024x1024 maps x 4 which is still slow in my opinion but it works. but the object is to pick some value between your near plane and far plane and decide where you want your best shadows to be and where you want your worst shadows to be. put your good shadows in a small lightViewProjection matrix and your bad shadows big. in my game i did 50f 100f 250f 650f, or .05 * farplane, .1 * farplane, .25 * farplane, etc. goood luck, i have a meeting to go to. | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 25/10/2008 at 17:16:31
| | Wow, thank you for that explanation! It's a lot simpler than many of the ways I've heard CSM explained. :) I managed to finally get shadows working with my deferred shader, still at low quality, but now I'll be able to move on to PSSM or CSM now that I have it working in my better project.
I did try VSM but it messed up so I got rid of it. I'll go back to it later, have you tried VSM? Or another method to get the soft shadow effect? | |
|
| | | | | | Poster | : IrishKoder | | Posts | : 27 | | Country | : United States | | City | : |
| | | | Posted by IrishKoder on 28/10/2008 at 19:17:25
| | | I just got an idea. Since only the r channel is used in the depth mapping, why is it necessary to use four shadow maps? Isn't it possible to use all four channels as each shadow map and pass in the four views and projections? If this worked as I am thinking it would draw each level into one texture, which could be a lot faster and still allow you to use 2048. I still have to test this to see if it works though... | |
|
| | | | | | Poster | : cpyburn | | Posts | : 29 | | Country | : UnitedStats | | City | : Memphis |
| | | | Posted by cpyburn on 12/12/2008 at 15:30:55
| | | that is a nice thought, but you still have to write to the shadow map 4 times, and read it 4 times, it will take the same amount of time to read and write using the same shadowmap as it would using all 4 shadowmaps... it will save you a couple of megs of harddrive space using 1shadowmap with 4 channels though ;) | |
|
| | | | | | Poster | : Typon | | Posts | : 1 | | Country | : Sweden | | City | : xxx |
| | | | Posted by Typon on 11/09/2009 at 20:44:17
| | Hello! I'm trying to use cpyburn directional techinque. Is it possible to get a screenshot of the rendered depthmap so that I can compare? Also, have you changed something in your shader from the original?
Kind regards | |
|
| | | | | | Poster | : Anonymous | | Posts | : | | Country | : | | City | : |
| | | | Posted by Anonymous on 27/07/2012 at 14:43:23
| | | this record ciairfles the new facial appearance of the dx11 N cards, why the hell people talk about pcs and consoles=really irrelevant. And at the same time, this never apply to ati graphics and console hardwares(archi too ancient 7900gtx+). | |
|
|
 | | |  |
|
|
|
If you appreciate the amount of time I spend creating and updating these pages, feel free to donate -- any amount is welcome !
|
- Website design & DirectX code : Riemer Grootjans - ©2006 Riemer Grootjans
|
|