isl-org / isl-org/Open3D

How to implement a level of details visualizer for 3D meshes?

Open
#6,422 1 comment 0 reactions 0 assignees View on GitHub
question
Dominant language
C++
Stars
14k
Forks
2.6k
Avg merge
5d 18h
Merged PRs (30d)
6

Description

### Checklist

- [X] I have searched for [similar issues](https://github.com/isl-org/Open3D/issues).
- [X] For Python issues, I have tested with the [latest development wheel](http://www.open3d.org/docs/latest/getting_started.html#development-version-pip).
- [X] I have checked the [release documentation](http://www.open3d.org/docs/release/) and the [latest documentation](http://www.open3d.org/docs/latest/) (for `master` branch).

### My Question

I have trouble implementing a visualizer to visualize the level of detailed meshes. Below is my code:

```python
from typing import List

import tqdm
import numpy as np
import open3d as o3d

def create_lod_meshes(mesh, simplify_ratio: int = 4, num_lod_levels: int = 4) -> List:
# num_vertices = len(mesh.vertices)
num_triangles = len(mesh.triangles)

LOD_meshes = [mesh] # pylint: disable=C0103
pbar = tqdm.trange(num_lod_levels - 1, desc="Creating LOD meshes")
for i in range(num_lod_levels - 1):
target_number_of_triangles = num_triangles // ((i + 1) * simplify_ratio)
simplified_mesh = mesh.simplify_quadric_decimation(
target_number_of_triangles=target_number_of_triangles
)
LOD_meshes.append(simplified_mesh)
pbar.update(1)

return LOD_meshes

def calculate_camera_distance(mesh, view_control):
camera = view_control.convert_to_pinhole_camera_parameters()
view_matrix = camera.extrinsic
# Get the camera's position from the view matrix.
camera_position = np.linalg.inv(view_matrix)[:3, 3]

# Calculate the distance from the camera to the center of the mesh's bounding box.
mesh_center = np.mean(np.asarray(mesh.vertices), axis=0)
camera_distance = np.linalg.norm(camera_position - mesh_center)

return camera_distance

def determine_lod_level(camera_distance):
# Define LOD distance thresholds (you can adjust these ad needed)
# lod_thresholds = [10.0, 20.0, 30.0] # Example thresholds in units
lod_thresholds = [1.25, 2.50, 5.0] # Example thresholds in units

# Default LOD level (highest detail)
lod_level = 0

# Determine the LOD level based on camera distance.
for i, threshold in enumerate(lod_thresholds, 1):
print(f'i: {i}')
if camera_distance > threshold:
lod_level = i
else:
break

return lod_level

def visualize(mesh_path: str = ''):
mesh_path = 'mesh.obj' # For simplification, just replace the path with the path of your 3D object.

mesh_in = o3d.io.read_triangle_mesh(mesh_path)
mesh_in.compute_vertex_normals()

LOD_meshes = create_lod_meshes(mesh=mesh_in)

# Maintain a transformation matrix for the current LOD mesh
# current_transform = np.eye(4)

# Create a visualizer.
vis = o3d.visualization.Visualizer()
vis.create_window()

# Add the initial LOD mesh to the visualizer.
current_lod_mesh = LOD_meshes[-1]
vis.add_geometry(current_lod_mesh)
# camera = vis.get_view_control().convert_to_pinhole_camera_parameters()
# current_transform = camera.extrinsic

while True:
# Calculate camera distance
camera_distance = calculate_camera_distance(mesh_in, vis.get_view_control())
print(f'camera_distance: {camera_distance}')

# Determine LOD level based on camera distance.
lod_level = determine_lod_level(camera_distance)
print(f'lod_level: {lod_level}')

# Update the displayed LOD mesh.
if current_lod_mesh != LOD_meshes[lod_level]:
vis.remove_geometry(current_lod_mesh)

# # Apply the last transformation to the new LOD mesh.
# LOD_meshes[lod_level].transform(current_transform)

current_lod_mesh = LOD_meshes[lod_level]
vis.add_geometry(current_lod_mesh)

print(f"Vertices: {len(current_lod_mesh.vertices)} Triangles: {len(current_lod_mesh.triangles)}")

# vis.remove_geometry(vis.get_geometries()[0]) # Remove the current LOD mesh
# vis.add_geometry(LOD_meshes[lod_level])
# vis.update_geometry(LOD_meshes[lod_level])
vis.poll_events()
vis.update_renderer()

# Update the current_transform to match the transformation of the current LOD mesh.
# current_transform = current_lod_mesh.get_transform()
# camera = vis.get_view_control().convert_to_pinhole_camera_parameters()
# current_transform = camera.extrinsic

# Close the visualizer window on exit.
vis.destroy_window()

if __name__ == "__main__":
visualize()
```

When the visualizer loads the updated mesh, the geometry will be set to the original position. How can I keep it in the same position as the last mesh?

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.