bind method
Binds this material's render-pass state, uniforms, and textures.
The base implementation enables back-face culling with
counter-clockwise winding (matching the glTF convention). Subclasses
must call super.bind and then bind any per-material uniforms and
textures expected by their fragment shader. lighting carries the
IBL EnvironmentMap (and its intensity) plus the analytic lights and
shadow resources that materials shade against.
Implementation
@override
void bind(
gpu.RenderPass pass,
TransientWriter transientsBuffer,
Lighting lighting,
) {
pass.setCullMode(renderCullMode);
pass.setWindingOrder(gpu.WindingOrder.counterClockwise);
final shader = fragmentShaderForLighting(lighting);
if (shadingModel != FmatShadingModel.unlit) {
final env = environment ?? lighting.environmentMap;
final fragInfo = _fragInfoScratch
..fillRange(0, _fragInfoScratch.length, 0);
EngineLightingUniforms.packInto(fragInfo, lighting, env);
// radiance_blend.zw [162]/[163]: this item's punctual-light slice
// (count, offset) into the per-frame light-index buffer.
fragInfo[162] = lightListCount.toDouble();
fragInfo[163] = lightListOffset.toDouble();
pass.bindUniform(
shader.getUniformSlot('FragInfo'),
transientsBuffer.emplace(_fragInfoBytes),
);
// TODO(material-permutations): add an SSAO sampler to filtered scene
// color permutations without exceeding the backend sampler limit.
EngineLightingUniforms.bindEngineTextures(
pass,
shader,
lighting,
env,
bindSsao: !_sceneInputs.contains(RenderInput.filteredSceneColor),
bindShadows: lighting.shadowMap != null,
cubeShader: usesRadianceCubeVariant(lighting),
);
if (_sceneInputs.isNotEmpty) {
EngineLightingUniforms.bindSceneInputTextures(
pass,
shader,
lighting,
_sceneInputs,
);
}
// Lit `.fmat` shaders include the lighting framework (and thus fog.glsl),
// so they carry the FogInfo block. Unlit `.fmat` shaders do not; fog on
// those is a TODO(fog): give the unlit `.fmat` template the fog block.
EngineLightingUniforms.bindFog(pass, shader, transientsBuffer, lighting);
}
parameters.bind(pass, shader, transientsBuffer);
// Bind the fragment keep-alive block (name matches kFragmentKeepAliveBlock
// in the emitter) to zero. The generated fragment references every
// declared parameter resource through it (the MaterialParams block and
// any unreferenced samplers) so none can be optimized out; the emitter
// declares it whenever the material has any parameter.
if (parameters.hasAnyParameters) {
pass.bindUniform(
shader.getUniformSlot('FragmentKeepAlive'),
transientsBuffer.emplace(_zeroKeepAlive),
);
}
}