simvx.core.nodes_3d.camera¶
Camera3D, OrbitCamera3D – 3D camera nodes.
Module Contents¶
Classes¶
3D camera providing view and projection matrices. |
|
Camera that orbits a pivot point, for editors, inspectors and strategy views. |
API¶
- class simvx.core.nodes_3d.camera.Camera3D(look_at=None, up=None, **kwargs)[source]¶
Bases:
simvx.core.nodes_3d.node3d.Node3D3D camera providing view and projection matrices.
The first
Camera3Dfound in the scene tree is used by the renderer. Position and orientation are inherited fromNode3D; the camera adds projection parameters (field of view, clip planes).Conventions (full reference:
docs/graphics/cameras.md):Right-handed, Y-up.
Forward = local -Z.
camera.forwardisworld_rotation * (0, 0, -1). Matches Godot / glTF / OpenGL; clashes with Unity / Unreal (+Z forward): assets ported from those engines must negate the forward vector once at import.look_at(target)and :meth:~Node3D.face_alongboth align the local -Z axis with the supplied direction.Internal angles in radians;
fovis stored in degrees only as an inspector convenience.Matrices are row-major; the renderer transposes at the GPU boundary and applies a Vulkan-only Y-flip in
- meth:
projection_matrix.
Attributes: projection:
"perspective"(default) or"orthographic". Selects which of the two parameter sets below builds :meth:projection_matrix; the other set is ignored but retained, so toggling back and forth is lossless. fov: Vertical field of view in degrees (1 – 179). Perspective only. ortho_size: Full vertical height of the orthographic view volume in world units, matching Godot’sCamera3D.size: at20.0the camera sees 10 units above and 10 below its centre line, and the horizontal extent follows from the aspect ratio. Orthographic only. near: Near clip plane distance. far: Far clip plane distance. clip_plane: Optional world-space oblique near-clip plane(nx, ny, nz, d)with equationn . x + d = 0; geometry on then . x + d > 0side is kept.None(default) keeps the standard near plane. Set per frame by :func:~simvx.core.planar_reflection_cameraso a mirrored camera never renders geometry behind the reflection plane (Lengyel oblique-frustum technique). A plain runtime attribute, not a serialised Property: it is a derived, per-frame value.Example::
camera = Camera3D(position=(0, 5, 10), look_at=(0, 0, 0), fov=75.0) isometric = Camera3D( position=(10, 10, 10), look_at=(0, 0, 0), projection="orthographic", ortho_size=16.0, )Initialization
- projection¶
‘Property(…)’
- fov¶
‘Property(…)’
- ortho_size¶
‘Property(…)’
- near¶
‘Property(…)’
- far¶
‘Property(…)’
- exposure¶
‘Property(…)’
- cull_mask¶
‘Bitmask(…)’
- gizmo_colour¶
‘Colour(…)’
- set_cull_mask_layer(index: int, enabled: bool = True) None[source]¶
Enable or disable a specific cull mask layer (0-31).
- is_cull_mask_layer_enabled(index: int) bool[source]¶
Check if a specific cull mask layer is enabled (0-31).
- get_gizmo_lines() list[tuple[simvx.core.math.types.Vec3, simvx.core.math.types.Vec3]][source]¶
Return view-volume wireframe lines: a frustum, or a box when orthographic.
- property view_matrix: numpy.ndarray[source]¶
View matrix computed from this node’s global transform.
Cached: the matrix is rebuilt only after the camera’s transform changes (its own or an ancestor’s), so projecting many points per frame pays for one build. Each read returns a fresh copy that the caller may mutate freely.
Returns: 4x4 view matrix as numpy array (row-major)
- projection_matrix(aspect: float = 16 / 9) numpy.ndarray[source]¶
Projection matrix for the given aspect ratio (Vulkan clip space).
Built from :attr:
fovwhen :attr:projectionis"perspective"and from :attr:ortho_sizewhen it is"orthographic". In both cases the vertical extent is the one held fixed and the horizontal extent follows from aspect, so widening the window reveals more of the scene rather than stretching it.Cached: the matrix is rebuilt only when :attr:
projection,- Attr:
fov, :attr:ortho_size, :attr:near, :attr:faror aspect differ from the previous call. Each read returns a fresh array that the caller may mutate freely. An oblique :attr:clip_planeis applied on top of the cached base per call, since it and the view matrix it depends on change per frame.
Args: aspect: Aspect ratio (width / height)
Returns: 4x4 projection matrix as numpy array (row-major) Includes Y-flip for Vulkan rendering
- 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
- dev_checks: ClassVar[bool]¶
None
- script_error_raised¶
‘Signal(…)’
- dynamic: bool¶
False
- visible¶
‘Property(…)’
- update_mode¶
‘Property(…)’
- __properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]¶
None
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property visible_in_tree: bool¶
- reset_error() None¶
- add_child(node: simvx.core.node.T) simvx.core.node.T¶
- remove_child(node: simvx.core.node.Node) None¶
- reparent(new_parent: simvx.core.node.Node)¶
- node_at(path, default=_NO_DEFAULT)¶
- find(target, *, direct: bool = False)¶
- find_all(target, *, direct: bool = False)¶
- expect(target, *, direct: bool = False)¶
- ancestor(target)¶
- walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- property is_scene_root: bool¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- on_ready() 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()¶
- property destroying: bool¶
- 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__()¶
- class simvx.core.nodes_3d.camera.OrbitCamera3D(**kwargs)[source]¶
Bases:
simvx.core.nodes_3d.camera.Camera3DCamera that orbits a pivot point, for editors, inspectors and strategy views.
The camera’s
positionand orientation are derived: they are recomputed from :attr:pivot, :attr:distance, :attr:yawand- Attr:
pitchby :meth:update_transform, and the camera always looks at the pivot. Assigningpositiondirectly is therefore pointless, since the next :meth:update_transformoverwrites it: move :attr:pivotinstead.- Meth:
orbit, :meth:panand :meth:zoomare the intended controls and call :meth:update_transformfor you. After assigning the orbit properties by hand (including from a scene file or the inspector), call- Meth:
update_transformyourself.
Angles are radians, like everywhere else in the engine. Yaw sweeps around the world Y axis; negative pitch places the camera above the pivot looking down, which is why the default view is a raised three-quarter angle.
- Meth:
orbitclamps pitch just short of the poles, but direct assignment does not.
Example::
cam = OrbitCamera3D(pivot=Vec3(0, 1, 0), distance=12.0) cam.orbit(math.radians(15.0), 0.0) # sweep 15 degrees to the side cam.zoom(2.0) # move 2 units closer
Initialization
- pivot¶
‘Property(…)’
- distance¶
‘Property(…)’
- yaw¶
‘Property(…)’
- pitch¶
‘Property(…)’
- orbit(dyaw: float, dpitch: float)[source]¶
Orbit the camera around its pivot point by yaw and pitch deltas (radians).
- update_transform()[source]¶
Recompute :attr:
positionand look-at orientation from the orbit parameters (:attr:pivot, :attr:distance, :attr:yaw, :attr:pitch).Call this after assigning orbit parameters directly so the world-space transform reflects the new values immediately. :meth:
orbit,- Meth:
pan, and :meth:zoominvoke it for you.
- projection¶
‘Property(…)’
- fov¶
‘Property(…)’
- ortho_size¶
‘Property(…)’
- near¶
‘Property(…)’
- far¶
‘Property(…)’
- exposure¶
‘Property(…)’
- cull_mask¶
‘Bitmask(…)’
- gizmo_colour¶
‘Colour(…)’
- on_enter_tree()¶
- set_cull_mask_layer(index: int, enabled: bool = True) None¶
- is_cull_mask_layer_enabled(index: int) bool¶
- get_gizmo_lines() list[tuple[simvx.core.math.types.Vec3, simvx.core.math.types.Vec3]]¶
- property view_matrix: numpy.ndarray¶
- projection_matrix(aspect: float = 16 / 9) numpy.ndarray¶
- 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
- dev_checks: ClassVar[bool]¶
None
- script_error_raised¶
‘Signal(…)’
- dynamic: bool¶
False
- visible¶
‘Property(…)’
- update_mode¶
‘Property(…)’
- __properties__: ClassVar[dict[str, simvx.core.descriptors.Property]]¶
None
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property visible_in_tree: bool¶
- reset_error() None¶
- add_child(node: simvx.core.node.T) simvx.core.node.T¶
- remove_child(node: simvx.core.node.Node) None¶
- reparent(new_parent: simvx.core.node.Node)¶
- node_at(path, default=_NO_DEFAULT)¶
- find(target, *, direct: bool = False)¶
- find_all(target, *, direct: bool = False)¶
- expect(target, *, direct: bool = False)¶
- ancestor(target)¶
- walk(*, include_self: bool = True) collections.abc.Iterator[simvx.core.node.Node]¶
- property path: str¶
- property is_scene_root: bool¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- on_ready() 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()¶
- property destroying: bool¶
- 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__()¶