Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What coordinate system does Open3D use? #6508

Open
3 tasks done
cod3monk3y opened this issue Nov 26, 2023 · 5 comments
Open
3 tasks done

What coordinate system does Open3D use? #6508

cod3monk3y opened this issue Nov 26, 2023 · 5 comments
Labels

Comments

@cod3monk3y
Copy link

cod3monk3y commented Nov 26, 2023

Checklist

My Question

I can't find any reference to the coordinate system used in Open3D.

For instance, OpenGL uses RH y-up (z backward), Blender uses RH z-up, DirectX uses LH y UP, and Unreal uses RH with x to the right and y up).

# OpenGL RH y UP
#    y
#    |
#    +---x
#   /
#  z

# Blender RH z UP
#    z
#    | y
#    |/
#    +---x

# Direct X (not used here), LH y UP
#    y
#    | z
#    |/
#    +---x

# Unreal Engine, RH, x RIGHT y UP
#    y
#    |
#    +---x
#   /
#  z

This is pretty fundamental, so I probably just missed it in the docs. If it's not in the docs, this would be really helpful to add up front in the docs.

I'm passing my data (point cloud, meshes) through several applications with potentially different coordinate systems, and want to make sure I have all my transformations correct. I'm quite familiar with this domain, so I only a reference to which coordinate system is in use. Thanks!

@cod3monk3y
Copy link
Author

cod3monk3y commented Nov 26, 2023

Using code adapted from Draw Line Set, it looks like the coordinate system is RH y UP, which matches OpenGL, etc.

def generate_axes(scale: float) -> List[o3d.geometry.LineSet]:
    points = [
        [0, 0, 0],
        [scale, 0, 0],
        [0, scale, 0],
        [0, 0, scale],
    ]
    lines = [
        [0, 1],
        [0, 2],
        [0, 3]
    ]
    colors = [
        [1, 0, 0],
        [0, 1, 0],
        [0, 0, 1]
    ]
    line_set = o3d.geometry.LineSet(
        points=o3d.utility.Vector3dVector(points),
        lines=o3d.utility.Vector2iVector(lines),
    )
    line_set.colors = o3d.utility.Vector3dVector(colors)
    return [line_set, ]

The part that confuses me, maybe, is the front argument to draw_geometries. When I set it to [0, 0, 1] the camera points down the negative z axis, and when I set it to [0, 0, -1] it points down the positive z axis. This seems backwards. Am I misinterpreting this front vector? I'm thinking of this as the initial forward vector of the camera. But look-at calculations are usually:

  1. set camera position and look-at
  2. fwd = (look_at - camera_pos).normalized
  3. right = fwd x up, normalize if paranoid
  4. true up = right x fwd

So this front argument seems like maybe it's not the forward vector of the camera, but the vector from the origin to the camera position. Setting this to [0, 0, 10] doesn't seem to move the camera any farther away.

        o3d.visualization.draw_geometries(
            to_view,
            zoom=0.3412,    
            front=[0, 0, 1],
            lookat=[0, 0, 0],
            up=[0, 1, 0],
            point_show_normal=True
        )

Camera position (slightly adjusted for visibility) when front=[0, 0, -1]
open3d_front_nz

Camera position when front=[0, 0, 1]
open3d_front_pz

@cod3monk3y
Copy link
Author

cod3monk3y commented Nov 26, 2023

I'm also confused because the normals in this "F" synthetic point cloud are all 0, 1, 0, which should point along the positive Y (green axis).

-1.624193 0.000000 -1.892043 0.000000 1.000000 0.000000

EDIT scratch this comment. I was flipping the normals myself.

@cod3monk3y
Copy link
Author

cod3monk3y commented Nov 26, 2023

Okay, I think this is right, and maybe helpful to someone else:

  1. Coordinate system is right handed (RH), x RIGHT, y UP, (thus z BACKWARDS), which matches OpenGL
  2. The lookat argument of draw_geometries is as expected from any "look at" calculation.
  3. The front argument is not the forward vector of the camera, It's a vector FROM the look-at target TO the camera. This argument will be normalized, so if you want to get a 45 degree downward view, this can be [0, 1, 1].
  4. To get the full position of the camera, multiply the zoom argument and the front vector.

Here's an annotated version of the arguments.

o3d.visualization.draw_geometries(
    to_view,
    # Camera position is calculated as `lookat + (zoom * front)`
    front=[0, 1, 1],  # vector FROM origin TO camera (will be normalized)
    zoom=1,  # multiplies normalized `front` vector to determine position of camera
    lookat=[-2, 0, -2],  # look at position, determines true forward vector of camera
    up=[0, 1, 0],  # starting up vector, determines true right vector of camera
    point_show_normal=True
)

@cod3monk3y
Copy link
Author

Verified the output .obj file is consistent with OpenGL coordinate system. Importing into blender with

  • -Z forward
  • Y up

gives the correct orientation of the test F mesh.

image
image

@jackjansen
Copy link

@cod3monk3y thank you very much! This is the first consistent explanation of hoe the open3d coordinate system works that I have found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants