ScreenNode.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. import Node from '../core/Node.js';
  2. import { NodeUpdateType } from '../core/constants.js';
  3. import { uniform } from '../core/UniformNode.js';
  4. import { Fn, nodeImmutable, vec2 } from '../tsl/TSLBase.js';
  5. import { Vector2 } from '../../math/Vector2.js';
  6. import { Vector4 } from '../../math/Vector4.js';
  7. let _screenSizeVec, _viewportVec;
  8. /**
  9. * This node provides a collection of screen related metrics.
  10. * Depending on {@link ScreenNode#scope}, the nodes can represent
  11. * resolution or viewport data as well as fragment or uv coordinates.
  12. *
  13. * @augments Node
  14. */
  15. class ScreenNode extends Node {
  16. static get type() {
  17. return 'ScreenNode';
  18. }
  19. /**
  20. * Constructs a new screen node.
  21. *
  22. * @param {('coordinate'|'viewport'|'size'|'uv'|'dpr')} scope - The node's scope.
  23. */
  24. constructor( scope ) {
  25. super();
  26. /**
  27. * The node represents different metric depending on which scope is selected.
  28. *
  29. * - `ScreenNode.COORDINATE`: Window-relative coordinates of the current fragment according to WebGPU standards.
  30. * - `ScreenNode.VIEWPORT`: The current viewport defined as a four-dimensional vector.
  31. * - `ScreenNode.SIZE`: The dimensions of the current bound framebuffer.
  32. * - `ScreenNode.UV`: Normalized coordinates.
  33. * - `ScreenNode.DPR`: Device pixel ratio.
  34. *
  35. * @type {('coordinate'|'viewport'|'size'|'uv'|'dpr')}
  36. */
  37. this.scope = scope;
  38. /**
  39. * This output node.
  40. *
  41. * @type {?Node}
  42. * @default null
  43. */
  44. this._output = null;
  45. /**
  46. * This flag can be used for type testing.
  47. *
  48. * @type {boolean}
  49. * @readonly
  50. * @default true
  51. */
  52. this.isViewportNode = true;
  53. }
  54. /**
  55. * This method is overwritten since the node type depends on the selected scope.
  56. *
  57. * @return {('float'|'vec2'|'vec4')} The node type.
  58. */
  59. getNodeType() {
  60. if ( this.scope === ScreenNode.DPR ) return 'float';
  61. if ( this.scope === ScreenNode.VIEWPORT ) return 'vec4';
  62. else return 'vec2';
  63. }
  64. /**
  65. * This method is overwritten since the node's update type depends on the selected scope.
  66. *
  67. * @return {NodeUpdateType} The update type.
  68. */
  69. getUpdateType() {
  70. let updateType = NodeUpdateType.NONE;
  71. if ( this.scope === ScreenNode.SIZE || this.scope === ScreenNode.VIEWPORT || this.scope === ScreenNode.DPR ) {
  72. updateType = NodeUpdateType.RENDER;
  73. }
  74. this.updateType = updateType;
  75. return updateType;
  76. }
  77. /**
  78. * `ScreenNode` implements {@link Node#update} to retrieve viewport and size information
  79. * from the current renderer.
  80. *
  81. * @param {NodeFrame} frame - A reference to the current node frame.
  82. */
  83. update( { renderer } ) {
  84. const renderTarget = renderer.getRenderTarget();
  85. if ( this.scope === ScreenNode.VIEWPORT ) {
  86. if ( renderTarget !== null ) {
  87. _viewportVec.copy( renderTarget.viewport );
  88. } else {
  89. renderer.getViewport( _viewportVec );
  90. _viewportVec.multiplyScalar( renderer.getPixelRatio() );
  91. }
  92. } else if ( this.scope === ScreenNode.DPR ) {
  93. this._output.value = renderer.getPixelRatio();
  94. } else {
  95. if ( renderTarget !== null ) {
  96. _screenSizeVec.width = renderTarget.width;
  97. _screenSizeVec.height = renderTarget.height;
  98. } else {
  99. renderer.getDrawingBufferSize( _screenSizeVec );
  100. }
  101. }
  102. }
  103. setup( /*builder*/ ) {
  104. const scope = this.scope;
  105. let output = null;
  106. if ( scope === ScreenNode.SIZE ) {
  107. output = uniform( _screenSizeVec || ( _screenSizeVec = new Vector2() ) );
  108. } else if ( scope === ScreenNode.VIEWPORT ) {
  109. output = uniform( _viewportVec || ( _viewportVec = new Vector4() ) );
  110. } else if ( scope === ScreenNode.DPR ) {
  111. output = uniform( 1 );
  112. } else {
  113. output = vec2( screenCoordinate.div( screenSize ) );
  114. }
  115. this._output = output;
  116. return output;
  117. }
  118. generate( builder ) {
  119. if ( this.scope === ScreenNode.COORDINATE ) {
  120. let coord = builder.getFragCoord();
  121. if ( builder.isFlipY() ) {
  122. // follow webgpu standards
  123. const size = builder.getNodeProperties( screenSize ).outputNode.build( builder );
  124. coord = `${ builder.getType( 'vec2' ) }( ${ coord }.x, ${ size }.y - ${ coord }.y )`;
  125. }
  126. return coord;
  127. }
  128. return super.generate( builder );
  129. }
  130. }
  131. ScreenNode.COORDINATE = 'coordinate';
  132. ScreenNode.VIEWPORT = 'viewport';
  133. ScreenNode.SIZE = 'size';
  134. ScreenNode.UV = 'uv';
  135. ScreenNode.DPR = 'dpr';
  136. export default ScreenNode;
  137. // Screen
  138. /**
  139. * TSL object that represents the current DPR.
  140. *
  141. * @tsl
  142. * @type {ScreenNode<float>}
  143. */
  144. export const screenDPR = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.DPR );
  145. /**
  146. * TSL object that represents normalized screen coordinates, unitless in `[0, 1]`.
  147. *
  148. * @tsl
  149. * @type {ScreenNode<vec2>}
  150. */
  151. export const screenUV = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.UV );
  152. /**
  153. * TSL object that represents the screen resolution in physical pixel units.
  154. *
  155. * @tsl
  156. * @type {ScreenNode<vec2>}
  157. */
  158. export const screenSize = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.SIZE );
  159. /**
  160. * TSL object that represents the current `x`/`y` pixel position on the screen in physical pixel units.
  161. *
  162. * @tsl
  163. * @type {ScreenNode<vec2>}
  164. */
  165. export const screenCoordinate = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.COORDINATE );
  166. // Viewport
  167. /**
  168. * TSL object that represents the viewport rectangle as `x`, `y`, `width` and `height` in physical pixel units.
  169. *
  170. * @tsl
  171. * @type {ScreenNode<vec4>}
  172. */
  173. export const viewport = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.VIEWPORT );
  174. /**
  175. * TSL object that represents the viewport resolution in physical pixel units.
  176. *
  177. * @tsl
  178. * @type {ScreenNode<vec2>}
  179. */
  180. export const viewportSize = viewport.zw;
  181. /**
  182. * TSL object that represents the current `x`/`y` pixel position on the viewport in physical pixel units.
  183. *
  184. * @tsl
  185. * @type {ScreenNode<vec2>}
  186. */
  187. export const viewportCoordinate = /*@__PURE__*/ screenCoordinate.sub( viewport.xy );
  188. /**
  189. * TSL object that represents normalized viewport coordinates, unitless in `[0, 1]`.
  190. *
  191. * @tsl
  192. * @type {ScreenNode<vec2>}
  193. */
  194. export const viewportUV = /*@__PURE__*/ viewportCoordinate.div( viewportSize );
  195. // Deprecated
  196. /**
  197. * @deprecated since r169. Use {@link screenSize} instead.
  198. */
  199. export const viewportResolution = /*@__PURE__*/ ( Fn( () => { // @deprecated, r169
  200. console.warn( 'THREE.TSL: "viewportResolution" is deprecated. Use "screenSize" instead.' );
  201. return screenSize;
  202. }, 'vec2' ).once() )();
粤ICP备19079148号