|
@@ -643,20 +643,24 @@ function WebGLRenderer( parameters ) {
|
|
|
|
|
|
function deallocateMaterial( material ) {
|
|
|
|
|
|
- releaseMaterialProgramReference( material );
|
|
|
+ releaseMaterialProgramReferences( material );
|
|
|
|
|
|
properties.remove( material );
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
- function releaseMaterialProgramReference( material ) {
|
|
|
+ function releaseMaterialProgramReferences( material ) {
|
|
|
|
|
|
- const programInfo = properties.get( material ).program;
|
|
|
+ const programs = properties.get( material ).programs;
|
|
|
|
|
|
- if ( programInfo !== undefined ) {
|
|
|
+ if ( programs !== undefined ) {
|
|
|
|
|
|
- programCache.releaseProgram( programInfo );
|
|
|
+ programs.forEach( function ( program ) {
|
|
|
+
|
|
|
+ programCache.releaseProgram( program );
|
|
|
+
|
|
|
+ } );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -900,8 +904,6 @@ function WebGLRenderer( parameters ) {
|
|
|
|
|
|
currentRenderState.setupLights();
|
|
|
|
|
|
- const compiled = new WeakMap();
|
|
|
-
|
|
|
scene.traverse( function ( object ) {
|
|
|
|
|
|
const material = object.material;
|
|
@@ -914,19 +916,13 @@ function WebGLRenderer( parameters ) {
|
|
|
|
|
|
const material2 = material[ i ];
|
|
|
|
|
|
- if ( compiled.has( material2 ) === false ) {
|
|
|
-
|
|
|
- initMaterial( material2, scene, object );
|
|
|
- compiled.set( material2 );
|
|
|
-
|
|
|
- }
|
|
|
+ getProgram( material2, scene, object );
|
|
|
|
|
|
}
|
|
|
|
|
|
- } else if ( compiled.has( material ) === false ) {
|
|
|
+ } else {
|
|
|
|
|
|
- initMaterial( material, scene, object );
|
|
|
- compiled.set( material );
|
|
|
+ getProgram( material, scene, object );
|
|
|
|
|
|
}
|
|
|
|
|
@@ -1323,7 +1319,7 @@ function WebGLRenderer( parameters ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function initMaterial( material, scene, object ) {
|
|
|
+ function getProgram( material, scene, object ) {
|
|
|
|
|
|
if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...
|
|
|
|
|
@@ -1337,67 +1333,62 @@ function WebGLRenderer( parameters ) {
|
|
|
const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
|
|
|
const programCacheKey = programCache.getProgramCacheKey( parameters );
|
|
|
|
|
|
- let program = materialProperties.program;
|
|
|
- let programChange = true;
|
|
|
+ let programs = materialProperties.programs;
|
|
|
|
|
|
- // always update environment and fog - changing these trigger an initMaterial call, but it's possible that the program doesn't change
|
|
|
+ // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change
|
|
|
|
|
|
materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
|
|
|
materialProperties.fog = scene.fog;
|
|
|
materialProperties.envMap = cubemaps.get( material.envMap || materialProperties.environment );
|
|
|
|
|
|
- if ( program === undefined ) {
|
|
|
+ if ( programs === undefined ) {
|
|
|
|
|
|
// new material
|
|
|
+
|
|
|
material.addEventListener( 'dispose', onMaterialDispose );
|
|
|
|
|
|
- } else if ( program.cacheKey !== programCacheKey ) {
|
|
|
+ programs = new Map();
|
|
|
+ materialProperties.programs = programs;
|
|
|
|
|
|
- // changed glsl or parameters
|
|
|
- releaseMaterialProgramReference( material );
|
|
|
+ }
|
|
|
|
|
|
- } else if ( materialProperties.lightsStateVersion !== lightsStateVersion ) {
|
|
|
+ let program = programs.get( programCacheKey );
|
|
|
|
|
|
- programChange = false;
|
|
|
+ if ( program !== undefined ) {
|
|
|
|
|
|
- } else if ( parameters.shaderID !== undefined ) {
|
|
|
+ // early out if program and light state is identical
|
|
|
|
|
|
- // same glsl and uniform list
|
|
|
- return;
|
|
|
+ if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) {
|
|
|
|
|
|
- } else {
|
|
|
+ updateCommonMaterialProperties( material, parameters );
|
|
|
|
|
|
- // only rebuild uniform list
|
|
|
- programChange = false;
|
|
|
+ return program;
|
|
|
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
- if ( programChange ) {
|
|
|
+ } else {
|
|
|
|
|
|
parameters.uniforms = programCache.getUniforms( material );
|
|
|
|
|
|
material.onBeforeCompile( parameters, _this );
|
|
|
|
|
|
program = programCache.acquireProgram( parameters, programCacheKey );
|
|
|
+ programs.set( programCacheKey, program );
|
|
|
|
|
|
- materialProperties.program = program;
|
|
|
materialProperties.uniforms = parameters.uniforms;
|
|
|
- materialProperties.outputEncoding = parameters.outputEncoding;
|
|
|
|
|
|
}
|
|
|
|
|
|
const uniforms = materialProperties.uniforms;
|
|
|
|
|
|
- if ( ! material.isShaderMaterial &&
|
|
|
- ! material.isRawShaderMaterial ||
|
|
|
- material.clipping === true ) {
|
|
|
+ if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) {
|
|
|
|
|
|
- materialProperties.numClippingPlanes = clipping.numPlanes;
|
|
|
- materialProperties.numIntersection = clipping.numIntersection;
|
|
|
uniforms.clippingPlanes = clipping.uniform;
|
|
|
|
|
|
}
|
|
|
|
|
|
+ updateCommonMaterialProperties( material, parameters );
|
|
|
+
|
|
|
// store the light setup it was created for
|
|
|
|
|
|
materialProperties.needsLights = materialNeedsLights( material );
|
|
@@ -1430,11 +1421,25 @@ function WebGLRenderer( parameters ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
- const progUniforms = materialProperties.program.getUniforms();
|
|
|
+ const progUniforms = program.getUniforms();
|
|
|
const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms );
|
|
|
|
|
|
+ materialProperties.currentProgram = program;
|
|
|
materialProperties.uniformsList = uniformsList;
|
|
|
|
|
|
+ return program;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function updateCommonMaterialProperties( material, parameters ) {
|
|
|
+
|
|
|
+ const materialProperties = properties.get( material );
|
|
|
+
|
|
|
+ materialProperties.outputEncoding = parameters.outputEncoding;
|
|
|
+ materialProperties.instancing = parameters.instancing;
|
|
|
+ materialProperties.numClippingPlanes = parameters.numClippingPlanes;
|
|
|
+ materialProperties.numIntersection = parameters.numClipIntersection;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
function setProgram( camera, scene, material, object ) {
|
|
@@ -1468,49 +1473,66 @@ function WebGLRenderer( parameters ) {
|
|
|
|
|
|
}
|
|
|
|
|
|
- if ( material.version === materialProperties.__version ) {
|
|
|
+ //
|
|
|
|
|
|
- if ( material.fog && materialProperties.fog !== fog ) {
|
|
|
+ let needsProgramChange = false;
|
|
|
|
|
|
- initMaterial( material, scene, object );
|
|
|
+ if ( material.version === materialProperties.__version ) {
|
|
|
|
|
|
- } else if ( materialProperties.environment !== environment ) {
|
|
|
+ if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
|
|
|
|
|
|
- initMaterial( material, scene, object );
|
|
|
+ needsProgramChange = true;
|
|
|
|
|
|
- } else if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {
|
|
|
+ } else if ( materialProperties.outputEncoding !== encoding ) {
|
|
|
|
|
|
- initMaterial( material, scene, object );
|
|
|
+ needsProgramChange = true;
|
|
|
|
|
|
- } else if ( materialProperties.numClippingPlanes !== undefined &&
|
|
|
- ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
|
|
|
- materialProperties.numIntersection !== clipping.numIntersection ) ) {
|
|
|
+ } else if ( object.isInstancedMesh && materialProperties.instancing === false ) {
|
|
|
|
|
|
- initMaterial( material, scene, object );
|
|
|
+ needsProgramChange = true;
|
|
|
|
|
|
- } else if ( materialProperties.outputEncoding !== encoding ) {
|
|
|
+ } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) {
|
|
|
|
|
|
- initMaterial( material, scene, object );
|
|
|
+ needsProgramChange = true;
|
|
|
|
|
|
} else if ( materialProperties.envMap !== envMap ) {
|
|
|
|
|
|
- initMaterial( material, scene, object );
|
|
|
+ needsProgramChange = true;
|
|
|
+
|
|
|
+ } else if ( material.fog && materialProperties.fog !== fog ) {
|
|
|
+
|
|
|
+ needsProgramChange = true;
|
|
|
+
|
|
|
+ } else if ( materialProperties.numClippingPlanes !== undefined &&
|
|
|
+ ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
|
|
|
+ materialProperties.numIntersection !== clipping.numIntersection ) ) {
|
|
|
+
|
|
|
+ needsProgramChange = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
|
|
|
- initMaterial( material, scene, object );
|
|
|
+ needsProgramChange = true;
|
|
|
materialProperties.__version = material.version;
|
|
|
|
|
|
}
|
|
|
|
|
|
+ //
|
|
|
+
|
|
|
+ let program = materialProperties.currentProgram;
|
|
|
+
|
|
|
+ if ( needsProgramChange === true ) {
|
|
|
+
|
|
|
+ program = getProgram( material, scene, object );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
let refreshProgram = false;
|
|
|
let refreshMaterial = false;
|
|
|
let refreshLights = false;
|
|
|
|
|
|
- const program = materialProperties.program,
|
|
|
- p_uniforms = program.getUniforms(),
|
|
|
+ const p_uniforms = program.getUniforms(),
|
|
|
m_uniforms = materialProperties.uniforms;
|
|
|
|
|
|
if ( state.useProgram( program.program ) ) {
|