threepipe
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

SSAAPlugin.ts 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. import {OrthographicCamera, PerspectiveCamera} from 'three'
  2. import {AViewerPluginSync, ThreeViewer} from '../../viewer'
  3. import {uiFolderContainer, uiSlider, uiToggle} from 'uiconfig.js'
  4. import {IEvent, onChange, serialize} from 'ts-browser-helpers'
  5. import {ICamera, ILight} from '../../core'
  6. import {ProgressivePlugin} from './ProgressivePlugin'
  7. export type SSAAPluginEventTypes = ''
  8. export type TCamera = ICamera & (PerspectiveCamera|OrthographicCamera)
  9. /**
  10. * SSAA Plugin
  11. *
  12. * Jitters the render camera and optionally other cameras in the scene
  13. * to create a super-sampled anti-aliasing effect.
  14. * This is done across multiple frames by integrating with the ProgressivePlugin
  15. * @category Plugins
  16. */
  17. @uiFolderContainer('SSAA Plugin')
  18. export class SSAAPlugin extends AViewerPluginSync<SSAAPluginEventTypes> {
  19. public static readonly PluginType = 'SSAAPlugin'
  20. @serialize() @uiToggle('Enabled')
  21. @onChange(SSAAPlugin.prototype.setDirty)
  22. enabled = true
  23. @serialize() @uiSlider('Renders/Frame', [1, 32], 1)
  24. @onChange(SSAAPlugin.prototype.setDirty)
  25. rendersPerFrame = 1
  26. @serialize() @uiToggle('Render Camera')
  27. @onChange(SSAAPlugin.prototype.setDirty)
  28. jitterRenderCamera = true
  29. @serialize() @uiToggle('Light Cameras')
  30. @onChange(SSAAPlugin.prototype.setDirty)
  31. jitterLightCameras = true
  32. private _hasSetOffsetRC = false
  33. private _hasSetOffsetLC = false
  34. public trackedJitterCameras = new Set<[TCamera, {width: number, height: number}]>() // todo register other cameras and light shadows cameras when added to the scene and changed.
  35. dependencies = [ProgressivePlugin]
  36. constructor(rendersPerFrame = 1) {
  37. super()
  38. this.rendersPerFrame = rendersPerFrame
  39. }
  40. onAdded(viewer: ThreeViewer) {
  41. super.onAdded(viewer)
  42. viewer.addEventListener('preRender', this._preRender)
  43. viewer.addEventListener('postRender', this._postRender)
  44. viewer.scene.addEventListener('addSceneObject', this._addSceneObject)
  45. }
  46. onRemove(viewer: ThreeViewer): void {
  47. viewer.removeEventListener('preRender', this._preRender)
  48. viewer.removeEventListener('postRender', this._postRender)
  49. viewer.scene.removeEventListener('addSceneObject', this._addSceneObject)
  50. return super.onRemove(viewer)
  51. }
  52. setDirty() {
  53. if (!this._viewer) return
  54. this._viewer.rendersPerFrame = this.rendersPerFrame
  55. this._viewer.setDirty()
  56. this.uiConfig?.uiRefresh?.(true, 'postFrame')
  57. }
  58. private _addSceneObject = (event: IEvent<string>)=> {
  59. event.object?.traverse((o: ILight)=>{
  60. if (o && o.shadow && o.shadow.camera && o.shadow.mapSize) {
  61. this.trackedJitterCameras.add([o.shadow.camera as TCamera, o.shadow.mapSize])
  62. }
  63. // if (o?.material) {
  64. // if (o.material.alphaMap) console.log(o.material) //todo why?
  65. // }
  66. })
  67. }
  68. private _jitter(camera: TCamera, size: {
  69. width: number,
  70. height: number
  71. }, frameCount: number) {
  72. if (camera.userData.disableJitter) return
  73. if (camera.userData.__jittered) {
  74. this._viewer?.console.warn('SSAAPlugin: Camera already jittered')
  75. return
  76. }
  77. const sample = {...this.jitterOffsets[frameCount % this.jitterOffsets.length]}
  78. // const sample = {...offsets[Math.floor(Math.random() * (offsets.length - 0.001))]}
  79. // {
  80. // sample.x += 1 * (Math.random() - 0.5)
  81. // sample.y += 1 * (Math.random() - 0.5)
  82. // }
  83. camera.setViewOffset(size.width, size.height, sample.x, sample.y, size.width, size.height)
  84. camera.userData.__jittered = true
  85. }
  86. private _clearJitter(camera: TCamera) {
  87. if (!camera.userData.__jittered) return
  88. camera.clearViewOffset()
  89. delete camera.userData.__jittered
  90. }
  91. private _preRender = ()=> {
  92. const v = this._viewer
  93. if (!v || !this.enabled || v.renderManager.frameCount <= 1) return
  94. this.rendersPerFrame = v.rendersPerFrame // just to sync. todo: should this be here?. ideally there should be a event fired from the viewer when the prop changes
  95. const cam = v.scene.renderCamera as TCamera
  96. if (this.jitterRenderCamera) this._jitter(cam, {
  97. width: v.renderManager.renderSize.x * v.renderManager.renderScale,
  98. height: v.renderManager.renderSize.y * v.renderManager.renderScale,
  99. }, v.renderManager.frameCount)
  100. if (this.jitterLightCameras)
  101. this.trackedJitterCameras.forEach((a) => this._jitter(...a, v.renderManager.frameCount))
  102. this._hasSetOffsetRC = this.jitterRenderCamera
  103. this._hasSetOffsetLC = this.jitterLightCameras
  104. v.renderManager.resetShadows()
  105. }
  106. private _postRender = ()=> {
  107. const v = this._viewer
  108. if (!v) return
  109. if (this._hasSetOffsetRC) {
  110. this._clearJitter(v.scene.renderCamera as TCamera)
  111. this._hasSetOffsetRC = false
  112. }
  113. if (this._hasSetOffsetLC) {
  114. this.trackedJitterCameras.forEach(([camera]) => this._clearJitter(camera))
  115. this._hasSetOffsetLC = false
  116. }
  117. }
  118. jitterOffsets = [
  119. {x: 0, y: 0},
  120. {x: -0.5, y: 0},
  121. {x: -0.375, y: -0.25},
  122. {x: -0.1875, y: -0.125},
  123. {x: -0.125, y: -0.375},
  124. {x: 0.0625, y: -0.0625},
  125. {x: 0.125, y: -0.3125},
  126. {x: 0.375, y: -0.4375},
  127. {x: 0.3125, y: -0.1875},
  128. {x: 0.25, y: 0.0625},
  129. {x: 0.4375, y: 0.25},
  130. {x: 0.1875, y: 0.3125},
  131. {x: 0, y: 0.4375},
  132. {x: -0.0625, y: 0.1875},
  133. {x: -0.25, y: 0.375},
  134. {x: -0.4375, y: 0.5},
  135. {x: -0.3125, y: 0.125},
  136. ]
  137. }