Sign in to follow this  

MDX - Matrix.shadow?

This topic is 4388 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

Hi, I'm trying to render a simple cube mesh along with it's projected shadow albeit a cube mesh rotated using the mesh.shadow method. I'm using mesh.shadow but I can't seem to get the desired results. In terms of expected output I'm trying to create a top down view for an overhead scroller. I haven't bothered setting an ortho projection matrix as I will be using transforms etc for my sprite rotation etc. I've posted a few lines of code in the hope someone can help me render a simple cube along with a cube that represents its shadow simulating a top down view. My matrices in the setup are ok for rendering my tiles etc however my light vector and place used in the matrix.shadow function are really just guesses. Can someone please help me set these up correctly? Light ______+++ ______+++* ______+++** _______*****
  'Matrices set up - Working for tiles
  .Transform.World = Matrix.Identity
  .Transform.View = Matrix.LookAtLH(New Vector3(Xposition, Yposition, 9), New Vector3(Xposition, Yposition, 0), New Vector3(0.0F, 1.0F, 0.0F))
  .Transform.Projection = Matrix.PerspectiveFovLH(1, 1, 0.0F, 5.0F)

  '------------------------------------------------------------------------
  'Simple Cube Mesh using fo shadows
  myMesh = Mesh.Box(D3Ddevice, 0.1, 0.1, 1)

  'Light position and plane, not sure what goes here?
  Dim myLight As New Vector4(-0.1, 0.1, 7, 0.2)
  Dim myPlane As New Plane(0, 0, 5, -1)
  Dim myMatrix As New Matrix
  mymatrix.shadow(myLight, myPlane)

  'Draw shadow cube
  .Transform.Projection = myMatrix
  myMesh.DrawSubset(0)

  'Draw cube for reference only
  .Transform.Projection = Matrix.PerspectiveFovLH(Math.PI / 4, 1, 0.0F, 5.0F)
   myMesh.DrawSubset(0)




Share this post


Link to post
Share on other sites
Quote:
Original post by remigius
I haven't used Matrix.Shadow myself, but Armadon has an excellent tutorial with sources on how to use it:

- click here (the link to the source is at the top of the tutorial)

It is in C# though, but I hope it helps :)


Thanks, it certianly shows that my projection/transform code is incorrect but as I'm happy with my current world, transform and projection setup in relation to my tiles I don't know what it should be in terms of my cube/shadows?

:(

Share this post


Link to post
Share on other sites
Well, IF I'm correct, you should be able to just multiply your world tranform with the matrix obtained from Matrix.Shadow(..), like this (in C#, don't know VB):

[source lang=c#]
device.Transform.View = yourViewMatrix;
device.Transform.Projection = yourProjectionMatrix;

// draw the cube itself
device.Transform.World = yourWorldTransformMatrix;
cubeMesh.DrawSubset(0);

// construct shadow matrix and draw shadow
Plane plane = Plane.FromPointNormal( new Vector3(), new Vector3(0, 1, 0));
Vector4 light = new Vector4( 0, -1, 0, 0 );

Matrix shadowMatrix = Matrix.Shadow(light, plane);
device.Transform.World = yourWorldTransformMatrix * shadowMatrix;
cubeMesh.DrawSubset(0);




I hope this clears some things up, even if it's in C#. You can check out the documentation for more info on the Matrix.Shadow parameters btw, just noticed it has some special behaviours, for example for the light vector's W component (0 for directional lights, 1 for point lights).

Share this post


Link to post
Share on other sites
Quote:
Original post by remigius
Well, IF I'm correct, you should be able to just multiply your world tranform with the matrix obtained from Matrix.Shadow(..), like this (in C#, don't know VB):

*** Source Snippet Removed ***

I hope this clears some things up, even if it's in C#. You can check out the documentation for more info on the Matrix.Shadow parameters btw, just noticed it has some special behaviours, for example for the light vector's W component (0 for directional lights, 1 for point lights).


Yes thanks Remigius. I have it working although I still haven't grasped the correclation between my existing tile based world/projection/view setup and the cube/shadow render yet :(

I'm also beginning to think that the reason I'm going to use this technique anyway may not look very good in relation to an overhead scroller anyway. I suspect that shadow volumes in combinaiton with quads alphablended won't look too realistic as I dont think that each shadow volume take into consideration other light sources. i.e. if a light is in the same area as rendered shadow quad shouldn't it actually light that area?

Share this post


Link to post
Share on other sites
Quote:
I have it working although I still haven't grasped the correclation between my existing tile based world/projection/view setup and the cube/shadow render yet :(


I tried drawing this for you, but I think explaining it in text should be clearer. So here goes :)

When you render your cube it gets transformed from the object space you defined it in, to 2D coordinates on your screen. This transformation process consists of 3 steps, which are executed in the following order:

World transform

The object is scaled, rotated and/or translated to it's actual place in your world. Since you're using the Matrix.Identity matrix, the object isn't altered in any way and remains standing there at the origin (0,0,0) of the world space. You could use a combination of matrices to transform your cube (or any other mesh) in world space. These matrices can be 'glued together' by multiplying them in the order you wish to apply them.

For example,

Matrix.Translate(0, -1, 0) * Matrix.RotateX( (float)Math.PI ) will first move your cube to (0,-1,0) and then rotate it 180 degrees around the X axes, so it will end up upside-down at (0,1,0)

On the other hand,

Matrix.RotateX( (float)Math.PI ) * Matrix.Translate(0, -1, 0) will rotate it 180 degrees around the X axes and then move it to (0,-1,0), so it will still end up upside-down but at (0,-1,0)

We'll need this later on, when we discuss the Matrix.Shadow matrix. For now, we'll continue with the...

View matrix

This matrix will translate your world space objects to screen space coordinates, using the parameters you specify in Matrix.LookAt(...). The actualy transformations are a bit complicated and I can't explain them very well. Some more info can be found Toymaker's excellent site, but you don't need to worry about it much, as the Matrix.LookAt method will take care of the technicalities for you.

Projection matrix

This final matrix will apply the perpective to your scene (or not, if you use orthogonal project matrices) and take care of the near and far clipping planes. Again, don't worry to much about these, as the methods in the Matrix class can be used to generate these for you.


So basically that's what happens to your cube vertices when you call mesh.DrawSubset(i). They get transformed through this 'pipeline', ending up where you want them on the screen (most of the time, anyway :). Now where does the Matrix.Shadow matrix fit in?

The matrix obtained from Matrix.Shadow is just a special transformation matrix that will 'flatten' your cube (or other mesh) onto the plane you specify when you create it. It will use the light vector you supply to determine the size of the flattened mesh on your plane (essentially tracing the light ray along the vertices of your mesh until it hits the ground plane, just like in physics class). Now, that may sound complicated, but it's just another matrix.

So, when we finally have this shadow matrix, we'll glue it to our exisiting world matrix, again by multiplication. Since we start with the existing world matrix, your mesh will be properly transformed first, before it gets flattened onto the ground plane by the shadow matrix. Your view and projection matrix tranforms come after this step, but you don't need to worry about them.

I hope this cleared it up some more... and now I really should get back to work, if you don't have any further questions :))

Share this post


Link to post
Share on other sites
Quote:
Original post by remigius
Quote:
I have it working although I still haven't grasped the correclation between my existing tile based world/projection/view setup and the cube/shadow render yet :(


I tried drawing this for you, but I think explaining it in text should be clearer. So here goes :)

When you render your cube it gets transformed from the object space you defined it in, to 2D coordinates on your screen. This transformation process consists of 3 steps, which are executed in the following order:

World transform

The object is scaled, rotated and/or translated to it's actual place in your world. Since you're using the Matrix.Identity matrix, the object isn't altered in any way and remains standing there at the origin (0,0,0) of the world space. You could use a combination of matrices to transform your cube (or any other mesh) in world space. These matrices can be 'glued together' by multiplying them in the order you wish to apply them.

For example,

Matrix.Translate(0, -1, 0) * Matrix.RotateX( (float)Math.PI ) will first move your cube to (0,-1,0) and then rotate it 180 degrees around the X axes, so it will end up upside-down at (0,1,0)

On the other hand,

Matrix.RotateX( (float)Math.PI ) * Matrix.Translate(0, -1, 0) will rotate it 180 degrees around the X axes and then move it to (0,-1,0), so it will still end up upside-down but at (0,-1,0)

We'll need this later on, when we discuss the Matrix.Shadow matrix. For now, we'll continue with the...

View matrix

This matrix will translate your world space objects to screen space coordinates, using the parameters you specify in Matrix.LookAt(...). The actualy transformations are a bit complicated and I can't explain them very well. Some more info can be found Toymaker's excellent site, but you don't need to worry about it much, as the Matrix.LookAt method will take care of the technicalities for you.

