EnvironmentNode.js 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import LightingNode from './LightingNode.js';
  2. import ContextNode from '../core/ContextNode.js';
  3. import MaxMipLevelNode from '../utils/MaxMipLevelNode.js';
  4. import { ShaderNode, float, add, mul, div, log2, clamp, roughness, reflect, mix, vec3, positionViewDirection, negate, normalize, transformedNormalView, transformedNormalWorld, transformDirection, cameraViewMatrix } from '../shadernode/ShaderNodeElements.js';
  5. // taken from here: http://casual-effects.blogspot.ca/2011/08/plausible-environment-lighting-in-two.html
  6. const getSpecularMIPLevel = new ShaderNode( ( { texture, levelNode } ) => {
  7. const maxMIPLevelScalar = new MaxMipLevelNode( texture );
  8. const sigma = div( mul( Math.PI, mul( levelNode, levelNode ) ), add( 1.0, levelNode ) );
  9. const desiredMIPLevel = add( maxMIPLevelScalar, log2( sigma ) );
  10. return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );
  11. } );
  12. class EnvironmentNode extends LightingNode {
  13. constructor( envNode = null ) {
  14. super();
  15. this.envNode = envNode;
  16. }
  17. construct( builder ) {
  18. const envNode = this.envNode;
  19. const properties = builder.getNodeProperties( this );
  20. const flipNormalWorld = vec3( negate( transformedNormalWorld.x ), transformedNormalWorld.yz );
  21. let reflectVec = reflect( negate( positionViewDirection ), transformedNormalView );
  22. reflectVec = normalize( mix( reflectVec, transformedNormalView, mul( roughness, roughness ) ) );
  23. reflectVec = transformDirection( reflectVec, cameraViewMatrix );
  24. reflectVec = vec3( negate( reflectVec.x ), reflectVec.yz );
  25. const radianceContext = new ContextNode( envNode, {
  26. tempRead: false,
  27. uvNode: reflectVec,
  28. levelNode: roughness,
  29. levelShaderNode: getSpecularMIPLevel
  30. } );
  31. const irradianceContext = new ContextNode( envNode, {
  32. tempRead: false,
  33. uvNode: flipNormalWorld,
  34. levelNode: float( 1 ),
  35. levelShaderNode: getSpecularMIPLevel
  36. } );
  37. // it's used to cache the construct only if necessary: See `CubeTextureNode.getConstructReference()`
  38. radianceContext.context.environmentContext = radianceContext;
  39. irradianceContext.context.environmentContext = irradianceContext;
  40. builder.context.radiance.add( radianceContext );
  41. builder.context.iblIrradiance.add( mul( Math.PI, irradianceContext ) );
  42. properties.radianceContext = radianceContext;
  43. properties.irradianceContext = irradianceContext;
  44. }
  45. }
  46. export default EnvironmentNode;