MDX - Matrix.shadow?

Started by
11 comments, last by Seiko 18 years, 4 months ago
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)




Advertisement
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 :)
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
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?

:(
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 itselfdevice.Transform.World = yourWorldTransformMatrix;cubeMesh.DrawSubset(0);    // construct shadow matrix and draw shadowPlane 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).
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
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?

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 :))
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
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!

:)
You're welcome :)
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!
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?
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.
Rim van Wersch [ MDXInfo ] [ XNAInfo ] [ YouTube ] - Do yourself a favor and bookmark this excellent free online D3D/shader book!

This topic is closed to new replies.

Advertisement