Godot 3D Vector/Physics Cheat-Sheet:

wombatstampedewombatstampede Posts: 176Member
edited December 2019 in Tutorials

This is supposed to be a reference for use with 3D Vector/Transform/Physics operations.
It won't contain much explanations but some examples. And it is supposed to never be complete.

There is already some information about 3D Vectors and Transforms:

https://docs.godotengine.org/en/stable/tutorials/3d/using_transforms.html
http://docs.godotengine.org/en/stable/learning/features/math/vector_math.html
http://docs.godotengine.org/en/stable/learning/features/math/matrices_and_transforms.html

http://kidscancode.org/godot_recipes/math/transforms/

I also did two little godot demo projects which should be attached to this post:

Just some Basics:

Units:

Godot has values but no units. If you work with physics you might want some units sooner or later to have a scale or for output purposes.
I assume that the value 1 in Godots coordinate space is one metre. The phyics engine also seems to implicitly use 1 second as time scale.
I also assume that the mass value of 1 equals 1kg. Weight (better ignore it) depends on the gravity and is 1N(ewton) at 1g = 9.81m/sec².

So a velocity of 1 is 1 m/sec = 3.6 km/h.
So a gravity value 9.8 equals 9.8m/sec².
A force of 1 probably is 1N*m (Newton metre or 1 Joule)

Transform:

http://docs.godotengine.org/en/stable/classes/class_transform.html?highlight=Transform

contains 2 members:

origin:

Just a Vector3 with the 3 coordinates of the position. So transform.origin equals the property translation.

basis:

A matrix of 3 x Vector3. It contains the normalized direction vectors of X/Y/Z-Axis.
B.t.w.: "normalized" means a vector is scaled to length 1

transform.basis.z therefore is a Vector3 that contains the direction of the Z-Axis

