Sharp-It / util.py
YiftachEde's picture
add
e03a824
import numpy as np
import torch
from shap_e.models.nn.camera import DifferentiableCameraBatch, DifferentiableProjectiveCamera
from shap_e.util.collections import AttrDict
def create_custom_cameras(size: int, device: torch.device, azimuths=None, elevations=None, fov_degrees=30, distance=3.0) -> DifferentiableCameraBatch:
"""
Create custom camera angles for rendering.
Args:
size: The width and height of the rendered image.
device: The device to put the camera parameters on.
azimuths: List of azimuth angles in degrees.
elevations: List of elevation angles in degrees.
fov_degrees: Field of view in degrees.
distance: Distance from the origin.
Returns:
A DifferentiableCameraBatch containing the specified cameras.
"""
if azimuths is None:
azimuths = [0]
if elevations is None:
elevations = [0]
origins = []
xs = []
ys = []
zs = []
for azimuth, elevation in zip(azimuths, elevations):
# Convert to radians
azimuth_rad = np.deg2rad(azimuth)
elevation_rad = np.deg2rad(elevation)
# Calculate camera position
x_pos = distance * np.cos(elevation_rad) * np.sin(azimuth_rad)
y_pos = distance * np.cos(elevation_rad) * np.cos(azimuth_rad)
z_pos = distance * np.sin(elevation_rad)
# Camera origin (position)
origin = np.array([x_pos, y_pos, z_pos])
# Camera z-axis (looking at the origin)
z = -origin / np.linalg.norm(origin)
# Camera x-axis (right)
x = np.array([np.cos(azimuth_rad + np.pi/2), np.sin(azimuth_rad + np.pi/2), 0.0])
x = x - np.dot(x, z) * z # Make orthogonal to z
x = x / np.linalg.norm(x) # Normalize
# Camera y-axis (up, computed as z cross x)
y = np.cross(z, x)
y = y / np.linalg.norm(y) # Normalize
origins.append(origin)
xs.append(x)
ys.append(y)
zs.append(z)
# Convert from radians to the appropriate x and y fov
fov_rad = np.deg2rad(fov_degrees)
return DifferentiableCameraBatch(
shape=(1, len(origins)),
flat_camera=DifferentiableProjectiveCamera(
origin=torch.from_numpy(np.stack(origins, axis=0)).float().to(device),
x=torch.from_numpy(np.stack(xs, axis=0)).float().to(device),
y=torch.from_numpy(np.stack(ys, axis=0)).float().to(device),
z=torch.from_numpy(np.stack(zs, axis=0)).float().to(device),
width=size,
height=size,
x_fov=fov_rad,
y_fov=fov_rad,
),
)