Projecting a Quad from light source and Normal Vector

Started by
17 comments, last by AhmedCoeia 10 years ago

Hi All,

I'm having a decal mesh( a quad) which has a shadow texture. and I have a bike, which has its forward direction, I have the normal to the ground, and normal touching point to ground. I have also the direction of light.

My quad on the floor has 4 vertices, so I assumed as the figure Points C,D is set to be parallel with the front wheel and the back wheel.

I would like to get the maths and get the points A, B with respect to the light direction.

My current code is : I would like to determine both vxPosSide2, and VxPosSide3


Quaternion rot = Quaternion.AngleAxis(Source.rotation.eulerAngles.y, normal) * Quaternion.FromToRotation(new Vector3(0, 1, 0), normal);
Vector3 pos = point + new Vector3(0, 0.1f, 0);
Color32 colorSideTexture = mRenderer.sharedMaterial.GetColor("_Color");

Vector3 vxPos1Side = pos + rot * (new Vector3(-1.4f, 0, -0.7f) * scale);
Vector3 vxPos2Side = pos + rot * (new Vector3(0, 0, -0.7f) * scale);
Vector3 vxPos3Side = pos + rot * (new Vector3(0, 0, 0.7f) * scale);
Vector3 vxPos4Side = pos + rot * (new Vector3(-1.4f, 0, 0.7f) * scale);
 
mDecalSide.SetVertex(0, vxPos1Side, colorSideTexture);
mDecalSide.SetVertex(1, vxPos2Side, colorSideTexture);
mDecalSide.SetVertex(2, vxPos3Side, colorSideTexture);
mDecalSide.SetVertex(3, vxPos4Side, colorSideTexture);
Advertisement
I'm not sure I understood correctly. Your image is confusing.
The A and B vertices are to be displaced in the same direction as the light source, but limited to the ground.

For this, you just need the (normalized) look direction of the light source. This is usually the local positive Z direction of the object converted to world space.
It seems that you are using Unity. In that case, it would be something like the following:

Vector3 lightOffset = lightSource.transform.forward.normalized
lightOffset.y = 0 // Make the light vector projected to the ground.

Vector3 vxPos1Side = pos + rot * (new Vector3(-1.4f, 0, -0.7f) * scale);
Vector3 vxPos4Side = pos + rot * (new Vector3(-1.4f, 0, 0.7f) * scale);

Vector3 vxPos2Side = pos + rot * ( vxPos1Side + lightOffset * scale ) * scale );
Vector3 vxPos3Side = pos + rot * ( vxPos4Side + lightOffset * scale ) * scale );
This is untested and might need some fixes.
Essentially, the A and B points are actually the C and D points offset by the light vector but projected on the ground.

Kryzon, Thanks so much for reply.

I actually did that, but I need also to add "shearing" points A and B, not only translation, so that when I steer, the shadow also steers ( point A,B).

First, I believe that a change in the naming convention is best.

Let A and B be the two points are positioned at either wheel of the bike.
To calculate their positions, you do the following:
- Obtain the normalized forward vector of the bike. Call it 'normBike.'
- Point A position is (bikePosition - normBike * scaleBike). Point B position is (bikePosition + normBike * scaleBike).

Let C and D be the two points that are offset from the bike based on the direction of the light source.
- Obtain the normalized forward vector of the light source. Call it 'normLight.'
- Point C position is (pointA + normLight * scaleShadow). Point D position is (pointB + normLight * scaleShadow).

This will account for any light position and bike orientation.

EDIT: There may be some confusion as to which values are in world space and which values are in the local space of the shadow mesh. In order to facilitate things, keep the shadow mesh transform placed at the world origin (0,0,0), and without any rotations or scaling. This way the vertex positions will all be in world space as well.

EDIT 2: The scale used for the points C and D ("scaleShadow"), which controls how "tall" the shadow is. is different than the scale used for points A and B ("scaleBike"), which controls how wide the shadow should be.

Hi Kryzon,

