Riley: Speckle sphere

Here we render a sphere mesh of TRI6 elements with a speckle pattern texture shader.

Texture shaders use a 2D image and wrap this around a 3D object using normalised coordinates called UVs in computer graphics. The texture shader itself then uses these UV coordinates to map into and interpolate the colour for a pixel.

The quality of the reconstruction is dependent on the resolution of the texture relative to the final camera image size, the texture sampling function and the pixel integration parameters (i.e. pixel subsampling).

It is common to want to map a speckle pattern onto a 3D surface using UV coordinates for digital image correlation simulation. We provide a set of examples on UV mapping for common cases in the “Render UVs” example gallery.

There are also much more advanced tools for UV mapping in Blender if you require them.

from pathlib import Path

import numpy as np
import riley
from scipy.spatial.transform import Rotation

import pyvale.data as dataset
import pyvale.dataio as io
from pyvale import render

1. Load the mesh and assign a texture shader

data_dir: Path = dataset.riley_sphere200_case_path()

simulation = io.MeshLoader(
    load_dir=data_dir,
    coords_file="coords.csv",
    connect_files="connect.csv",
    load_opts=io.SimLoadOpts(coord_header=None),
).load_mesh()

uvs = io.load_array(data_dir / "uvs.csv", header=None, delimiter=",")

texture = riley.load_texture_mono_u8(dataset.riley_speckle_texture_path())

shader = riley.TextureShader(uvs=uvs, texture=texture)

mesh = render.meshes3d_from_simdata(
    simulation,
    {"connect": riley.ConnectConvention(
        riley.EElemType.TRI6, riley.EConnectAxis.ROW, 0,
        riley.ENodeOrder.RILEY,
    )},
    shaders={"connect": shader},
)["connect"]

2. Create and position the camera

pixels_num = np.array((800, 500))
pixels_size = np.array((5.3e-6, 5.3e-6))
focal_length = 50.0e-3
rotation = Rotation.identity()

camera = render.Camera(
    pixels_num=pixels_num,
    pixels_size=pixels_size,
    pos_world=np.zeros(3),
    rot_world=rotation,
    roi_cent_world=np.zeros(3),
    focal_length=focal_length,
    subsample=2,
)

camera = render.cam_frame_mesh(camera, mesh, fov_scale=1.0)

3. Configure and build the renderer

config = riley.create_raster_config(
    num_frames=1,
    total_threads=4,
    save_strategy=riley.SaveStrategy.disk,
)
output_dir = Path.cwd() / "pyvale-output" / "render3d_ex1b_riley_sphere200"

renderer = render.Riley(config, output_dir)

4. Build the scene and render it

scene = render.Scene3D(meshes=[mesh], cameras=[camera])
result = renderer.render(scene)

print(f"Rendered sphere render output to {output_dir}")
print(f"{result.images=}")

The first rendered frame is shown below.

A sphere with a speckle pattern

Gallery generated by Sphinx-Gallery