simvx.core.planar_reflection¶
Planar reflections: the main scene mirrored across a plane (design RM-B4).
Built on :class:~simvx.core.RenderView: a :class:PlanarReflection3D node
renders the MAIN scene through a camera mirrored across its own local XZ plane
(the node’s +Y axis is the plane normal) into an offscreen texture. A floor,
mirror or water Material samples that texture with a projective UV derived
from the fragment’s clip position, so pass the node straight to
Material(albedo_map=planar_reflection) and the surface shows the mirrored
world.
Two building blocks, usable separately:
- func:
planar_reflection_camera: reflect anyCamera3Dacross a world plane, returning a mirrored camera whose projection carries an oblique near-clip plane (Lengyel) so nothing behind the reflection plane is drawn.
- class:
PlanarReflection3D: the node that owns a mirrored camera, keeps it in sync with the active main camera every frame (the render backends call- meth:
~PlanarReflection3D.sync_reflectionwhile preparing offscreen targets), and publishes the reflection texture viaRenderView.texture.
The mirrored camera is built as a PROPER rotation (a reflected orthonormal
basis has determinant -1, which a Node3D cannot represent): reflecting the
camera’s forward and up vectors and rebuilding the basis flips the camera-space
X axis relative to the true mirror image. The material shaders compensate by
mirroring the horizontal projective UV, so the composition is exact for points
on the reflection plane, which is precisely the surface being shaded.
Pipelined render mode defers RenderView capture entirely (probe-capture precedent), so a PlanarReflection3D freezes there like any RenderView.
Module Contents¶
Classes¶
Mirrors the main scene across this node’s local XZ plane into a texture. |
Functions¶
Return a |
Data¶
API¶
- simvx.core.planar_reflection.__all__¶
[‘PlanarReflection3D’, ‘planar_reflection_camera’]
- simvx.core.planar_reflection.planar_reflection_camera(plane: tuple[float, float, float, float], main_camera: simvx.core.nodes_3d.camera.Camera3D, *, into: simvx.core.nodes_3d.camera.Camera3D | None = None) simvx.core.nodes_3d.camera.Camera3D[source]¶
Return a
Camera3Dmirroring main_camera across a world plane.The result views the scene from the far side of the plane (position, forward and up reflected) with main_camera’s fov/near/far, and carries
clip_plane = planeso its projection obliquely clips everything behind the reflection plane (:func:~simvx.core.math.oblique_near_plane).Args: plane: World-space plane
(nx, ny, nz, d), equationn . x + d = 0with unitn; the kept side isn . x + d > 0. main_camera: The camera to mirror (typically the scene’s active one). into: Optional existing camera to update in place (per-frame reuse without allocation). A new standaloneCamera3DwhenNone.Returns: The mirrored camera (
intowhen given). Its basis is a proper rotation: the rendered image equals the true mirror image flipped horizontally, which the planar-reflection material samples away by mirroring the horizontal projective UV.
- class simvx.core.planar_reflection.PlanarReflection3D(name='PlanarReflection3D', **kwargs)[source]¶
Bases:
simvx.core.render_view.RenderViewMirrors the main scene across this node’s local XZ plane into a texture.
Place the node ON the reflective surface: its world position is a point on the reflection plane and its world +Y axis is the plane normal. Every frame the backends re-mirror the scene’s active camera across that plane (with an oblique near clip, so nothing below the surface leaks into the reflection) and render the main tree from it, sized to the main viewport times
resolution_scaleso the projective UV stays aligned at any window size.Sample the reflection by passing the node as a Material albedo::
water = MeshInstance3D( mesh=Mesh.plane(...), material=Material(albedo_map=reflection, unlit=True), )A Material whose
albedo_mapis a PlanarReflection3D samples the texture with a mirrored projective UV from the fragment’s clip position (not the mesh UV), which is exact for fragments lying on the reflection plane.Properties: resolution_scale: Reflection resolution as a fraction of the main viewport (0.05 to 1.0). Half resolution by default: reflections tolerate softness well and the pass renders the whole scene again. clip_bias: World-space offset of the oblique clip plane along the normal. Keeps the reflective surface itself (and z-fighting slivers on it) out of its own reflection.
RenderView.camerais unused (the mirrored camera is internal and derived);sizeis driven fromresolution_scaleeach frame.Initialization
- resolution_scale¶
‘Property(…)’
- clip_bias¶
‘Property(…)’
- resolve_camera() simvx.core.nodes_3d.camera.Camera3D | None[source]¶
The internal mirrored camera;
Noneuntil first synced.
- world_plane() tuple[float, float, float, float][source]¶
This node’s reflection plane in world space,
(nx, ny, nz, d).The plane passes through the node’s world position with the node’s world +Y axis as its (unit) normal;
n . x + d = 0.
- sync_reflection(main_viewport_size: tuple[float, float]) bool[source]¶
Re-mirror the active main camera across this node’s plane.
Called by the render backends while preparing offscreen targets (after all node updates, before any offscreen render). Resizes the target to
main_viewport_size * resolution_scale(the projective UV requires the reflection aspect to match the main viewport) and rebuilds the internal mirrored camera. ReturnsFalse(view skipped, one-time warning in the manager) when no main camera exists.
- camera¶
‘NodePath(…)’
- size¶
‘Property(…)’
- render_target_update_mode¶
‘Property(…)’
- use_occlusion¶
‘Property(…)’
- property texture: int¶
- property texture_size: tuple[int, int]¶
- position¶
‘_SpatialVecProperty(…)’
- rotation¶
‘Property(…)’
- scale¶
‘_SpatialVecProperty(…)’
- render_layer¶
‘Property(…)’
- property rotation_degrees: simvx.core.math.types.Vec3¶
- property world_position: simvx.core.math.types.Vec3¶
- property world_rotation: simvx.core.math.types.Quat¶
- property world_scale: simvx.core.math.types.Vec3¶
- property forward: simvx.core.math.types.Vec3¶
- property right: simvx.core.math.types.Vec3¶
- property up: simvx.core.math.types.Vec3¶
- translate(offset: tuple[float, float, float] | numpy.ndarray)¶
- translate_global(offset: tuple[float, float, float] | numpy.ndarray)¶
- rotate(axis: tuple[float, float, float] | numpy.ndarray, angle: float)¶
- rotate_x(angle: float)¶
- rotate_y(angle: float)¶
- rotate_z(angle: float)¶
- look_at(target: tuple[float, float, float] | numpy.ndarray, up=None)¶
- face_along(forward: tuple[float, float, float] | numpy.ndarray, up: tuple[float, float, float] | numpy.ndarray | None = None) None¶
- set_render_layer(index: int, enabled: bool = True) None¶
- is_on_render_layer(index: int) bool¶
- wrap_bounds(bounds: tuple[float, float, float] | numpy.ndarray, margin: float = 1.0)¶
- strict_errors: ClassVar[bool]¶
True
- script_error_raised¶
‘Signal(…)’
- dynamic: bool¶
False
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property update_mode: simvx.core.descriptors.UpdateMode¶
- property visible: bool¶
- reset_error() None¶
- add_child(node: simvx.core.node.Node) simvx.core.node.Node¶
- remove_child(node: simvx.core.node.Node)¶
- reparent(new_parent: simvx.core.node.Node)¶
- get_node(path: str) simvx.core.node.Node¶
- get_node_or_none(path: str) simvx.core.node.Node | None¶
- find(target, *, direct: bool = False)¶
- find_all(target, *, direct: bool = False)¶
- walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- on_ready() None¶
- on_enter_tree() None¶
- on_exit_tree() None¶
- on_update(dt: float) None¶
- on_fixed_update(dt: float) None¶
- on_draw(renderer) None¶
- on_picked(event: simvx.core.events.InputEvent) None¶
- on_unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- queue_redraw() None¶
- property render_dirty: bool¶
- clear_children()¶
- destroy()¶
- call_deferred(method: collections.abc.Callable[..., Any], *args: Any) None¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- property physics¶
- property physics_2d¶
- __getitem__(key: str)¶
- classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