5
$\begingroup$

I'm working on a project where I need to determine the distance along the camera's local Z axis until it hits a plane in which a given object rests.

enter image description here

My thought process is to calculate a vecor from the camera to the focus object and then project that vector onto a vector representing the camera's local Z axis and then taking the magnitude of the projection. (If there is a better way to solve the problem, definitely let me know :)

I can easily calculate the first vector like so (in this case, the cube is the focus object):

cameraToFocus = bpy.data.objects['Camera'].location - bpy.data.objects['Cube'].location

I've been playing around with information from this answer to create a function that creates a unit vector reflecting the camera's rotation. This is what I've come up with so far and I'm not quite there:

def createUnitVectorFromRotation(rotation):
    #alpha, the angle measured from the X axis towards the y axis
    #beta is the angle measured from Y axis towards Z axis
    alpha = -rotation.z
    beta = pi/2-rotation.x
    x = cos(beta) * sin(alpha)
    y = cos(beta) * cos(alpha)
    z = sin(beta)
    
    unitVector = mathutils.Vector((x, y, z))
    return unitVector

I could probably keep adjusting the code until I get what I'm looking for, but is there a more straightforward way to create a vector representing the local Z axis of the camera, or a normal vector to the camera's field of view?

Thanks so much!

$\endgroup$

2 Answers 2

9
$\begingroup$

Local -Z axis of the camera.

To get the global vector representing the camera view, it's -Z axis can multiply

cam.matrix_world @ Vector((0, 0, -1))

The rotation part of a transform matrix matrix.to_3x3() will always be orthogonal or orthonormal in blender.

In linear algebra, an orthogonal matrix, or orthonormal matrix, is a real square matrix whose columns and rows are orthonormal vectors.

ie the local space axis vectors.

Blender matrices are defined in row order, an objects global axes are the columns of the rotation part of the matrix. (See link above, the columns are also the rows of the inverted or transposed ortho matrix)

cam_z_axis = cam.matrix_world.to_3x3().cols[2] 

If the rotation matrix is normalized it removes any issues re non regular scale.

Distance Point to Plane

There is a convenience method mathutils.geometry.distance_point_to_plane

>>> distance_point_to_plane(
distance_point_to_plane(pt, plane_co, plane_no)
.. function:: distance_point_to_plane(pt, plane_co, plane_no)
Returns the signed distance between a point and a plane    (negative when below the normal).
:arg pt: Point
:type pt: :class:`mathutils.Vector`
:arg plane_co: A point on the plane
:type plane_co: :class:`mathutils.Vector`
:arg plane_no: The direction the plane is facing
:type plane_no: :class:`mathutils.Vector`
:rtype: float

Test script. Find distance of all scene object origins to scene camera plane.

import bpy
from mathutils.geometry import distance_point_to_plane as dp2p

context = bpy.context
scene = context.scene
cam = scene.camera 

cam_axis = cam.matrix_world.to_3x3().normalized().col[2]
cam_axis.negate()
cam_loc = cam.matrix_world.translation

for o in scene.objects:
    if o is cam:
        continue
    d = dp2p(
        o.matrix_world.translation,
        cam_loc,
        cam_axis
        )
    print(f"{o.name} : {d}")

Or as suggested in question

    v = o.matrix_world.translation - cam_loc
    n = v.project(cam_axis)
    print(n.length)

with some extra test (n.dot(cam_axis) > 0) to determine if in front, or behind plane.

Related Constrain a camera to an object while also aligning it perfectly to the center of the object (relative to the camera) even while using perspective

$\endgroup$
2
  • 1
    $\begingroup$ This is incredible! It works like magic! I admit that I'm pretty rusty with my linear algebra. Would you be willing to expound a little bit more why 'cam.matrix_world.to_3x3().cols[2]' is applicable? Thank you again for the incredible answer! $\endgroup$ Commented Jul 28, 2021 at 23:05
  • $\begingroup$ Happy to assist on the path to "unleashing" . Added wiki link, basically if the ortho matrix is in row order its columns give axis vectors, and vice versa. Added a link which may be of interest, adds a camera plane aligned 2d bounding box around object of interest. $\endgroup$
    – batFINGER
    Commented Jul 29, 2021 at 10:20
0
$\begingroup$

If you know the linear distance to the object and the angle the camera makes with the direction of the object (which is the plane's direction) it's easy to calculate. The vertical distance of the camera to the plane can be calculated by noting that the vertical distance divided by the distance to the object equals the sine of the angle. Obviously, this ratio is always smaller than one. Only if you place the camera very high this approaches one. When the camera is on the plane, the sine is zero (and so is the distance).

Only knowing the distance of the camera to the object wont bring you anywhere. There are many heights for which the distance of the camera to the object stays the same. Some additional information is needed. Like the angle or horizontal distance.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .