Просмотр исходного кода

Add HDRiGroundPlugin and example, add CameraViewPluginOptions for CameraViewPlugin constructor options, implement ThreeViewer.fitToView, PickingPlugin.focusObject, add some three addons exports, Add plugins, load, onLoad in ThreeViewer constructor options. minor changes

master
Palash Bansal 2 лет назад
Родитель
Сommit
362007f9bb
Аккаунт пользователя с таким Email не найден

+ 57
- 5
README.md Просмотреть файл

@@ -98,6 +98,7 @@ To make changes and run the example, click on the CodePen button on the top righ
- [RenderTargetPreviewPlugin](#rendertargetpreviewplugin) - Preview any render target in a UI panel over the canvas
- [GeometryUVPreviewPlugin](#geometryuvpreviewplugin) - Preview UVs of any geometry in a UI panel over the canvas
- [FrameFadePlugin](#framefadeplugin) - Post-render pass to smoothly fade to a new rendered frame over time
- [HDRiGroundPlugin](#hdrigroundplugin) - Add support for ground projected hdri/skybox to the webgl background shader.
- [Rhino3dmLoadPlugin](#rhino3dmloadplugin) - Add support for loading .3dm files
- [PLYLoadPlugin](#plyloadplugin) - Add support for loading .ply files
- [STLLoadPlugin](#stlloadplugin) - Add support for loading .stl files
@@ -1042,8 +1043,9 @@ More options can be passed in the constructor to configure various built-in plug
### Constructor

```typescript
import {ThreeViewer} from 'threepipe'
import {ThreeViewer, CameraViewPlugin} from 'threepipe'

// Create a viewer. All options except canvas/container are optional
const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
// or a container like:
@@ -1080,11 +1082,24 @@ const viewer = new ThreeViewer({
// domElement: document.body,
// addOptions: { ... }
// importOptions: { ... }
}
},
// By default its false
// dropzone: false,
// To Enable without options
// dropzone: true
// Add some plugins after viewer creation.
plugins: [CameraViewPlugin, new CustomPlugin()],
// Shorthand to load files immediately after viewer initialization
load: {
src: 'https://example.com/file.glb',
environment: 'https://example.com/file.hdr',
background: 'https://example.com/file.png',
},
onLoad: (viewer) => {
// Called when all the files are loaded
},
})
```

@@ -1104,7 +1119,7 @@ const viewer = new ThreeViewer({...})
// Add a plugin
const plugin = viewer.addPluginSync(new TonemapPlugin())
// plugins can be added with just the class also
const plugin = viewer.addPluginSync(TonemapPlugin)
const plugin2 = viewer.addPluginSync(TonemapPlugin)

// Add multiple plugins at once
viewer.addPluginsSync([
@@ -1115,10 +1130,10 @@ viewer.addPluginsSync([
])

// Get a plugin
const plugin = viewer.getPlugin(TonemapPlugin)
const plugin3 = viewer.getPlugin(TonemapPlugin)
// Get or add a plugin, when not sure if the plugin is already added
const plugin = viewer.getOrAddPluginSync(TonemapPlugin)
const plugin4 = viewer.getOrAddPluginSync(TonemapPlugin)

// Remove a plugin
viewer.removePluginSync(TonemapPlugin)
@@ -2386,6 +2401,43 @@ To stop a transition, call `fadePlugin.stopTransition()`. This will immediately

The plugin automatically tracks `setDirty()` function calls in objects, materials and the scene. It can be triggerred by calling `setDirty` on any material or object in the scene. Check the [example](https://threepipe.org/examples/#frame-fade-plugin/) for a demo. This can be disabled by options in the plugin.

## HDRiGroundPlugin

[//]: # (todo: image)

Example: https://threepipe.org/examples/#hdri-ground-plugin/

Source Code: [src/plugins/pipeline/HDRiGroundPlugin.ts](./src/plugins/extras/HDRiGroundPlugin.ts)

API Reference: [FrameFadePlugin](https://threepipe.org/docs/classes/HDRiGroundPlugin.html)

HDRiGroundPlugin patches the background shader in the renderer to add support for ground projected environment map/skybox. Works simply by setting the background same as the environemnt and enabling the plugin.

The world radius, tripod height, and origin position(center offset) can be set in the plugin.

The plugin is disabled by default when added. Set `.enabled` to enable it or pass `true` in the constructor.
If the background is not the same as the environment when enabled, the user will be prompted for this, unless `promptOnBackgroundMismatch` is set to `false` in the plugin.

```typescript
import {ThreeViewer, FrameFadePlugin} from 'threepipe'

const viewer = new ThreeViewer({...})

const hdriGround = viewer.addPluginSync(new HDRiGrounPlugin())

// Load an hdr environment map
await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr')
// set background to environment
viewer.scene.background = 'environment'
// or
// viewer.scene.background = viewer.scene.environemnt

// enable the plugin
hdriGround.enabled = true
```

Check the [example](https://threepipe.org/examples/#hdri-ground-plugin/) for a demo.

## Rhino3dmLoadPlugin

Example: https://threepipe.org/examples/#rhino3dm-load/

+ 36
- 0
examples/hdri-ground-plugin/index.html Просмотреть файл

@@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HDRi Ground Plugin</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

<script type="importmap">
{
"imports": {
"threepipe": "./../../dist/index.mjs",
"@threepipe/plugin-tweakpane": "./../../plugins/tweakpane/dist/index.mjs"
}
}

</script>
<style id="example-style">
html, body, #canvas-container, #mcanvas {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
</style>
<script type="module" src="../examples-utils/simple-code-preview.mjs"></script>
<script id="example-script" type="module" src="./script.js" data-scripts="./script.ts;./script.js"></script>
</head>
<body>
<div id="canvas-container">
<canvas id="mcanvas"></canvas>
</div>

</body>

+ 50
- 0
examples/hdri-ground-plugin/script.ts Просмотреть файл

@@ -0,0 +1,50 @@
import {_testFinish, CameraViewPlugin, HDRiGroundPlugin, ThreeViewer} from 'threepipe'
import {TweakpaneUiPlugin} from '@threepipe/plugin-tweakpane'

async function init() {

const viewer = new ThreeViewer({
canvas: document.getElementById('mcanvas') as HTMLCanvasElement,
msaa: true,
dropzone: {
allowedExtensions: ['gltf', 'glb', 'hdr', 'bin', 'png', 'jpeg', 'webp', 'jpg', 'exr'],
addOptions: {
disposeSceneObjects: true,
autoSetEnvironment: true, // when hdr is dropped
autoSetBackground: true,
},
},
plugins: [CameraViewPlugin],
})
const hdriGround = viewer.addPluginSync(HDRiGroundPlugin)

await viewer.setEnvironmentMap('https://threejs.org/examples/textures/equirectangular/venice_sunset_1k.hdr', {
setBackground: true,
})
await viewer.load('https://threejs.org/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf', {
autoCenter: true,
autoScale: true,
autoScaleRadius: 10,
})

viewer.scene.background = 'environment' // this is not really required since setBackground is also set to true above

hdriGround.worldRadius = 50
hdriGround.tripodHeight = 10

const bounds = viewer.scene.getBounds(true, true)
bounds.getCenter(hdriGround.originPosition)
hdriGround.originPosition.y -= (bounds.max.y - bounds.min.y) / 2

hdriGround.enabled = true

console.log(hdriGround)

const ui = viewer.addPluginSync(new TweakpaneUiPlugin(true))
ui.setupPluginUi(HDRiGroundPlugin)

await viewer.fitToView(undefined, 2.5)

}

init().then(_testFinish)

+ 1
- 0
examples/index.html Просмотреть файл

@@ -278,6 +278,7 @@
</ul>
<h2 class="category">Utils</h2>
<ul>
<li><a href="./hdri-ground-plugin/">HDRi Ground Plugin <br/>(Projected Skybox)</a></li>
<li><a href="./render-target-preview/">Render Target Preview Plugin </a></li>
<li><a href="./geometry-uv-preview/">Geometry UV Preview Plugin </a></li>
<li><a href="./parallel-asset-import/">Parallel Asset Import </a></li>

+ 2
- 2
package-lock.json Просмотреть файл

@@ -1,12 +1,12 @@
{
"name": "threepipe",
"version": "0.0.14",
"version": "0.0.16",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "threepipe",
"version": "0.0.14",
"version": "0.0.16",
"license": "Apache-2.0",
"dependencies": {
"@types/three": "https://github.com/repalash/three-ts-types/releases/download/v0.152.1017/package.tgz",

+ 1
- 1
package.json Просмотреть файл

@@ -1,6 +1,6 @@
{
"name": "threepipe",
"version": "0.0.15",
"version": "0.0.16",
"description": "A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.",
"main": "src/index.ts",
"module": "dist/index.mjs",

+ 15
- 2
src/plugins/animation/CameraViewPlugin.ts Просмотреть файл

@@ -8,6 +8,8 @@ import {EasingFunctions, EasingFunctionType} from '../../utils'
import {CameraView, ICamera, ICameraView, PerspectiveCamera2} from '../../core'
import {AnimationResult, PopmotionPlugin} from './PopmotionPlugin'

export interface CameraViewPluginOptions{duration?: number, ease?: EasingFunctionType, interpolateMode?: 'spherical'|'linear'}

/**
* Camera View Plugin
*
@@ -23,7 +25,7 @@ export class CameraViewPlugin extends AViewerPluginSync<'viewChange'|'startViewC
// return this._animating
// }

constructor() {
constructor(options: CameraViewPluginOptions = {}) {
super()
this.addCurrentView = this.addCurrentView.bind(this)
this.resetToFirstView = this.resetToFirstView.bind(this)
@@ -32,8 +34,14 @@ export class CameraViewPlugin extends AViewerPluginSync<'viewChange'|'startViewC
// this._wheel = this._wheel.bind(this)
// this._pointerMove = this._pointerMove.bind(this)
// this._postFrame = this._postFrame.bind(this)

this.animDuration = options.duration ?? this.animDuration
this.animEase = options.ease ?? this.animEase
this.interpolateMode = options.interpolateMode ?? this.interpolateMode
}



@serialize('cameraViews')
private _cameraViews: CameraView[] = []
get cameraViews(): CameraView[] {
@@ -58,10 +66,15 @@ export class CameraViewPlugin extends AViewerPluginSync<'viewChange'|'startViewC
*/
@serialize() @uiDropdown('Ease', Object.keys(EasingFunctions).map((label:string)=>({label}))) animEase: EasingFunctionType = 'easeInOutSine' // ms
@serialize() @uiSlider('Duration', [10, 10000], 10) animDuration = 1000 // ms
@serialize() @uiSlider('RotationOffset', [0.2, 0.75], 0.01) rotationOffset = 0.25
@serialize() @uiDropdown('Interpolation', ['spherical', 'linear'].map((label:string)=>({label})))
interpolateMode: 'spherical'|'linear' = 'spherical'


// not used
@serialize()
// @uiSlider('RotationOffset', [0.2, 0.75], 0.01)
rotationOffset = 0.25

private _animating = false
get animating(): boolean {
return this._animating

+ 58
- 0
src/plugins/extras/HDRiGroundPlugin.glsl Просмотреть файл

@@ -0,0 +1,58 @@

#ifdef HDRi_GROUND_PROJ
// assuming vectors are all normalized
float intersectPlane1(const in vec3 r0, const in vec3 rd, const in vec3 n, const in vec3 p0)
{
float t = dot(p0 - r0, n) / (dot(n, rd)+1e-6);
return t < 0. ? 1000. : t;
}
// slightly modified version
float intersectSphere1(in vec3 ro, in vec3 rd, in vec3 sph, in float rad) {
vec3 oc = ro - sph;
float b = dot(oc, rd);
float c = dot(oc, oc) - rad*rad;
float t = b*b - c;
return t < 0.0 ? t : -b + sqrt(t);
}

#define PI_HALF 1.5707963267948966
uniform float worldRadius;
uniform float tripodHeight;
uniform vec3 originPosition;

vec3 hdriProject(){
vec3 p = normalize( vWorldDirection );
vec3 camPos = cameraPosition;
camPos.y -= tripodHeight;
float t = intersectSphere1(camPos, p, originPosition, worldRadius);
if(t>0.0) {
float t2 = intersectPlane1(camPos, p, vec3(0,-1,0), originPosition + vec3(0.0, -tripodHeight, 0.0));
p = (camPos + min(t, t2)*p)/worldRadius;
/*
if(t2 < t && tripodHeight < 0.001){
// float h = dot(p.xz, p.xz);
//vertical
// p.y = sqrt(1.-h);

//sterographic // https://math.stackexchange.com/questions/1729012/mapping-the-unit-disc-to-the-hemisphere
// p.x = p.x/(h+1.0);
// p.z = p.z/(h+1.0);
// p.y = (h-1.0)/(h+1.0);

// polar
float phi = atan(p.z, p.x);
float p1 = 0.4; // lens projection fix // experimental for hdrihaven
float l = length(p.xz);
p1 = (1.-p1*l)/(1.-p1);
float theta = sin(l*PI_HALF)*PI_HALF; // cancel out projection, map [0,1] to [0, PI/2]

p.x = sin(theta)*cos(phi)*p1;
p.y = -cos(theta);
p.z = sin(theta)*sin(phi)*p1;
}
*/
}
else p = vec3(0.0, 1.0, 0.0);
return p;
}
#endif

+ 117
- 0
src/plugins/extras/HDRiGroundPlugin.ts Просмотреть файл

@@ -0,0 +1,117 @@
import {DataTexture, EquirectangularReflectionMapping, ShaderLib, Vector3} from 'three'
import {onChange, serialize} from 'ts-browser-helpers'
import hdriGroundProj from './HDRiGroundPlugin.glsl'
import {AViewerPluginSync, ThreeViewer} from '../../viewer'
import {shaderReplaceString} from '../../utils'
import {uiPanelContainer, uiSlider, uiToggle, uiVector} from 'uiconfig.js'

@uiPanelContainer('HDRi Ground')
export class HDRiGroundPlugin extends AViewerPluginSync<'', ThreeViewer> {
static readonly PluginType = 'HDRiGroundPlugin'

@serialize()
@onChange(HDRiGroundPlugin.prototype._paramsChanged)
@uiToggle('Enabled')
enabled = false

@serialize()
@onChange(HDRiGroundPlugin.prototype._paramsChanged)
@uiSlider('World Radius', [1, 1000], 0.01)
worldRadius = 100

@serialize()
@onChange(HDRiGroundPlugin.prototype._paramsChanged)
@uiSlider('Tripod height', [0, 50], 0.01)
tripodHeight = 10

@serialize()
@onChange(HDRiGroundPlugin.prototype._paramsChanged)
@uiVector('Origin Position', undefined, 0.001, (t: HDRiGroundPlugin)=>({
onChange: t._paramsChanged, // this is for x, y, z values.
}))
originPosition = new Vector3(0, 0, 0)

@serialize()
@onChange(HDRiGroundPlugin.prototype._paramsChanged)
promptOnBackgroundMismatch = true

// todo
// /**
// * Automatically set the origin position based on the ground position in GroundPlugin
// */
// @serialize()
// @onChange(HDRiGroundPlugin.prototype._paramsChanged)
// @uiToggle('Auto Ground Position')
// autoGroundPosition = false

constructor(enabled = false, promptOnBackgroundMismatch = true) {
super()
this._paramsChanged = this._paramsChanged.bind(this)
this.enabled = enabled
this.promptOnBackgroundMismatch = promptOnBackgroundMismatch

this.addEventListener('deserialize', this._paramsChanged)
}

private _paramsChanged() {
if (!this._viewer) return
const bg = this._viewer.scene.background
if (this.enabled && bg !== this._viewer.scene.environment && bg !== 'environment') {
if (bg && (bg as any).isDataTexture) (bg as DataTexture).mapping = EquirectangularReflectionMapping
else {
const change = this.promptOnBackgroundMismatch ? this._viewer.dialog.confirmSync('Background must be same as environment, do you want to change it?') : true
if (change) {
// const bgui = this._viewer.getPlugin<SimpleBackgroundEnvUiPlugin>('SimpleBackgroundEnvUiPlugin1')
// if (bgui) {
// bgui.envmapBg = true
// bgui.uiConfig.uiRefresh?.('postFrame', true)
// } else
this._viewer.scene.background = 'environment'
} else this.enabled = false
}
}

const cubeMat = this._viewer.renderManager.renderer.background.getBoxMesh2()?.material
const unif = cubeMat?.uniforms ?? ShaderLib.backgroundCube.uniforms
if (!unif.tripodHeight) unif.tripodHeight = {value: 1.0}
if (!unif.worldRadius) unif.worldRadius = {value: 1.0}
if (!unif.originPosition) unif.originPosition = {value: new Vector3()}
unif.tripodHeight.value = this.tripodHeight
unif.worldRadius.value = this.worldRadius
unif.originPosition.value.copy(this.originPosition)
if (cubeMat) {
if (!this.enabled && cubeMat.defines.HDRi_GROUND_PROJ)
delete cubeMat.defines.HDRi_GROUND_PROJ
else if (this.enabled)
cubeMat.defines.HDRi_GROUND_PROJ = '1'
cubeMat.needsUpdate = true
}
this._viewer.setDirty()
// const m = this._viewer?.scene.modelRoot.children ?? []
// for (const m1 of m) {
// m1.position.y = -this.tripodHeight + new Box3B().expandByObject(m1, true, true).getSize(new Vector3()).y / 2
// }
}

onAdded(viewer: ThreeViewer): void {
super.onAdded(viewer)
if (this._viewer?.renderManager.webglRenderer?.background.getBoxMesh())
viewer.console.error('HDRi Ground Plugin must be added before setting any cube or env map')

if (!ShaderLib.backgroundCube.fragmentShader.includes('#ifdef HDRi_GROUND_PROJ')) {
ShaderLib.backgroundCube.fragmentShader = shaderReplaceString(ShaderLib.backgroundCube.fragmentShader, 'void main() {', hdriGroundProj, {prepend: true})
ShaderLib.backgroundCube.fragmentShader = shaderReplaceString(ShaderLib.backgroundCube.fragmentShader, 'vec3 vReflect = vWorldDirection;', `
vec3 vReflect =
#ifdef HDRi_GROUND_PROJ
hdriProject()
#else
vWorldDirection
#endif
;
`)
}

viewer.scene.addEventListener('environmentChanged', this._paramsChanged)
}

}

+ 4
- 1
src/plugins/index.ts Просмотреть файл

@@ -36,4 +36,7 @@ export {TonemapPlugin} from './postprocessing/TonemapPlugin'
// animation
export {GLTFAnimationPlugin} from './animation/GLTFAnimationPlugin'
export {PopmotionPlugin} from './animation/PopmotionPlugin'
export {CameraViewPlugin} from './animation/CameraViewPlugin'
export {CameraViewPlugin, type CameraViewPluginOptions} from './animation/CameraViewPlugin'

// extras
export {HDRiGroundPlugin} from './extras/HDRiGroundPlugin'

+ 2
- 5
src/plugins/interaction/PickingPlugin.ts Просмотреть файл

@@ -1,10 +1,9 @@
import {Object3D} from 'three'
import {Class, serialize} from 'ts-browser-helpers'
import {AViewerPluginSync, ThreeViewer} from '../../viewer'
import {ObjectPicker} from '../../three/utils/ObjectPicker'
import {BoxSelectionWidget, ObjectPicker, SelectionWidget} from '../../three'
import {IObject3D, IObject3DEvent, ISceneEvent} from '../../core'
import {IUiConfigContainer, UiObjectConfig} from 'uiconfig.js'
import {BoxSelectionWidget, SelectionWidget} from '../../three/utils/SelectionWidget'

export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'hoverObjectChanged'|'hitObject'> {
@serialize() enabled = true
@@ -192,10 +191,8 @@ export class PickingPlugin extends AViewerPluginSync<'selectedObjectChanged'|'ho
this.dispatchEvent(e)
}

// @ts-expect-error temporary
public async focusObject(selected?: Object3D) {
// const camViews = this._viewer?.getPluginByType<CameraViewPlugin>('CameraViews')
// await camViews?.animateToFitObject(selected, 1.25, 1000, 'easeOut', {min: (this._viewer?.scene.activeCamera.getControls<OrbitControls3>()?.minDistance ?? 0.5) + 0.5, max: 50.0})
this._viewer?.fitToView(selected, 1.25, 1000, 'easeOut')
}

public enableWidget(enable: boolean): void {

+ 7
- 0
src/three/Threejs.ts Просмотреть файл

@@ -1,3 +1,4 @@

export {WebGLArrayRenderTarget} from 'three'
export {WebGL3DRenderTarget} from 'three'
export {WebGLMultipleRenderTargets} from 'three'
@@ -221,3 +222,9 @@ export type {Shader} from 'three'
export * from 'three/examples/jsm/libs/fflate.module.js'

export {CopyShader} from 'three/examples/jsm/shaders/CopyShader.js'
export {Pass, FullScreenQuad} from 'three/examples/jsm/postprocessing/Pass.js'
export {RenderPass} from 'three/examples/jsm/postprocessing/RenderPass.js'
export {ShaderPass} from 'three/examples/jsm/postprocessing/ShaderPass.js'
export {EffectComposer} from 'three/examples/jsm/postprocessing/EffectComposer.js'

export {OrbitControls} from 'three/examples/jsm/controls/OrbitControls.js'

+ 4
- 2
src/utils/DialogWrapper.ts Просмотреть файл

@@ -1,10 +1,12 @@
export interface IDialogWrapper {
alert: (message?: string) => Promise<void>
confirm: (message?: string) => Promise<boolean>
prompt: (message?: string, _default?: string, cancel?: boolean) => Promise<string | null>
confirm: (message?: string) => Promise<boolean>
confirmSync: (message?: string) => boolean
}
export const windowDialogWrapper: IDialogWrapper = {
alert: async(message?: string) => window.alert(message),
confirm: async(message?: string) => window.confirm(message),
prompt: async(message?: string, _default?: string, _?: boolean) => window.prompt(message, _default),
confirm: async(message?: string) => window.confirm(message),
confirmSync: (message?: string) => window.confirm(message),
}

+ 46
- 12
src/viewer/ThreeViewer.ts Просмотреть файл

@@ -9,7 +9,7 @@ import {
Vector2,
Vector3,
} from 'three'
import {Class, createCanvasElement, onChange, serialize} from 'ts-browser-helpers'
import {Class, createCanvasElement, onChange, serialize, ValOrArr} from 'ts-browser-helpers'
import {TViewerScreenShader} from '../postprocessing'
import {
AddObjectOptions,
@@ -24,6 +24,7 @@ import {
import {ViewerRenderManager} from './ViewerRenderManager'
import {
convertArrayBufferToStringsInMeta,
EasingFunctionType,
getEmptyMeta,
GLStatsJS,
IDialogWrapper,
@@ -50,12 +51,14 @@ import {
import {IViewerPlugin, IViewerPluginSync} from './IViewerPlugin'
import {uiConfig, uiFolderContainer, UiObjectConfig} from 'uiconfig.js'
import {IRenderTarget} from '../rendering'
import type {ProgressivePlugin} from '../plugins'
import type {CameraViewPlugin, ProgressivePlugin} from '../plugins'
// noinspection ES6PreferShortImport
import {DropzonePlugin, DropzonePluginOptions} from '../plugins/interaction/DropzonePlugin'
// noinspection ES6PreferShortImport
import {TonemapPlugin} from '../plugins/postprocessing/TonemapPlugin'
import {VERSION} from './version'
import {Easing} from 'popmotion'
import {OrbitControls3} from '../three'

export type IViewerEvent = BaseEvent & {
type: 'update'|'preRender'|'postRender'|'preFrame'|'postFrame'|'dispose'|'addPlugin'|'renderEnabled'|'renderDisabled'
@@ -126,6 +129,31 @@ export interface ThreeViewerOptions {

debug?: boolean

/**
* Add initial plugins.
*/
plugins?: (IViewerPluginSync | Class<IViewerPluginSync>)[]

load?: {
/**
* Load one or more source files
*/
src?: ValOrArr<string | IAsset | null>

/**
* Load environment map
*/
environment?: string | IAsset | ITexture | undefined | null

/**
* Load background map
*/
background?: string | IAsset | ITexture | undefined | null

}
onLoad?: (results: any) => void


/**
* TonemapPlugin is added to the viewer if this is true.
* @default true
@@ -382,10 +410,17 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes
if (options.tonemap !== false) {
this.addPluginSync(new TonemapPlugin())
}
for (const p of options.plugins ?? []) this.addPluginSync(p)

this.console.log('ThreePipe Viewer instance initialized, version: ', ThreeViewer.VERSION)


if (options.load) {
const sources = [options.load.src].flat().filter(s=> s)
const promises: Promise<any>[] = sources.map(async s=> s && this.load(s))
if (options.load.environment) promises.push(this.setEnvironmentMap(options.load.environment))
if (options.load.background) promises.push(this.setBackgroundMap(options.load.background))
Promise.all(promises).then(options.onLoad)
}
}

/**
@@ -1080,15 +1115,14 @@ export class ThreeViewer extends EventDispatcher<IViewerEvent, IViewerEventTypes
// this.fromJSON(config, config.resources)
// }

// todo
// public async fitToView(selected?: Object3D, distanceMultiplier = 1.5, duration?: number, ease?: Easing|EasingFunctionType) {
// const camViews = this.getPluginByType<CameraViewPlugin>('CameraViews')
// if (!camViews) {
// this.console.error('CameraViews plugin is required for fitToView to work')
// return
// }
// await camViews?.animateToFitObject(selected, distanceMultiplier, duration, ease, {min: (this.scene.activeCamera.getControls<OrbitControls3>()?.minDistance ?? 0.5) + 0.5, max: 1000.0})
// }
public async fitToView(selected?: Object3D, distanceMultiplier = 1.5, duration?: number, ease?: Easing|EasingFunctionType) {
const camViews = this.getPlugin<CameraViewPlugin>('CameraViews')
if (!camViews) {
this.console.error('CameraViewPlugin (CameraViews) is required for fitToView to work')
return
}
await camViews?.animateToFitObject(selected, distanceMultiplier, duration, ease, {min: ((<OrbitControls3> this.scene.mainCamera.controls)?.minDistance ?? 0.5) + 0.5, max: 1000.0})
}

// todo: create/load texture utils


+ 1
- 1
src/viewer/version.ts Просмотреть файл

@@ -1 +1 @@
export const VERSION = '0.0.15'
export const VERSION = '0.0.16'

Загрузка…
Отмена
Сохранить