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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  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()
  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) {
  248. [...this.modelRoot.children].forEach(child => child.dispose ? child.dispose() : child.removeFromParent())
  249. this.modelRoot.clear()
  250. if (setDirty) this.setDirty({refreshScene: true})
  251. }
  252. private _onEnvironmentChange() {
  253. // console.warn('environment changed')
  254. if (this.environment?.mapping === UVMapping) {
  255. this.environment.mapping = EquirectangularReflectionMapping // for PMREMGenerator
  256. this.environment.needsUpdate = true
  257. }
  258. this.dispatchEvent({type: 'environmentChanged', environment: this.environment})
  259. this.setDirty({refreshScene: true, geometryChanged: false})
  260. this.refreshUi?.()
  261. }
  262. onBackgroundChange() {
  263. this.dispatchEvent({type: 'backgroundChanged', background: this.background, backgroundColor: this.backgroundColor})
  264. this.setDirty({refreshScene: true, geometryChanged: false})
  265. this.refreshUi?.()
  266. }
  267. /**
  268. * @deprecated Use {@link addObject}
  269. */
  270. add(...object: Object3D[]): this {
  271. super.add(...object)
  272. // this._onSceneUpdate() // this is not needed, since it will be bubbled up from the object3d and we will get event objectUpdate
  273. return this
  274. }
  275. /**
  276. * Sets the backgroundColor property from a string, number or Color, and updates the scene.
  277. * @param color
  278. */
  279. setBackgroundColor(color: string | number | Color | null) {
  280. this.backgroundColor = color ? new Color(color) : null
  281. }
  282. /**
  283. * Mark the scene dirty, and force render in the next frame.
  284. * @param options - set `refreshScene` to true to mark that any object transformations have changed. It might trigger effects like frame fade depening on plugins.
  285. * @returns {this}
  286. */
  287. setDirty(options?: ISceneSetDirtyOptions): this {
  288. // todo: for onChange calls -> check options.key for specific key that's changed and use it to determine refreshScene
  289. if (options?.sceneUpdate) {
  290. console.warn('sceneUpdate is deprecated, use refreshScene instead.')
  291. options.refreshScene = true
  292. }
  293. if (options?.refreshScene) {
  294. this.refreshScene(options)
  295. } else {
  296. this.dispatchEvent({type: 'update'}) // todo remove
  297. iObjectCommons.setDirty.call(this, {...options, scene: this})
  298. } // this sets dirty in the viewer
  299. return this
  300. }
  301. private _mainCameraUpdate = () => {
  302. this.setDirty({refreshScene: false})
  303. this.refreshActiveCameraNearFar()
  304. this.dispatchEvent({type: 'mainCameraUpdate'})
  305. this.dispatchEvent({type: 'activeCameraUpdate'}) // deprecated
  306. }
  307. // cached values
  308. private _sceneBounds: Box3B = new Box3B
  309. private _sceneBoundingRadius = 0
  310. /**
  311. * For visualizing the scene bounds. API incomplete.
  312. * @type {Box3Helper}
  313. */
  314. // readonly boxHelper: Box3Helper
  315. refreshScene(event?: Partial<ISceneEvent> & ISceneSetDirtyOptions): this {
  316. if (event && event.type === 'objectUpdate' && event.object === this) return this // ignore self
  317. if (event?.sceneUpdate === false || event?.refreshScene === false) return this.setDirty(event) // so that it doesn't trigger frame fade, shadow refresh etc
  318. // console.warn(event)
  319. this.refreshActiveCameraNearFar()
  320. this._sceneBounds = this.getBounds(false, true)
  321. // this.boxHelper?.boxHelper?.copy?.(this._sceneBounds)
  322. this._sceneBoundingRadius = this._sceneBounds.getSize(new Vector3()).length() / 2.
  323. this.dispatchEvent({...event, type: 'sceneUpdate', hierarchyChanged: ['addedToParent', 'removedFromParent'].includes(event?.change || '')})
  324. iObjectCommons.setDirty.call(this, event)
  325. return this
  326. }
  327. refreshUi = iObjectCommons.refreshUi.bind(this)
  328. /**
  329. * Dispose the scene and clear all resources.
  330. * @warn Not fully implemented yet, just clears the scene.
  331. */
  332. dispose(): void {
  333. this.disposeSceneModels();
  334. [...this.children].forEach(child => child.dispose ? child.dispose() : child.removeFromParent())
  335. this.clear()
  336. // todo: dispose more stuff?
  337. this.environment?.dispose()
  338. if ((this.background as ITexture)?.isTexture) (this.background as ITexture)?.dispose?.()
  339. this.environment = null
  340. this.background = null
  341. return
  342. }
  343. /**
  344. * Returns the bounding box of the scene model root.
  345. * @param precise
  346. * @param ignoreInvisible
  347. * @param ignoreWidgets
  348. * @param ignoreObject
  349. * @returns {Box3B}
  350. */
  351. getBounds(precise = false, ignoreInvisible = true, ignoreWidgets = true, ignoreObject?: (obj: Object3D)=>boolean): Box3B {
  352. // See bboxVisible in userdata in Box3B
  353. return new Box3B().expandByObject(this, precise, ignoreInvisible, (o: any)=>{
  354. if (ignoreWidgets && ((o as IWidget).isWidget || o.assetType === 'widget')) return true
  355. return ignoreObject?.(o) ?? false
  356. })
  357. }
  358. private _v1 = new Vector3()
  359. private _v2 = new Vector3()
  360. /**
  361. * For Programmatically toggling autoNearFar. This property is not supposed to be in the UI or serialized.
  362. * Use camera.userData.autoNearFar for UI and serialization
  363. * This is used in PickingPlugin
  364. * autoNearFar will still be disabled if this is true and camera.userData.autoNearFar is false
  365. */
  366. autoNearFarEnabled = true
  367. /**
  368. * Refreshes the scene active camera near far values, based on the scene bounding box.
  369. * This is called automatically every time the camera is updated.
  370. */
  371. refreshActiveCameraNearFar(): void {
  372. const camera = this.mainCamera as TCamera
  373. if (!camera) return
  374. if (!this.autoNearFarEnabled || camera.userData.autoNearFar === false) {
  375. camera.near = camera.userData.minNearPlane ?? 0.5
  376. camera.far = camera.userData.maxFarPlane ?? 1000
  377. return
  378. }
  379. // 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
  380. const bbox = this.getBounds(false) // todo: can we use this._sceneBounds or will it have some issue with animation?
  381. camera.getWorldPosition(this._v1).sub(bbox.getCenter(this._v2))
  382. const radius = 1.5 * bbox.getSize(this._v2).length() / 2.
  383. const dist = this._v1.length()
  384. // new way
  385. const dist1 = Math.max(0.1, -this._v1.normalize().dot(camera.getWorldDirection(new Vector3())))
  386. const near = Math.max(Math.max(camera.userData.minNearPlane ?? 0.5, 0.001), dist1 * (dist - radius))
  387. const far = Math.min(Math.max(near + radius, dist1 * (dist + radius)), camera.userData.maxFarPlane ?? 1000)
  388. // old way, has issues when panning very far from the camera target
  389. // const near = Math.max(camera.userData.minNearPlane ?? 0.2, dist - radius)
  390. // const far = Math.min(Math.max(near + 1, dist + radius), camera.userData.maxFarPlane ?? 1000)
  391. camera.near = near
  392. camera.far = far
  393. // todo try using minimum of all 6 endpoints of bbox.
  394. // camera.near = 3
  395. // camera.far = 20
  396. }
  397. updateShaderProperties(material: {defines: Record<string, string|number|undefined>, uniforms: {[name: string]: IUniform}}): this {
  398. if (material.uniforms.sceneBoundingRadius) material.uniforms.sceneBoundingRadius.value = this._sceneBoundingRadius
  399. else console.warn('RootScene: no uniform: sceneBoundingRadius')
  400. return this
  401. }
  402. /**
  403. * Serialize the scene properties
  404. * @param meta
  405. * @returns {any}
  406. */
  407. toJSON(meta?: any): any {
  408. const o = ThreeSerialization.Serialize(this, meta, true)
  409. // console.log(o)
  410. return o
  411. }
  412. /**
  413. * Deserialize the scene properties
  414. * @param json - object from {@link toJSON}
  415. * @param meta
  416. * @returns {this<TCamera>}
  417. */
  418. fromJSON(json: any, meta?: any): this {
  419. const env = json.environment
  420. if (env !== undefined) {
  421. this.environment = ThreeSerialization.Deserialize(env, this.environment, meta, false)
  422. delete json.environment
  423. }
  424. ThreeSerialization.Deserialize(json, this, meta, true)
  425. json.environment = env
  426. return this
  427. }
  428. addEventListener<T extends ISceneEventTypes>(type: T, listener: EventListener<ISceneEvent, T, this>): void {
  429. if (type === 'activeCameraChange') console.error('activeCameraChange is deprecated. Use mainCameraChange instead.')
  430. if (type === 'activeCameraUpdate') console.error('activeCameraUpdate is deprecated. Use mainCameraUpdate instead.')
  431. if (type === 'sceneMaterialUpdate') console.error('sceneMaterialUpdate is deprecated. Use materialUpdate instead.')
  432. if (type === 'update') console.error('update is deprecated. Use sceneUpdate instead.')
  433. super.addEventListener(type, listener)
  434. }
  435. // region inherited type fixes
  436. // re-declaring from IObject3D because: https://github.com/microsoft/TypeScript/issues/16936
  437. traverse: (callback: (object: IObject3D) => void) => void
  438. traverseVisible: (callback: (object: IObject3D) => void) => void
  439. traverseAncestors: (callback: (object: IObject3D) => void) => void
  440. getObjectById: <T extends IObject3D = IObject3D>(id: number) => T | undefined
  441. getObjectByName: <T extends IObject3D = IObject3D>(name: string) => T | undefined
  442. getObjectByProperty: <T extends IObject3D = IObject3D>(name: string, value: string) => T | undefined
  443. copy: (source: this, recursive?: boolean, ...args: any[]) => this
  444. clone: (recursive?: boolean) => this
  445. remove: (...object: IObject3D[]) => this
  446. dispatchEvent: (event: ISceneEvent) => void
  447. parent: null
  448. children: IObject3D[]
  449. // endregion
  450. // region deprecated
  451. // /**
  452. // * Set the scene environment map, this will be processed with PMREM automatically later.
  453. // * @param asset
  454. // * @returns {void}
  455. // */
  456. // public setEnvironment(asset: ITexture|null|undefined): void {
  457. // if (!asset) {
  458. // // eslint-disable-next-line deprecation/deprecation
  459. // this.environment = null
  460. // this._onEnvironmentChange()
  461. // return
  462. // }
  463. // if (!asset.isTexture) {
  464. // console.error('Unknown Environment type', asset)
  465. // return
  466. // }
  467. // if (asset.mapping === UVMapping) {
  468. // asset.mapping = EquirectangularReflectionMapping // for PMREMGenerator
  469. // asset.needsUpdate = true
  470. // }
  471. // // eslint-disable-next-line deprecation/deprecation
  472. // this.environment = asset
  473. // // eslint-disable-next-line deprecation/deprecation
  474. // // this.background = texture // for testing.
  475. // this._onEnvironmentChange()
  476. // }
  477. //
  478. // /**
  479. // * Get the current scene environment map
  480. // * @returns {ITexture<Texture>}
  481. // */
  482. // getEnvironment(): ITexture | null {
  483. // return this.environment || null
  484. // }
  485. /**
  486. * Find objects by name exact match in the complete hierarchy.
  487. * @deprecated Use {@link getObjectByName} instead.
  488. * @param name - name
  489. * @param parent - optional root node to start search from
  490. * @returns Array of found objects
  491. */
  492. public findObjectsByName(name: string, parent?: IObject3D): IObject3D[] {
  493. const o: IObject3D[] = [];
  494. (parent ?? this).traverse(object => {
  495. if (object.name === name) o.push(object)
  496. })
  497. return o
  498. }
  499. /**
  500. * @deprecated
  501. * Sets the camera pointing towards the object at a specific distance.
  502. * @param rootObject - The object to point at.
  503. * @param centerOffset - The distance offset from the object to point at.
  504. * @param targetOffset - The distance offset for the target from the center of object to point at.
  505. * @param options - Not used yet.
  506. */
  507. resetCamera(rootObject:Object3D|undefined = undefined, centerOffset = new Vector3(1, 1, 1), targetOffset = new Vector3(0, 0, 0)): void {
  508. if (this._mainCamera) {
  509. this.matrixWorldNeedsUpdate = true
  510. this.updateMatrixWorld(true)
  511. const bounds = rootObject ? new Box3B().expandByObject(rootObject, true, true) : this.getBounds(true)
  512. const center = bounds.getCenter(new Vector3())
  513. const radius = bounds.getSize(new Vector3()).length() * 0.5
  514. center.add(targetOffset.clone().multiplyScalar(radius))
  515. this._mainCamera.position = new Vector3( // todo: for nested cameras?
  516. center.x + centerOffset.x * radius,
  517. center.y + centerOffset.y * radius,
  518. center.z + centerOffset.z * radius,
  519. )
  520. this._mainCamera.target = center
  521. // this.scene.mainCamera.controls?.targetOffset.set(0, 0, 0)
  522. this.setDirty()
  523. }
  524. }
  525. /**
  526. * Minimum Camera near plane
  527. * @deprecated - use camera.minNearPlane instead
  528. */
  529. get minNearDistance(): number {
  530. console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead')
  531. return this.mainCamera.userData.minNearPlane ?? 0.02
  532. }
  533. /**
  534. * @deprecated - use camera.minNearPlane instead
  535. */
  536. set minNearDistance(value: number) {
  537. console.error('minNearDistance is deprecated. Use camera.userData.minNearPlane instead')
  538. if (this.mainCamera)
  539. this.mainCamera.userData.minNearPlane = value
  540. }
  541. /**
  542. * @deprecated
  543. */
  544. get activeCamera(): TCamera {
  545. console.error('activeCamera is deprecated. Use mainCamera instead.')
  546. return this.mainCamera
  547. }
  548. /**
  549. * @deprecated
  550. */
  551. set activeCamera(camera: TCamera | undefined) {
  552. console.error('activeCamera is deprecated. Use mainCamera instead.')
  553. this.mainCamera = camera
  554. }
  555. /**
  556. * Get the threejs scene object
  557. * @deprecated
  558. */
  559. get modelObject(): this {
  560. return this as any
  561. }
  562. /**
  563. * @deprecated use {@link envMapIntensity} instead
  564. */
  565. get environmentIntensity(): number {
  566. return this.envMapIntensity
  567. }
  568. /**
  569. * @deprecated use {@link envMapIntensity} instead
  570. */
  571. set environmentIntensity(value: number) {
  572. this.envMapIntensity = value
  573. }
  574. /**
  575. * Add any processed scene object to the scene.
  576. * @deprecated renamed to {@link addObject}
  577. * @param imported
  578. * @param options
  579. */
  580. addSceneObject<T extends IObject3D|Object3D = IObject3D>(imported: T, options?: AddObjectOptions): T {
  581. return this.addObject(imported, options)
  582. }
  583. /**
  584. * Equivalent to setDirty({refreshScene: true}), dispatches 'sceneUpdate' event with the specified options.
  585. * @deprecated use refreshScene
  586. * @param options
  587. */
  588. updateScene(options?: AnyOptions): this {
  589. console.warn('updateScene is deprecated. Use refreshScene instead')
  590. return this.refreshScene(options || {})
  591. }
  592. /**
  593. * @deprecated renamed to {@link clearSceneModels}
  594. */
  595. removeSceneModels() {
  596. this.clearSceneModels()
  597. }
  598. // endregion
  599. }