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 );
							 |