simvx.graphics.materials.custom_shader

Custom shader material system — user-facing API for custom GLSL shaders.

Provides ShaderMaterial for per-object custom shaders, UniformBuffer for GPU-side uniform data, and ShaderMaterialManager for pipeline caching and hot-reload.

Module Contents

Classes

ShaderMaterial

User-facing custom shader material.

UniformBuffer

GPU buffer for custom shader uniforms (std140 layout).

ShaderMaterialManager

Caches compiled pipelines by shader combination and manages hot-reload.

Data

API

simvx.graphics.materials.custom_shader.__all__

[‘ShaderMaterial’, ‘UniformBuffer’, ‘ShaderMaterialManager’]

simvx.graphics.materials.custom_shader.log

‘getLogger(…)’

class simvx.graphics.materials.custom_shader.ShaderMaterial(vertex_path: str | pathlib.Path | None = None, fragment_path: str | pathlib.Path | None = None, *, vertex_source: str | None = None, fragment_source: str | None = None)

User-facing custom shader material.

Allows using custom GLSL vertex/fragment shaders with user-defined uniforms. Works alongside the engine’s existing uber-shader pipeline by creating its own separate Vulkan pipeline.

Example::

mat = ShaderMaterial(
    vertex_path="shaders/wave.vert",
    fragment_path="shaders/gradient.frag",
)
mat.set_uniform("time", 0.0)
mat.set_uniform("color", (1.0, 0.5, 0.2, 1.0))

Or with inline source::

mat = ShaderMaterial(
    vertex_source="""
        #version 450
        layout(location=0) in vec3 pos;
        void main() { gl_Position = vec4(pos, 1.0); }
    """,
    fragment_source="""
        #version 450
        layout(location=0) out vec4 out_color;
        void main() { out_color = vec4(1.0, 0.0, 0.0, 1.0); }
    """,
)

Initialization

property is_compiled: bool

Whether shaders have been compiled to SPIR-V and loaded.

property uniforms: dict[str, Any]

All current uniform values.

set_uniform(name: str, value: Any) None

Set a shader uniform by name.

Supported types: float, int, vec2, vec3, vec4, mat4, and numpy arrays. Type is inferred automatically from the value.

set_uniform_typed(name: str, value: Any, utype: str) None

Set a uniform with an explicit GLSL type string.

get_uniform(name: str) Any

Get the current value of a uniform. Raises KeyError if not set.

compile(device: Any, shader_dir: pathlib.Path | None = None) None

Compile shaders to SPIR-V and create Vulkan shader modules.

Uses file paths if provided, otherwise writes inline source to temp files for compilation via glslc.

Args: device: Vulkan logical device handle. shader_dir: Base directory for resolving relative shader paths and includes.

get_pipeline_key() tuple

Return a hashable key unique to this shader combination.

Used for pipeline caching in ShaderMaterialManager.

has_source_changed() bool

Check if shader source files have been modified since last compile.

cleanup(device: Any) None

Destroy Vulkan shader modules.

class simvx.graphics.materials.custom_shader.UniformBuffer(max_size: int = 1024)

GPU buffer for custom shader uniforms (std140 layout).

Manages a host-visible Vulkan buffer and descriptor set for binding user-defined uniforms to a custom shader pipeline.

The buffer is laid out according to std140 rules so it can be directly consumed by a GLSL uniform block.

Initialization

property is_created: bool
create(device: Any, physical_device: Any) None

Create the GPU buffer and descriptor resources.

update(device: Any, uniform_data: dict[str, Any], uniform_types: dict[str, str]) None

Upload uniform values to the GPU buffer using std140 layout.

Args: device: Vulkan logical device. uniform_data: Name-to-value mapping of uniforms. uniform_types: Name-to-GLSL-type mapping (e.g. {“time”: “float”}).

get_descriptor_set() Any

Return the Vulkan descriptor set for binding to a pipeline.

get_descriptor_layout() Any

Return the descriptor set layout for pipeline creation.

cleanup(device: Any) None

Destroy GPU resources.

class simvx.graphics.materials.custom_shader.ShaderMaterialManager

Caches compiled pipelines by shader combination and manages hot-reload.

Tracks all registered ShaderMaterial instances and their compiled pipelines. Pipelines are cached by the shader source/path combination so that multiple objects sharing the same shaders reuse one pipeline.

Example::

manager = ShaderMaterialManager()
pipeline, layout = manager.get_or_create_pipeline(
    material, device, physical_device, render_pass, extent, ssbo_layout,
)

Initialization

register_material(material: simvx.graphics.materials.custom_shader.ShaderMaterial) None

Track a ShaderMaterial for hot-reload monitoring.

get_or_create_pipeline(material: simvx.graphics.materials.custom_shader.ShaderMaterial, device: Any, physical_device: Any, render_pass: Any, extent: tuple[int, int], ssbo_layout: Any, texture_layout: Any | None = None, shader_dir: pathlib.Path | None = None) tuple[Any, Any]

Get a cached pipeline for this material, or compile and create one.

Args: material: The ShaderMaterial to get/create a pipeline for. device: Vulkan logical device. physical_device: Vulkan physical device. render_pass: Vulkan render pass. extent: Swapchain extent (width, height). ssbo_layout: Descriptor set layout for SSBOs (set 0). texture_layout: Optional texture descriptor layout. shader_dir: Base directory for shader file resolution.

Returns: Tuple of (VkPipeline, VkPipelineLayout).

get_uniform_buffer(material: simvx.graphics.materials.custom_shader.ShaderMaterial) simvx.graphics.materials.custom_shader.UniformBuffer | None

Get the UniformBuffer associated with a material, if any.

update_uniforms(material: simvx.graphics.materials.custom_shader.ShaderMaterial, device: Any) None

Upload current uniform values for a material to its GPU buffer.

check_hot_reload(device: Any, physical_device: Any, render_pass: Any, extent: tuple[int, int], ssbo_layout: Any, texture_layout: Any | None = None, shader_dir: pathlib.Path | None = None) list[simvx.graphics.materials.custom_shader.ShaderMaterial]

Check all registered materials for source file changes and recompile.

Returns a list of materials that were recompiled.

cleanup(device: Any) None

Destroy all cached pipelines, uniform buffers, and shader modules.