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

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