ReflectNode.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import { TempNode } from '../core/TempNode.js';
  2. import { PositionNode } from './PositionNode.js';
  3. import { NormalNode } from './NormalNode.js';
  4. class ReflectNode extends TempNode {
  5. constructor( scope ) {
  6. super( 'v3' );
  7. this.scope = scope || ReflectNode.CUBE;
  8. }
  9. getUnique( builder ) {
  10. return ! builder.context.viewNormal;
  11. }
  12. getType( /* builder */ ) {
  13. switch ( this.scope ) {
  14. case ReflectNode.SPHERE:
  15. return 'v2';
  16. }
  17. return this.type;
  18. }
  19. generate( builder, output ) {
  20. const isUnique = this.getUnique( builder );
  21. if ( builder.isShader( 'fragment' ) ) {
  22. let result, code, reflectVec;
  23. switch ( this.scope ) {
  24. case ReflectNode.VECTOR:
  25. const viewNormalNode = new NormalNode( NormalNode.VIEW );
  26. const roughnessNode = builder.context.roughness;
  27. const viewNormal = viewNormalNode.build( builder, 'v3' );
  28. const viewPosition = new PositionNode( PositionNode.VIEW ).build( builder, 'v3' );
  29. const roughness = roughnessNode ? roughnessNode.build( builder, 'f' ) : undefined;
  30. let method = `reflect( -normalize( ${viewPosition} ), ${viewNormal} )`;
  31. if ( roughness ) {
  32. // Mixing the reflection with the normal is more accurate and keeps rough objects from gathering light from behind their tangent plane.
  33. method = `normalize( mix( ${method}, ${viewNormal}, ${roughness} * ${roughness} ) )`;
  34. }
  35. code = `inverseTransformDirection( ${method}, viewMatrix )`;
  36. if ( isUnique ) {
  37. builder.addNodeCode( `vec3 reflectVec = ${code};` );
  38. result = 'reflectVec';
  39. } else {
  40. result = code;
  41. }
  42. break;
  43. case ReflectNode.CUBE:
  44. reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
  45. code = 'vec3( -' + reflectVec + '.x, ' + reflectVec + '.yz )';
  46. if ( isUnique ) {
  47. builder.addNodeCode( `vec3 reflectCubeVec = ${code};` );
  48. result = 'reflectCubeVec';
  49. } else {
  50. result = code;
  51. }
  52. break;
  53. case ReflectNode.SPHERE:
  54. reflectVec = new ReflectNode( ReflectNode.VECTOR ).build( builder, 'v3' );
  55. code = 'normalize( ( viewMatrix * vec4( ' + reflectVec + ', 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) ).xy * 0.5 + 0.5';
  56. if ( isUnique ) {
  57. builder.addNodeCode( `vec2 reflectSphereVec = ${code};` );
  58. result = 'reflectSphereVec';
  59. } else {
  60. result = code;
  61. }
  62. break;
  63. }
  64. return builder.format( result, this.getType( builder ), output );
  65. } else {
  66. console.warn( 'THREE.ReflectNode is not compatible with ' + builder.shader + ' shader.' );
  67. return builder.format( 'vec3( 0.0 )', this.type, output );
  68. }
  69. }
  70. toJSON( meta ) {
  71. let data = this.getJSONNode( meta );
  72. if ( ! data ) {
  73. data = this.createJSONNode( meta );
  74. data.scope = this.scope;
  75. }
  76. return data;
  77. }
  78. }
  79. ReflectNode.CUBE = 'cube';
  80. ReflectNode.SPHERE = 'sphere';
  81. ReflectNode.VECTOR = 'vector';
  82. ReflectNode.prototype.nodeType = 'Reflect';
  83. export { ReflectNode };