134 lines
4.4 KiB
Python
134 lines
4.4 KiB
Python
# modified from https://github.com/Profactor/continuous-remeshing
|
|
import torch
|
|
import numpy as np
|
|
import trimesh
|
|
from typing import Tuple
|
|
|
|
def to_numpy(*args):
|
|
def convert(a):
|
|
if isinstance(a,torch.Tensor):
|
|
return a.detach().cpu().numpy()
|
|
assert a is None or isinstance(a,np.ndarray)
|
|
return a
|
|
|
|
return convert(args[0]) if len(args)==1 else tuple(convert(a) for a in args)
|
|
|
|
def laplacian(
|
|
num_verts:int,
|
|
edges: torch.Tensor #E,2
|
|
) -> torch.Tensor: #sparse V,V
|
|
"""create sparse Laplacian matrix"""
|
|
V = num_verts
|
|
E = edges.shape[0]
|
|
|
|
#adjacency matrix,
|
|
idx = torch.cat([edges, edges.fliplr()], dim=0).type(torch.long).T # (2, 2*E)
|
|
ones = torch.ones(2*E, dtype=torch.float32, device=edges.device)
|
|
A = torch.sparse.FloatTensor(idx, ones, (V, V))
|
|
|
|
#degree matrix
|
|
deg = torch.sparse.sum(A, dim=1).to_dense()
|
|
idx = torch.arange(V, device=edges.device)
|
|
idx = torch.stack([idx, idx], dim=0)
|
|
D = torch.sparse.FloatTensor(idx, deg, (V, V))
|
|
|
|
return D - A
|
|
|
|
def _translation(x, y, z, device):
|
|
return torch.tensor([[1., 0, 0, x],
|
|
[0, 1, 0, y],
|
|
[0, 0, 1, z],
|
|
[0, 0, 0, 1]],device=device) #4,4
|
|
|
|
def _projection(r, device, l=None, t=None, b=None, n=1.0, f=50.0, flip_y=True):
|
|
"""
|
|
see https://blog.csdn.net/wodownload2/article/details/85069240/
|
|
"""
|
|
if l is None:
|
|
l = -r
|
|
if t is None:
|
|
t = r
|
|
if b is None:
|
|
b = -t
|
|
p = torch.zeros([4,4],device=device)
|
|
p[0,0] = 2*n/(r-l)
|
|
p[0,2] = (r+l)/(r-l)
|
|
p[1,1] = 2*n/(t-b) * (-1 if flip_y else 1)
|
|
p[1,2] = (t+b)/(t-b)
|
|
p[2,2] = -(f+n)/(f-n)
|
|
p[2,3] = -(2*f*n)/(f-n)
|
|
p[3,2] = -1
|
|
return p #4,4
|
|
|
|
def _orthographic(r, device, l=None, t=None, b=None, n=1.0, f=50.0, flip_y=True):
|
|
if l is None:
|
|
l = -r
|
|
if t is None:
|
|
t = r
|
|
if b is None:
|
|
b = -t
|
|
o = torch.zeros([4,4],device=device)
|
|
o[0,0] = 2/(r-l)
|
|
o[0,3] = -(r+l)/(r-l)
|
|
o[1,1] = 2/(t-b) * (-1 if flip_y else 1)
|
|
o[1,3] = -(t+b)/(t-b)
|
|
o[2,2] = -2/(f-n)
|
|
o[2,3] = -(f+n)/(f-n)
|
|
o[3,3] = 1
|
|
return o #4,4
|
|
|
|
def make_star_cameras(az_count,pol_count,distance:float=10.,r=None,image_size=[512,512],device='cuda'):
|
|
if r is None:
|
|
r = 1/distance
|
|
A = az_count
|
|
P = pol_count
|
|
C = A * P
|
|
|
|
phi = torch.arange(0,A) * (2*torch.pi/A)
|
|
phi_rot = torch.eye(3,device=device)[None,None].expand(A,1,3,3).clone()
|
|
phi_rot[:,0,2,2] = phi.cos()
|
|
phi_rot[:,0,2,0] = -phi.sin()
|
|
phi_rot[:,0,0,2] = phi.sin()
|
|
phi_rot[:,0,0,0] = phi.cos()
|
|
|
|
theta = torch.arange(1,P+1) * (torch.pi/(P+1)) - torch.pi/2
|
|
theta_rot = torch.eye(3,device=device)[None,None].expand(1,P,3,3).clone()
|
|
theta_rot[0,:,1,1] = theta.cos()
|
|
theta_rot[0,:,1,2] = -theta.sin()
|
|
theta_rot[0,:,2,1] = theta.sin()
|
|
theta_rot[0,:,2,2] = theta.cos()
|
|
|
|
mv = torch.empty((C,4,4), device=device)
|
|
mv[:] = torch.eye(4, device=device)
|
|
mv[:,:3,:3] = (theta_rot @ phi_rot).reshape(C,3,3)
|
|
mv = _translation(0, 0, -distance, device) @ mv
|
|
|
|
return mv, _projection(r,device)
|
|
|
|
def make_star_cameras_orthographic(az_count,pol_count,distance:float=10.,r=None,image_size=[512,512],device='cuda'):
|
|
mv, _ = make_star_cameras(az_count,pol_count,distance,r,image_size,device)
|
|
if r is None:
|
|
r = 1
|
|
return mv, _orthographic(r,device)
|
|
|
|
def make_sphere(level:int=2,radius=1.,device='cuda') -> Tuple[torch.Tensor,torch.Tensor]:
|
|
sphere = trimesh.creation.icosphere(subdivisions=level, radius=1.0, color=None)
|
|
vertices = torch.tensor(sphere.vertices, device=device, dtype=torch.float32) * radius
|
|
faces = torch.tensor(sphere.faces, device=device, dtype=torch.long)
|
|
return vertices,faces
|
|
|
|
from pytorch3d.renderer import (
|
|
FoVOrthographicCameras,
|
|
look_at_view_transform,
|
|
)
|
|
|
|
def get_camera(R, T, focal_length=1 / (2**0.5)):
|
|
focal_length = 1 / focal_length
|
|
camera = FoVOrthographicCameras(device=R.device, R=R, T=T, min_x=-focal_length, max_x=focal_length, min_y=-focal_length, max_y=focal_length)
|
|
return camera
|
|
|
|
def make_star_cameras_orthographic_py3d(azim_list, device, focal=2/1.35, dist=1.1):
|
|
R, T = look_at_view_transform(dist, 0, azim_list)
|
|
focal_length = 1 / focal
|
|
return FoVOrthographicCameras(device=R.device, R=R, T=T, min_x=-focal_length, max_x=focal_length, min_y=-focal_length, max_y=focal_length).to(device)
|