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 process():
def process(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.
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.