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 colorSpace = ( _currentRenderTarget == null ) ? outputColorSpace : ( _currentRenderTarget?.isXRRenderTarget == true ? _currentRenderTarget?.texture.colorSpace : LinearSRGBColorSpace );
final envMap = ( material is MeshStandardMaterial ? cubeuvmaps.get( material.envMap ?? environment ) : cubemaps.get( material.envMap ?? environment ) );
final vertexAlphas = material.vertexColors &&
geometry?.attributes['color'] != null &&
geometry?.attributes['color'].itemSize == 4;
final vertexTangents = geometry?.attributes['tangent'] != null && (material.normalMap != null || (material is MeshPhysicalMaterial && material.anisotropy > 0));
final morphTargets = geometry?.morphAttributes['position'] != null;
final morphNormals = geometry?.morphAttributes['normal'] != null;
final morphColors = geometry?.morphAttributes['color'] != null;
int toneMapping = NoToneMapping;
if ( material.toneMapped ) {
if ( _currentRenderTarget == null || _currentRenderTarget?.isXRRenderTarget == true ) {
toneMapping = toneMapping;
}
}
final morphAttribute = geometry?.morphAttributes['position'] ?? geometry?.morphAttributes['normal'] ?? geometry?.morphAttributes['color'];
final morphTargetsCount = ( morphAttribute != null ) ? morphAttribute.length : 0;
final materialProperties = properties.get( material );
final lights = currentRenderState?.state.lights;
if (_clippingEnabled) {
if (_localClippingEnabled || 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['outputColorSpace'] != colorSpace ) {
needsProgramChange = true;
} else if ( object is BatchedMesh && materialProperties['batching'] == false ) {
needsProgramChange = true;
} else if (object is! BatchedMesh && materialProperties['batching'] == true ) {
needsProgramChange = true;
}else if ( object is BatchedMesh && materialProperties['batchingColor'] == true && object.colorsTexture == null ) {
needsProgramChange = true;
} else if ( object is BatchedMesh && materialProperties['batchingColor'] == false && object.colorsTexture != null ) {
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 ( object is InstancedMesh && materialProperties['instancingColor'] == true && object.instanceColor == null ) {
needsProgramChange = true;
} else if ( object is InstancedMesh && materialProperties['instancingColor'] == false && object.instanceColor != null ) {
needsProgramChange = true;
} else if ( object is InstancedMesh && materialProperties['instancingMorph'] == true && object.morphTexture == null ) {
needsProgramChange = true;
} else if ( object is InstancedMesh && materialProperties['instancingMorph'] == false && object.morphTexture != null ) {
needsProgramChange = true;
} else if ( materialProperties['envMap'] != envMap ) {
needsProgramChange = true;
} else if ( material.fog == true && 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 ( 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 WebGLUniforms? pUniformS = program?.getUniforms();
final 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 ) {
// common camera uniforms
final reverseDepthBuffer = (state.buffers['depth'] as DepthBuffer).getReversed();
if ( reverseDepthBuffer ) {
_currentProjectionMatrix.setFrom( camera.projectionMatrix );
toNormalizedProjectionMatrix( _currentProjectionMatrix );
toReversedProjectionMatrix( _currentProjectionMatrix );
pUniformS?.setValue( _gl, 'projectionMatrix', _currentProjectionMatrix );
}
else {
pUniformS?.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );
}
pUniformS?.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );
final uCamPos = pUniformS?.map['cameraPosition'];
if ( uCamPos != null ) {
uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );
}
if ( capabilities.logarithmicDepthBuffer ) {
pUniformS?.setValue( _gl, 'logDepthBufFC', 2.0 / ( math.log( camera.far + 1.0 ) / math.ln2 ) );
}
// consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067
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);
}
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
}
}
// skinning and morph target uniforms must be set even if material didn't change
// auto-setting of texture unit for bone and morph texture must go before other textures
// otherwise textures used for skinning and morphing 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 ( skeleton.boneTexture == null ) skeleton.computeBoneTexture();
pUniformS?.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );
}
}
if ( object is BatchedMesh ) {
pUniformS?.setOptional( _gl, object, 'batchingTexture' );
pUniformS?.setValue( _gl, 'batchingTexture', object.matricesTexture, textures );
pUniformS?.setOptional( _gl, object, 'batchingIdTexture' );
pUniformS?.setValue( _gl, 'batchingIdTexture', object.indirectTexture, textures );
pUniformS?.setOptional( _gl, object, 'batchingColorTexture' );
if ( object.colorsTexture != null ) {
pUniformS?.setValue( _gl, 'batchingColorTexture', object.colorsTexture, textures );
}
}
final morphAttributes = geometry?.morphAttributes;
if ( morphAttributes?['position'] != null || morphAttributes?['normal'] != null || ( morphAttributes?['color'] != null ) ) {
morphtargets.update( object, geometry!, program! );
}
if ( refreshMaterial || materialProperties['receiveShadow'] != object.receiveShadow ) {
materialProperties['receiveShadow'] = object.receiveShadow;
pUniformS?.setValue( _gl, 'receiveShadow', object.receiveShadow );
}
// https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512
if ( material is MeshGouraudMaterial && material.envMap != null ) {
mUniformS['envMap']['value'] = envMap;
mUniformS['flipEnvMap']['value'] = ( envMap is CubeTexture && envMap.isRenderTargetTexture == false ) ? - 1 : 1;
}
if ( material is MeshStandardMaterial && material.envMap == null && scene.environment != null ) {
mUniformS['envMapIntensity']['value'] = scene.environmentIntensity;
}
if ( refreshMaterial ) {
pUniformS?.setValue( _gl, 'toneMappingExposure', toneMappingExposure );
if ( materialProperties['needsLights'] == true) {
markUniformsLightsNeedsUpdate( mUniformS, refreshLights );
}
// refresh uniforms common to several materials
if (fog != null && material.fog == true ) {
materials.refreshFogUniforms( mUniformS, fog );
}
materials.refreshMaterialUniforms( mUniformS, material, _pixelRatio, _height, currentRenderState?.state.transmissionRenderTarget[ camera.id ] );
WebGLUniforms.upload( _gl, getUniformList( materialProperties ), mUniformS, textures );
}
if ( material is ShaderMaterial && material.uniformsNeedUpdate == true ) {
WebGLUniforms.upload( _gl, getUniformList( materialProperties ), mUniformS, textures );
material.uniformsNeedUpdate = false;
}
if ( material is SpriteMaterial ) {
pUniformS?.setValue( _gl, 'center', (object as Sprite).center );
}
// common matrices
pUniformS?.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
pUniformS?.setValue( _gl, 'normalMatrix', object.normalMatrix );
pUniformS?.setValue( _gl, 'modelMatrix', object.matrixWorld );
// UBOs
if ( material is ShaderMaterial || material is RawShaderMaterial ) {
late final List groups;
if ( material is ShaderMaterial) {
groups = material.uniformsGroups;
}
else if(material is RawShaderMaterial){
groups = material.uniformsGroups;
}
for ( int i = 0, l = groups.length; i < l; i ++ ) {
final group = groups[i];
uniformsGroups.update( group, program );
uniformsGroups.bind( group, program );
}
}
return program!;
}