134 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			134 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import LightingNode from './LightingNode.js';
 | |
| import { cache } from '../core/CacheNode.js';
 | |
| import { context } from '../core/ContextNode.js';
 | |
| import { roughness, clearcoatRoughness } from '../core/PropertyNode.js';
 | |
| import { cameraViewMatrix } from '../accessors/CameraNode.js';
 | |
| import { transformedClearcoatNormalView, transformedNormalView, transformedNormalWorld } from '../accessors/NormalNode.js';
 | |
| import { positionViewDirection } from '../accessors/PositionNode.js';
 | |
| import { addNodeClass } from '../core/Node.js';
 | |
| import { float } from '../shadernode/ShaderNode.js';
 | |
| import { reference } from '../accessors/ReferenceNode.js';
 | |
| import { transformedBentNormalView } from '../accessors/AccessorsUtils.js';
 | |
| import { pmremTexture } from '../pmrem/PMREMNode.js';
 | |
| 
 | |
| const envNodeCache = new WeakMap();
 | |
| 
 | |
| class EnvironmentNode extends LightingNode {
 | |
| 
 | |
| 	constructor( envNode = null ) {
 | |
| 
 | |
| 		super();
 | |
| 
 | |
| 		this.envNode = envNode;
 | |
| 
 | |
| 	}
 | |
| 
 | |
| 	setup( builder ) {
 | |
| 
 | |
| 		let envNode = this.envNode;
 | |
| 
 | |
| 		if ( envNode.isTextureNode ) {
 | |
| 
 | |
| 			let cacheEnvNode = envNodeCache.get( envNode.value );
 | |
| 
 | |
| 			if ( cacheEnvNode === undefined ) {
 | |
| 
 | |
| 				cacheEnvNode = pmremTexture( envNode.value );
 | |
| 
 | |
| 				envNodeCache.set( envNode.value, cacheEnvNode );
 | |
| 
 | |
| 			}
 | |
| 
 | |
| 			envNode	= cacheEnvNode;
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 		//
 | |
| 
 | |
| 		const { material } = builder;
 | |
| 
 | |
| 		const envMap = material.envMap;
 | |
| 		const intensity = envMap ? reference( 'envMapIntensity', 'float', builder.material ) : reference( 'environmentIntensity', 'float', builder.scene ); // @TODO: Add materialEnvIntensity in MaterialNode
 | |
| 
 | |
| 		const useAnisotropy = material.useAnisotropy === true || material.anisotropy > 0;
 | |
| 		const radianceNormalView = useAnisotropy ? transformedBentNormalView : transformedNormalView;
 | |
| 
 | |
| 		const radiance = context( envNode, createRadianceContext( roughness, radianceNormalView ) ).mul( intensity );
 | |
| 		const irradiance = context( envNode, createIrradianceContext( transformedNormalWorld ) ).mul( Math.PI ).mul( intensity );
 | |
| 
 | |
| 		const isolateRadiance = cache( radiance );
 | |
| 
 | |
| 		//
 | |
| 
 | |
| 		builder.context.radiance.addAssign( isolateRadiance );
 | |
| 
 | |
| 		builder.context.iblIrradiance.addAssign( irradiance );
 | |
| 
 | |
| 		//
 | |
| 
 | |
| 		const clearcoatRadiance = builder.context.lightingModel.clearcoatRadiance;
 | |
| 
 | |
| 		if ( clearcoatRadiance ) {
 | |
| 
 | |
| 			const clearcoatRadianceContext = context( envNode, createRadianceContext( clearcoatRoughness, transformedClearcoatNormalView ) ).mul( intensity );
 | |
| 			const isolateClearcoatRadiance = cache( clearcoatRadianceContext );
 | |
| 
 | |
| 			clearcoatRadiance.addAssign( isolateClearcoatRadiance );
 | |
| 
 | |
| 		}
 | |
| 
 | |
| 	}
 | |
| 
 | |
| }
 | |
| 
 | |
| const createRadianceContext = ( roughnessNode, normalViewNode ) => {
 | |
| 
 | |
| 	let reflectVec = null;
 | |
| 
 | |
| 	return {
 | |
| 		getUV: () => {
 | |
| 
 | |
| 			if ( reflectVec === null ) {
 | |
| 
 | |
| 				reflectVec = positionViewDirection.negate().reflect( normalViewNode );
 | |
| 
 | |
| 				// Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane.
 | |
| 				reflectVec = roughnessNode.mul( roughnessNode ).mix( reflectVec, normalViewNode ).normalize();
 | |
| 
 | |
| 				reflectVec = reflectVec.transformDirection( cameraViewMatrix );
 | |
| 
 | |
| 			}
 | |
| 
 | |
| 			return reflectVec;
 | |
| 
 | |
| 		},
 | |
| 		getTextureLevel: () => {
 | |
| 
 | |
| 			return roughnessNode;
 | |
| 
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| };
 | |
| 
 | |
| const createIrradianceContext = ( normalWorldNode ) => {
 | |
| 
 | |
| 	return {
 | |
| 		getUV: () => {
 | |
| 
 | |
| 			return normalWorldNode;
 | |
| 
 | |
| 		},
 | |
| 		getTextureLevel: () => {
 | |
| 
 | |
| 			return float( 1.0 );
 | |
| 
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| };
 | |
| 
 | |
| export default EnvironmentNode;
 | |
| 
 | |
| addNodeClass( 'EnvironmentNode', EnvironmentNode );
 |