Skip to content
140 changes: 81 additions & 59 deletions src/renderers/WebGLRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 );

} );

}

Expand Down Expand Up @@ -900,8 +904,6 @@ function WebGLRenderer( parameters ) {

currentRenderState.setupLights();

const compiled = new WeakMap();

scene.traverse( function ( object ) {

const material = object.material;
Expand All @@ -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 );

}

Expand Down Expand Up @@ -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, ...

Expand All @@ -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 );
Expand Down Expand Up @@ -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 ) {
Expand Down Expand Up @@ -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 ) ) {
Expand Down