ScreenNode.js 6.3 KB

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