Custom Shaders¶
ShaderMaterial lets you write custom GLSL vertex and fragment shaders for any MeshInstance3D.
Basic Usage¶
from simvx.graphics.materials.custom_shader import ShaderMaterial
from simvx.core import MeshInstance3D, Mesh
mat = ShaderMaterial(
vertex_source="""
#version 450
layout(location = 0) in vec3 position;
layout(push_constant) uniform PC { mat4 mvp; };
void main() {
gl_Position = mvp * vec4(position, 1.0);
}
""",
fragment_source="""
#version 450
layout(location = 0) out vec4 frag_colour;
layout(set = 2, binding = 0) uniform UBO { float time; vec3 tint; };
void main() {
frag_colour = vec4(tint * (0.5 + 0.5 * sin(time)), 1.0);
}
""",
)
mat.set_uniform("time", 0.0)
mat.set_uniform("tint", (1.0, 0.3, 0.1))
cube = MeshInstance3D(mesh=Mesh.cube(), material=mat)
self.add_child(cube)
Update uniforms each frame in on_update():
def on_update(self, dt):
mat.set_uniform("time", self.elapsed_time)
Loading from Files¶
mat = ShaderMaterial(
vertex_path="shaders/wave.vert",
fragment_path="shaders/wave.frag",
)
GLSL files are compiled to SPIR-V automatically via glslc. Hot-reload is supported: modified shader files are detected and recompiled at runtime.
Uniforms¶
Set uniforms by name. Types are inferred from the Python value:
mat.set_uniform("speed", 2.5) # float
mat.set_uniform("offset", (1.0, 0.0)) # vec2
mat.set_uniform("colour", (1.0, 0.5, 0.0)) # vec3
mat.set_uniform("tint", (1.0, 0.5, 0.0, 1.0)) # vec4
mat.set_uniform("count", 10) # int
For explicit type control:
mat.set_uniform_typed("grid_size", (8, 8), "ivec2")
Supported types: float, int, uint, vec2, vec3, vec4, ivec2, ivec3, ivec4, mat4.
Web export¶
Opaque, UBO-only ShaderMaterials are transpiled GLSL→WGSL at export time
(build-time naga) and render through a per-material pipeline on WebGPU. To be
web-portable a shader must follow the unified binding ABI:
camera UBO at
set = 0, binding = 0(mat4 view; mat4 proj;), not apush_constant(push constants don’t translate to WGSL)transforms SSBO at
set = 1, binding = 0(mat4[], indexed bygl_InstanceIndex)per-material UBO at
set = 2, binding = 0, then separated textures/samplers atbinding = 1+
Shaders using separated textures (set = 2 binding 1+) or transparency warn and
fall back to the underlying Material on web. Export with simvx export web --strict
to fail the build on any fallback instead of degrading silently.
Example¶
See packages/graphics/examples/3d_custom_shader.py for custom ShaderMaterial with animated uniforms.
API Reference¶
See simvx.graphics.materials.custom_shader for the complete shader API.