bind method

  1. @override
void bind(
  1. RenderPass pass,
  2. TransientWriter transientsBuffer,
  3. Lighting lighting
)
override

Binds this material's render-pass state, uniforms, and textures.

The base implementation enables back-face culling with clockwise winding on the Y-down rasterizer (accepting model-space CCW front faces). 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.clockwise);
  final shader = fragmentShaderForLighting(lighting);

  if (shadingModel == FmatShadingModel.shadowCatcher) {
    _packEngineFragInfo(lighting, lighting.environmentMap);
    pass.bindUniform(
      shader.getUniformSlot('FragInfo'),
      transientsBuffer.emplace(_fragInfoBytes),
    );
    // The catcher's generated fragment samples only the shadow atlas, the
    // occlusion chain, and (in its shadow variant) the punctual textures.
    // The radiance/BRDF/SH samplers and the fog block are compiled out of
    // it, and binding an absent slot fails, so it takes its own bind set.
    EngineLightingUniforms.bindShadowCatcherTextures(pass, shader, lighting);
  } else if (shadingModel != FmatShadingModel.unlit) {
    final env = environment ?? lighting.environmentMap;
    _packEngineFragInfo(lighting, env);
    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,
      bindDiffuseSh: !usesLightmapVariant,
      cubeShader: usesRadianceCubeVariant(lighting),
    );
    if (usesLightmapVariant) {
      bindLightmap(pass, shader, transientsBuffer);
    }
    if (_sceneInputs.isNotEmpty) {
      EngineLightingUniforms.bindSceneInputTextures(
        pass,
        shader,
        lighting,
        _sceneInputs,
      );
    }
    if (_usesPlanarReflection) {
      _bindPlanarReflection(pass, shader, transientsBuffer, lighting);
    }
    // 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),
    );
  }
}