ShaderMaterial class

A Material backed by a caller-supplied fragment shader.

ShaderMaterial is the foundation for writing custom materials in flutter_scene. Use it when UnlitMaterial and PhysicallyBasedMaterial don't cover what you need: stylized shading, custom alpha modes, screen-space effects, vertex-painted looks, and so on.

Authoring a custom material

  1. Write a fragment shader. It should consume the engine's standard vertex outputs and declare its own uniform blocks / samplers for any parameters. See MATERIALS.md for the full contract.
  2. Compile the shader through the flutter_gpu_shaders build hook into a .shaderbundle packaged with your app.
  3. Load the bundle at runtime with gpu.ShaderLibrary.fromAsset('path/to/your.shaderbundle') and pull out the fragment shader entry.
  4. Construct a ShaderMaterial pointing at the shader, populate its uniform blocks and textures by name, and attach it to a MeshPrimitive.

Engine-bound resources available to your fragment shader

These vertex outputs are written by the engine's standard vertex shader and are always available as in declarations in your fragment shader (the names are part of the engine contract):

in vec3 v_position;        // world space
in vec3 v_normal;          // world space (not necessarily unit)
in vec3 v_viewvector;      // camera_position - vertex_position, world space
in vec2 v_texture_coords;
in vec4 v_color;           // per-vertex color, white when absent

Setting useEnvironment to true makes the engine bind the active environment's IBL textures by their standard names when your fragment shader declares them: prefiltered_radiance (the PMREM-style roughness-band atlas; sample it with SamplePrefilteredRadiance from texture.glsl) and brdf_lut (both as sampler2D). The diffuse irradiance SH coefficients are not bound generically; declare them in your own uniform block if you need them. Useful when a custom shader still wants the engine's image-based lighting.

Uniform block packing

Flutter GPU resolves uniform blocks by name (via gpu.Shader.getUniformSlot) but the block's contents are a flat byte buffer that your code packs and the GPU interprets according to the shader's std140 layout. Common rules:

  • float, int, bool occupy 4 bytes.
  • vec2 occupies 8 bytes aligned to 8.
  • vec3, vec4 occupy 16 bytes aligned to 16.
  • mat4 occupies 64 bytes; mat3 occupies 48 bytes laid out as three vec4 columns (12 bytes of padding).
  • Array elements stride to the next 16 bytes.

Put a Float32List together that matches the block's declared member order (including padding) and pass it via setUniformBlock.

TODO(https://github.com/bdero/flutter_scene/issues/22): generate this packing code at build time from a declarative material source so callers don't write it by hand.

Inheritance

Constructors

ShaderMaterial({Shader? fragmentShader, bool useEnvironment = false, CullMode cullingMode = gpu.CullMode.backFace, WindingOrder windingOrder = gpu.WindingOrder.counterClockwise, bool isOpaqueOverride = true})
Creates a ShaderMaterial wrapping fragmentShader.

Properties

cullingMode ↔ CullMode
Backface culling mode applied before drawing. Defaults to gpu.CullMode.backFace to match the standard materials.
getter/setter pair
doubleSided bool
Whether to render both faces of triangles drawn with this material (glTF's material.doubleSided). When true, bind disables back-face culling so the geometry is visible from both sides; otherwise back faces are culled. Defaults to false. The runtime importer sets it from the glTF material.
getter/setter pairinherited
fragmentShader Shader
The fragment shader used when rendering geometry with this material.
no setterinherited
hashCode int
The hash code for this object.
no setterinherited
isOpaqueOverride bool
Whether this material participates in the opaque pass.
getter/setter pair
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
textureNames Iterable<String>
All currently-bound sampler names. Order is insertion order.
no setter
uniformBlockNames Iterable<String>
All currently-bound uniform block names. Order is insertion order.
no setter
useEnvironment bool
Whether the engine should bind the active environment's IBL textures (prefiltered_radiance, brdf_lut) when the fragment shader declares them. Defaults to false.
getter/setter pair
windingOrder ↔ WindingOrder
Triangle winding order. Defaults to gpu.WindingOrder.counterClockwise to match the glTF convention and the standard materials.
getter/setter pair

Methods

bind(RenderPass pass, HostBuffer transientsBuffer, Lighting lighting) → void
Binds this material's render-pass state, uniforms, and textures.
override
getTexture(String name) Texture?
Read back a previously-set texture binding, or null when none has been set.
getUniformBlock(String name) ByteData?
Read back a previously-set uniform block, or null when none has been set.
isOpaque() bool
Whether geometry rendered with this material is fully opaque.
override
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
setFragmentShader(Shader shader) → void
Assigns the fragment shader used when this material is drawn.
inherited
setTexture(String name, Texture? texture, {SamplerOptions? sampler}) → void
Assign a texture to a sampler uniform by name.
setUniformBlock(String name, ByteData? bytes) → void
Assign the byte contents of a uniform block by name.
setUniformBlockFromFloats(String name, List<double> floats) → void
Convenience wrapper around setUniformBlock that packs a list of float values. The caller is still responsible for std140 padding; see the class doc.
toString() String
A string representation of this object.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited