Kaynağa Gözat

Minor type fixes, add keepWorldPosition to IGeometry.center, make interactionsEnabled readonly, add setInteractions function in ICamera, update ts-browser-helpers

master
Palash Bansal 2 yıl önce
ebeveyn
işleme
4286cfa904
No account linked to committer's email address

+ 1
- 0
.gitignore Dosyayı Görüntüle

@@ -1,4 +1,5 @@
dist
lib
docs
/index.html
examples/**/*.js

+ 1
- 1
examples/examples-utils/simple-code-preview.mjs Dosyayı Görüntüle

@@ -19,7 +19,7 @@ function replaceImports(code) {
.replaceAll(` from '../`, ` from '${rootPath+examplePath}`)
}
setupCodePreview(
document.getElementById('canvas-container') || document.querySelector('.code-preview-container') || document.body,
document.querySelector('.code-preview-container') || document.getElementById('canvas-container') || document.body,
scripts,
scripts.map(s=>s.textContent ? 'js' : s.split('.').pop()), // title
scripts.map(s=>(typeof s === 'string' && s.endsWith('.js')) ? s : (codePath+examplePath+window.location.pathname.split('/examples/').pop().replace('index.html', '')+(s.textContent ? 'index.html' : s))), // todo: github link

+ 1
- 0
examples/index.html Dosyayı Görüntüle

@@ -240,6 +240,7 @@
<li><a href="./camera-view-plugin/">Camera View (Animation) Plugin </a></li>
<li><a href="./dropzone-plugin/">Dropzone (Drag & Drop) Plugin </a></li>
<li><a href="./fullscreen-plugin/">FullScreen Plugin </a></li>
<li><a href="./geometry-generator-plugin/">Geometry Generator Plugin </a></li>
</ul>
<h2 class="category">Import</h2>
<ul>

+ 3
- 3
package.json Dosyayı Görüntüle

@@ -92,21 +92,21 @@
"rollup-plugin-license": "^3.0.1",
"rollup-plugin-glsl": "^1.3.0",
"rollup-plugin-postcss": "^4.0.2",
"stats.js": "^0.17.0",
"three": "https://github.com/repalash/three.js-modded/releases/download/v0.152.2018/package.tgz",
"tslib": "^2.5.0",
"typedoc": "^0.24.7",
"typescript": "^5.0.4",
"typescript-plugin-css-modules": "^5.0.1",
"uiconfig.js": "^0.0.9",
"@rollup/plugin-replace": "^5.0.2",
"popmotion": "^11.0.5"
},
"dependencies": {
"stats.js": "^0.17.0",
"uiconfig.js": "^0.0.9",
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1018/package.tgz",
"@types/webxr": "^0.5.1",
"@types/wicg-file-system-access": "^2020.9.5",
"ts-browser-helpers": "^0.8.0"
"ts-browser-helpers": "^0.9.0"
},
"//": {
"dependencies": {

+ 1
- 1
src/assetmanager/AssetManager.ts Dosyayı Görüntüle

@@ -52,7 +52,7 @@ export interface AssetManagerOptions{
storage?: Cache | Storage | boolean
}

export type AddAssetOptions = AddObjectOptions & {
export interface AddAssetOptions extends AddObjectOptions{
/**
* Automatically set any loaded HDR, EXR file as the scene environment map
* @default true

+ 8
- 6
src/assetmanager/IAssetImporter.ts Dosyayı Görüntüle

@@ -1,5 +1,5 @@
import {BaseEvent, EventDispatcher, LoadingManager, Object3D} from 'three'
import {AnyOptions, IDisposable} from 'ts-browser-helpers'
import {IDisposable} from 'ts-browser-helpers'
import {IAsset, IFile} from './IAsset'
import {ILoader} from './IImporter'
import {ICamera, IMaterial, IObject3D, ITexture} from '../core'
@@ -59,7 +59,7 @@ export interface IImportResultUserData{
__sourceBlob?: IFile
}

export type ProcessRawOptions = {
export interface ProcessRawOptions {
/**
* default = true, toggle to control the processing of the raw objects in the proecssRaw method
*/
@@ -94,7 +94,9 @@ export type ProcessRawOptions = {
* @deprecated use processRaw instead
*/
processImported?: boolean, // same as processRaw
} & AnyOptions

[key: string]: any
}

export interface LoadFileOptions {
fileHandler?: any, // custom {@link ILoader} for the file
@@ -105,9 +107,9 @@ export interface LoadFileOptions {
rootPath?: string, // internal use
}

export type ImportFilesOptions = ProcessRawOptions & LoadFileOptions & {allowedExtensions?: string[]}
export interface ImportFilesOptions extends ProcessRawOptions, LoadFileOptions {allowedExtensions?: string[]}

export type ImportAssetOptions = {
export interface ImportAssetOptions extends ProcessRawOptions, LoadFileOptions {
/**
* Default = false. If true, the asset will be imported again on subsequent calls, even if it is already imported.
*/
@@ -129,7 +131,7 @@ export type ImportAssetOptions = {
* Pass a custom file to use for the import. This will be used in the importer, and nothing will be fetched from the path
*/
importedFile?: IFile,
} & ProcessRawOptions & LoadFileOptions & AnyOptions
}

export type IAssetImporterEventTypes = 'onLoad' | 'onProgress' | 'onStop' | 'onError' | 'onStart' | 'loaderCreate' | 'importFile' | 'importFiles' | 'processRaw' | 'processRawStart'
export interface IAssetImporter extends EventDispatcher<BaseEvent, IAssetImporterEventTypes>, IDisposable {

+ 3
- 3
src/core/ICamera.ts Dosyayı Görüntüle

@@ -54,13 +54,13 @@ export interface ICamera<E extends ICameraEvent = ICameraEvent, ET extends ICame
*/
position: Vector3,

// todo: make disable/enable functions with key like in FrameFadePlugin
interactionsEnabled: boolean;
readonly interactionsEnabled: boolean;
setInteractions(enabled: boolean, by: string): void;

/**
* Check whether user can interact with this camera.
* Interactions can be enabled/disabled in a variety of ways,
* like {@link interactionsEnabled}, {@link controlsMode}, {@link isMainCamera} property
* like {@link setInteractions}, {@link controlsMode}, {@link isMainCamera} property
*/
readonly canUserInteract: boolean;


+ 2
- 1
src/core/IGeometry.ts Dosyayı Görüntüle

@@ -1,4 +1,4 @@
import {BufferGeometry, Event, NormalBufferAttributes, NormalOrGLBufferAttributes} from 'three'
import {BufferGeometry, Event, NormalBufferAttributes, NormalOrGLBufferAttributes, Vector3} from 'three'
import {IUiConfigContainer, UiObjectConfig} from 'uiconfig.js'
import {AnyOptions} from 'ts-browser-helpers'
import {IObject3D} from './IObject'
@@ -18,6 +18,7 @@ export interface IGeometry<Attributes extends NormalOrGLBufferAttributes = Norma
refreshUi(): void;
uiConfig?: UiObjectConfig
appliedMeshes: Set<IObject3D>
center(offset?: Vector3, keepWorldPosition?: boolean): this

// Note: for userData: add _ in front of for private use, which is preserved while cloning but not serialisation, and __ for private use, which is not preserved while cloning and serialisation
userData: IGeometryUserData

+ 2
- 1
src/core/IObject.ts Dosyayı Görüntüle

@@ -78,6 +78,8 @@ export interface IObject3DUserData extends IImportResultUserData {

autoScaleRadius?: number
autoScaled?: boolean
geometriesCentered?: boolean

/**
* should this object be taken into account when calculating bounding box, default true
@@ -239,7 +241,6 @@ export interface IObject3D<E extends Event = IObject3DEvent, ET = IObject3DEvent
parent: IObject3D | null
children: IObject3D[]


// endregion

}

+ 12
- 0
src/core/IScene.ts Dosyayı Görüntüle

@@ -16,6 +16,17 @@ export interface AddObjectOptions {
* @default false
*/
autoCenter?: boolean,
/**
* Automatically center the geometries(pivots) in the object hierarchy before adding.
* @default false
*/
centerGeometries?: boolean,
/**
* This centers the geometry while keeping the world position, i.e the mesh(Object3D) positions will change.
* {@link centerGeometries} must be true for this to work.
* @default true
*/
centerGeometriesKeepPosition?: boolean,
/**
* Add a license to the object
*/
@@ -27,6 +38,7 @@ export interface AddObjectOptions {
autoScale?: boolean
/**
* Radius to use for {@link autoScale}
* {@link autoScale} must be true for this to work.
* @default 2
*/
autoScaleRadius?: number

+ 27
- 10
src/core/camera/PerspectiveCamera2.ts Dosyayı Görüntüle

@@ -124,7 +124,7 @@ export class PerspectiveCamera2 extends PerspectiveCamera implements ICamera {


// const ae = this._canvas.addEventListener
// todo: this breaks UI.
// todo: this breaks tweakpane UI.
// this._canvas.addEventListener = (type: string, listener: any, options1: any) => { // see https://github.com/mrdoob/three.js/pull/19782
// ae(type, listener, type === 'wheel' && typeof options1 !== 'boolean' ? {
// ...typeof options1 === 'object' ? options1 : {},
@@ -141,21 +141,38 @@ export class PerspectiveCamera2 extends PerspectiveCamera implements ICamera {
// @serialize('camOptions') //todo handle deserialization of this

// region interactionsEnabled
private _interactionsEnabled = true

get canUserInteract() {
return this._interactionsEnabled && this.isMainCamera && this.controlsMode !== ''
}
// private _interactionsEnabled = true
//
// get interactionsEnabled(): boolean {
// return this._interactionsEnabled
// }
//
// set interactionsEnabled(value: boolean) {
// if (this._interactionsEnabled !== value) {
// this._interactionsEnabled = value
// this.refreshCameraControls(true)
// }
// }

private _interactionsDisabledBy = new Set<string>()

get interactionsEnabled(): boolean {
return this._interactionsEnabled
return this._interactionsDisabledBy.size === 0
}

set interactionsEnabled(value: boolean) {
if (this._interactionsEnabled !== value) {
this._interactionsEnabled = value
this.refreshCameraControls(true)
setInteractions(enabled: boolean, by: string): void {
const size = this._interactionsDisabledBy.size
if (enabled) {
this._interactionsDisabledBy.delete(by)
} else {
this._interactionsDisabledBy.add(by)
}
if (size !== this._interactionsDisabledBy.size) this.refreshCameraControls(true)
}

get canUserInteract() {
return this.interactionsEnabled && this.isMainCamera && this.controlsMode !== ''
}

// endregion

+ 20
- 8
src/core/geometry/iGeometryCommons.ts Dosyayı Görüntüle

@@ -17,6 +17,24 @@ export const iGeometryCommons = {
superDispose.call(this)
},
upgradeGeometry: upgradeGeometry,
center: (superCenter: BufferGeometry['center']): IGeometry['center'] =>
function(this: IGeometry, offset?: Vector3, keepWorldPosition = false): IGeometry {
if (keepWorldPosition) {
offset = offset ? offset.clone() : new Vector3()
superCenter.call(this, offset)
offset.negate()
const meshes = this.appliedMeshes
for (const m of meshes) {
m.updateMatrix()
m.position.copy(offset).applyMatrix4(m.matrix)
m.setDirty()
}
} else {
superCenter.call(this, offset)
}
this.setDirty()
return this
},
makeUiConfig: function(this: IGeometry): UiObjectConfig {
if (this.uiConfig) return this.uiConfig
return {
@@ -37,20 +55,13 @@ export const iGeometryCommons = {
label: 'Center Geometry',
value: () => {
this.center()
this.setDirty()
},
},
{
type: 'button',
label: 'Center Geometry (keep position)',
value: () => {
const offset = new Vector3()
this.center(offset)
const meshes = this.appliedMeshes
meshes.forEach(m=>{
m.position.sub(offset)
m.setDirty && m.setDirty()
})
this.center(undefined, true)
},
},
{
@@ -154,6 +165,7 @@ function upgradeGeometry(this: IGeometry) {
this.assetType = 'geometry'

this.dispose = iGeometryCommons.dispose(this.dispose)
this.center = iGeometryCommons.center(this.center)

if (!this.setDirty) this.setDirty = iGeometryCommons.setDirty
if (!this.refreshUi) this.refreshUi = iGeometryCommons.refreshUi

+ 19
- 3
src/core/object/RootScene.ts Dosyayı Görüntüle

@@ -185,7 +185,7 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I
}

/**
Load model root scene exported to GLTF format. Used internally by {@link ThreeViewer.addSceneObject}.
* Load model root scene exported to GLTF format. Used internally by {@link ThreeViewer.addSceneObject}.
* @param obj
* @param options
*/
@@ -227,7 +227,7 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I
.map(c=>this.addObject(c, {...options, clearSceneObjects: false, disposeSceneObjects: false}))
}

private _addObject3D(model: IObject3D|null, {autoCenter = false, autoScale = false, autoScaleRadius = 2., addToRoot = false, license}: AddObjectOptions = {}): void {
private _addObject3D(model: IObject3D|null, {autoCenter = false, centerGeometries = false, centerGeometriesKeepPosition = true, autoScale = false, autoScaleRadius = 2., addToRoot = false, license}: AddObjectOptions = {}): void {
const obj = model
if (!obj) {
console.error('Invalid object, cannot add to scene.')
@@ -247,6 +247,14 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I
} else {
obj.userData.autoScaled = true // mark as auto-scaled, so that autoScale is not called again when file is reloaded.
}
if (centerGeometries && !obj.userData.geometriesCentered) {
obj.traverse((o)=>{
if (o.geometry) o.geometry.center(undefined, centerGeometriesKeepPosition)
})
obj.userData.geometriesCentered = true
} else {
obj.userData.geometriesCentered = true // mark as centered, so that geometry center is not called again when file is reloaded.
}

if (license) obj.userData.license = [obj.userData.license, license].filter(v=>v).join(', ')

@@ -388,6 +396,14 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I
private _v1 = new Vector3()
private _v2 = new Vector3()

/**
* For Programmatically toggling autoNearFar. This property is not supposed to be in the UI or serialized.
* Use camera.userData.autoNearFar for UI and serialization
* This is used in PickingPlugin
* autoNearFar will still be disabled if this is true and camera.userData.autoNearFar is false
*/
autoNearFarEnabled = true

/**
* Refreshes the scene active camera near far values, based on the scene bounding box.
* This is called automatically every time the camera is updated.
@@ -395,7 +411,7 @@ export class RootScene extends Scene<ISceneEvent, ISceneEventTypes> implements I
refreshActiveCameraNearFar(): void {
const camera = this.mainCamera as ICamera
if (!camera) return
if (camera.userData.autoNearFar === false) {
if (!this.autoNearFarEnabled || camera.userData.autoNearFar === false) {
camera.near = camera.userData.minNearPlane ?? 0.5
camera.far = camera.userData.maxFarPlane ?? 1000
return

+ 4
- 14
src/plugins/animation/CameraViewPlugin.ts Dosyayı Görüntüle

@@ -88,23 +88,9 @@ export class CameraViewPlugin extends AViewerPluginSync<'viewChange'|'startViewC
onAdded(viewer: ThreeViewer): void {
super.onAdded(viewer)

let interactionsDisabled = false // we need this because interactionsEnabled is also set in PickingPlugin

// todo: move to PopmotionPlugin
// todo: remove event listener
viewer.addEventListener('preFrame', (_: any)=>{
if (/* this.seekOnScroll || */ this._animating) {
if (this._viewer!.scene.mainCamera.interactionsEnabled) {
this._viewer!.scene.mainCamera.interactionsEnabled = false
interactionsDisabled = true
// console.log(interactionsDisabled)
}
} else if (interactionsDisabled) {
this._viewer!.scene.mainCamera.interactionsEnabled = true
interactionsDisabled = false
// console.log(interactionsDisabled)
}

// console.log(ev.deltaTime)

// this._updaters.forEach(u=>{
@@ -263,6 +249,9 @@ export class CameraViewPlugin extends AViewerPluginSync<'viewChange'|'startViewC

this._currentView = view
this._animating = true

this._viewer?.scene.mainCamera.setInteractions(false, CameraViewPlugin.PluginType) // todo: also for seekOnScroll

this.dispatchEvent({type: 'startViewChange', view})

const popmotion = this._viewer?.getPlugin(PopmotionPlugin)
@@ -279,6 +268,7 @@ export class CameraViewPlugin extends AViewerPluginSync<'viewChange'|'startViewC
if (throwOnStop) throw e
})

this._viewer?.scene.mainCamera.setInteractions(true, CameraViewPlugin.PluginType)
this._animating = false

this._viewer?.setDirty()

+ 1
- 8
src/plugins/base/PipelinePassPlugin.ts Dosyayı Görüntüle

@@ -1,6 +1,6 @@
import {IPassID, IPipelinePass} from '../../postprocessing'
import {AViewerPluginSync, ISerializedConfig, ThreeViewer} from '../../viewer'
import {AnyFunction, serialize} from 'ts-browser-helpers'
import {serialize, wrapThisFunction} from 'ts-browser-helpers'
import {SerializationMetaType} from '../../utils'
import {uiConfig, uiToggle} from 'uiconfig.js'

@@ -71,10 +71,3 @@ export abstract class PipelinePassPlugin<T extends IPipelinePass, TPassId extend
}

}

function wrapThisFunction<T extends AnyFunction, T2>(f1: ()=>void, f2?: T): T {
return function(this: T2, ...args: Parameters<T>) {
f1()
return f2 && f2.call(this, ...args)
} as T
}

+ 3
- 1
src/plugins/interaction/DropzonePlugin.ts Dosyayı Görüntüle

@@ -38,7 +38,7 @@ export class DropzonePlugin extends AViewerPluginSync<'drop'> {
@serialize() autoImport = true
/**
* Automatically add dropped and imported assets to the scene.
Works only if {@link autoImport} is true.
* Works only if {@link autoImport} is true.
*/
@uiToggle() @serialize() autoAdd = true

@@ -58,6 +58,8 @@ export class DropzonePlugin extends AViewerPluginSync<'drop'> {
importConfig: true,
autoScale: true,
autoScaleRadius: 2,
centerGeometries: false, // in the whole hierarchy
centerGeometriesKeepPosition: true, // this centers while keeping world position
license: '',
clearSceneObjects: false,
disposeSceneObjects: false,

+ 2
- 0
src/three/controls/OrbitControls3.ts Dosyayı Görüntüle

@@ -54,4 +54,6 @@ export class OrbitControls3 extends OrbitControls implements IUiConfigContainer,

throttleUpdate = 60 // throttle to 60 updates per second (implemented in OrbitControls.js.update() method)

// todo add to three-ts-types
stopDamping!: () => void
}

+ 0
- 1
src/three/utils/SelectionWidget.ts Dosyayı Görüntüle

@@ -22,7 +22,6 @@ export class SelectionWidget extends Group implements IWidget {
const scale = bbox.getBoundingSphere(new Sphere()).radius
this.scale.setScalar(scale * this.boundingScaleMultiplier)
this.setVisible(true)

} else {
this.setVisible(false)
}

+ 3
- 3
src/utils/browser-helpers.ts Dosyayı Görüntüle

@@ -1,6 +1,6 @@
export type {IEvent, IEventDispatcher} from 'ts-browser-helpers'
export type {ImageCanvasOptions} from 'ts-browser-helpers'
export type {AnyFunction, AnyOptions, Class, IDisposable, IJSONSerializable, PartialPick, PartialRecord, StringKeyOf, Fof, ValOrFunc, ValOrArr, ValOrArrOp} from 'ts-browser-helpers'
export type {AnyFunction, AnyOptions, Class, IDisposable, IJSONSerializable, PartialPick, PartialRecord, StringKeyOf, Fof, ValOrFunc, ValOrArr, ValOrFuncOp, ValOrArrOp} from 'ts-browser-helpers'
export type {Serializer} from 'ts-browser-helpers'
export {PointerDragHelper} from 'ts-browser-helpers'
export {Damper} from 'ts-browser-helpers'
@@ -11,13 +11,13 @@ export {escapeRegExp, getFilenameFromPath, parseFileExtension, replaceAll, toTit
export {prettyScrollbar} from 'ts-browser-helpers'
export {blobToDataURL, downloadBlob, downloadFile, uploadFile, mobileAndTabletCheck} from 'ts-browser-helpers'
export {LinearToSRGB, SRGBToLinear, colorToDataUrl} from 'ts-browser-helpers'
export {onChange, onChange2, onChange3, serialize, serializable} from 'ts-browser-helpers'
export {onChange, onChange2, onChange3, onChangeDispatchEvent, serialize, serializable} from 'ts-browser-helpers'
export {aesGcmDecrypt, aesGcmEncrypt} from 'ts-browser-helpers'
export {verifyPermission, writeFile, getFileHandle, getNewFileHandle, readFile} from 'ts-browser-helpers'
export {embedUrlRefs, htmlToCanvas, htmlToPng, htmlToSvg} from 'ts-browser-helpers'
export {imageToCanvas, imageBitmapToBase64, imageUrlToImageData, imageDataToCanvas, isWebpExportSupported, canvasFlipY} from 'ts-browser-helpers'
export {absMax, clearBit, updateBit} from 'ts-browser-helpers'
export {includesAll} from 'ts-browser-helpers'
export {includesAll, wrapThisFunction, findLastIndex} from 'ts-browser-helpers'
export {copyProps, getOrCall, getPropertyDescriptor, isPropertyWritable, safeSetProperty} from 'ts-browser-helpers'
export {deepAccessObject, getKeyByValue, objectHasOwn, objectMap2, objectMap} from 'ts-browser-helpers'
export {makeColorSvg, makeTextSvg, makeColorSvgCircle, svgToCanvas, svgToPng} from 'ts-browser-helpers'

+ 1
- 1
src/viewer/AViewerPlugin.ts Dosyayı Görüntüle

@@ -58,7 +58,7 @@ export abstract class AViewerPlugin<T extends string = string, TViewer extends T
else this.fromJSON?.(state)
}

protected _viewerListeners: PartialRecord<IViewerEventTypes, (e: Event)=>void> = {}
protected _viewerListeners: PartialRecord<IViewerEventTypes, (e: IViewerEvent)=>void> = {}
protected _onViewerEvent = (e: IViewerEvent)=> {
const et = e.eType
et && this._viewerListeners[et]?.(e)

+ 1
- 1
src/viewer/ThreeViewer.ts Dosyayı Görüntüle

@@ -60,7 +60,7 @@ import {VERSION} from './version'
import {Easing} from 'popmotion'
import {OrbitControls3} from '../three'

export type IViewerEvent = BaseEvent & {
export interface IViewerEvent extends BaseEvent, Partial<IAnimationLoopEvent> {
type: '*'|'update'|'preRender'|'postRender'|'preFrame'|'postFrame'|'dispose'|'addPlugin'|'renderEnabled'|'renderDisabled'
eType?: '*'|'update'|'preRender'|'postRender'|'preFrame'|'postFrame'|'dispose'|'addPlugin'|'renderEnabled'|'renderDisabled'
[p: string]: any

Loading…
İptal
Kaydet