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,
) {
_ensurePreparedVariant();
final prepared = _preparedVariant;
if (prepared != null) {
prepared
..name = name
..doubleSided = doubleSided
..depthBias = depthBias
..lodFade = lodFade
..lightListOffset = lightListOffset
..lightListCount = lightListCount
..environment = environment;
prepared.bind(pass, transientsBuffer, lighting);
return;
}
super.bind(pass, transientsBuffer, lighting);
// The variant the pipeline was built from, which differs from
// [fragmentShader] when the bound environment picks the cube radiance
// layout. Slots must come from the shader actually drawn with.
final shader = fragmentShaderForLighting(lighting);
final EnvironmentMap env = environment ?? lighting.environmentMap;
// FragInfo std140 layout (624 bytes / 156 floats). EngineLightingUniforms
// packs the shared engine lighting, image-based-lighting, and shadow
// fields (identical for every lit material); this material fills only its
// own, disjoint fields:
// [0..3] vec4 color
// [4..7] vec4 emissive_factor
// [120] float vertex_color_weight
// [121] float metallic_factor
// [122] float roughness_factor
// [123] float has_normal_map
// [124] float normal_scale
// [125] float occlusion_strength
// [132] float alpha_mode (0 opaque, 1 mask, 2 blend)
// [133] float alpha_cutoff
// [138] float specular_aa_variance
// [139] float specular_aa_threshold
// A shared scratch (zeroed each bind, matching a fresh allocation's
// unwritten slots) instead of a per-draw allocation; emplace below copies
// the bytes out immediately.
final fragInfo = _fragInfoScratch..fillRange(0, _fragInfoScratch.length, 0);
EngineLightingUniforms.packInto(fragInfo, lighting, env);
fragInfo[0] = baseColorFactor.r;
fragInfo[1] = baseColorFactor.g;
fragInfo[2] = baseColorFactor.b;
fragInfo[3] = baseColorFactor.a;
fragInfo[4] = emissiveFactor.r;
fragInfo[5] = emissiveFactor.g;
fragInfo[6] = emissiveFactor.b;
fragInfo[7] = emissiveStrength;
fragInfo[120] = vertexColorWeight;
fragInfo[121] = metallicFactor;
fragInfo[122] = roughnessFactor;
fragInfo[123] = normalTexture != null ? 1.0 : 0.0;
fragInfo[124] = normalScale;
fragInfo[125] = occlusionStrength;
fragInfo[132] = alphaMode.index.toDouble();
fragInfo[133] = alphaCutoff;
fragInfo[138] = specularAntiAliasingVariance;
fragInfo[139] = specularAntiAliasingThreshold;
fragInfo[EngineLightingUniforms.fadeIndex] = lodFade;
// 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),
);
final textureTransforms = _textureTransformsScratch;
_packTextureTransform(
textureTransforms,
0,
baseColorTextureTransform,
baseColorTextureTexCoord,
);
_packTextureTransform(
textureTransforms,
8,
metallicRoughnessTextureTransform,
metallicRoughnessTextureTexCoord,
);
_packTextureTransform(
textureTransforms,
16,
normalTextureTransform,
normalTextureTexCoord,
);
_packTextureTransform(
textureTransforms,
24,
emissiveTextureTransform,
emissiveTextureTexCoord,
);
_packTextureTransform(
textureTransforms,
32,
occlusionTextureTransform,
occlusionTextureTexCoord,
);
pass.bindUniform(
shader.getUniformSlot('TextureTransforms'),
transientsBuffer.emplace(ByteData.sublistView(textureTransforms)),
);
_bindSlot(pass, shader, 'base_color_texture', baseColorTexture);
_bindSlot(pass, shader, 'emissive_texture', emissiveTexture);
_bindSlot(
pass,
shader,
'metallic_roughness_texture',
metallicRoughnessTexture,
);
_bindSlot(pass, shader, 'normal_texture', normalTexture, normal: true);
_bindSlot(pass, shader, 'occlusion_texture', occlusionTexture);
// Image-based-lighting atlas, BRDF LUT, and shadow map. Shared with
// PreprocessedMaterial: the sampler choices (radiance repeat/clamp, LUT
// clamp/clamp, shadow nearest/clamp) and the white shadow placeholder
// live in EngineLightingUniforms.
EngineLightingUniforms.bindEngineTextures(
pass,
shader,
lighting,
env,
cubeShader: usesRadianceCubeVariant(lighting),
);
EngineLightingUniforms.bindFog(pass, shader, transientsBuffer, lighting);
}