bind method

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

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,
  gpu.HostBuffer transientsBuffer,
  Lighting lighting,
) {
  super.bind(pass, transientsBuffer, lighting);

  final EnvironmentMap env = environment ?? lighting.environmentMap;

  // FragInfo std140 layout (608 bytes / 152 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
  //   [133]     float alpha_mode (0 opaque, 1 mask, 2 blend)
  //   [134]     float alpha_cutoff
  final fragInfo = Float32List(EngineLightingUniforms.fragInfoFloatCount);
  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] = emissiveFactor.a;
  fragInfo[120] = vertexColorWeight;
  fragInfo[121] = metallicFactor;
  fragInfo[122] = roughnessFactor;
  fragInfo[123] = normalTexture != null ? 1.0 : 0.0;
  fragInfo[124] = normalScale;
  fragInfo[125] = occlusionStrength;
  fragInfo[133] = alphaMode.index.toDouble();
  fragInfo[134] = alphaCutoff;
  pass.bindUniform(
    fragmentShader.getUniformSlot("FragInfo"),
    transientsBuffer.emplace(ByteData.sublistView(fragInfo)),
  );

  pass.bindTexture(
    fragmentShader.getUniformSlot('base_color_texture'),
    Material.whitePlaceholder(baseColorTexture),
    sampler: gpu.SamplerOptions(
      widthAddressMode: gpu.SamplerAddressMode.repeat,
      heightAddressMode: gpu.SamplerAddressMode.repeat,
    ),
  );
  pass.bindTexture(
    fragmentShader.getUniformSlot('emissive_texture'),
    Material.whitePlaceholder(emissiveTexture),
    sampler: gpu.SamplerOptions(
      widthAddressMode: gpu.SamplerAddressMode.repeat,
      heightAddressMode: gpu.SamplerAddressMode.repeat,
    ),
  );
  pass.bindTexture(
    fragmentShader.getUniformSlot('metallic_roughness_texture'),
    Material.whitePlaceholder(metallicRoughnessTexture),
    sampler: gpu.SamplerOptions(
      widthAddressMode: gpu.SamplerAddressMode.repeat,
      heightAddressMode: gpu.SamplerAddressMode.repeat,
    ),
  );
  pass.bindTexture(
    fragmentShader.getUniformSlot('normal_texture'),
    Material.normalPlaceholder(normalTexture),
    sampler: gpu.SamplerOptions(
      widthAddressMode: gpu.SamplerAddressMode.repeat,
      heightAddressMode: gpu.SamplerAddressMode.repeat,
    ),
  );
  pass.bindTexture(
    fragmentShader.getUniformSlot('occlusion_texture'),
    Material.whitePlaceholder(occlusionTexture),
    sampler: gpu.SamplerOptions(
      widthAddressMode: gpu.SamplerAddressMode.repeat,
      heightAddressMode: gpu.SamplerAddressMode.repeat,
    ),
  );
  // Image-based-lighting atlas, BRDF LUT, and shadow map. Shared with
  // PreprocessedMaterial: the sampler choices (radiance repeat/clamp, LUT
  // clamp/clamp, shadow bilinear/clamp) and the white shadow placeholder
  // live in EngineLightingUniforms.
  EngineLightingUniforms.bindEngineTextures(
    pass,
    fragmentShader,
    lighting,
    env,
  );
}