simvx.core.surface_tool¶
Procedural geometry construction tool and convenience mesh generators.
SurfaceTool provides a vertex-by-vertex mesh building API inspired by Godot’s SurfaceTool. ImmediateGeometry3D rebuilds its mesh every frame from a user callback, suitable for debug visualisations, trails, and dynamic geometry.
Usage::
from simvx.core import SurfaceTool, PrimitiveType
st = SurfaceTool()
st.begin(PrimitiveType.TRIANGLES)
st.set_normal((0, 1, 0))
st.set_uv((0, 0))
st.add_vertex((0, 0, 0))
st.set_uv((1, 0))
st.add_vertex((1, 0, 0))
st.set_uv((0.5, 1))
st.add_vertex((0.5, 1, 0))
mesh = st.commit()
Module Contents¶
Classes¶
Primitive topology for SurfaceTool. |
|
Vertex-by-vertex mesh construction tool. |
|
A 3D node whose mesh is rebuilt every frame via a callback. |
Functions¶
Create a box mesh centred at the origin. |
|
Create a UV sphere mesh centred at the origin. |
|
Create a cylinder mesh along the Y axis, centred at the origin. |
|
Create a flat plane on the XZ plane, centred at the origin. |
|
Create a capsule mesh (cylinder with hemispherical caps) along the Y axis. |
Data¶
API¶
- simvx.core.surface_tool.__all__¶
[‘SurfaceTool’, ‘PrimitiveType’, ‘ImmediateGeometry3D’, ‘create_box’, ‘create_sphere’, ‘create_cylin…
- class simvx.core.surface_tool.PrimitiveType[source]¶
Bases:
enum.IntEnumPrimitive topology for SurfaceTool.
Initialization
Initialize self. See help(type(self)) for accurate signature.
- TRIANGLES¶
0
- LINES¶
1
- POINTS¶
2
- TRIANGLE_STRIP¶
3
- __abs__()¶
- __add__()¶
- __and__()¶
- __bool__()¶
- __ceil__()¶
- __delattr__()¶
- __dir__()¶
- __divmod__()¶
- __eq__()¶
- __float__()¶
- __floor__()¶
- __floordiv__()¶
- __format__()¶
- __ge__()¶
- __getattribute__()¶
- __getnewargs__()¶
- __getstate__()¶
- __gt__()¶
- __hash__()¶
- __index__()¶
- __int__()¶
- __invert__()¶
- __le__()¶
- __lshift__()¶
- __lt__()¶
- __mod__()¶
- __mul__()¶
- __ne__()¶
- __neg__()¶
- __new__()¶
- __or__()¶
- __pos__()¶
- __pow__()¶
- __radd__()¶
- __rand__()¶
- __rdivmod__()¶
- __reduce__()¶
- __reduce_ex__()¶
- __repr__()¶
- __rfloordiv__()¶
- __rlshift__()¶
- __rmod__()¶
- __rmul__()¶
- __ror__()¶
- __round__()¶
- __rpow__()¶
- __rrshift__()¶
- __rshift__()¶
- __rsub__()¶
- __rtruediv__()¶
- __rxor__()¶
- __setattr__()¶
- __sizeof__()¶
- __str__()¶
- __sub__()¶
- __subclasshook__()¶
- __truediv__()¶
- __trunc__()¶
- __xor__()¶
- as_integer_ratio()¶
- bit_count()¶
- bit_length()¶
- conjugate()¶
- class denominator¶
- class imag¶
- is_integer()¶
- class numerator¶
- class real¶
- to_bytes()¶
- __deepcopy__(memo)¶
- __copy__()¶
- name()¶
- value()¶
- class simvx.core.surface_tool.SurfaceTool[source]¶
Vertex-by-vertex mesh construction tool.
Accumulates vertex attributes then emits a
Meshoncommit(). Set per-vertex attributes (normal, uv, colour) before callingadd_vertex()– the current values are latched when the vertex is added.Initialization
- __slots__¶
(‘_primitive’, ‘_positions’, ‘_normals’, ‘_uvs’, ‘_colours’, ‘_indices’, ‘_cur_normal’, ‘_cur_uv’, ‘…
- begin(primitive: simvx.core.surface_tool.PrimitiveType = PrimitiveType.TRIANGLES) None[source]¶
Start a new surface. Clears any previously accumulated data.
- set_normal(normal: collections.abc.Sequence[float] | simvx.core.math.types.Vec3) None[source]¶
Set the normal for subsequent vertices.
- set_uv(uv: collections.abc.Sequence[float] | simvx.core.math.types.Vec2) None[source]¶
Set the UV coordinate for subsequent vertices.
- set_colour(colour: collections.abc.Sequence[float]) None[source]¶
Set the vertex colour (RGBA) for subsequent vertices.
- add_vertex(position: collections.abc.Sequence[float] | simvx.core.math.types.Vec3) None[source]¶
Add a vertex with the currently set attributes.
- add_triangle_fan(vertices: collections.abc.Sequence[collections.abc.Sequence[float]], uvs: collections.abc.Sequence[collections.abc.Sequence[float]] | None = None, normals: collections.abc.Sequence[collections.abc.Sequence[float]] | None = None) None[source]¶
Add a triangle fan as indexed triangles.
The first vertex is the hub; triangles are formed with consecutive pairs of the remaining vertices.
- generate_normals() None[source]¶
Auto-compute smooth normals from triangle geometry.
Only works when primitive type is TRIANGLES. Uses the index list if present, otherwise assumes every three consecutive vertices form a triangle.
- generate_tangents() None[source]¶
Auto-compute tangents using Lengyel’s method (MikkTSpace-lite).
Stores tangent data on the resulting mesh as a
tangentsattribute (Nx4 float32 array with w = handedness). This is a best-effort implementation suitable for normal mapping.
- commit() simvx.core.graphics.mesh.Mesh[source]¶
Build and return a
Meshfrom the accumulated vertex data.
- property vertex_count: int¶
Number of vertices accumulated so far.
- property index_count: int¶
Number of indices accumulated so far.
- class simvx.core.surface_tool.ImmediateGeometry3D(**kwargs)[source]¶
Bases:
simvx.core.nodes_3d.node3d.Node3DA 3D node whose mesh is rebuilt every frame via a callback.
Override
_draw_geometryor connect to thedrawsignal to provide geometry each frame. The node creates a freshSurfaceTool, passes it to your callback, and commits the result as the renderable mesh.Usage::
class MyTrail(ImmediateGeometry3D): def _draw_geometry(self, st: SurfaceTool) -> None: st.begin(PrimitiveType.TRIANGLES) # ... add vertices ...Or with signals::
def draw_fn(st: SurfaceTool) -> None: st.begin(PrimitiveType.TRIANGLES) # ... ig = ImmediateGeometry3D() ig.draw.connect(draw_fn)Initialization
- render_layer¶
‘Property(…)’
- property position¶
- property rotation: simvx.core.math.types.Quat¶
- property scale¶
- 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)¶
- 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(…)’
- classmethod __init_subclass__(**kwargs)¶
- property name: str¶
- property process_mode: simvx.core.descriptors.ProcessMode¶
- 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¶
- find_child(name: str, recursive: bool = False) simvx.core.node.Node | None¶
- find(node_type: type, recursive: bool = True) simvx.core.node.Node | None¶
- property path: str¶
- add_to_group(group: str)¶
- remove_from_group(group: str)¶
- is_in_group(group: str) bool¶
- ready() None¶
- enter_tree() None¶
- exit_tree() None¶
- physics_process(dt: float) None¶
- draw(renderer) None¶
- input_event(event: simvx.core.events.InputEvent) None¶
- input(event: simvx.core.events.TreeInputEvent) None¶
- unhandled_input(event: simvx.core.events.TreeInputEvent) None¶
- start_coroutine(gen: simvx.core.descriptors.Coroutine) simvx.core.descriptors.CoroutineHandle¶
- stop_coroutine(gen_or_handle)¶
- clear_children()¶
- destroy()¶
- property app¶
- property tree: simvx.core.scene_tree.SceneTree¶
- get_tree() simvx.core.scene_tree.SceneTree¶
- __getitem__(key: str)¶
- classmethod get_properties() dict[str, simvx.core.descriptors.Property]¶
- __repr__()¶
- simvx.core.surface_tool.create_box(size: float | collections.abc.Sequence[float] = 1.0) simvx.core.graphics.mesh.Mesh[source]¶
Create a box mesh centred at the origin.
Args: size: Uniform size (float) or per-axis extents (x, y, z).
Returns: A
Meshwith 24 vertices and 36 indices.
- simvx.core.surface_tool.create_sphere(radius: float = 1.0, rings: int = 16, sectors: int = 16) simvx.core.graphics.mesh.Mesh[source]¶
Create a UV sphere mesh centred at the origin.
Args: radius: Sphere radius. rings: Number of horizontal rings (latitude divisions). sectors: Number of vertical sectors (longitude divisions).
Returns: A
Meshwith smooth normals and UVs.
- simvx.core.surface_tool.create_cylinder(radius: float = 0.5, height: float = 1.0, segments: int = 16) simvx.core.graphics.mesh.Mesh[source]¶
Create a cylinder mesh along the Y axis, centred at the origin.
Args: radius: Cylinder radius. height: Total height. segments: Number of radial segments.
Returns: A
Meshwith side, top cap, and bottom cap geometry.
- simvx.core.surface_tool.create_plane(size: float | collections.abc.Sequence[float] = 1.0, subdivisions: int = 1) simvx.core.graphics.mesh.Mesh[source]¶
Create a flat plane on the XZ plane, centred at the origin.
Args: size: Uniform size (float) or (width, depth) tuple. subdivisions: Number of subdivisions per axis (1 = single quad).
Returns: A
Meshwith upward-facing normals.
- simvx.core.surface_tool.create_capsule(radius: float = 0.5, height: float = 1.0, rings: int = 8, sectors: int = 16) simvx.core.graphics.mesh.Mesh[source]¶
Create a capsule mesh (cylinder with hemispherical caps) along the Y axis.
Args: radius: Capsule radius. height: Total height including the hemispherical caps. rings: Number of rings per hemisphere. sectors: Number of radial sectors.
Returns: A
Meshwith smooth normals.