I have tried your formula as :


        Vector3 vxPos2Side = pos + rot * (new Vector3(0, 0, -0.7f) * scale);
        Vector3 vxPos3Side = pos + rot * (new Vector3(0, 0, 0.7f) * scale);
        Vector3 vxPos1Side = vxPos2Side + lightDir;
        Vector3 vxPos4Side = vxPos3Side + lightDir;

It's working now,

but as you see in the picture, the yellow shadow which is from the hard shadow ( real time ), compared to the billboard shadow(my shadow).

Still I need shearing, or skewing it.

Would you tell me please, the maths ( magic ) for adding the light vector to the vertices? why would I do that? " adding" two vectors ?

I also have a problem with blending that side projected shadow, and the top projected shadow. there are angles that both of them are shown to the viewer.:/

You are adding a vector to the position of a point (and this position is also a vector) because you want to displace\move\translate the point by that vector.

I suggest that you study linear algebra and trigonometry, as they are fundamental for game programming.
http://www.wildbunny.co.uk/blog/vector-maths-a-primer-for-games-programmers/
http://blog.wolfire.com/2009/07/linear-algebra-for-game-developers-part-1/
http://blog.wolfire.com/2009/07/linear-algebra-for-game-developers-part-2/
http://blog.wolfire.com/2010/07/Linear-algebra-for-game-developers-part-3/
http://blog.wolfire.com/2010/07/Linear-algebra-for-game-developers-part-4/
http://www.softlion.nl/download/article/Trigonometry.pdf

It may seem like "magic" for now, but there's a reason behind each calculation. Once you understand how it all works, you get three benefits:
1) You will understand the suggestions and support that people will give you on forums.
2) You will identify problems or errors in your programs and fix them by yourself.
3) You will design techniques and formulate calculations by yourself, without having to go through support forums and relying on others which is something that takes a lot of time.

Considering that you are also interested in blending the two shadows - and this depends on how Unity treats the rendering of shaders and materials - you need to ask for help on the official Unity support forums.

Hi Kryzon,

Today I tried another idea. I assumed points C, D comes from ray to plan intersection. So I have the normal point of the plane, and the normal of the bike, light direction, and point A and C. I tried that, but the shadow gets extended, and it gets very big, unlike your method.

Would you tell me how to get point C,D using pseudo code ? maybe I'm doing some wrong maths.

C = RayToPlane(normal, touchPoint, lightDir.normalized, VxPos1)

D = RayToPlane(normal, touchPoint, lightDir.normalized, VxPos2)

Hello.
The ideal distance of points C and D (the points that are extruded outside of the motorcycle) is calculated with the HEIGHT of the motorcycle and the normalized VIEW DIRECTION of the light.
You can use the Y component of the normalized light view direction to retrieve the "angle" that the light is pointing down.

motorcycle_Shadow1.png

With the angle you can calculate its tangent, which is (oppositeSide / adjacentSide) or as it is in that triangle (b / Height). With this you can discover the length of "b" relative to the motorcycle height.

motorcycle_Shadow2.png

The expression "ASin( 1.0 + lightNorm.y )" manipulates the Arc Sinus function to result in degree values that go from zero (when the light is pointing straight down) to 90 (when the light is pointing to the horizon). Since it's a sun type light, it won't point up (that is, above the horizon) or else the entire world will become dark.
When you input values from that [0, 90] range in Tan(), you get values from [0, +infinity] respectively.
This means that the more the light points to the horizon, the larger the shadow mesh will be.

Consider "b" as the actual "shadow size." If you understand how the tangent function works, you will see that multiplying the tangent by the motorcycle height results in the ideal shadow distance for that particular direction of light.
Then you can position the points C and D with:




/* Null the Y component of the light direction to make the light direction parallel 
to the ground, or the points C and D will go below the ground. */

groundLightDirection = lightNorm
groundLightDirection.y = 0
 
/* Move the points C and D away from the position of A and B by the direction 
of "groundLightDirection" and as distant as "shadowSize." */

C = A + ( groundLightDirection * shadowSize ) 
D = B + ( groundLightDirection * shadowSize )

Amazing Thanks so much

This topic is closed to new replies.

Advertisement