• 3D
  • How to make a plane be always perpendicular to the camera?

I'm using a StaticBody with a CollisionShape/PlaneShape to intersect raycasts so I can drag&drop objects in 3D space. This plane is invisible, and it's supposed to make axis locking while dragging objects. (I'm doing editing gizmos for a 3D editor, rather than an in-game drag&drop functionality.)

But to make this work properly I need to make the plane be always be perpendicular to the camera. Or in other words, it has to always have its normal pointing parallel to the camera's normal, but in the opposite direction, as I illustrate in the image below.

How can I achieve this?

Note: the camera has a pivot node as its parent, much like FPS cameras, and they each rotate in a different axis.

The simplest solution would probably be to take the Camera's rotation, and then rotate the plane by 90 (or 180) degrees in a given axis, which should make it perpendicular to the camera. The hard part may be choosing the axis to rotate the vector on, so you get the results you are expecting. I also think the cross function is useful for generating a vector that is perpendicular to two input Vector3s, but I'm not sure how to use it to the get desired result in this case, but it may be worth looking into.

I actually just managed to do it by adding 180 to each component of the angle (camera+pivot+180).

Turns out, always perpendicular isn't exactly what I need.

For dragging vertically I just need the plane to sit vertically and spin only around Y to have the normal opposite to the camera, and that works perfectly. And for that, all I need to do is use the camera's pivot rotation in Y and change the plane in the CollisionShape itself to face the opposite way.

Dragging horizontally is the tricky part. Having the plane face the camera seems no good, as it limits the gizmo to how much the mouse can move on the screen, and the result is you can't drag the gizmo that much far away. This is because, the X position of the mouse in the plane (the raycast hit) is what I'm assigning to the X position of the gizmo. The same goes for Z.

Having the plane simply sitting still horizontally kinda works, except when the camera is about leveled with the plane. But I also have some problems with the gizmo being dragged way too much, depending on where the mouse is and maybe also where the camera is facing. Having the plane vertically also has the same problems.

I'm thinking maybe I need to keep it leaning to some degree depending on the camera's perspective, but I'm not sure.

EDIT: indeed, from playing around in blender a bit, I can already tell that the plane's normal should always be pointing toward the camera's position, but stay flat along the X axis (if locking to X).

Well, this seems to work:

var p_y = _camera.get_parent().rotation.y
var cam_pos = _camera.get_parent().translation

if current_axis in _VERTICAL_AXES:
	rotation.y = p_y
elif current_axis in _HORIZONTAL_AXES:
	var point = Vector3(translation.x, cam_pos.y, cam_pos.z)
	look_at(point, Vector3.UP)

Won't work in Z as it is, still needs many tweaks, but at least it seems I got the rotations right. :)

18 days later

The other thing you can do is use kinematic instead of a static shape and slave it to the camera.

like:

in kinematic._physics_process() var t:Transform = camera.global_transform t.origin += Vector3.FORWARD * DISTANCE self.global_transform = t

You can then slightly modify the plane's orientation as you see fit WRT to the camera