ReflectorNode.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. import Node from '../core/Node.js';
  2. import TextureNode from '../accessors/TextureNode.js';
  3. import { nodeObject } from '../tsl/TSLBase.js';
  4. import { NodeUpdateType } from '../core/constants.js';
  5. import { screenUV } from '../display/ScreenNode.js';
  6. import { HalfFloatType, LinearMipMapLinearFilter, WebGPUCoordinateSystem } from '../../constants.js';
  7. import { Plane } from '../../math/Plane.js';
  8. import { Object3D } from '../../core/Object3D.js';
  9. import { Vector2 } from '../../math/Vector2.js';
  10. import { Vector3 } from '../../math/Vector3.js';
  11. import { Vector4 } from '../../math/Vector4.js';
  12. import { Matrix4 } from '../../math/Matrix4.js';
  13. import { RenderTarget } from '../../core/RenderTarget.js';
  14. import { DepthTexture } from '../../textures/DepthTexture.js';
  15. /** @module ReflectorNode **/
  16. const _reflectorPlane = new Plane();
  17. const _normal = new Vector3();
  18. const _reflectorWorldPosition = new Vector3();
  19. const _cameraWorldPosition = new Vector3();
  20. const _rotationMatrix = new Matrix4();
  21. const _lookAtPosition = new Vector3( 0, 0, - 1 );
  22. const clipPlane = new Vector4();
  23. const _view = new Vector3();
  24. const _target = new Vector3();
  25. const _q = new Vector4();
  26. const _size = new Vector2();
  27. const _defaultRT = new RenderTarget();
  28. const _defaultUV = screenUV.flipX();
  29. _defaultRT.depthTexture = new DepthTexture( 1, 1 );
  30. let _inReflector = false;
  31. /**
  32. * This node can be used to implement mirror-like flat reflective surfaces.
  33. *
  34. * ```js
  35. * const groundReflector = reflector();
  36. * material.colorNode = groundReflector;
  37. *
  38. * const plane = new Mesh( geometry, material );
  39. * plane.add( groundReflector.target );
  40. * ```
  41. *
  42. * @augments module:TextureNode~TextureNode
  43. */
  44. class ReflectorNode extends TextureNode {
  45. static get type() {
  46. return 'ReflectorNode';
  47. }
  48. /**
  49. * Constructs a new reflector node.
  50. *
  51. * @param {Object} [parameters={}] - An object holding configuration parameters.
  52. * @param {Object3D} [parameters.target=new Object3D()] - The 3D object the reflector is linked to.
  53. * @param {Number} [parameters.resolution=1] - The resolution scale.
  54. * @param {Boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not.
  55. * @param {Boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not.
  56. * @param {Boolean} [parameters.depth=false] - Whether depth data should be generated or not.
  57. * @param {TextureNode} [parameters.defaultTexture] - The default texture node.
  58. * @param {ReflectorBaseNode} [parameters.reflector] - The reflector base node.
  59. */
  60. constructor( parameters = {} ) {
  61. super( parameters.defaultTexture || _defaultRT.texture, _defaultUV );
  62. /**
  63. * A reference to the internal reflector base node which holds the actual implementation.
  64. *
  65. * @private
  66. * @type {ReflectorBaseNode?}
  67. * @default null
  68. */
  69. this._reflectorBaseNode = parameters.reflector || new ReflectorBaseNode( this, parameters );
  70. /**
  71. * A reference to the internal depth node.
  72. *
  73. * @private
  74. * @type {Node?}
  75. * @default null
  76. */
  77. this._depthNode = null;
  78. this.setUpdateMatrix( false );
  79. }
  80. /**
  81. * A reference to the internal reflector node.
  82. *
  83. * @type {ReflectorBaseNode}
  84. */
  85. get reflector() {
  86. return this._reflectorBaseNode;
  87. }
  88. /**
  89. * A reference to 3D object the reflector is linked to.
  90. *
  91. * @type {Object3D}
  92. */
  93. get target() {
  94. return this._reflectorBaseNode.target;
  95. }
  96. /**
  97. * Returns a node representing the mirror's depth. That can be used
  98. * to implement more advanced reflection effects like distance attenuation.
  99. *
  100. * @return {Node} The depth node.
  101. */
  102. getDepthNode() {
  103. if ( this._depthNode === null ) {
  104. if ( this._reflectorBaseNode.depth !== true ) {
  105. throw new Error( 'THREE.ReflectorNode: Depth node can only be requested when the reflector is created with { depth: true }. ' );
  106. }
  107. this._depthNode = nodeObject( new ReflectorNode( {
  108. defaultTexture: _defaultRT.depthTexture,
  109. reflector: this._reflectorBaseNode
  110. } ) );
  111. }
  112. return this._depthNode;
  113. }
  114. setup( builder ) {
  115. // ignore if used in post-processing
  116. if ( ! builder.object.isQuadMesh ) this._reflectorBaseNode.build( builder );
  117. return super.setup( builder );
  118. }
  119. clone() {
  120. const texture = new this.constructor( this.reflectorNode );
  121. texture._reflectorBaseNode = this._reflectorBaseNode;
  122. return texture;
  123. }
  124. }
  125. /**
  126. * Holds the actual implementation of the reflector.
  127. *
  128. * TODO: Explain why `ReflectorBaseNode`. Originally the entire logic was implemented
  129. * in `ReflectorNode`, see #29619.
  130. *
  131. * @private
  132. * @augments Node
  133. */
  134. class ReflectorBaseNode extends Node {
  135. static get type() {
  136. return 'ReflectorBaseNode';
  137. }
  138. /**
  139. * Constructs a new reflector base node.
  140. *
  141. * @param {TextureNode} textureNode - Represents the rendered reflections as a texture node.
  142. * @param {Object} [parameters={}] - An object holding configuration parameters.
  143. * @param {Object3D} [parameters.target=new Object3D()] - The 3D object the reflector is linked to.
  144. * @param {Number} [parameters.resolution=1] - The resolution scale.
  145. * @param {Boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not.
  146. * @param {Boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not.
  147. * @param {Boolean} [parameters.depth=false] - Whether depth data should be generated or not.
  148. */
  149. constructor( textureNode, parameters = {} ) {
  150. super();
  151. const {
  152. target = new Object3D(),
  153. resolution = 1,
  154. generateMipmaps = false,
  155. bounces = true,
  156. depth = false
  157. } = parameters;
  158. /**
  159. * Represents the rendered reflections as a texture node.
  160. *
  161. * @type {TextureNode}
  162. */
  163. this.textureNode = textureNode;
  164. /**
  165. * The 3D object the reflector is linked to.
  166. *
  167. * @type {Object3D}
  168. * @default {new Object3D()}
  169. */
  170. this.target = target;
  171. /**
  172. * The resolution scale.
  173. *
  174. * @type {Number}
  175. * @default {1}
  176. */
  177. this.resolution = resolution;
  178. /**
  179. * Whether mipmaps should be generated or not.
  180. *
  181. * @type {Boolean}
  182. * @default {false}
  183. */
  184. this.generateMipmaps = generateMipmaps;
  185. /**
  186. * Whether reflectors can render other reflector nodes or not.
  187. *
  188. * @type {Boolean}
  189. * @default {true}
  190. */
  191. this.bounces = bounces;
  192. /**
  193. * Whether depth data should be generated or not.
  194. *
  195. * @type {Boolean}
  196. * @default {false}
  197. */
  198. this.depth = depth;
  199. /**
  200. * The `updateBeforeType` is set to `NodeUpdateType.RENDER` when {@link ReflectorBaseNode#bounces}
  201. * is `true`. Otherwise it's `NodeUpdateType.FRAME`.
  202. *
  203. * @type {String}
  204. * @default 'render'
  205. */
  206. this.updateBeforeType = bounces ? NodeUpdateType.RENDER : NodeUpdateType.FRAME;
  207. /**
  208. * Weak map for managing virtual cameras.
  209. *
  210. * @type {WeakMap<Camera, Camera>}
  211. */
  212. this.virtualCameras = new WeakMap();
  213. /**
  214. * Weak map for managing render targets.
  215. *
  216. * @type {WeakMap<Camera, RenderTarget>}
  217. */
  218. this.renderTargets = new WeakMap();
  219. }
  220. /**
  221. * Updates the resolution of the internal render target.
  222. *
  223. * @private
  224. * @param {RenderTarget} renderTarget - The render target to resize.
  225. * @param {Renderer} renderer - The renderer that is used to determine the new size.
  226. */
  227. _updateResolution( renderTarget, renderer ) {
  228. const resolution = this.resolution;
  229. renderer.getDrawingBufferSize( _size );
  230. renderTarget.setSize( Math.round( _size.width * resolution ), Math.round( _size.height * resolution ) );
  231. }
  232. setup( builder ) {
  233. this._updateResolution( _defaultRT, builder.renderer );
  234. return super.setup( builder );
  235. }
  236. /**
  237. * Returns a virtual camera for the given camera. The virtual camera is used to
  238. * render the scene from the reflector's view so correct reflections can be produced.
  239. *
  240. * @param {Camera} camera - The scene's camera.
  241. * @return {Camera} The corresponding virtual camera.
  242. */
  243. getVirtualCamera( camera ) {
  244. let virtualCamera = this.virtualCameras.get( camera );
  245. if ( virtualCamera === undefined ) {
  246. virtualCamera = camera.clone();
  247. this.virtualCameras.set( camera, virtualCamera );
  248. }
  249. return virtualCamera;
  250. }
  251. /**
  252. * Returns a render target for the given camera. The reflections are rendered
  253. * into this render target.
  254. *
  255. * @param {Camera} camera - The scene's camera.
  256. * @return {RenderTarget} The render target.
  257. */
  258. getRenderTarget( camera ) {
  259. let renderTarget = this.renderTargets.get( camera );
  260. if ( renderTarget === undefined ) {
  261. renderTarget = new RenderTarget( 0, 0, { type: HalfFloatType } );
  262. if ( this.generateMipmaps === true ) {
  263. renderTarget.texture.minFilter = LinearMipMapLinearFilter;
  264. renderTarget.texture.generateMipmaps = true;
  265. }
  266. if ( this.depth === true ) {
  267. renderTarget.depthTexture = new DepthTexture();
  268. }
  269. this.renderTargets.set( camera, renderTarget );
  270. }
  271. return renderTarget;
  272. }
  273. updateBefore( frame ) {
  274. if ( this.bounces === false && _inReflector ) return false;
  275. _inReflector = true;
  276. const { scene, camera, renderer, material } = frame;
  277. const { target } = this;
  278. const virtualCamera = this.getVirtualCamera( camera );
  279. const renderTarget = this.getRenderTarget( virtualCamera );
  280. renderer.getDrawingBufferSize( _size );
  281. this._updateResolution( renderTarget, renderer );
  282. //
  283. _reflectorWorldPosition.setFromMatrixPosition( target.matrixWorld );
  284. _cameraWorldPosition.setFromMatrixPosition( camera.matrixWorld );
  285. _rotationMatrix.extractRotation( target.matrixWorld );
  286. _normal.set( 0, 0, 1 );
  287. _normal.applyMatrix4( _rotationMatrix );
  288. _view.subVectors( _reflectorWorldPosition, _cameraWorldPosition );
  289. // Avoid rendering when reflector is facing away
  290. if ( _view.dot( _normal ) > 0 ) return;
  291. _view.reflect( _normal ).negate();
  292. _view.add( _reflectorWorldPosition );
  293. _rotationMatrix.extractRotation( camera.matrixWorld );
  294. _lookAtPosition.set( 0, 0, - 1 );
  295. _lookAtPosition.applyMatrix4( _rotationMatrix );
  296. _lookAtPosition.add( _cameraWorldPosition );
  297. _target.subVectors( _reflectorWorldPosition, _lookAtPosition );
  298. _target.reflect( _normal ).negate();
  299. _target.add( _reflectorWorldPosition );
  300. //
  301. virtualCamera.coordinateSystem = camera.coordinateSystem;
  302. virtualCamera.position.copy( _view );
  303. virtualCamera.up.set( 0, 1, 0 );
  304. virtualCamera.up.applyMatrix4( _rotationMatrix );
  305. virtualCamera.up.reflect( _normal );
  306. virtualCamera.lookAt( _target );
  307. virtualCamera.near = camera.near;
  308. virtualCamera.far = camera.far;
  309. virtualCamera.updateMatrixWorld();
  310. virtualCamera.projectionMatrix.copy( camera.projectionMatrix );
  311. // Now update projection matrix with new clip plane, implementing code from: http://www.terathon.com/code/oblique.html
  312. // Paper explaining this technique: http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
  313. _reflectorPlane.setFromNormalAndCoplanarPoint( _normal, _reflectorWorldPosition );
  314. _reflectorPlane.applyMatrix4( virtualCamera.matrixWorldInverse );
  315. clipPlane.set( _reflectorPlane.normal.x, _reflectorPlane.normal.y, _reflectorPlane.normal.z, _reflectorPlane.constant );
  316. const projectionMatrix = virtualCamera.projectionMatrix;
  317. _q.x = ( Math.sign( clipPlane.x ) + projectionMatrix.elements[ 8 ] ) / projectionMatrix.elements[ 0 ];
  318. _q.y = ( Math.sign( clipPlane.y ) + projectionMatrix.elements[ 9 ] ) / projectionMatrix.elements[ 5 ];
  319. _q.z = - 1.0;
  320. _q.w = ( 1.0 + projectionMatrix.elements[ 10 ] ) / projectionMatrix.elements[ 14 ];
  321. // Calculate the scaled plane vector
  322. clipPlane.multiplyScalar( 1.0 / clipPlane.dot( _q ) );
  323. const clipBias = 0;
  324. // Replacing the third row of the projection matrix
  325. projectionMatrix.elements[ 2 ] = clipPlane.x;
  326. projectionMatrix.elements[ 6 ] = clipPlane.y;
  327. projectionMatrix.elements[ 10 ] = ( renderer.coordinateSystem === WebGPUCoordinateSystem ) ? ( clipPlane.z - clipBias ) : ( clipPlane.z + 1.0 - clipBias );
  328. projectionMatrix.elements[ 14 ] = clipPlane.w;
  329. //
  330. this.textureNode.value = renderTarget.texture;
  331. if ( this.depth === true ) {
  332. this.textureNode.getDepthNode().value = renderTarget.depthTexture;
  333. }
  334. material.visible = false;
  335. const currentRenderTarget = renderer.getRenderTarget();
  336. const currentMRT = renderer.getMRT();
  337. const currentAutoClear = renderer.autoClear;
  338. renderer.setMRT( null );
  339. renderer.setRenderTarget( renderTarget );
  340. renderer.autoClear = true;
  341. renderer.render( scene, virtualCamera );
  342. renderer.setMRT( currentMRT );
  343. renderer.setRenderTarget( currentRenderTarget );
  344. renderer.autoClear = currentAutoClear;
  345. material.visible = true;
  346. _inReflector = false;
  347. }
  348. }
  349. /**
  350. * TSL function for creating a reflector node.
  351. *
  352. * @function
  353. * @param {Object} [parameters={}] - An object holding configuration parameters.
  354. * @param {Object3D} [parameters.target=new Object3D()] - The 3D object the reflector is linked to.
  355. * @param {Number} [parameters.resolution=1] - The resolution scale.
  356. * @param {Boolean} [parameters.generateMipmaps=false] - Whether mipmaps should be generated or not.
  357. * @param {Boolean} [parameters.bounces=true] - Whether reflectors can render other reflector nodes or not.
  358. * @param {Boolean} [parameters.depth=false] - Whether depth data should be generated or not.
  359. * @param {TextureNode} [parameters.defaultTexture] - The default texture node.
  360. * @param {ReflectorBaseNode} [parameters.reflector] - The reflector base node.
  361. * @returns {ReflectorNode}
  362. */
  363. export const reflector = ( parameters ) => nodeObject( new ReflectorNode( parameters ) );
  364. export default ReflectorNode;
粤ICP备19079148号