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.

RootScene.ts 26KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. import {
  2. Color,
  3. EquirectangularReflectionMapping,
  4. EventListener,
  5. IUniform,
  6. Object3D,
  7. Scene,
  8. UVMapping,
  9. Vector3,
  10. } from 'three'
  11. import type {IObject3D, IObjectProcessor} from '../IObject'
  12. import {type ICamera} from '../ICamera'
  13. import {Box3B} from '../../three'
  14. import {AnyOptions, onChange2, onChange3, serialize} from 'ts-browser-helpers'
  15. import {PerspectiveCamera2} from '../camera/PerspectiveCamera2'
  16. import {ThreeSerialization} from '../../utils'
  17. import {ITexture} from '../ITexture'
  18. import {AddObjectOptions, IScene, ISceneEvent, ISceneEventTypes, ISceneSetDirtyOptions, IWidget} from '../IScene'
  19. import {iObjectCommons} from './iObjectCommons'
  20. import {RootSceneImportResult} from '../../assetmanager'
  21. import {uiButton, uiColor, uiConfig, uiFolderContainer, uiImage, UiObjectConfig, uiSlider, uiToggle} from 'uiconfig.js'
  22. import {IGeometry} from '../IGeometry'
  23. export type TCamera = ICamera
  24. @uiFolderContainer('Root Scene')
  25. export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements IScene<ISceneEvent, ISceneEventTypes> {
  26. readonly isRootScene = true
  27. assetType = 'model' as const
  28. uiConfig!: UiObjectConfig
  29. // private _processors = new ObjectProcessorMap<'environment' | 'background'>()
  30. // private _sceneObjects: ISceneObject[] = []
  31. private _mainCamera: TCamera | null = null
  32. /**
  33. * The root object where all imported objects are added.
  34. */
  35. readonly modelRoot: IObject3D
  36. @uiColor<RootScene>('Background Color', (s)=>({
  37. onChange: ()=>s?.onBackgroundChange(),
  38. }))
  39. @serialize() @onChange2(RootScene.prototype.onBackgroundChange)
  40. backgroundColor: Color | null = null // read in three.js WebGLBackground
  41. @onChange2(RootScene.prototype.onBackgroundChange)
  42. @serialize() @uiImage('Background Image')
  43. background: null | Color | ITexture | 'environment' = null
  44. /**
  45. * The intensity for the environment light.
  46. */
  47. @serialize() @onChange3(RootScene.prototype.setDirty)
  48. @uiSlider('Background Intensity', [0, 10], 0.01)
  49. backgroundIntensity = 1
  50. @uiImage('Environment')
  51. @serialize() @onChange2(RootScene.prototype._onEnvironmentChange)
  52. environment: ITexture | null = null
  53. /**
  54. * The intensity for the environment light.
  55. */
  56. @uiSlider('Environment Intensity', [0, 10], 0.01)
  57. @serialize() @onChange3(RootScene.prototype.setDirty)
  58. envMapIntensity = 1
  59. /**
  60. * Fixed direction environment reflections irrespective of camera position.
  61. */
  62. @uiToggle('Fixed Env Direction')
  63. @serialize() @onChange3(RootScene.prototype.setDirty)
  64. fixedEnvMapDirection = false
  65. /**
  66. * The default camera in the scene
  67. */
  68. @uiConfig() @serialize() readonly defaultCamera: TCamera
  69. // private _environmentLight?: IEnvironmentLight
  70. // required just because we don't want activeCamera to be null.
  71. private _dummyCam = new PerspectiveCamera2('') as TCamera
  72. get mainCamera(): TCamera {
  73. return this._mainCamera || this._dummyCam
  74. }
  75. set mainCamera(camera: TCamera | undefined) {
  76. const cam = this.mainCamera
  77. if (!camera) camera = this.defaultCamera
  78. if (cam === camera) return
  79. if (cam) {
  80. cam.deactivateMain(undefined, true)
  81. cam.removeEventListener('cameraUpdate', this._mainCameraUpdate)
  82. }
  83. if (camera) {
  84. this._mainCamera = camera
  85. camera.addEventListener('cameraUpdate', this._mainCameraUpdate)
  86. camera.activateMain(undefined, true)
  87. } else {
  88. this._mainCamera = null
  89. }
  90. this.dispatchEvent({type: 'activeCameraChange', lastCamera: cam, camera}) // deprecated
  91. this.dispatchEvent({type: 'mainCameraChange', lastCamera: cam, camera})
  92. this.setDirty()
  93. }
  94. private _renderCamera: TCamera | undefined
  95. get renderCamera() {
  96. return this._renderCamera ?? this.mainCamera
  97. }
  98. set renderCamera(camera: TCamera) {
  99. const cam = this._renderCamera
  100. this._renderCamera = camera
  101. this.dispatchEvent({type: 'renderCameraChange', lastCamera: cam, camera})
  102. }
  103. /**
  104. * Create a scene instance. This is done automatically in the {@link ThreeViewer} and must not be created separately.
  105. * @param camera
  106. * @param objectProcessor
  107. */
  108. constructor(camera: TCamera, objectProcessor?: IObjectProcessor) {
  109. super()
  110. this.setDirty = this.setDirty.bind(this)
  111. iObjectCommons.upgradeObject3D.call(this, undefined, objectProcessor)
  112. // this is called from parentDispatch since scene is a parent.
  113. this.addEventListener('materialUpdate', ()=>this.dispatchEvent({type: 'sceneMaterialUpdate'}))
  114. this.addEventListener('objectUpdate', this.refreshScene)
  115. this.addEventListener('geometryUpdate', this.refreshScene)
  116. this.addEventListener('geometryChanged', this.refreshScene)
  117. this.defaultCamera = camera
  118. this.modelRoot = new Object3D() as IObject3D
  119. this.modelRoot.userData.rootSceneModelRoot = true
  120. this.modelRoot.name = 'Scene' // for the UI
  121. // this.modelRoot.addEventListener('update', this.setDirty) // todo: where was this dispatched from/used ?
  122. // eslint-disable-next-line deprecation/deprecation
  123. this.add(this.modelRoot as any)
  124. // this.addSceneObject(this.modelRoot as any, {addToRoot: true, autoScale: false})
  125. // this.addSceneObject(this.defaultCamera, {addToRoot: true})
  126. // eslint-disable-next-line deprecation/deprecation
  127. this.add(this.defaultCamera)
  128. this.mainCamera = this.defaultCamera
  129. // this.boxHelper = new Box3Helper(this.getBounds())
  130. // this.boxHelper.userData.bboxVisible = false
  131. // this.boxHelper.visible = false
  132. // this.add(this.boxHelper)
  133. }
  134. /**
  135. * Add a widget (non-physical/interactive) object to the scene. like gizmos, ui components etc.
  136. * @param model
  137. * @param options
  138. */
  139. // addWidget(model: IWidget, options: AnyOptions = {}): void {
  140. // if (model.assetType !== 'widget') {
  141. // console.warn('Invalid asset type for ', model, ', adding anyway')
  142. // }
  143. // this.add(model.modelObject)
  144. //
  145. // // todo: dispatch event, add event listeners, etc
  146. // }
  147. /**
  148. * Add any object to the scene.
  149. * @param imported
  150. * @param options
  151. */
  152. addObject<T extends IObject3D|Object3D = IObject3D>(imported: T, options?: AddObjectOptions): T&IObject3D {
  153. if (options?.clearSceneObjects || options?.disposeSceneObjects) {
  154. this.clearSceneModels(options.disposeSceneObjects)
  155. }
  156. if (!imported) return imported
  157. if (!imported.isObject3D) {
  158. console.error('Invalid object, cannot add to scene.', imported)
  159. return imported as T&IObject3D
  160. }
  161. this._addObject3D(<IObject3D>imported, options)
  162. this.dispatchEvent({type: 'addSceneObject', object: <IObject3D>imported, options})
  163. return imported as T&IObject3D
  164. }
  165. /**
  166. * Load model root scene exported to GLTF format. Used internally by {@link ThreeViewer.addSceneObject}.
  167. * @param obj
  168. * @param options
  169. */
  170. loadModelRoot(obj: RootSceneImportResult, options?: AddObjectOptions) {
  171. if (options?.clearSceneObjects || options?.disposeSceneObjects) {
  172. this.clearSceneModels(options.disposeSceneObjects)
  173. }
  174. if (!obj.userData?.rootSceneModelRoot) {
  175. console.error('Invalid model root scene object. Trying to add anyway.', obj)
  176. }
  177. if (obj.userData) {
  178. // todo deep merge all userdata?
  179. if (obj.userData.__importData)
  180. this.modelRoot.userData.__importData = {
  181. ...this.modelRoot.userData.__importData,
  182. ...obj.userData.__importData,
  183. }
  184. if (obj.userData.gltfAsset) {
  185. this.modelRoot.userData.__gltfAsset = { // todo: merge values?
  186. ...this.modelRoot.userData.__gltfAsset,
  187. ...obj.userData.gltfAsset,
  188. }
  189. }
  190. if (obj.userData.gltfExtras)
  191. this.modelRoot.userData.__gltfExtras = {
  192. ...this.modelRoot.userData.__gltfExtras,
  193. ...obj.userData.gltfExtras,
  194. }
  195. }
  196. if (obj.userData?.gltfAsset?.copyright) obj.children.forEach(c => !c.userData.license && (c.userData.license = obj.userData.gltfAsset?.copyright))
  197. if (obj.animations) {
  198. if (!this.modelRoot.animations) this.modelRoot.animations = []
  199. for (const animation of obj.animations) {
  200. if (this.modelRoot.animations.includes(animation)) continue
  201. this.modelRoot.animations.push(animation)
  202. }
  203. }
  204. return [...obj.children] // need to clone
  205. .map(c=>this.addObject(c, {...options, clearSceneObjects: false, disposeSceneObjects: false}))
  206. }
  207. private _addObject3D(model: IObject3D|null, {autoCenter = false, centerGeometries = false, centerGeometriesKeepPosition = true, autoScale = false, autoScaleRadius = 2., addToRoot = false, license}: AddObjectOptions = {}): void {
  208. const obj = model
  209. if (!obj) {
  210. console.error('Invalid object, cannot add to scene.')
  211. return
  212. }
  213. // eslint-disable-next-line deprecation/deprecation
  214. if (addToRoot) this.add(obj)
  215. else this.modelRoot.add(obj)
  216. if (autoCenter && !obj.userData.isCentered && !obj.userData.pseudoCentered) { // pseudoCentered is legacy
  217. obj.autoCenter?.()
  218. } else {
  219. obj.userData.isCentered = true // mark as centered, so that autoCenter is not called again when file is reloaded.
  220. }
  221. if (autoScale && !obj.userData.autoScaled) {
  222. obj.autoScale?.(obj.userData.autoScaleRadius || autoScaleRadius)
  223. } else {
  224. obj.userData.autoScaled = true // mark as auto-scaled, so that autoScale is not called again when file is reloaded.
  225. }
  226. if (centerGeometries && !obj.userData.geometriesCentered) {
  227. this.centerAllGeometries(centerGeometriesKeepPosition, obj)
  228. obj.userData.geometriesCentered = true
  229. } else {
  230. obj.userData.geometriesCentered = true // mark as centered, so that geometry center is not called again when file is reloaded.
  231. }
  232. if (license) obj.userData.license = [obj.userData.license, license].filter(v=>v).join(', ')
  233. this.setDirty({refreshScene: true})
  234. }
  235. @uiButton(undefined, {sendArgs: false})
  236. centerAllGeometries(keepPosition = true, obj?: IObject3D) {
  237. const geoms = new Set<IGeometry>()
  238. ;(obj ?? this.modelRoot).traverse((o) => o.geometry && geoms.add(o.geometry))
  239. geoms.forEach(g => g.center(undefined, keepPosition))
  240. }
  241. clearSceneModels(dispose = false, setDirty = true): void {
  242. if (dispose) return this.disposeSceneModels(setDirty)
  243. this.modelRoot.clear()
  244. this.modelRoot.children = []
  245. setDirty && this.setDirty({refreshScene: true})
  246. }
  247. disposeSceneModels(setDirty = true, clear = true) {
  248. if (clear) {
  249. [...this.modelRoot.children].forEach(child => child.dispose ? child.dispose() : child.removeFromParent())
  250. this.modelRoot.clear()
  251. if (setDirty) this.setDirty({refreshScene: true})
  252. } else {
  253. this.modelRoot.children.forEach(child => child.dispose && child.dispose())
  254. }
  255. }
  256. private _onEnvironmentChange() {
  257. // console.warn('environment changed')
  258. if (this.environment?.mapping === UVMapping) {
  259. this.environment.mapping = EquirectangularReflectionMapping // for PMREMGenerator
  260. this.environment.needsUpdate = true
  261. }
  262. this.dispatchEvent({type: 'environmentChanged', environment: this.environment})
  263. this.setDirty({refreshScene: true, geometryChanged: false})
  264. this.refreshUi?.()
  265. }
  266. onBackgroundChange() {
  267. this.dispatchEvent({type: 'backgroundChanged', background: this.background, backgroundColor: this.backgroundColor})
  268. this.setDirty({refreshScene: true, geometryChanged: false})
  269. this.refreshUi?.()
  270. }
  271. /**
  272. * @deprecated Use {@link addObject}
  273. */
  274. add(...object: Object3D[]): this {
  275. super.add(...object)
  276. // this._onSceneUpdate() // this is not needed, since it will be bubbled up from the object3d and we will get event objectUpdate
  277. return this
  278. }
  279. /**
  280. * Sets the backgroundColor property from a string, number or Color, and updates the scene.
  281. * @param color
  282. */
  283. setBackgroundColor(color: string | number | Color | null) {
  284. this.backgroundColor = color ? new Color(color) : null
  285. }
  286. /**
  287. * Mark the scene dirty, and force render in the next frame.
  288. * @param options - set `refreshScene` to true to mark that any object transformations have changed. It might trigger effects like frame fade depening on plugins.
  289. * @returns {this}
  290. */
  291. setDirty(options?: ISceneSetDirtyOptions): this {
  292. // todo: for onChange calls -> check options.key for specific key that's changed and use it to determine refreshScene
  293. if (options?.sceneUpdate) {
  294. console.warn('sceneUpdate is deprecated, use refreshScene instead.')
  295. options.refreshScene = true
  296. }
  297. if (options?.refreshScene) {
  298. this.refreshScene(options)
  299. } else {
  300. this.dispatchEvent({type: 'update'}) // todo remove
  301. iObjectCommons.setDirty.call(this, {...options, scene: this})
  302. } // this sets dirty in the viewer
  303. return this
  304. }
  305. private _mainCameraUpdate = () => {
  306. this.setDirty({refreshScene: false})
  307. this.refreshActiveCameraNearFar()
  308. this.dispatchEvent({type: 'mainCameraUpdate'})
  309. this.dispatchEvent({type: 'activeCameraUpdate'}) // deprecated
  310. }
  311. // cached values
  312. private _sceneBounds: Box3B = new Box3B
  313. private _sceneBoundingRadius = 0
  314. /**
  315. * For visualizing the scene bounds. API incomplete.
  316. * @type {Box3Helper}
  317. */
  318. // readonly boxHelper: Box3Helper
  319. refreshScene(event?: Partial<ISceneEvent> & ISceneSetDirtyOptions): this {
  320. if (event && event.type === 'objectUpdate' && event.object === this) return this // ignore self
  321. if (event?.sceneUpdate === false || event?.refreshScene === false) return this.setDirty(event) // so that it doesn't trigger frame fade, shadow refresh etc
  322. // console.warn(event)
  323. this.refreshActiveCameraNearFar()
  324. this._sceneBounds = this.getBounds(false, true)
  325. // this.boxHelper?.boxHelper?.copy?.(this._sceneBounds)
  326. this._sceneBoundingRadius = this._sceneBounds.getSize(new Vector3()).length() / 2.
  327. this.dispatchEvent({...event, type: 'sceneUpdate', hierarchyChanged: ['addedToParent', 'removedFromParent'].includes(event?.change || '')})
  328. iObjectCommons.setDirty.call(this, event)
  329. return this
  330. }
  331. refreshUi = iObjectCommons.refreshUi.bind(this)
  332. /**
  333. * Dispose the scene and clear all resources.
  334. * @warn Not fully implemented yet, just clears the scene.
  335. */
  336. dispose(clear = true): void {
  337. this.disposeSceneModels(false, clear)
  338. if (clear) {
  339. [...this.children].forEach(child => child.dispose ? child.dispose() : child.removeFromParent())
  340. this.clear()
  341. }
  342. // todo: dispose more stuff?
  343. this.environment?.dispose()
  344. if ((this.background as ITexture)?.isTexture) (this.background as ITexture)?.dispose?.()
  345. if (clear) {
  346. this.environment = null
  347. this.background = null
  348. }
  349. return
  350. }
  351. /**
  352. * Returns the bounding box of the scene model root.
  353. * @param precise
  354. * @param ignoreInvisible
  355. * @param ignoreWidgets
  356. * @param ignoreObject
  357. * @returns {Box3B}
  358. */
  359. getBounds(precise = false, ignoreInvisible = true, ignoreWidgets = true, ignoreObject?: (obj: Object3D)=>boolean): Box3B {
  360. // See bboxVisible in userdata in Box3B
  361. return new Box3B().expandByObject(this, precise, ignoreInvisible, (o: any)=>{
  362. if (ignoreWidgets && ((o as IWidget).isWidget || o.assetType === 'widget')) return true
  363. return ignoreObject?.(o) ?? false
  364. })
  365. }
  366. private _v1 = new Vector3()
  367. private _v2 = new Vector3()
  368. /**
  369. * For Programmatically toggling autoNearFar. This property is not supposed to be in the UI or serialized.
  370. * Use camera.userData.autoNearFar for UI and serialization
  371. * This is used in PickingPlugin
  372. * autoNearFar will still be disabled if this is true and camera.userData.autoNearFar is false
  373. */
  374. autoNearFarEnabled = true
  375. /**
  376. * Refreshes the scene active camera near far values, based on the scene bounding box.
  377. * This is called automatically every time the camera is updated.
  378. */
  379. refreshActiveCameraNearFar(): void {
  380. const camera = this.mainCamera as TCamera
  381. if (!camera) return
  382. if (!this.autoNearFarEnabled || camera.userData.autoNearFar === false) {
  383. camera.near = camera.userData.minNearPlane ?? 0.5
  384. camera.far = camera.userData.maxFarPlane ?? 1000
  385. return
  386. }
  387. // todo check if this takes too much time with large scenes(when moving the camera and not animating), but we also need to support animations
  388. const bbox = this.getBounds(false) // todo: can we use this._sceneBounds or will it have some issue with animation?
  389. camera.getWorldPosition(this._v1).sub(bbox.getCenter(this._v2))
  390. const radius = 1.5 * bbox.getSize(this._v2).length() / 2.
  391. const dist = this._v1.length()
  392. // new way
  393. const dist1 = Math.max(0.1, -this._v1.normalize().dot(camera.getWorldDirection(new Vector3())))
  394. const near = Math.max(Math.max(camera.userData.minNearPlane ?? 0.5, 0.001), dist1 * (dist - radius))
  395. const far = Math.min(Math.max(near + radius, dist1 * (dist + radius)), camera.userData.maxFarPlane ?? 1000)
  396. // old way, has issues when panning very far from the camera target
  397. // const near = Math.max(camera.userData.minNearPlane ?? 0.2, dist - radius)
  398. // const far = Math.min(Math.max(near + 1, dist + radius), camera.userData.maxFarPlane ?? 1000)
  399. camera.near = near
  400. camera.far = far
  401. // todo try using minimum of all 6 endpoints of bbox.
  402. // camera.near = 3
  403. // camera.far = 20
  404. }
  405. updateShaderProperties(material: {defines: Record<string, string|number|undefined>, uniforms: {[name: string]: IUniform}}): this {
  406. if (material.uniforms.sceneBoundingRadius) material.uniforms.sceneBoundingRadius.value = this._sceneBoundingRadius
  407. else console.warn('RootScene: no uniform: sceneBoundingRadius')
  408. return this
  409. }
  410. /**
  411. * Serialize the scene properties
  412. * @param meta
  413. * @returns {any}
  414. */
  415. toJSON(meta?: any): any {
  416. const o = ThreeSerialization.Serialize(this, meta, true)
  417. // console.log(o)
  418. return o
  419. }
  420. /**
  421. * Deserialize the scene properties
  422. * @param json - object from {@link toJSON}
  423. * @param meta
  424. * @returns {this<TCamera>}
  425. */
  426. fromJSON(json: any, meta?: any): this {
  427. const env = json.environment
  428. if (env !== undefined) {
  429. this.environment = ThreeSerialization.Deserialize(env, this.environment, meta, false)
  430. delete json.environment
  431. }
  432. ThreeSerialization.Deserialize(json, this, meta, true)
  433. json.environment = env
  434. return this
  435. }
  436. addEventListener<T extends ISceneEventTypes>(type: T, listener: EventListener<ISceneEvent, T, this>): void {
  437. if (type === 'activeCameraChange') console.error('activeCameraChange is deprecated. Use mainCameraChange instead.')
  438. if (type === 'activeCameraUpdate') console.error('activeCameraUpdate is deprecated. Use mainCameraUpdate instead.')
  439. if (type === 'sceneMaterialUpdate') console.error('sceneMaterialUpdate is deprecated. Use materialUpdate instead.')
  440. if (type === 'update') console.error('update is deprecated. Use sceneUpdate instead.')
  441. super.addEventListener(type, listener)
  442. }
  443. // region inherited type fixes
  444. // re-declaring from IObject3D because: https://github.com/microsoft/TypeScript/issues/16936
  445. traverse: (callback: (object: IObject3D) => void) => void
  446. traverseVisible: (callback: (object: IObject3D) => void) => void
  447. traverseAncestors: (callback: (object: IObject3D) => void) => void
  448. getObjectById: <T extends IObject3D = IObject3D>(id: number) => T | undefined
  449. getObjectByName: <T extends IObject3D = IObject3D>(name: string) => T | undefined
  450. getObjectByProperty: <T extends IObject3D = IObject3D>(name: string, value: string) => T | undefined
  451. copy: (source: this, recursive?: boolean, ...args: any[]) => this
  452. clone: (recursive?: boolean) => this
  453. remove: (...object: IObject3D[]) => this
  454. dispatchEvent: (event: ISceneEvent) => void
  455. parent: null
  456. children: IObject3D[]
  457. // endregion
  458. // region deprecated
  459. // /**
  460. // * Set the scene environment map, this will be processed with PMREM automatically later.
  461. // * @param asset
  462. // * @returns {void}
  463. // */
  464. // public setEnvironment(asset: ITexture|null|undefined): void {
  465. // if (!asset) {
  466. // // eslint-disable-next-line deprecation/deprecation
  467. // this.environment = null
  468. // this._onEnvironmentChange()
  469. // return
  470. // }
  471. // if (!asset.isTexture) {
  472. // console.error('Unknown Environment type', asset)
  473. // return
  474. // }
  475. // if (asset.mapping === UVMapping) {
  476. // asset.mapping = EquirectangularReflectionMapping // for PMREMGenerator
  477. // asset.needsUpdate = true
  478. // }
  479. // // eslint-disable-next-line deprecation/deprecation
  480. // this.environment = asset
  481. // // eslint-disable-next-line deprecation/deprecation
  482. // // this.background = texture // for testing.
  483. // this._onEnvironmentChange()
  484. // }
  485. //
  486. // /**
  487. // * Get the current scene environment map
  488. // * @returns {ITexture<Texture>}
  489. // */
  490. // getEnvironment(): ITexture | null {
  491. // return this.environment || null
  492. // }
  493. /**
  494. * Find objects by name exact match in the complete hierarchy.
  495. * @deprecated Use {@link getObjectByName} instead.
  496. * @param name - name
  497. * @param parent - optional root node to start search from
  498. * @returns Array of found objects
  499. */
  500. public findObjectsByName(name: string, parent?: IObject3D): IObject3D[] {
  501. const o: IObject3D[] = [];
  502. (parent ?? this).traverse(object => {
  503. if (object.name === name) o.push(object)
  504. })
  505. return o
  506. }
  507. /**
  508. * @deprecated
  509. * Sets the camera pointing towards the object at a specific distance.
  510. * @param rootObject - The object to point at.
  511. * @param centerOffset - The distance offset from the object to point at.
  512. * @param targetOffset - The distance offset for the target from the center of object to point at.
  513. * @param options - Not used yet.
  514. */
  515. resetCamera(rootObject:Object3D|undefined = undefined, centerOffset = new Vector3(1, 1, 1), targetOffset = new Vector3(0, 0, 0)): void {
  516. if (this._mainCamera) {
  517. this.matrixWorldNeedsUpdate = true
  518. this.updateMatrixWorld(true)
  519. const bounds = rootObject ? new Box3B().expandByObject(rootObject, true, true) : this.getBounds(true)
  520. const center = bounds.getCenter(new Vector3())
  521. const radius = bounds.getSize(new Vector3()).length() * 0.5
  522. center.add(targetOffset.clone().multiplyScalar(radius))
  523. this._mainCamera.position = new Vector3( // todo: for nested cameras?
  524. center.x + centerOffset.x * radius,
  525. center.y + centerOffset.y * radius,
  526. center.z + centerOffset.z * radius,
  527. )
  528. this._mainCamera.target = center
  529. // this.scene.mainCamera.controls?.targetOffset.set(0, 0, 0)
  530. this.setDirty()
  531. }
  532. }
  533. /**
  534. * Minimum Camera near plane
  535. * @deprecated - use camera.minNearPlane instead
  536. */
  537. get minNearDistance(): number {
  538. console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead')
  539. return this.mainCamera.userData.minNearPlane ?? 0.02
  540. }
  541. /**
  542. * @deprecated - use camera.minNearPlane instead
  543. */
  544. set minNearDistance(value: number) {
  545. console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead')
  546. if (this.mainCamera)
  547. this.mainCamera.userData.minNearPlane = value
  548. }
  549. /**
  550. * @deprecated
  551. */
  552. get activeCamera(): TCamera {
  553. console.error('activeCamera is deprecated. Use mainCamera instead.')
  554. return this.mainCamera
  555. }
  556. /**
  557. * @deprecated
  558. */
  559. set activeCamera(camera: TCamera | undefined) {
  560. console.error('activeCamera is deprecated. Use mainCamera instead.')
  561. this.mainCamera = camera
  562. }
  563. /**
  564. * Get the threejs scene object
  565. * @deprecated
  566. */
  567. get modelObject(): this {
  568. return this as any
  569. }
  570. /**
  571. * @deprecated use {@link envMapIntensity} instead
  572. */
  573. get environmentIntensity(): number {
  574. return this.envMapIntensity
  575. }
  576. /**
  577. * @deprecated use {@link envMapIntensity} instead
  578. */
  579. set environmentIntensity(value: number) {
  580. this.envMapIntensity = value
  581. }
  582. /**
  583. * Add any processed scene object to the scene.
  584. * @deprecated renamed to {@link addObject}
  585. * @param imported
  586. * @param options
  587. */
  588. addSceneObject<T extends IObject3D|Object3D = IObject3D>(imported: T, options?: AddObjectOptions): T {
  589. return this.addObject(imported, options)
  590. }
  591. /**
  592. * Equivalent to setDirty({refreshScene: true}), dispatches 'sceneUpdate' event with the specified options.
  593. * @deprecated use refreshScene
  594. * @param options
  595. */
  596. updateScene(options?: AnyOptions): this {
  597. console.warn('updateScene is deprecated. Use refreshScene instead')
  598. return this.refreshScene(options || {})
  599. }
  600. /**
  601. * @deprecated renamed to {@link clearSceneModels}
  602. */
  603. removeSceneModels() {
  604. this.clearSceneModels()
  605. }
  606. // endregion
  607. }