Projection matrix

This final matrix will apply the perpective to your scene (or not, if you use orthogonal project matrices) and take care of the near and far clipping planes. Again, don't worry to much about these, as the methods in the Matrix class can be used to generate these for you.


So basically that's what happens to your cube vertices when you call mesh.DrawSubset(i). They get transformed through this 'pipeline', ending up where you want them on the screen (most of the time, anyway :). Now where does the Matrix.Shadow matrix fit in?

The matrix obtained from Matrix.Shadow is just a special transformation matrix that will 'flatten' your cube (or other mesh) onto the plane you specify when you create it. It will use the light vector you supply to determine the size of the flattened mesh on your plane (essentially tracing the light ray along the vertices of your mesh until it hits the ground plane, just like in physics class). Now, that may sound complicated, but it's just another matrix.

So, when we finally have this shadow matrix, we'll glue it to our exisiting world matrix, again by multiplication. Since we start with the existing world matrix, your mesh will be properly transformed first, before it gets flattened onto the ground plane by the shadow matrix. Your view and projection matrix tranforms come after this step, but you don't need to worry about them.

I hope this cleared it up some more... and now I really should get back to work, if you don't have any further questions :))



Wow, thanks for this great reply. Thankfully I'm aware of what the relevant matrices do however I cannot sync my plane and light position and subsequent mesh render in terms of position, scale etc. i.e. I'm using transformed vert cordinates for my tiles but using anything similiar for my mesh just makes the mesh/shadow either disappear or appear much larger. I guess I just need to play around and see if I can get it accurate. Hopefully then the penny will drop and I can tie in my tile vertices positions to that of my shadow quads with ease and accuracy.
I can then start to play with a stencil buffer in order to combine the shadow areas and cancel shadows out that are effect by another light. Once again, many thanks for such a great reply!

:)

Share this post


Link to post
Share on other sites
Quote:
Original post by remigius
You're welcome :)


I'am getting a little closer but still cant quite nail it. I still have an alignment problem as can be seen here.
click here

Basically the wireframe is the shadow mesh. Sphere = light position albeit 0.5 lower than actual light. Cube = shadow castor.

This is a simple extract


With D3Ddevice
.Transform.World = Matrix.Identity
.Transform.Projection = Matrix.PerspectiveFovLH(Math.PI / 4, 1.33, 0.0F, 500.0F)

'Light position
PositionMatrix.Translate(New Vector3(.Lights(0).XPosition, .Lights(0).YPosition, 0.5))
.Transform.World = PositionMatrix
.Material = cubematerial
SphereMesh.DrawSubset(0)

'Cube position
PositionMatrix.Translate(New Vector3(1, 0, 0))
RotationMatrix.RotateYawPitchRoll(0, 0, Radians(Angle))
RotationMatrix.Multiply(PositionMatrix)

'Calculate shadow
Dim shadowplane As New Plane(0.0F, 0.0F, 1.0F, 0.0F)
Dim LightPosition As New Vector4(.Lights(0).XPosition, .Lights(0).YPosition, .Lights(0).ZPosition, 0.0F)
Dim ShadowMatrix As New Matrix

ShadowMatrix.Shadow(LightPosition, shadowplane)
ShadowMatrix.Multiply(RotationMatrix)

'Render shadow mesh
.Transform.World = ShadowMatrix
.Material = shadowmaterial
myMesh.DrawSubset(0)

'Render cube mesh
.Transform.World = RotationMatrix
.Material = cubematerial
myMesh.DrawSubset(0)

End With





any ideas why my shadow mesh is so incorrect? BTW, they do actually rotate correctly but obviously the show itself is not correct? Wrong length, wrong position or both?

Share this post


Link to post
Share on other sites
It looks like you're using your light as a Point light, since you're using the light's coordinates to set up your light vector. If your light is indeed a point light, you should change the W component (the 4th one) of the light vector you pass into Matrix.Shadow(..) to 1, like this:


Dim LightPosition As New Vector4(.Lights(0).XPosition, .Lights(0).YPosition, .Lights(0).ZPosition, 1)


A W component of 0 indicates a directional light, whereas a W value of 1 indicates a point light. If your light is a directional light, it doesn't really have a position and you'll have to supply a vector describing the xyz directions of the light to the Matrix.Shadow(..) method.

I hope this helps, as I can see nothing else wrong with your code.

Share this post


