ScreenNode.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. import Node from '../core/Node.js';
  2. import { NodeUpdateType } from '../core/constants.js';
  3. import { uniform } from '../core/UniformNode.js';
  4. import { 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. * @private
  42. * @type {?Node}
  43. * @default null
  44. */
  45. this._output = null;
  46. /**
  47. * This flag can be used for type testing.
  48. *
  49. * @type {boolean}
  50. * @readonly
  51. * @default true
  52. */
  53. this.isViewportNode = true;
  54. }
  55. /**
  56. * This method is overwritten since the node type depends on the selected scope.
  57. *
  58. * @return {('float'|'vec2'|'vec4')} The node type.
  59. */
  60. generateNodeType() {
  61. if ( this.scope === ScreenNode.DPR ) return 'float';
  62. if ( this.scope === ScreenNode.VIEWPORT ) return 'vec4';
  63. else return 'vec2';
  64. }
  65. /**
  66. * This method is overwritten since the node's update type depends on the selected scope.
  67. *
  68. * @return {NodeUpdateType} The update type.
  69. */
  70. getUpdateType() {
  71. let updateType = NodeUpdateType.NONE;
  72. if ( this.scope === ScreenNode.SIZE || this.scope === ScreenNode.VIEWPORT || this.scope === ScreenNode.DPR ) {
  73. updateType = NodeUpdateType.RENDER;
  74. }
  75. this.updateType = updateType;
  76. return updateType;
  77. }
  78. /**
  79. * `ScreenNode` implements {@link Node#update} to retrieve viewport and size information
  80. * from the current renderer.
  81. *
  82. * @param {NodeFrame} frame - A reference to the current node frame.
  83. */
  84. update( { renderer } ) {
  85. const renderTarget = renderer.getRenderTarget();
  86. if ( this.scope === ScreenNode.VIEWPORT ) {
  87. if ( renderTarget !== null ) {
  88. _viewportVec.copy( renderTarget.viewport );
  89. } else {
  90. renderer.getViewport( _viewportVec );
  91. _viewportVec.multiplyScalar( renderer.getPixelRatio() );
  92. }
  93. } else if ( this.scope === ScreenNode.DPR ) {
  94. this._output.value = renderer.getPixelRatio();
  95. } else {
  96. if ( renderTarget !== null ) {
  97. _screenSizeVec.width = renderTarget.width;
  98. _screenSizeVec.height = renderTarget.height;
  99. } else {
  100. renderer.getDrawingBufferSize( _screenSizeVec );
  101. }
  102. }
  103. }
  104. setup( /*builder*/ ) {
  105. const scope = this.scope;
  106. let output = null;
  107. if ( scope === ScreenNode.SIZE ) {
  108. output = uniform( _screenSizeVec || ( _screenSizeVec = new Vector2() ) );
  109. } else if ( scope === ScreenNode.VIEWPORT ) {
  110. output = uniform( _viewportVec || ( _viewportVec = new Vector4() ) );
  111. } else if ( scope === ScreenNode.DPR ) {
  112. output = uniform( 1 );
  113. } else {
  114. output = vec2( screenCoordinate.div( screenSize ) );
  115. }
  116. this._output = output;
  117. return output;
  118. }
  119. generate( builder ) {
  120. if ( this.scope === ScreenNode.COORDINATE ) {
  121. let coord = builder.getFragCoord();
  122. if ( builder.isFlipY() ) {
  123. // follow webgpu standards
  124. const size = builder.getNodeProperties( screenSize ).outputNode.build( builder );
  125. coord = `${ builder.getType( 'vec2' ) }( ${ coord }.x, ${ size }.y - ${ coord }.y )`;
  126. }
  127. return coord;
  128. }
  129. return super.generate( builder );
  130. }
  131. }
  132. ScreenNode.COORDINATE = 'coordinate';
  133. ScreenNode.VIEWPORT = 'viewport';
  134. ScreenNode.SIZE = 'size';
  135. ScreenNode.UV = 'uv';
  136. ScreenNode.DPR = 'dpr';
  137. export default ScreenNode;
  138. // Screen
  139. /**
  140. * TSL object that represents the current DPR.
  141. *
  142. * @tsl
  143. * @type {ScreenNode<float>}
  144. */
  145. export const screenDPR = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.DPR );
  146. /**
  147. * TSL object that represents normalized screen coordinates, unitless in `[0, 1]`.
  148. *
  149. * @tsl
  150. * @type {ScreenNode<vec2>}
  151. */
  152. export const screenUV = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.UV );
  153. /**
  154. * TSL object that represents the screen resolution in physical pixel units.
  155. *
  156. * @tsl
  157. * @type {ScreenNode<vec2>}
  158. */
  159. export const screenSize = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.SIZE );
  160. /**
  161. * TSL object that represents the current `x`/`y` pixel position on the screen in physical pixel units.
  162. *
  163. * @tsl
  164. * @type {ScreenNode<vec2>}
  165. */
  166. export const screenCoordinate = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.COORDINATE );
  167. // Viewport
  168. /**
  169. * TSL object that represents the viewport rectangle as `x`, `y`, `width` and `height` in physical pixel units.
  170. *
  171. * @tsl
  172. * @type {ScreenNode<vec4>}
  173. */
  174. export const viewport = /*@__PURE__*/ nodeImmutable( ScreenNode, ScreenNode.VIEWPORT );
  175. /**
  176. * TSL object that represents the viewport resolution in physical pixel units.
  177. *
  178. * @tsl
  179. * @type {ScreenNode<vec2>}
  180. */
  181. export const viewportSize = viewport.zw;
  182. /**
  183. * TSL object that represents the current `x`/`y` pixel position on the viewport in physical pixel units.
  184. *
  185. * @tsl
  186. * @type {ScreenNode<vec2>}
  187. */
  188. export const viewportCoordinate = /*@__PURE__*/ screenCoordinate.sub( viewport.xy );
  189. /**
  190. * TSL object that represents normalized viewport coordinates, unitless in `[0, 1]`.
  191. *
  192. * @tsl
  193. * @type {ScreenNode<vec2>}
  194. */
  195. export const viewportUV = /*@__PURE__*/ viewportCoordinate.div( viewportSize );
粤ICP备19079148号