I would like to create cameras looking at origin uniformly distributed in a sphere. I got most of it right...but the cameras are looking away from the origin. I know I can get it right by a certain combination of rotations, but I want to be sure that what I am doing is 100% correct. Can someone familiar with this help me point out what's the right way to do it?
By changing the lookat slightly in the "wrong" way I can get what is expected result. However, what I would like to do is apply the coordinate transform matrix to the camera matrix after the "right" lookat is computed(right lookat==x-right,y-down,z-forward,i.e. the cv convention).
There is an additional problem with the code that looks right. The camera scale is negated for some reason. I thought scale is not affected by transform matrix. Having negative scale causes some other problem when I am converting the camera back to cv work.
looks wrong but should be correct?
looks right but wrong.
code to create cameras
import bpy
import bmesh
import random
import math
import numpy as np
from mathutils import Matrix
def sphere_golden_spiral(num_pts=1000):
from numpy import pi, cos, sin, arccos, arange
indices = arange(0, num_pts, dtype=float) + 0.5
phi = arccos(1 - 2*indices/num_pts)
theta = pi * (1 + 5**0.5) * indices
x, y, z = cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi)
points = np.stack((x,y,z),axis=-1)
return points
def norm(v):
return v/np.linalg.norm(v)
def lookat(eye,at=np.array([0.,0,0]),up=np.array([0.,1,0])):
z = norm(eye-at)
x = norm(np.cross(z,up))
y = np.cross(x,z)
z = -z
view_mat = np.zeros((4, 4))
t =np.array([0.,0,0])
t[0] = -np.dot(x,eye)
t[1] = -np.dot(y,eye)
t[2] = -np.dot(z,eye)
view_mat[0,:3]=x
view_mat[1,:3]=y
view_mat[2,:3]=z
view_mat[:3,3]=t
view_mat[3,3]=1
return np.linalg.inv(view_mat)
def rotx(a):
from math import cos,sin
return np.array([[1,0,0,0],
[0,cos(a),-sin(a),0],
[0,sin(a),cos(a),0],
[0,0,0,1]])
def roty(a):
from math import cos,sin
return np.array([[cos(a),0,sin(a),0],
[0,1,0,0],
[-sin(a),0,cos(a),0],
[0,0,0,1]])
def rotz(a):
from math import cos,sin
return np.array([[cos(a),-sin(a),0],
[sin(a),cos(a),0,0],
[0,0,1,0],
[0,0,0,1]])
def cams_sphere(points):
points = np.array(sphere_golden_spiral(points))
group = bpy.data.groups.new('Trg_sphere')
context = bpy.context
for i in range(len(points)):
p = points[i]
bpy.ops.object.camera_add()
cam = context.object
cam.name='Traj_sphere_%i'%i
transform = lookat(p*10)
#print(rotx(math.radians(-90)))
#transform = np.matmul(transform,roty(math.radians(-180)))
cam.matrix_world = Matrix(transform)
group.objects.link(cam)
cams_sphere(100)