Link to post
Share on other sites
Quote:
Original post by remigius
It looks like you're using your light as a Point light, since you're using the light's coordinates to set up your light vector. If your light is indeed a point light, you should change the W component (the 4th one) of the light vector you pass into Matrix.Shadow(..) to 1, like this:


Dim LightPosition As New Vector4(.Lights(0).XPosition, .Lights(0).YPosition, .Lights(0).ZPosition, 1)


A W component of 0 indicates a directional light, whereas a W value of 1 indicates a point light. If your light is a directional light, it doesn't really have a position and you'll have to supply a vector describing the xyz directions of the light to the Matrix.Shadow(..) method.

I hope this helps, as I can see nothing else wrong with your code.


Thanks it does but it isn't quite right. When I rotate cube the shadow rotates with it like a beacon of light. The shadow should simply stay put but obviously change it's shape as the faces of the cube that face the light change. If I move the multiply before the shadow calulation it doesn't move at all?

i.e.

shadow doesnt rotate

Share this post


Link to post
Share on other sites
I've created a quick 'n' dirty test project in C# in which I got this working. I'm using about the same code as you, as far as I can tell, so I'm a bit puzzled too what the problem might be... The only difference seems to be that I'm using the * operate to multiply the matrices, instead of the method you're calling. It shouldn't make a difference, but if VB.NET supports the * operator on matrices, it might be worth a shot to try that.

The only other problem I can think of would be how you handle your matrices. I can't tell for sure what's going on in your code snippet, but it seems like you're transforming the same matrices over and over again (if the code is from your render method, that is), which may produce the faulty result. I'm recreating the world matrix every frame and use it like this:

[source lang=c#]
// in the test app, the worldmatrix is different each frame
Matrix worldTransform = Matrix.Translation(-1, 1, -1);

device.Transform.World = worldTransform;
device.Material = normalMaterial;
cube.DrawSubset(0);

device.Transform.World = worldTransform * shadowMatrix;
device.Material = shadowMaterial;
cube.DrawSubset(0);





You can download my C# project from the link below. It uses the sampleframework from the SDK, so it may be a bit messy. The relevant code can be found in the OnCreateDevice, OnResetDevice and OnFrameRender methods.

- C# project dealing with shadows, 750KB zip

Hope this helps :)

Share this post


Link to post
Share on other sites
Quote:
Original post by remigius
I've created a quick 'n' dirty test project in C# in which I got this working. I'm using about the same code as you, as far as I can tell, so I'm a bit puzzled too what the problem might be... The only difference seems to be that I'm using the * operate to multiply the matrices, instead of the method you're calling. It shouldn't make a difference, but if VB.NET supports the * operator on matrices, it might be worth a shot to try that.

The only other problem I can think of would be how you handle your matrices. I can't tell for sure what's going on in your code snippet, but it seems like you're transforming the same matrices over and over again (if the code is from your render method, that is), which may produce the faulty result. I'm recreating the world matrix every frame and use it like this:

*** Source Snippet Removed ***

You can download my C# project from the link below. It uses the sampleframework from the SDK, so it may be a bit messy. The relevant code can be found in the OnCreateDevice, OnResetDevice and OnFrameRender methods.

- C# project dealing with shadows, 750KB zip

Hope this helps :)


Thanks, I've been playing somemore this morning and now suspect that it is the shadow matrix. It doesn't seem to take into consideration the cubes position in relation to the light position. I noticed this when I set the cube position to (1x,0y) and light position to (0x,0y). The shadow appears directly underneath the light but it's nothing more than a larger rectangle i.e. as if teh cube was at 0x,0y. If the light moves 1 unit left the shadow is then stretched correctly. I don't know how to set the shadow matrix intially to represent the cubes position. If I set it to the cubes position before the shadow nothing happens. If I apply the position after the shadow then it moves but then it's actually the wrong shadow because the shadow was still calculated against the wrong position i.e. 0,0? I'm going round in circles now! :(

P.S. the source link didn't work for me and .net does not expose * for matrices.

Edit, a little more playing and it appears that the shadow function of a matrix simply blasts any other values. So with a temp matrix it appears to be a little closer to what I'm after. Still not correct however as it now appears to rotate the shadow on the wrong axis. Also when I move the light in relation to the cube the shadow doesn't position itself correctly in relation to the cube.

Still broken

position incorrect

[Edited by - Seiko on December 7, 2005 7:56:57 AM]

Share this post


Link to post
Share on other sites

This topic is 4388 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this