threepipe
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import {DataTexture, EquirectangularReflectionMapping, ShaderLib, Vector3} from 'three'
  2. import {onChange, serialize} from 'ts-browser-helpers'
  3. import hdriGroundProj from './HDRiGroundPlugin.glsl'
  4. import {AViewerPluginSync, ThreeViewer} from '../../viewer'
  5. import {shaderReplaceString} from '../../utils'
  6. import {uiPanelContainer, uiSlider, uiToggle, uiVector} from 'uiconfig.js'
  7. @uiPanelContainer('HDRi Ground')
  8. export class HDRiGroundPlugin extends AViewerPluginSync<'', ThreeViewer> {
  9. static readonly PluginType = 'HDRiGroundPlugin'
  10. @serialize()
  11. @onChange(HDRiGroundPlugin.prototype.setDirty)
  12. @uiToggle('Enabled')
  13. enabled = false
  14. @serialize()
  15. @onChange(HDRiGroundPlugin.prototype.setDirty)
  16. @uiSlider('World Radius', [1, 1000], 0.01)
  17. worldRadius = 100
  18. @serialize()
  19. @onChange(HDRiGroundPlugin.prototype.setDirty)
  20. @uiSlider('Tripod height', [0, 50], 0.01)
  21. tripodHeight = 10
  22. @serialize()
  23. @onChange(HDRiGroundPlugin.prototype.setDirty)
  24. @uiVector('Origin Position', undefined, 0.001, (t: HDRiGroundPlugin)=>({
  25. onChange: t.setDirty, // this is for x, y, z values.
  26. }))
  27. originPosition = new Vector3(0, 0, 0)
  28. @serialize()
  29. @onChange(HDRiGroundPlugin.prototype.setDirty)
  30. promptOnBackgroundMismatch = true
  31. // todo
  32. // /**
  33. // * Automatically set the origin position based on the ground position in GroundPlugin
  34. // */
  35. // @serialize()
  36. // @onChange(HDRiGroundPlugin.prototype.setDirty)
  37. // @uiToggle('Auto Ground Position')
  38. // autoGroundPosition = false
  39. constructor(enabled = false, promptOnBackgroundMismatch = true) {
  40. super()
  41. this.setDirty = this.setDirty.bind(this)
  42. this.enabled = enabled
  43. this.promptOnBackgroundMismatch = promptOnBackgroundMismatch
  44. this.addEventListener('deserialize', this.setDirty)
  45. }
  46. setDirty() {
  47. if (!this._viewer) return
  48. const bg = this._viewer.scene.background
  49. if (this.enabled && bg !== this._viewer.scene.environment && bg !== 'environment') {
  50. if (bg && (bg as any).isDataTexture) (bg as DataTexture).mapping = EquirectangularReflectionMapping
  51. else {
  52. const change = this.promptOnBackgroundMismatch ? this._viewer.dialog.confirmSync('Background must be same as environment, do you want to change it?') : true
  53. if (change) {
  54. // const bgui = this._viewer.getPlugin<SimpleBackgroundEnvUiPlugin>('SimpleBackgroundEnvUiPlugin1')
  55. // if (bgui) {
  56. // bgui.envmapBg = true
  57. // bgui.uiConfig.uiRefresh?.(true, 'postFrame')
  58. // } else
  59. this._viewer.scene.background = 'environment'
  60. } else this.enabled = false
  61. }
  62. }
  63. const cubeMat = this._viewer.renderManager.renderer.background.getBoxMesh2()?.material
  64. const unif = cubeMat?.uniforms ?? ShaderLib.backgroundCube.uniforms
  65. if (!unif.tripodHeight) unif.tripodHeight = {value: 1.0}
  66. if (!unif.worldRadius) unif.worldRadius = {value: 1.0}
  67. if (!unif.originPosition) unif.originPosition = {value: new Vector3()}
  68. unif.tripodHeight.value = this.tripodHeight
  69. unif.worldRadius.value = this.worldRadius
  70. unif.originPosition.value.copy(this.originPosition)
  71. if (cubeMat) {
  72. if (this.isDisabled() && cubeMat.defines.HDRi_GROUND_PROJ)
  73. delete cubeMat.defines.HDRi_GROUND_PROJ
  74. else if (!this.isDisabled())
  75. cubeMat.defines.HDRi_GROUND_PROJ = '1'
  76. cubeMat.needsUpdate = true
  77. }
  78. this._viewer.setDirty()
  79. // const m = this._viewer?.scene.modelRoot.children ?? []
  80. // for (const m1 of m) {
  81. // m1.position.y = -this.tripodHeight + new Box3B().expandByObject(m1, true, true).getSize(new Vector3()).y / 2
  82. // }
  83. }
  84. onAdded(viewer: ThreeViewer): void {
  85. super.onAdded(viewer)
  86. if (this._viewer?.renderManager.webglRenderer?.background.getBoxMesh())
  87. viewer.console.error('HDRi Ground Plugin must be added before setting any cube or env map')
  88. if (!ShaderLib.backgroundCube.fragmentShader.includes('#ifdef HDRi_GROUND_PROJ')) {
  89. ShaderLib.backgroundCube.fragmentShader = shaderReplaceString(ShaderLib.backgroundCube.fragmentShader, 'void main() {', hdriGroundProj, {prepend: true})
  90. ShaderLib.backgroundCube.fragmentShader = shaderReplaceString(ShaderLib.backgroundCube.fragmentShader, 'vec3 vReflect = vWorldDirection;', `
  91. vec3 vReflect =
  92. #ifdef HDRi_GROUND_PROJ
  93. hdriProject()
  94. #else
  95. vWorldDirection
  96. #endif
  97. ;
  98. `)
  99. }
  100. viewer.scene.addEventListener('environmentChanged', this.setDirty)
  101. }
  102. }