In the Blender Game Engine my Python script makes an empty follow my cursor in 3D space. I want a LookAt function for a general object rather than a camera. I want the object to look at the point I'm hovering (the empty position). I'm using a cube so one face should always face the empty.
All I have is a direction vector and I chose the X axis for the local look direction. So I need to calculate the Euler angles and convert them to axis-rotation angles (theta*[axis^]). I have in the Blender Game Engine mathutils (provide quaternions, Euler based rotations via axis-angles, and matrices). I have the object look at the empty when I rotate only the Z axis. I used trigonometry, so sign is handled and I don't need matrix or quaternions.
I want to rotate the Y axis for the up-down look (in 3D we need two rotations, the third is just for rotating the view upside-down, rolling the camera) since this rotation axis is the look direction vector.
My script:
import bge
from mathutils import Vector, Matrix
import math
# Basic stuff
cont = bge.logic.getCurrentController()
own = cont.owner
scene = bge.logic.getCurrentScene()
c = scene.objects["Cube"]
e = scene.objects["Empty"]
# axises (we're using localOrientation)
x = Vector((1.0,0.0,0.0))
y = Vector((0.0,1.0,0.0))
z = Vector((0.0,0.0,1.0))
vec = Vector(e.worldPosition - c.worldPosition) # direction vector
# Converting direction vector into euler angles
# Using trigonometry we get: tan(psi) = cos(phi2)/cos(phi1)
# Where phi1 is the angle between x axises (euler angle)
# and phi2 is the euler of the y axises.
# psi is the z rotation angle.
# get cos(euler_angle)
phi1 = vec.dot(x)/vec.length # = cos p1
phi2 = vec.dot(y)/vec.length # = cos p2
phi3 = vec.dot(z)/vec.length # = cos p3
# get the rotation/steer angles
zAngle = math.atan(phi2/phi1)
yAngle = math.atan2(phi3,phi1)
xAngle = math.atan(phi2/phi3)
# use only 2 as the third must adapt (also: view concept - x is the looking direction, rotating it would make rolling)
r = c.localOrientation.to_euler()
r.z = zAngle
r.y = -yAngle
#r.x = xAngle
c.localOrientation = r
Separately each axis works but combined there are jump glitches through the global Y axis. Also, it seems the "local" orientation in Blender is the same as the "worldOrientation" so I'm not sure in what frame of reference I'm working anymore.