Dynamic Environment Map

This example shows three objects.

Two rotating objects have a static env map that matches the skybox.

In the center is a sphere that has a dynamic environment map, which is updated using a CubeCamera. The two rotating objects are visible in the reflection of this object.

dynamic env map
import math
import time

import imageio.v3 as iio
import pylinalg as la
from wgpu.gui.auto import WgpuCanvas, run

import pygfx as gfx
from pygfx.utils.cube_camera import CubeCamera

renderer = gfx.renderers.WgpuRenderer(WgpuCanvas())
scene = gfx.Scene()


# Create the static env map

env_img = iio.imread("imageio:meadow_cube.jpg")
cube_size = env_img.shape[1]
env_img.shape = 6, cube_size, cube_size, env_img.shape[-1]

env_static = gfx.Texture(
    env_img, dim=2, size=(cube_size, cube_size, 6), generate_mipmaps=True
)

# Create the dynamic env map

env_dynamic = gfx.Texture(
    dim=2, size=(512, 512, 6), format="rgba8unorm", generate_mipmaps=True
)

cube_camera = CubeCamera(env_dynamic)

# Create a background skybox

background = gfx.Background(None, gfx.BackgroundSkyboxMaterial(map=env_static))
scene.add(background)

# Create the sphere

material1 = gfx.MeshStandardMaterial(roughness=0.05, metalness=1)
material1.side = "Front"
material1.env_map = env_dynamic
sphere = gfx.Mesh(
    gfx.sphere_geometry(15, 64, 64),
    material1,
)

scene.add(sphere)

# Create the other two objects

material2 = gfx.MeshStandardMaterial(roughness=0.15, metalness=1)
material2.env_map = env_static

ob1 = gfx.Mesh(gfx.geometries.klein_bottle_geometry(15), material2)
scene.add(ob1)

ob2 = gfx.Mesh(gfx.torus_knot_geometry(8, 3, 128, 16), material2)
scene.add(ob2)


# Camera and controller

camera = gfx.PerspectiveCamera(70, 16 / 9)
camera.show_object(scene, scale=2)

controller = gfx.OrbitController(camera, register_events=renderer)


def animate():
    t = time.time()

    ob1.local.position = (
        math.cos(t) * 30,
        math.sin(t) * 30,
        math.sin(t) * 30,
    )

    rot = la.quat_from_euler((0.02, 0.03), order="XY")
    ob1.local.rotation = la.quat_mul(rot, ob1.local.rotation)

    ob2.local.position = (
        math.cos(t + 10) * 30,
        math.sin(t + 10) * 30,
        math.sin(t + 10) * 30,
    )

    ob2.local.rotation = la.quat_mul(rot, ob2.local.rotation)

    cube_camera.render(scene)
    renderer.render(scene, camera)
    renderer.request_draw()


if __name__ == "__main__":
    renderer.request_draw(animate)
    run()

Total running time of the script: (0 minutes 12.174 seconds)

Gallery generated by Sphinx-Gallery