setProgram method
WebGLProgram
setProgram(
- Camera camera,
- Object3D? scene,
- BufferGeometry? geometry,
- Material material,
- Object3D object,
Implementation
WebGLProgram setProgram(Camera camera, Object3D? scene, BufferGeometry? geometry, Material material, Object3D object) {
if (scene is! Scene) scene = _emptyScene;
// scene could be a Mesh, Line, Points, ...
textures.resetTextureUnits();
final fog = scene.fog;
final environment = material is MeshStandardMaterial ? scene.environment : null;
final encoding = (_currentRenderTarget == null)
? outputEncoding
: (_currentRenderTarget!.isXRRenderTarget == true ? _currentRenderTarget!.texture.encoding : LinearEncoding);
Texture? envMap;
if (material is MeshStandardMaterial) {
envMap = cubeuvmaps.get(material.envMap ?? environment);
} else {
envMap = cubemaps.get(material.envMap ?? environment);
}
bool vertexAlphas = material.vertexColors == true &&
geometry != null &&
geometry.attributes["color"] != null &&
geometry.attributes["color"].itemSize == 4;
bool vertexTangents = material.normalMap != null && geometry != null && geometry.attributes["tangent"] != null;
bool morphTargets = geometry != null && geometry.morphAttributes["position"] != null;
bool morphNormals = geometry != null && geometry.morphAttributes["normal"] != null;
bool morphColors = geometry != null && geometry.morphAttributes["color"] != null;
int toneMapping = material.toneMapped ? this.toneMapping : NoToneMapping;
List<BufferAttribute>? morphAttribute = geometry != null
? (geometry.morphAttributes["position"] ??
geometry.morphAttributes["normal"] ??
geometry.morphAttributes["color"])
: null;
int morphTargetsCount = (morphAttribute != null) ? morphAttribute.length : 0;
Map<String, dynamic> materialProperties = properties.get(material);
WebGLLights lights = currentRenderState!.state.lights;
if (_clippingEnabled == true) {
if (_localClippingEnabled == true || camera != _currentCamera) {
final useCache = camera == _currentCamera && material.id == _currentMaterialId;
// we might want to call this function with some ClippingGroup
// object instead of the material, once it becomes feasible
// (#8465, #8379)
clipping.setState(material, camera, useCache);
}
}
//
bool needsProgramChange = false;
if (material.version == materialProperties["__version"]) {
if (materialProperties["needsLights"] != null &&
(materialProperties["lightsStateVersion"] != lights.state.version)) {
needsProgramChange = true;
} else if (materialProperties["outputEncoding"] != encoding) {
needsProgramChange = true;
} else if (object is InstancedMesh && materialProperties["instancing"] == false) {
needsProgramChange = true;
} else if (object is! InstancedMesh && materialProperties["instancing"] == true) {
needsProgramChange = true;
} else if (object is SkinnedMesh && materialProperties["skinning"] == false) {
needsProgramChange = true;
} else if (object is! SkinnedMesh && materialProperties["skinning"] == true) {
needsProgramChange = true;
} else if (materialProperties["envMap"] != envMap) {
needsProgramChange = true;
} else if (material.fog && materialProperties["fog"] != fog) {
needsProgramChange = true;
} else if (materialProperties["numClippingPlanes"] != null &&
(materialProperties["numClippingPlanes"] != clipping.numPlanes ||
materialProperties["numIntersection"] != clipping.numIntersection)) {
needsProgramChange = true;
} else if (materialProperties["vertexAlphas"] != vertexAlphas) {
needsProgramChange = true;
} else if (materialProperties["vertexTangents"] != vertexTangents) {
needsProgramChange = true;
} else if (materialProperties["morphTargets"] != morphTargets) {
needsProgramChange = true;
} else if (materialProperties["morphNormals"] != morphNormals) {
needsProgramChange = true;
} else if (materialProperties["morphColors"] != morphColors) {
needsProgramChange = true;
} else if (materialProperties["toneMapping"] != toneMapping) {
needsProgramChange = true;
} else if (capabilities.isWebGL2 == true && materialProperties["morphTargetsCount"] != morphTargetsCount) {
needsProgramChange = true;
}
} else {
needsProgramChange = true;
materialProperties["__version"] = material.version;
}
WebGLProgram? program = materialProperties["currentProgram"];
if (needsProgramChange) {
program = getProgram(material, scene, object);
}
bool refreshProgram = false;
bool refreshMaterial = false;
bool refreshLights = false;
final pUniforms = program!.getUniforms();
Map<String, dynamic> mUniforms = materialProperties["uniforms"];
if (state.useProgram(program.program)) {
refreshProgram = true;
refreshMaterial = true;
refreshLights = true;
}
if (material.id != _currentMaterialId) {
_currentMaterialId = material.id;
refreshMaterial = true;
}
if (refreshProgram || _currentCamera != camera) {
pUniforms.setValue(_gl, 'projectionMatrix', camera.projectionMatrix, textures);
if (capabilities.logarithmicDepthBuffer) {
pUniforms.setValue(_gl, 'logDepthBufFC', 2.0 / (math.log(camera.far + 1.0) / math.ln2), textures);
}
if (_currentCamera != camera) {
_currentCamera = camera;
// lighting uniforms depend on the camera so enforce an update
// now, in case this material supports lights - or later, when
// the next material that does gets activated:
refreshMaterial = true; // set to true on material change
refreshLights = true; // remains set until update done
}
// load material specific uniforms
// (shader material also gets them for the sake of genericity)
if (material is ShaderMaterial ||
material is MeshPhongMaterial ||
material is MeshToonMaterial ||
material is MeshStandardMaterial ||
material.envMap != null) {
final uCamPos = pUniforms.map["cameraPosition"];
if (uCamPos != null) {
uCamPos.setValue(_gl, _vector3.setFromMatrixPosition(camera.matrixWorld));
}
}
if (material is MeshPhongMaterial ||
material is MeshToonMaterial ||
material is MeshLambertMaterial ||
material is MeshBasicMaterial ||
material is MeshStandardMaterial ||
material is ShaderMaterial) {
pUniforms.setValue(_gl, 'isOrthographic', camera is OrthographicCamera, textures);
}
if (material is MeshPhongMaterial ||
material is MeshToonMaterial ||
material is MeshLambertMaterial ||
material is MeshBasicMaterial ||
material is MeshStandardMaterial ||
material is ShaderMaterial ||
material is ShadowMaterial ||
object is SkinnedMesh) {
pUniforms.setValue(_gl, 'viewMatrix', camera.matrixWorldInverse, textures);
}
}
// skinning uniforms must be set even if material didn't change
// auto-setting of texture unit for bone texture must go before other textures
// otherwise textures used for skinning can take over texture units reserved for other material textures
if (object is SkinnedMesh) {
pUniforms.setOptional(_gl, object, 'bindMatrix');
pUniforms.setOptional(_gl, object, 'bindMatrixInverse');
final skeleton = object.skeleton;
if (skeleton != null) {
if (capabilities.floatVertexTextures) {
if (skeleton.boneTexture == null) skeleton.computeBoneTexture();
pUniforms.setValue(_gl, 'boneTexture', skeleton.boneTexture, textures);
pUniforms.setValue(_gl, 'boneTextureSize', skeleton.boneTextureSize, textures);
} else {
console.warning('WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.');
}
}
}
final morphAttributes = geometry!.morphAttributes;
if (morphAttributes["position"] != null ||
morphAttributes["normal"] != null ||
(morphAttributes["color"] != null && capabilities.isWebGL2 == true)) {
morphtargets.update(object, geometry, material, program);
}
if (refreshMaterial || materialProperties["receiveShadow"] != object.receiveShadow) {
materialProperties["receiveShadow"] = object.receiveShadow;
pUniforms.setValue(_gl, 'receiveShadow', object.receiveShadow, textures);
}
// print(" setProgram .......... material: ${material.type} ");
if (refreshMaterial) {
pUniforms.setValue(_gl, 'toneMappingExposure', toneMappingExposure, textures);
if (materialProperties["needsLights"]) {
// the current material requires lighting info
// note: all lighting uniforms are always set correctly
// they simply reference the renderer's state for their
// values
//
// use the current material's .needsUpdate flags to set
// the GL state when required
markUniformsLightsNeedsUpdate(mUniforms, refreshLights);
}
// refresh uniforms common to several materials
if (fog != null && material.fog) {
materials.refreshFogUniforms(mUniforms, fog);
}
materials.refreshMaterialUniforms(mUniforms, material, _pixelRatio, _height, _transmissionRenderTarget);
WebGLUniforms.upload(_gl, materialProperties["uniformsList"], mUniforms, textures);
}
if (material is ShaderMaterial && material.uniformsNeedUpdate == true) {
WebGLUniforms.upload(_gl, materialProperties["uniformsList"], mUniforms, textures);
material.uniformsNeedUpdate = false;
}
if (material is SpriteMaterial) {
dynamic c = object;
pUniforms.setValue(_gl, 'center', c.center, textures);
}
// common matrices
pUniforms.setValue(_gl, 'modelViewMatrix', object.modelViewMatrix, textures);
pUniforms.setValue(_gl, 'normalMatrix', object.normalMatrix, textures);
pUniforms.setValue(_gl, 'modelMatrix', object.matrixWorld, textures);
return program;
}