This basically defines the rotation of a Transform. A single component (i.e. transform.basis.x) will give you the direction but not the orientation (where's the upside of the object/transform?).

global/local:

For each Spatial you can either use the property transform or global_transform

local?

A local transform specifies the local rotation and position of a Spatial inside its parent.
So:
transform.basis.x|y|z will return the axis-vectors rotated by the local rotation.
transform.origin will return the local offset of a Spatial inside its parent.

global?

Rotation/position in the games 3D-Space.

Example:
A turret on a tank. The transform of the turret won't change when the tank moves and turns. But the global_transform will.
If the turret turns, the values of the turrets transform.basis will change to represet its rotation relative to the tank.

looking_at / look_at / look_at_from_position

These methods basically all do the same:
Spatial (and descendants) offers void look_at ( Vector3 target, Vector3 up ) and void look_at_from_position ( Vector3 position, Vector3 target, Vector3 up )
http://docs.godotengine.org/en/stable/classes/class_spatial.html?highlight=look_at#class-spatial-look-at
Transform offers Transform looking_at ( Vector3 target, Vector3 up )
http://docs.godotengine.org/en/stable/classes/class_transform.html?highlight=transform#class-transform-looking-at

This methods calculates the transform.basis (rotation) matrix which is needed to let the forward vector (Vector3(0,0,-1)) point from Transform.origin to the target coordinates. The "up" Vector defines the orientation of the resulting Transform.basis.

Example:
You have a node with a "head" mesh. When you let that head "look_at" another node and you pass a down-vector (Vector3(0,-1,0)) then the hair will be below the head. If you pass an up-vector (Vector3(0,1,0)) then the hair will be on the upside of the head. In any way the head will always point in the right direction, only the orientation is different.

Limiting the look_at to a plane:
You might often want to limit the rotation of your "head" to one axis. This can be achieved by setting the coord outside the plane to the same value. For example: If you want to limit the rotation to the y-axis (x/z-plane) then use the same y-coordinate for source and target.
head.look_at_from_pos(Vector3(get_translation().x,target.get_translation().y,get_translation().z), \ target.get_translation(),Vector3(0,1,0))

Angles:

Avoid whereever possible. Try to reduce coords to 2D when working with angles or you might enter the "gimbal lock" hell.
That is: Angles tend to "suddenly" switch "upside down" at one point in rotation which can mess up angle based calculation.

Course/Heading angle:

Spatials heading in X/Z space should be something like this:
Vector2(get_transform().basis.z.x,get_transform().basis.z.z).angle_to(Vector2(0,-1))

Since godot 3.x (yes it changed from godot 2.x) the coordinate system turns counter clock-wise. So if you want a compass heading you'd need to calc a bit: compass_heading = 360-rad2deg(angle) (untested)

Rotating a local offset by Spatials rotation:

Another way to rotate a local offset:
var relOffset = (0,0,-1)
var relRotPos = transform.basis.xform(relOffset)

Velocities: (and some 3D Vector math)

Usually a Vector3 of a Body (i.e. RigidBody)
linear_velocity delivers always the global velocity.

If you want to know how to convert this to a local/rotated velocity, see below.

Tangential velocity:

This should calculate the speed of a point on a rotating Body:
var relativePosition = Vector3(0,0,-1) #sample value, 1m to "front"
var tangVelo = angular_velocity.cross(relativePosition)

How much km/h are this?
var kph = tangVelo.length() * 3.6
Note: this velocity is relative to the parent and the objects velocity.
The absolute/global speed of the rotating point should be angular_velocity.cross(relativePosition)+linear_velocity

"Forward" velocity:

Which (local) "forward" speed has a Body?
Rotate global velocity by rotation basis in Bodies global_transform and use only the z-component of the relative velocity.
var kph = global_transform.basis.xform_inv(linear_velocity).z*-3.6
Note: global_transform is used because the linear_velocity is also global.

Absolute velocity of a child node which is on a rotating and moving parent body:

#1: Get the position of a person on a rotating platform (in parent coords):

The person is at relative coordinate x=-2, z=-3 on that platform. (before rotation)
Now rotate this:
var relRotPos = transform.basis.x * -2 + transform.basis.z*-3
(see also "rotating a local offset" above)

#2: Now calculate the tangential velocity (rotation speed) and add it to the current velocity (moving speed):

var absVelocity=angular_velocity.cross(relRotPos)+linear_velocity

Continued here

Downloads:

There are file attachments with the demo projects:
3d_vectors_demo_v3.zip: Is for use with Godot 3.x (tested in Godot 3.1 beta 3)
3d_vectors_demo.zip: Is for use with Godot 2.x (!)

(As download link because of technical difficulties in forum)
spaceship.zip: Simple space game about forces, rigidbodies with a following camera.

Comments

  • Great !
    You led me to the right directions to find how coding movements and rotations for any object into a scene (including camera(s)). Without forgetting this excellent point about values and units into Godot.
    It seems I have tons yet to read into the Godots docs :wink: … and all of this will be very usefull, many thanks.

  • wombatstampedewombatstampede Posts: 176Member
    edited March 19

    ..continued

    Physics and forces:

    apply_impulse(position,force):

    You'll probably need this a lot when working with 3D Phyics and i.e. RigidBodies.

    The catch is that "position" is relative and global at the same time.

    It is "relative" because the offset is relative to the Bodies global_transform.origin. (position)
    It is "a bit global" because it is in global coordinate space, (so a local offset has to be rotated to the Bodies direction if you want to use it)
    So "position" is a relative rotated coordinate. Just check above for geting a local offset rotated to global space.
    Or: Just an offset in global coordinate space.

    The force vector is actually global, similar to the linear_velocity.

    Inertia:

    The (angular) inertia of Bodies is implicitly calculated in the physics engine by using the collision shapes of a Body.
    This process ignores the scale of the collision shapes. So don't scale your collision shapes but edit the extents!
    Collision shapes based on custom shapes/meshes are probably ignored. I don't know if this changed in 3.x.

    apply_impulse or apply_force, where's the difference?

    Applying an impulse is relatively straight forward to understand. It is like kicking a football. Applying a force could be understood as applying a force in a more permanent manner over a some period of time (=work).

    In the case of apply_force it is important to understand that the applied force is automatically reset after each physics frame. So you don't have to reset a once applied force but you have to apply it again and again for each physics frame if you want it to be applied permanently.

    The difference between a force and an impulse should become more visible when the physics frame rate is lower than the screen frame rate. If you regularly apply an impulse each physics frame then (if the physics frame rate is low enough) the object should move more irregular compared to appying a force.

  • wombatstampedewombatstampede Posts: 176Member

    I added a demo_project to the initial post. Probably much easier to try this out in Godot. :-)

  • MagicLordMagicLord Posts: 578Unconfirmed

    This should be pinned.
    It has so much information about Godot 3D.

  • wombatstampedewombatstampede Posts: 176Member

    I updated the initial post regarding Godot 3.x. If you want to download the demo project for Godot 3.x be sure to use file 3d_vectors_demo_v3.zip

  • wombatstampedewombatstampede Posts: 176Member
    edited June 2019

    (moved to another post further up)

  • MegalomaniakMegalomaniak Posts: 2,898Admin
    edited June 2019

    You could separate the OP into multiple replies in the thread and link to them from the OP.

    edit: It's also worth a mention that this is something you should consider contributing to the documentation project.

  • wombatstampedewombatstampede Posts: 176Member

    Hi Megalomaniak. I split up & linked the post .
    I have doubts though to add this to the documentation project. There are other pages on the godot doc site which cover similar topics. I.e. this (IMHO very good) post:
    https://docs.godotengine.org/en/stable/tutorials/3d/using_transforms.html

  • MegalomaniakMegalomaniak Posts: 2,898Admin

    I mean if you find anything that isn't covered in docs yet but there is an article the info could fit with then you can probably open an issue on the tracker if you are not confident about making a pull request in there. ;)

  • wombatstampedewombatstampede Posts: 176Member
    edited November 2019

    I added another demo project. It is a simplistic spaceship game which demonstrates the use of "forces" and rigidbodies. See the first post in this thread for a little preview gif. There's a download link at the bottom of the post.

    I sometimes read posts/questions of people who are struggling with the use of rigidbodies. They try to directly rotate and move rigidbodies like they are used to do with kinetic bodies. Perhaps the demo project helps a bit. Be the "forces" with you.

  • noah_gengonoah_gengo Posts: 2Member

    Thank you so much for this . The official docs were completely opaque to me. Now I'm starting to actually understand 3D in Godot

  • cyberealitycybereality Posts: 1,049Moderator

    Yeah, nice job!

  • novaleafnovaleaf Posts: 83Member

    Here's another great vector math (dot product) tutorial: https://www.allenchou.net/2020/01/dot-product-projection-reflection/

  • ericwood73ericwood73 Posts: 5Member

    A little more about inertia that I discovered. From what I can tell, Godot determines inertia by looking at the collision shape and the extents. If you use a sphere for example, then godot uses the formula for a hollow sphere of the same radius as the extents. If you use a cylinder it uses the formula for a hollow cylinder. If you use a box, however, it uses the formula for a solid cuboid with the extents. This is nice because you can use the extents to precisely control the moments of inertia about each of the body axes, but doing so requires solving a system of 3 quadratic equations for the extents. Note that offsetting the collision shape from the center of mass has no effect on the moment of inertia, as far as I can tell.

Sign In or Register to comment.