0
$\begingroup$

About the script: I would like to add a camera in front of a selected object. The front of the object is based on a calculation using a pre-defined polarangle, azimuthal angle and distance.

The problem: When I rotate the selected object on the Y axis I can't compensate for it, the conversion between the Cartesian and Spheric coordinates resulting a wrongly added camera. It works when Y is 0.

I am using the following function to defined the xyz coordinates based on the distance and the angles from an object.

import bpy
import math

# https://planetcalc.com/7952/
def calculateDirectionPoint(distance,pol,az):
    # calculates the coordinates based on distance and angles (Spheric to Cartesian coordinates)
    x = distance * math.sin(pol) * math.cos(az)
    y = distance * math.sin(pol) * math.sin(az) 
    z = distance * math.cos(pol) 
    return [x,y,z]

I am using the following code to define the selected object location and the relevant angles.

# following object rotation
object = bpy.data.objects['Suzanne']
objrot = object.rotation_euler
o_x = objrot[0]
o_y = objrot[1]
o_z = objrot[2]

# FRONT x and z
#pol_x = 1.570796327
pol_x = math.radians(90)
#az_z = -1.570796327
az_z = math.radians(90)*-1

if o_y == 0:
    az_m = 0
    pol_m = 0
else:
    # This is the part where the I can't define the right correction for the o_y value from the object y rotation.
    pol_m = math.pi-o_x
    az_m = o_y*((math.pi/2)/o_y)
  
coord = calculateDirectionPoint(
    6,
    (pol_x+o_x)+pol_m,
    (az_z+o_z)+az_m
    )

cam = bpy.data.objects['Camera']
cam.location = (coord[0], coord[1], coord[2])
cam.rotation_euler = (pol_x+o_x, o_y, (az_z+math.pi/2)+o_z)

So technically I would like to convert the Euler coordinates to spherical coordinates. Can someone advise how should I compensate for the Y axis? Thanks.

I also tried the rotation matrix, which works perfectly again when the y axis rotation is 0.

import math
import bpy

locator = bpy.data.objects['Camera']
myobject = bpy.data.objects['Suzanne']

frontVector = [0,-6,0]
#Calculates a rotation of a point in 3d space
def rotationMatrix(vector,roll,pitch,yaw):
    x = vector[0]*(math.cos(pitch)*math.cos(yaw))+vector[1]*(math.cos(pitch)*-math.sin(yaw)*math.cos(roll)+math.sin(pitch)*math.sin(roll))+vector[2]*(math.sin(pitch)*math.cos(roll)+(math.cos(pitch)*-math.sin(yaw))*-math.sin(roll))
    y = vector[0]*math.sin(yaw)+vector[1]*(math.cos(yaw)*math.cos(roll))+vector[2]*(math.cos(yaw)*-math.sin(roll))
    z = vector[0]*(-math.sin(pitch)*math.cos(yaw))+vector[1]*(-math.sin(pitch)*-math.sin(yaw)*math.cos(roll)+math.cos(pitch)*math.sin(roll))+vector[2]*(math.cos(pitch)*math.cos(roll)+-math.sin(pitch)*-math.sin(yaw)*-math.sin(roll))
    print(x,y,z)
    return(x,y,z)

coordinates =   rotationMatrix(frontVector,myobject.rotation_euler[0],myobject.rotation_euler[1],myobject.rotation_euler[2])

locator.location = (coordinates[0],coordinates[1],coordinates[2])
```
$\endgroup$

2 Answers 2

0
$\begingroup$

If "az" is rotation around the z-axis and "pol" is rotation around the y-axis:

  • Consider moving the frame of reference. Specifically, rotate the y-axis around the z-axis "az" degrees before the y-axis rotation.

  • Or consider using Quaternion instead of Euler Angles.

$\endgroup$
1
  • $\begingroup$ "pol" stands for polar angle, which is the angle from the x axis. "az" stands for azimuthal angle, which is the angle on the z en.wikipedia.org/wiki/Spherical_coordinate_system I did not check the Quaternion yet, thx for the suggestion! $\endgroup$
    – Sneider
    Nov 20, 2023 at 18:00
0
$\begingroup$

After a long and exhausting search I conclude that it is not possible to directly convert Euler rotation to Spherical Coordinates.

However, here is how I circumvent this "small" problem.

The initial problem: I wanted to keep a point which is front of an object in the same absolute position to the object. For me this means that if an object rotates 45 degrees to any direction, the given point will rotate with it and from a viewer PoV it remains in the same position.

Steps:

  1. Define a Vector, which is in front of an ideal object. Ideal object has 0,0,0 rotation and at the 0,0,0 point.
  2. The Euler Rotation order matters! Convert everything to the same rotation, but I am using XYZ rotation.
  3. Get the rotation from your object.
  4. Rotate your Vector around the object coordinates (call it rotation point) with the given object rotation.
  5. Once you have the new Vector coordinates, you can calculate the Spherical coordinates, as you can convert Cartesian coordinates to Spherical coordinates. The reason for it if you want to decrease or increase the distance from the object, but not the rotation.

Currently this is the code I am using for the vector rotation, it is still under testing but it works so far. I did not include the Cartesian/Spherical conversion.

import bpy
import math

myobject = bpy.data.objects["Suzanne"]
myobject.rotation_mode = 'XYZ'
cam_obj = bpy.data.objects["Camera"]
cam_obj.rotation_mode = 'XYZ'

def rotate_vector_around_point(vector, point, angles_radians):
    # Convert angles from degrees to radians
    #angles_radians = [math.radians(angle) for angle in angles_degrees]

    # Translate the vector to the origin
    translated_vector = [vector[i] - point[i] for i in range(3)]

    # Apply the rotation around X axis
    rotated_vector = [
        translated_vector[0],
        translated_vector[1] * math.cos(angles_radians[0]) - translated_vector[2] * math.sin(angles_radians[0]),
        translated_vector[1] * math.sin(angles_radians[0]) + translated_vector[2] * math.cos(angles_radians[0])
    ]

    # Apply the rotation around Y axis
    rotated_vector = [
        rotated_vector[0] * math.cos(angles_radians[1]) + rotated_vector[2] * math.sin(angles_radians[1]),
        rotated_vector[1],
        -rotated_vector[0] * math.sin(angles_radians[1]) + rotated_vector[2] * math.cos(angles_radians[1])
    ]

    # Apply the rotation around Z axis
    rotated_vector = [
        rotated_vector[0] * math.cos(angles_radians[2]) - rotated_vector[1] * math.sin(angles_radians[2]),
        rotated_vector[0] * math.sin(angles_radians[2]) + rotated_vector[1] * math.cos(angles_radians[2]),
        rotated_vector[2]
    ]

    # Translate the vector back to its original position
    final_vector = [rotated_vector[i] + point[i] for i in range(3)]

    return final_vector

# Example usage:
initial_vector = [0, -6, 0]
rotation_point = [0, 0, 0]
rotation_angles = myobject.rotation_euler

result_vector = rotate_vector_around_point(initial_vector, rotation_point, rotation_angles)
cam_obj.location = result_vector
$\endgroup$

You must log in to answer this question.

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