getProgram method

WebGLProgram getProgram(
  1. Material material,
  2. Object3D? scene,
  3. Object3D object
)

Implementation

WebGLProgram getProgram(Material material, Object3D? scene, Object3D object) {
  if (scene is! Scene) scene = _emptyScene;
  // scene could be a Mesh, Line, Points, ...

  var materialProperties = properties.get(material);

  var lights = currentRenderState!.state.lights;
  var shadowsArray = currentRenderState!.state.shadowsArray;

  var lightsStateVersion = lights.state.version;

  var parameters = programCache.getParameters(
      material, lights.state, shadowsArray, scene, object);
  var programCacheKey = programCache.getProgramCacheKey(parameters);

  Map? programs = materialProperties["programs"];

  // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change

  materialProperties["environment"] =
      material is MeshStandardMaterial ? scene.environment : null;
  materialProperties["fog"] = scene.fog;

  Texture? _envMap;
  if (material is MeshStandardMaterial) {
    _envMap =
        cubeuvmaps.get(material.envMap ?? materialProperties["environment"]);
  } else {
    _envMap =
        cubemaps.get(material.envMap ?? materialProperties["environment"]);
  }

  materialProperties["envMap"] = _envMap;

  if (programs == null) {
    // new material

    material.addEventListener('dispose', onMaterialDispose);

    programs = {};
    materialProperties["programs"] = programs;
  }

  WebGLProgram? program = programs[programCacheKey];

  if (program != null) {
    // early out if program and light state is identical

    if (materialProperties["currentProgram"] == program &&
        materialProperties["lightsStateVersion"] == lightsStateVersion) {
      updateCommonMaterialProperties(material, parameters);

      return program;
    }
  } else {
    parameters.uniforms = programCache.getUniforms(material);

    material.onBuild(parameters, this);

    if (material.onBeforeCompile != null) {
      material.onBeforeCompile!(parameters, this);
    }

    program = programCache.acquireProgram(parameters, programCacheKey);
    programs[programCacheKey] = program;

    materialProperties["uniforms"] = parameters.uniforms;
  }

  Map<String, dynamic> uniforms = materialProperties["uniforms"];

  if ((material is! ShaderMaterial && material is! RawShaderMaterial) ||
      material.clipping == true) {
    uniforms["clippingPlanes"] = clipping.uniform;
  }

  updateCommonMaterialProperties(material, parameters);

  // store the light setup it was created for

  materialProperties["needsLights"] = materialNeedsLights(material);
  materialProperties["lightsStateVersion"] = lightsStateVersion;

  if (materialProperties["needsLights"] == true) {
    // wire up the material to this renderer's lighting state

    uniforms["ambientLightColor"]["value"] = lights.state.ambient;
    uniforms["lightProbe"]["value"] = lights.state.probe;
    uniforms["directionalLights"]["value"] = lights.state.directional;
    uniforms["directionalLightShadows"]["value"] =
        lights.state.directionalShadow;
    uniforms["spotLights"]["value"] = lights.state.spot;
    uniforms["spotLightShadows"]["value"] = lights.state.spotShadow;
    uniforms["rectAreaLights"]["value"] = lights.state.rectArea;
    uniforms["ltc_1"]["value"] = lights.state.rectAreaLTC1;
    uniforms["ltc_2"]["value"] = lights.state.rectAreaLTC2;
    uniforms["pointLights"]["value"] = lights.state.point;
    uniforms["pointLightShadows"]["value"] = lights.state.pointShadow;
    uniforms["hemisphereLights"]["value"] = lights.state.hemi;

    uniforms["directionalShadowMap"]["value"] =
        lights.state.directionalShadowMap;
    uniforms["directionalShadowMatrix"]["value"] =
        lights.state.directionalShadowMatrix;
    uniforms["spotShadowMap"]["value"] = lights.state.spotShadowMap;
    uniforms["spotShadowMatrix"]["value"] = lights.state.spotShadowMatrix;
    uniforms["pointShadowMap"]["value"] = lights.state.pointShadowMap;
    uniforms["pointShadowMatrix"]["value"] = lights.state.pointShadowMatrix;

    // TODO (abelnation): add area lights shadow info to uniforms
  }

  var progUniforms = program!.getUniforms();
  var uniformsList = WebGLUniforms.seqWithValue(progUniforms.seq, uniforms);

  materialProperties["currentProgram"] = program;
  materialProperties["uniformsList"] = uniformsList;

  return program;
}