Calculate angle of incidence during Ray cast

I am trying to handle gravitational effect on my player project (while on an inclined plane) without using a dedicated Physics engine.

The reason behind my decision has something to do with the issues I encountered while trying to use Cannon JS.

I am now using moveWithCollisions to avoid walking through solid objects (that have checkCollisions set to true). However, that will also result in my player slowly sliding down any inclined plane while standing still.

My plan is to use Ray cast every frame to detect any ground underneath the player.

If none is detected, the player will “fall”.
If ground is detected, I want to find the angle of incidence of the ray with the intercepting mesh. If the angle is lesser than a certain limit (say 15 degrees), my player won’t slide (I’ll set the gravity vector for that frame to 0).

Problem is that I cannot seem to find out the angle of incidence (angle at which the ray hits mesh) during ray cast hit. Googling did not help.

Can someone please guide me in this regard?

Also, what do you think of my plan to fake the physics part in this manner?

I’d take the dot product of up axis and face nomal. If it’s below some value (maybe .9?) then do what you need to do with gravity.

The plan is worth a try. I’ve done something similar, but I use oimo and apply a force toward the ground (negative ground normal). I also added some custom code to oimo so that I don’t have to use a ray (I’m not using bjs physics plugin).

1 Like

Thank you for your reply.
However, I am not very experienced with 3d stuff. I am not sure how the dot product would help me.

My code is this -

const ray = new Ray(this.player.position, new Vector3(0, -1, 0), 10)
const intersectedPoint = this.scene.pickWithRay(ray)
const faceNormal = intersectedPoint.getNormal(true)

return Vector3.Dot(faceNormal, new Vector3(0, 1, 0))

This gives me a value of 0.9848...
I am not sure what to do with that.

Btw, my ground object is rotated by 10 degrees.

ground.rotate(Axis.X, Math.PI / 18)

How do I find out the angle from that value?

I tried doing this, but it returned NaN.

const gravity = new Vector3(0, 1, 0)
return Math.acos(Vector3.Dot(normal, gravity) / Vector3.Cross(normal, gravity))

I remember learning something like at school -

dot product / cross product = cos(angle)

Its

angle = acos(a.b / |a||b|) where |a| is length of a.

Even better as your gravity is a unit vector using faceNormal.normalize() will make that a unit vector and so then

Vector3.Dot(faceNormal, new Vector3(0, 1, 0))

will give you the angle in radians between the faceNormal and the vertical.

1 Like

If both vectors are normalized, the dot product returns 1 if vectors are the same, -1 if vectors are opposite and 0 if vectors are perpendicular.

@adam Shouldn’t do! a.normalize() returns a/|a|
a/|a| . b|b| = a.b / |a||b|

See https://www.babylonjs-playground.com/##UNRA96

The end result always seems to be around 57 degrees! I don’t know why. :sob:

const normal = intersectedPoint.getNormal().normalize()
const gravity = new Vector3(0, 1, 0)
return Vector3.Dot(normal, gravity) * 180 / Math.PI

I checked that intersectedPoint.pickedMesh is my ground object - which is currently rotated by 1 degree

ground.rotate(Axis.X, Math.PI / customValue)

Irrespective of the value of customValue (18 or 180), the end result is always the same - 57 degrees!

Apparently, it also does not matter whether I normalize the face normal vector.

Please produce playground of a simplified version of your project for us to help further.

Okay. I’ll try to reproduce my code in a playground.

In the meanwhile, can someone please clarify a concept to me?

I just did this -

const gravity = new Vector3(0, 1, 0)
console.log('angle in degrees is ', Vector3.Dot(gravity, gravity) * 180 / Math.PI)

The result is 57!
Shouldn’t it be 0 degrees instead?

It seems like I am doing the conversion wrong!

Should be 0 degrees. Try (0, 1, 0) in the playground (PG) I added in my post above.

I don’t understand. Shouldn’t do?

Shouldn’t do that. Normalized vectors still give angle.

dot(a,b) gives you the cos of the angle between a and b (if a and b are both normalized).

So, don’t do:

Vector3.Dot(gravity, gravity) * 180 / Math.PI

but:

Math.acos(Vector3.Dot(gravity, gravity)) * 180 / Math.PI

to get the angle in degrees.

1 Like

The definition of the dot product is (Dot product - Wikipedia):

image

If the vectors are normalized, it reduces to:

a . b = cos(theta)

can just do (1 - dot)*90 is just wrong, it only works when dot = 0 or 1 or -1.

Try this:

v1 = new BABYLON.Vector2(1, 0).normalize();
v2 = new BABYLON.Vector2(1, 1).normalize();
dot = BABYLON.Vector2.Dot(v1, v2);
console.log(Math.acos(dot) * 180 / Math.PI, (1 - dot) * 90)

Result: 45.00000000000001 26.360389693210728

45° is the right answer.

Ok i think I got it. It’s not linear. My bad. Thanks for the explanation.

Thank you; thank you so much… Just checked it; the final result is now exactly what I wanted!
:slight_smile: :slight_smile: :slight_smile:

Thanks to all of you for helping me with this. I guess I should have paid more attention in school. :stuck_out_tongue: