diff --git a/.gitignore b/.gitignore
index 0f902b1..f75b5a0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ export/
data/
.vscode/
tests/failure/
+installer/
# Copied from https://github.com/github/gitignore/blob/main/Jekyll.gitignore
# Ignore metadata generated by Jekyll
diff --git a/aitviewer.py b/aitviewer.py
new file mode 100644
index 0000000..91b83f2
--- /dev/null
+++ b/aitviewer.py
@@ -0,0 +1,8 @@
+"""
+Entry point of the aitviewer binary dist.
+"""
+
+from aitviewer.viewer import Viewer
+
+v = Viewer()
+v.run()
diff --git a/aitviewer/configuration.py b/aitviewer/configuration.py
index cd38026..0170b12 100644
--- a/aitviewer/configuration.py
+++ b/aitviewer/configuration.py
@@ -16,7 +16,7 @@
"""
import os
-import torch
+# import torch
from omegaconf import OmegaConf
from omegaconf.dictconfig import DictConfig
@@ -47,7 +47,7 @@ def __init__(self):
self._conf.merge_with(conf)
self._gui_counter = 0
- self._gpu_available = torch.cuda.is_available()
+ # self._gpu_available = torch.cuda.is_available()
def update_conf(self, conf_obj):
"""Update the configuration with another configuration file or another OmegaConf configuration object."""
@@ -59,15 +59,15 @@ def update_conf(self, conf_obj):
def __getattr__(self, item):
if hasattr(self._conf, item):
- # Some attributes of the config are converted to torch objects automatically.
- if item == "device":
- return torch.device(self._conf.get("device", "cuda:0") if self._gpu_available else "cpu")
- elif item == "f_precision":
- return getattr(torch, "float{}".format(self._conf.get("f_precision", 32)))
- elif item == "i_precision":
- return getattr(torch, "int{}".format(self._conf.get("i_precision", 64)))
- else:
- return getattr(self._conf, item)
+ # # Some attributes of the config are converted to torch objects automatically.
+ # if item == "device":
+ # return torch.device(self._conf.get("device", "cuda:0") if self._gpu_available else "cpu")
+ # elif item == "f_precision":
+ # return getattr(torch, "float{}".format(self._conf.get("f_precision", 32)))
+ # elif item == "i_precision":
+ # return getattr(torch, "int{}".format(self._conf.get("i_precision", 64)))
+ # else:
+ return getattr(self._conf, item)
else:
# Default behavior.
return self.__getattribute__(item)
diff --git a/aitviewer/renderables/billboard.py b/aitviewer/renderables/billboard.py
index 29da0c9..078347e 100644
--- a/aitviewer/renderables/billboard.py
+++ b/aitviewer/renderables/billboard.py
@@ -18,11 +18,12 @@
import pickle
from typing import List, Union
-import cv2
+# import cv2
import moderngl
import numpy as np
from moderngl_window.opengl.vao import VAO
-from pxr import Gf, Sdf, UsdGeom
+
+# from pxr import Gf, Sdf, UsdGeom
from trimesh.triangles import points_to_barycentric
from aitviewer.scene.camera import Camera, OpenCVCamera
diff --git a/aitviewer/renderables/meshes.py b/aitviewer/renderables/meshes.py
index 591a823..c5e467a 100644
--- a/aitviewer/renderables/meshes.py
+++ b/aitviewer/renderables/meshes.py
@@ -26,7 +26,8 @@
import trimesh.geometry
from moderngl_window.opengl.vao import VAO
from PIL import Image
-from pxr import Gf, Sdf, UsdGeom
+
+# from pxr import Gf, Sdf, UsdGeom
from trimesh.triangles import points_to_barycentric
from aitviewer.scene.node import Node
diff --git a/aitviewer/renderables/plane.py b/aitviewer/renderables/plane.py
index da2d525..e441d89 100644
--- a/aitviewer/renderables/plane.py
+++ b/aitviewer/renderables/plane.py
@@ -16,7 +16,6 @@
"""
import moderngl
import numpy as np
-from pxr import Gf, UsdGeom
from aitviewer.renderables.meshes import Meshes
from aitviewer.scene.node import Node
@@ -24,6 +23,8 @@
from aitviewer.utils import set_lights_in_program, set_material_properties
from aitviewer.utils.decorators import hooked
+# from pxr import Gf, UsdGeom
+
class Plane(Node):
"""
diff --git a/aitviewer/scene/node.py b/aitviewer/scene/node.py
index bfbda4e..5fce8cd 100644
--- a/aitviewer/scene/node.py
+++ b/aitviewer/scene/node.py
@@ -738,7 +738,7 @@ def export_usd(self, stage, usd_path: str, directory: str = None, verbose=False)
:param stage: an object of type Usd.Stage into which to export the node
:param usd_path: the path of the parent object in the USD file scene hierarchy.
"""
- from pxr import Gf, UsdGeom
+ # from pxr import Gf, UsdGeom
usd_path = f"{usd_path}/{self.name.replace(' ', '_')}_{self.uid:03}"
diff --git a/aitviewer/streamables/webcam.py b/aitviewer/streamables/webcam.py
index 2ff8157..cb6fc11 100644
--- a/aitviewer/streamables/webcam.py
+++ b/aitviewer/streamables/webcam.py
@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see .
"""
-import cv2
+# import cv2
import numpy as np
from moderngl_window import geometry
diff --git a/aitviewer/utils/so3.py b/aitviewer/utils/so3.py
index 75abc59..7b29ac3 100644
--- a/aitviewer/utils/so3.py
+++ b/aitviewer/utils/so3.py
@@ -15,30 +15,30 @@
along with this program. If not, see .
"""
import numpy as np
-import roma
-import torch
+
+# import roma
+# import torch
from scipy.spatial.transform import Rotation as R
from scipy.spatial.transform import RotationSpline
-
-def rot2aa_torch(rotation_matrices):
- """
- Convert rotation matrices to rotation vectors (angle-axis representation).
- :param rotation_matrices: A torch tensor of shape (..., 3, 3).
- :return: A torch tensor of shape (..., 3).
- """
- assert isinstance(rotation_matrices, torch.Tensor)
- return roma.rotmat_to_rotvec(rotation_matrices)
-
-
-def aa2rot_torch(rotation_vectors):
- """
- Convert rotation vectors (angle-axis representation) to rotation matrices.
- :param rotation_vectors: A torch tensor of shape (..., 3).
- :return: A torch tensor of shape (..., 3, 3).
- """
- assert isinstance(rotation_vectors, torch.Tensor)
- return roma.rotvec_to_rotmat(rotation_vectors)
+# def rot2aa_torch(rotation_matrices):
+# """
+# Convert rotation matrices to rotation vectors (angle-axis representation).
+# :param rotation_matrices: A torch tensor of shape (..., 3, 3).
+# :return: A torch tensor of shape (..., 3).
+# """
+# assert isinstance(rotation_matrices, torch.Tensor)
+# return roma.rotmat_to_rotvec(rotation_matrices)
+
+
+# def aa2rot_torch(rotation_vectors):
+# """
+# Convert rotation vectors (angle-axis representation) to rotation matrices.
+# :param rotation_vectors: A torch tensor of shape (..., 3).
+# :return: A torch tensor of shape (..., 3, 3).
+# """
+# assert isinstance(rotation_vectors, torch.Tensor)
+# return roma.rotvec_to_rotmat(rotation_vectors)
def rot2aa_numpy(rotation_matrices):
diff --git a/aitviewer/utils/usd.py b/aitviewer/utils/usd.py
index 3b80333..9095444 100644
--- a/aitviewer/utils/usd.py
+++ b/aitviewer/utils/usd.py
@@ -3,7 +3,8 @@
import numpy as np
from PIL import Image
-from pxr import Sdf, UsdShade
+
+# from pxr import Sdf, UsdShade
def _get_texture_paths(path, name, directory):
diff --git a/aitviewer/utils/utils.py b/aitviewer/utils/utils.py
index 3bce463..537b069 100644
--- a/aitviewer/utils/utils.py
+++ b/aitviewer/utils/utils.py
@@ -18,19 +18,20 @@
import subprocess
import numpy as np
-import torch
+
+# import torch
from scipy.interpolate import CubicSpline
-from aitviewer.utils.so3 import aa2rot_torch as aa2rot
-from aitviewer.utils.so3 import rot2aa_torch as rot2aa
+# from aitviewer.utils.so3 import aa2rot_torch as aa2rot
+# from aitviewer.utils.so3 import rot2aa_torch as rot2aa
-def to_torch(x, dtype, device):
- if x is None:
- return None
- if isinstance(x, np.ndarray):
- return torch.from_numpy(x).to(dtype=dtype, device=device)
- return x.to(dtype=dtype, device=device)
+# def to_torch(x, dtype, device):
+# if x is None:
+# return None
+# if isinstance(x, np.ndarray):
+# return torch.from_numpy(x).to(dtype=dtype, device=device)
+# return x.to(dtype=dtype, device=device)
def to_numpy(x):
@@ -166,28 +167,28 @@ def resample_positions(positions, fps_in, fps_out):
return interpolate_positions(positions, ts_in, ts_out)
-def compute_vertex_and_face_normals_torch(vertices, faces, vertex_faces, normalize=False):
- """
- Compute (unnormalized) vertex normals for the given vertices.
- :param vertices: A tensor of shape (N, V, 3).
- :param faces: A tensor of shape (F, 3) indexing into `vertices`.
- :param vertex_faces: A tensor of shape (V, MAX_VERTEX_DEGREE) that lists the face IDs each vertex is a part of.
- :param normalize: Whether to make the normals unit length or not.
- :return: The vertex and face normals as tensors of shape (N, V, 3) and (N, F, 3) respectively.
- """
- vs = vertices[:, faces.to(dtype=torch.long)]
- face_normals = torch.cross(vs[:, :, 1] - vs[:, :, 0], vs[:, :, 2] - vs[:, :, 0], dim=-1) # (N, F, 3)
+# def compute_vertex_and_face_normals_torch(vertices, faces, vertex_faces, normalize=False):
+# """
+# Compute (unnormalized) vertex normals for the given vertices.
+# :param vertices: A tensor of shape (N, V, 3).
+# :param faces: A tensor of shape (F, 3) indexing into `vertices`.
+# :param vertex_faces: A tensor of shape (V, MAX_VERTEX_DEGREE) that lists the face IDs each vertex is a part of.
+# :param normalize: Whether to make the normals unit length or not.
+# :return: The vertex and face normals as tensors of shape (N, V, 3) and (N, F, 3) respectively.
+# """
+# vs = vertices[:, faces.to(dtype=torch.long)]
+# face_normals = torch.cross(vs[:, :, 1] - vs[:, :, 0], vs[:, :, 2] - vs[:, :, 0], dim=-1) # (N, F, 3)
- ns_all_faces = face_normals[:, vertex_faces] # (N, V, MAX_VERTEX_DEGREE, 3)
- ns_all_faces[:, vertex_faces == -1] = 0.0
- vertex_degrees = (vertex_faces > -1).sum(dim=-1).to(dtype=ns_all_faces.dtype)
- vertex_normals = ns_all_faces.sum(dim=-2) / vertex_degrees[None, :, None] # (N, V, 3)
+# ns_all_faces = face_normals[:, vertex_faces] # (N, V, MAX_VERTEX_DEGREE, 3)
+# ns_all_faces[:, vertex_faces == -1] = 0.0
+# vertex_degrees = (vertex_faces > -1).sum(dim=-1).to(dtype=ns_all_faces.dtype)
+# vertex_normals = ns_all_faces.sum(dim=-2) / vertex_degrees[None, :, None] # (N, V, 3)
- if normalize:
- face_normals = face_normals / torch.norm(face_normals, dim=-1).unsqueeze(-1)
- vertex_normals = vertex_normals / torch.norm(vertex_normals, dim=-1).unsqueeze(-1)
+# if normalize:
+# face_normals = face_normals / torch.norm(face_normals, dim=-1).unsqueeze(-1)
+# vertex_normals = vertex_normals / torch.norm(vertex_normals, dim=-1).unsqueeze(-1)
- return vertex_normals, face_normals
+# return vertex_normals, face_normals
def compute_vertex_and_face_normals(vertices, faces, vertex_faces, normalize=False):
@@ -329,38 +330,38 @@ def compute_union_of_current_bounds(nodes):
return bounds
-def local_to_global(poses, parents, output_format="aa", input_format="aa"):
- """
- Convert relative joint angles to global ones by unrolling the kinematic chain.
- :param poses: A tensor of shape (N, N_JOINTS*3) defining the relative poses in angle-axis format.
- :param parents: A list of parents for each joint j, i.e. parent[j] is the parent of joint j.
- :param output_format: 'aa' or 'rotmat'.
- :param input_format: 'aa' or 'rotmat'
- :return: The global joint angles as a tensor of shape (N, N_JOINTS*DOF).
- """
- assert output_format in ["aa", "rotmat"]
- assert input_format in ["aa", "rotmat"]
- dof = 3 if input_format == "aa" else 9
- n_joints = poses.shape[-1] // dof
- if input_format == "aa":
- local_oris = aa2rot(poses.reshape((-1, 3)))
- else:
- local_oris = poses
- local_oris = local_oris.reshape((-1, n_joints, 3, 3))
- global_oris = torch.zeros_like(local_oris)
-
- for j in range(n_joints):
- if parents[j] < 0:
- # root rotation
- global_oris[..., j, :, :] = local_oris[..., j, :, :]
- else:
- parent_rot = global_oris[..., parents[j], :, :]
- local_rot = local_oris[..., j, :, :]
- global_oris[..., j, :, :] = torch.matmul(parent_rot, local_rot)
-
- if output_format == "aa":
- global_oris = rot2aa(global_oris.reshape((-1, 3, 3)))
- res = global_oris.reshape((-1, n_joints * 3))
- else:
- res = global_oris.reshape((-1, n_joints * 3 * 3))
- return res
+# def local_to_global(poses, parents, output_format="aa", input_format="aa"):
+# """
+# Convert relative joint angles to global ones by unrolling the kinematic chain.
+# :param poses: A tensor of shape (N, N_JOINTS*3) defining the relative poses in angle-axis format.
+# :param parents: A list of parents for each joint j, i.e. parent[j] is the parent of joint j.
+# :param output_format: 'aa' or 'rotmat'.
+# :param input_format: 'aa' or 'rotmat'
+# :return: The global joint angles as a tensor of shape (N, N_JOINTS*DOF).
+# """
+# assert output_format in ["aa", "rotmat"]
+# assert input_format in ["aa", "rotmat"]
+# dof = 3 if input_format == "aa" else 9
+# n_joints = poses.shape[-1] // dof
+# if input_format == "aa":
+# local_oris = aa2rot(poses.reshape((-1, 3)))
+# else:
+# local_oris = poses
+# local_oris = local_oris.reshape((-1, n_joints, 3, 3))
+# global_oris = torch.zeros_like(local_oris)
+
+# for j in range(n_joints):
+# if parents[j] < 0:
+# # root rotation
+# global_oris[..., j, :, :] = local_oris[..., j, :, :]
+# else:
+# parent_rot = global_oris[..., parents[j], :, :]
+# local_rot = local_oris[..., j, :, :]
+# global_oris[..., j, :, :] = torch.matmul(parent_rot, local_rot)
+
+# if output_format == "aa":
+# global_oris = rot2aa(global_oris.reshape((-1, 3, 3)))
+# res = global_oris.reshape((-1, n_joints * 3))
+# else:
+# res = global_oris.reshape((-1, n_joints * 3 * 3))
+# return res
diff --git a/aitviewer/viewer.py b/aitviewer/viewer.py
index 8f0dae2..253d2f4 100644
--- a/aitviewer/viewer.py
+++ b/aitviewer/viewer.py
@@ -38,7 +38,8 @@
from aitviewer.scene.camera import PinholeCamera, ViewerCamera
from aitviewer.scene.node import Node
from aitviewer.scene.scene import Scene
-from aitviewer.server import ViewerServer
+
+# from aitviewer.server import ViewerServer
from aitviewer.shaders import clear_shader_cache
from aitviewer.streamables.streamable import Streamable
from aitviewer.utils import path
@@ -1753,7 +1754,7 @@ def export_frame(self, file_path, scale_factor: float = None, transparent_backgr
self._last_frame_rendered_at = self.timer.time
def export_usd(self, path: str, export_as_directory=False, verbose=False):
- from pxr import Usd, UsdGeom
+ # from pxr import Usd, UsdGeom
if export_as_directory:
if path.endswith(".usd"):
diff --git a/installer.py b/installer.py
new file mode 100644
index 0000000..4df4224
--- /dev/null
+++ b/installer.py
@@ -0,0 +1,39 @@
+import PyInstaller.__main__
+import os
+import shutil
+
+OUTPUT_DIR = "installer"
+BUILD_PATH = os.path.join(OUTPUT_DIR, "build")
+DIST_PATH = os.path.join(OUTPUT_DIR, "dist")
+
+os.makedirs(OUTPUT_DIR, exist_ok=True)
+
+PyInstaller.__main__.run([
+ "aitviewer.py",
+ "--noconfirm",
+ "--windowed",
+ # "--exclude", "PyQt5",
+ "--exclude", "matplotlib",
+ "--exclude", "pandas",
+ "--exclude", "cv2",
+ "--exclude", "open3d",
+ "--hidden-import", "moderngl_window.loaders.program.separate",
+ "--hidden-import", "moderngl_window.loaders.program.single",
+ "--hidden-import", "moderngl_window.loaders.program",
+ "--hidden-import", "moderngl_window.context.pyglet",
+ "--hidden-import", "glcontext",
+ "--workpath", BUILD_PATH,
+ "--distpath", DIST_PATH,
+ "--specpath", OUTPUT_DIR,
+ "--add-data", os.path.join("..", "aitviewer", "resources", "*") + os.pathsep + os.path.join("aitviewer", "resources"),
+ "--add-data", os.path.join("..", "aitviewer", "shaders", "**", "*") + os.pathsep + os.path.join("aitviewer", "shaders"),
+ "--add-data", os.path.join("..", "aitviewer", "aitvconfig.yaml") + os.pathsep + os.path.join("aitviewer"),
+])
+
+root = os.path.join(DIST_PATH, "aitviewer")
+shutil.copytree(os.path.join("aitviewer", "resources"), os.path.join(root, "aitviewer", "resources"), dirs_exist_ok=True)
+shutil.copytree(os.path.join("aitviewer", "shaders"), os.path.join(root, "aitviewer", "shaders"), dirs_exist_ok=True)
+shutil.copy(os.path.join("aitviewer", "aitvconfig.yaml"), os.path.join(root, "aitviewer"))
+
+# moderngl.window requires a scene folder to exist.
+os.makedirs(os.path.join(OUTPUT_DIR, "dist", "aitviewer", "moderngl_window", "scene", "programs"))
\ No newline at end of file