marcomusy / vedo

A python module for scientific analysis of 3D data based on VTK and Numpy
https://vedo.embl.es
MIT License
2.05k stars 266 forks source link

Creating a plot with objects out of scene, seems to break calls to render #1170

Closed xehartnort closed 3 months ago

xehartnort commented 3 months ago

Hi!

I think we have found a weird bug, the steps to reproduce it are shown below:

  1. Create a plotter instance with a mesh out of camera using show (thus with an empty screenshot).
  2. Move it back to camera range and render the plot using render(resetcam=False).
  3. Take a screenshot, which should display the object, however the screenshot is empty.

The problem seems to disappear if the plotter instance is created with the object in camera range (show_problem=False)

You can download the mesh in the example from: https://github.com/user-attachments/files/16443482/canonical_face.zip

import vedo
import cv2
import numpy as np

# Transform that moves the object of ot the camera range
t = np.eye(4)
t[2, 3] = -500
inv_t = t.copy()
inv_t[2, 3] = 500
mesh = vedo.load("canonical_face.obj")

# Whether to show the bug or not
show_problem = True

## Part: 1
plt = mesh.show(
    offscreen=False,
    interactive=False,
    camera=vedo.utils.oriented_camera(),
    bg="black",
)
img1 = plt.screenshot(asarray=True)

print("Out of camera range? (It should be False): ", img1.max() == 0)
cv2.imwrite("image0.png", img1)

## Part: 2
if not show_problem:
    mesh = mesh.apply_transform(t)
    plt.render(resetcam=False)
else:
    mesh = mesh.apply_transform(t)
    plt = mesh.show(
        offscreen=False,
        interactive=False,
        camera=vedo.utils.oriented_camera(),
        bg="black",
    )

img1 = plt.screenshot(asarray=True)
print("Out of camera range? (It should be True): ", img1.max() == 0)
cv2.imwrite("image1.png", img1)

## Part: 3
# Return to original position
mesh = mesh.apply_transform(inv_t)
# Preserve camera position
plt.render(resetcam=False)
img2 = plt.screenshot(asarray=True)

print("Out of camera range? (It should be False): ", img2.max() == 0)
cv2.imwrite("image2.png", img2)

Thank you for your time :smile:

marcomusy commented 3 months ago

Hi sorry for the late reply, I just added another method to fix this. Check out:

import vedo
import numpy as np

# Transform that moves the object out of the camera range
t = np.eye(4)
t[2, 3] = -500
inv_t = t.copy()
inv_t[2, 3] = 500
mesh = vedo.Mesh("canonical_face.obj")

cam = vedo.utils.oriented_camera(
    center=(0, 0, 0), up_vector=(0, 1, 0), backoff_vector=(0, 0, 1), backoff=1.0
)

## Part: 1##########
plt = mesh.show(camera=cam, bg="black", interactive=False)
img = plt.screenshot(asarray=True)
print("Out of camera range? (It should be False): ", img.max() == 0)
vedo.Image(img).write("image0.png")

## Part: 2##########
mesh.apply_transform(t)
plt.show(mesh, interactive=False, camera=cam, bg="black")

img = plt.screenshot(asarray=True)
print("Out of camera range? (It should be True): ", img.max() == 0)
vedo.Image(img).write("image1.png")

## Part: 3##########  Return to original position
mesh.apply_transform(inv_t)
plt.reset_clipping_range()  ########## This line fixes the problem
plt.render()
img = plt.screenshot(asarray=True)
print("Out of camera range? (It should be False): ", img.max() == 0)
vedo.Image(img).write("image2.png")