import numpy as np
import os
import meshio
from py3dframe import Frame
from pyblenderSDIC import Camera, SpotLight, BlenderExperiment
from pyblenderSDIC.meshes import create_axisymmetric_mesh, create_xy_heightmap_mesh
from pyblenderSDIC.materials import MaterialBSDF, get_iron_material, get_copper_material, get_mirror_material
from pyblenderSDIC.patterns import get_mouchtichu_path, get_speckle_path
"""
We observe a demi-cylinder with a mouchtichu pattern on it.
The cylinder is observed by a camera using a indirect view.
The camera observes a mirror reflexion of the cylinder.
We place all the obsects at y=0 to simplify the creation of the scene.
Because y-axis will be fixed for all the objects.
"""
# =======================================================================
# ========== Example of how to use the package `pyblenderSDIC` ==========
# =======================================================================
# ====================
# 1. CREATE THE MESH
# ====================
# Set the cylinder parameters
cylinder_center = np.array([0.0, 0.0, 10.0])
cylinder_z_axis = np.array([0.0, 0.0, 1.0])
cylinder_x_axis = np.array([1.0, 0.0, 0.0])
cylinder_y_axis = np.cross(cylinder_z_axis, cylinder_x_axis)
cylinder_frame = Frame(
origin=cylinder_center,
x_axis=cylinder_x_axis,
y_axis=cylinder_y_axis,
z_axis=cylinder_z_axis
)
cylinder_radius = 5.0
cylinder_height_min = -2.0
cylinder_height_max = 2.0
cylinder_theta_min = -0.25
cylinder_theta_max = 0.25
cylinder_Nheight = 100
cylinder_Ntheta = 100
cylinder_mesh = create_axisymmetric_mesh(
profile_curve=lambda z: cylinder_radius,
frame=cylinder_frame,
height_bounds=(cylinder_height_min, cylinder_height_max),
theta_bounds=(cylinder_theta_min, cylinder_theta_max),
Nheight=cylinder_Nheight,
Ntheta=cylinder_Ntheta,
closed=False,
)
# ========================
# 2. Preparing the camera (part 1)
# ========================
# We select the position of the camera to allow defining the mirror
camera_position = np.array([20.0, 0.0, 60.0])
camera_target = cylinder_center + cylinder_radius*cylinder_x_axis
# ====================
# 3. CREATE THE MIRROR
# ====================
# The mirror is a plane with a normal vector allowing to reflect the cylinder on the camera
mirror_center = np.array([75.0, 0.0, 20.0])
mirror_y_axis = np.array([0.0, 1.0, 0.0])
# The normal vector of the mirror must reflect "camera_target" on "camera_position".
input_ray = mirror_center - camera_target
input_ray /= np.linalg.norm(input_ray)
output_ray = camera_position - mirror_center
output_ray /= np.linalg.norm(output_ray)
mirror_z_axis = output_ray - input_ray
mirror_z_axis /= np.linalg.norm(mirror_z_axis)
mirror_x_axis = np.cross(mirror_y_axis, mirror_z_axis)
mirror_frame = Frame(
origin=mirror_center,
x_axis=mirror_x_axis,
y_axis=mirror_y_axis,
z_axis=mirror_z_axis
)
mirror_mesh = create_xy_heightmap_mesh(
height_function=lambda x, y: 0.0,
frame=mirror_frame,
x_bounds=(-8.0, 8.0),
y_bounds=(-8.0, 8.0),
Nx=2,
Ny=2,
)
# ====================
# 4. CREATE THE CAMERA (part 2)
# ====================
# The camera is observing the cylinder through the mirror
camera_direction = mirror_center - camera_position
camera_z_axis = camera_direction / np.linalg.norm(camera_direction)
camera_y_axis = np.array([0.0, 1.0, 0.0])
camera_x_axis = np.cross(camera_y_axis, camera_z_axis)
camera_frame = Frame(
origin=camera_position,
x_axis=camera_x_axis,
y_axis=camera_y_axis,
z_axis=camera_z_axis
)
camera = Camera(
frame=camera_frame,
intrinsic_matrix=np.array([[20000.0, 0.0, 499.5], [0.0, 20000.0, 503.5], [0.0, 0.0, 1.0]]),
resolution=(1000, 1000), # Image resolution
pixel_size=(0.01, 0.01), # Pixel size in mm
)
# ====================
# 5. CREATE THE LIGHT
# ====================
light_position = np.array([70.0, 0.0, -20.0])
light_target = cylinder_center + cylinder_radius*cylinder_x_axis
light_z_axis = light_target - light_position
light_y_axis = np.array([0.0, 1.0, 0.0])
light_x_axis = np.cross(light_y_axis, light_z_axis)
light_frame = Frame(
origin=light_position,
x_axis=light_x_axis,
y_axis=light_y_axis,
z_axis=light_z_axis
)
light = SpotLight(
frame=light_frame,
energy=50000.0,
spot_size=0.5,
spot_blend=0.5,
)
# ======================
# 6. CREATE THE MATERIAL
# ======================
cylinder_material = get_iron_material()
mirror_material = get_mirror_material()
# ==========================
# 7. CREATE THE EXPERIMENT
# ==========================
STOP_BEFORE_RENDER = False
dat_folder = os.path.dirname(__file__)
experiment = BlenderExperiment(Nb_frames=1)
experiment.set_default_background()
# Reading the mesh and adding it to the experiment
print("Adding the mesh to the experiment...")
experiment.add_mesh("Cylinder", cylinder_mesh) # The mesh TIME 0 is only active for the first frame
experiment.add_mesh_material("Cylinder", cylinder_material)
experiment.add_mesh_pattern("Cylinder", get_mouchtichu_path())
experiment.add_mesh("Mirror", mirror_mesh) # The mesh TIME 0 is only active for the first frame
experiment.add_mesh_material("Mirror", mirror_material) # No pattern for the mirror
# Adding the camera to the experiment
print("Adding the camera to the experiment...")
experiment.add_camera("Camera", camera)
# Adding the light to the experiment
print("Adding the light to the experiment...")
experiment.add_spotlight("Light", light)
# ==========================
# 6. RENDERING THE SCENE
# ==========================
if not STOP_BEFORE_RENDER:
# Selecting the frame and the camera for rendering
experiment.set_active_camera("Camera")
experiment.set_active_frame(1) # Blender frame start at 1
# Rendering the scene
print("Rendering the scene...")
experiment.render(
os.path.join(dat_folder, "mirror_reflexion.tiff"),
N_samples=200,
)