Quellcode durchsuchen

Add duration multiplier to CameraView, wip spline interpolation

master
Palash Bansal vor 1 Jahr
Ursprung
Commit
c8e415e479
Es ist kein Account mit der E-Mail-Adresse des Committers verbunden

+ 10
- 1
src/core/camera/CameraView.ts Datei anzeigen

target: Vector3 target: Vector3
quaternion: Quaternion quaternion: Quaternion
zoom: number zoom: number
/*
* Duration multiplier when the camera is animating to the view.
*/
duration?: number
isWorldSpace?: boolean isWorldSpace?: boolean
animate(camera?: ICamera, duration?: number): void animate(camera?: ICamera, duration?: number): void
set(camera?: ICamera): void set(camera?: ICamera): void
@serialize() @uiVector() target = new Vector3() @serialize() @uiVector() target = new Vector3()
@serialize() @uiVector() quaternion = new Quaternion() @serialize() @uiVector() quaternion = new Quaternion()
@serialize() @uiNumber() zoom = 1 @serialize() @uiNumber() zoom = 1
/**
* Duration multiplier. Set to 0 for instant camera jump.
*/
@serialize() @uiNumber() duration = 1
@serialize() isWorldSpace = true @serialize() isWorldSpace = true


@uiButton() set = (camera?: ICamera) => this.dispatchEvent({type: 'setView', camera, view: this}) @uiButton() set = (camera?: ICamera) => this.dispatchEvent({type: 'setView', camera, view: this})
@uiButton() delete = (camera?: ICamera) => this.dispatchEvent({type: 'deleteView', camera, view: this}) @uiButton() delete = (camera?: ICamera) => this.dispatchEvent({type: 'deleteView', camera, view: this})
@uiButton() animate = (camera?: ICamera, duration?: number) => this.dispatchEvent({type: 'animateView', camera, duration, view: this}) @uiButton() animate = (camera?: ICamera, duration?: number) => this.dispatchEvent({type: 'animateView', camera, duration, view: this})


constructor(name?: string, position?: Vector3, target?: Vector3, quaternion?: Quaternion, zoom?: number) {
constructor(name?: string, position?: Vector3, target?: Vector3, quaternion?: Quaternion, zoom?: number, duration = 1) {
super() super()
if (name !== undefined) this.name = name if (name !== undefined) this.name = name
if (position) this.position.copy(position) if (position) this.position.copy(position)
if (target) this.target.copy(target) if (target) this.target.copy(target)
if (quaternion) this.quaternion.copy(quaternion) if (quaternion) this.quaternion.copy(quaternion)
if (zoom !== undefined) this.zoom = zoom if (zoom !== undefined) this.zoom = zoom
if (duration !== undefined && duration !== 0) this.duration = duration
} }


private _nameChanged() { private _nameChanged() {

+ 71
- 3
src/plugins/animation/CameraViewPlugin.ts Datei anzeigen

*/ */
@serialize() @uiDropdown('Ease', Object.keys(EasingFunctions).map((label:string)=>({label}))) animEase: EasingFunctionType = 'easeInOutSine' // ms @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('Duration', [10, 10000], 10) animDuration = 1000 // ms
@serialize() @uiDropdown('Interpolation', ['spherical', 'linear'].map((label:string)=>({label})))
interpolateMode: 'spherical'|'linear' = 'spherical'
@serialize() @uiDropdown('Interpolation', ['spherical', 'linear'/* , 'spline (dev)'*/].map((label:string)=>({label, value: label.split(' ')[0]})))
interpolateMode: 'spherical'|'linear'|'spline' = 'spherical'
// todo spline
// @serialize() @uiDropdown('Spline Curve', ['centripetal', 'chordal', 'catmullrom'].map((label:string)=>({label})), (t: CameraViewPlugin)=>({hidden: ()=>t.interpolateMode !== 'spline', onChange: ()=>t.uiConfig?.uiRefresh?.()}))
// splineCurve: 'centripetal'|'chordal'|'catmullrom' = 'chordal'




// not used // not used
// const ease = (x:number)=>x // const ease = (x:number)=>x
// const driver = this._driver // const driver = this._driver
this._popAnimations = [] this._popAnimations = []

// const viewIndex = this.camViews.indexOf(view)
// let interpolateMode = this.interpolateMode
// if (viewIndex < 0) {
// if (interpolateMode === 'spline') {
// console.warn('CameraViewPlugin - Cannot animate along a spline with external camera view, fallback to spherical')
// interpolateMode = 'spherical'
// }
// }
//
// if (interpolateMode === 'spline') {
// const points = this.camViews.map(c=>c.position.clone())
// const spline = new CatmullRomCurve3(points, true, this.splineCurve)
//
// const getPosition = (t: number)=>{
// const v = new Vector3()
// const ip = 1. / points.length
// const i = viewIndex === 0 ? points.length : viewIndex
// const d = (i - 1) * ip
// spline.getPointAt(d + t * ip, v)
// return v
// }
//
// pms.push(animateAsync({
// // from: camera.position.clone(),
// // to: view.position.clone(),
// from: 0,
// to: 1,
// duration, ease, driver,
// onUpdate: (v) => camera.position = getPosition(v),
// onComplete: () => camera.position = getPosition(1), // camera.position = view.position,
// onStop: ()=> {
// throw new Error('Animation stopped')
// },
// }, popAnimations))
// // if (new Vector3().subVectors(camera.cameraObject.up, view.up).length() > 0.1)
// // pms.push(animateAsync({
// // from: camera.cameraObject.up.clone(),
// // to: view.up.clone(),
// // duration, ease, driver,
// // onUpdate: (v) => camera.cameraObject.up.copy(v),
// // onComplete: () => camera.cameraObject.up.copy(view.up),
// // }))
// // if (new Vector3().subVectors(camera.target, view.target).length() > 0.1)
// pms.push(animateAsync({
// from: camera.target.clone(),
// to: view.target.clone(),
// duration, ease, driver,
// onUpdate: (v) => {
// camera.target = v
// camera.targetUpdated()
// },
// onComplete: () => {
// camera.target = view.target
// camera.targetUpdated()
// },
// }, popAnimations))
// }

await popmotion.animateCameraAsync(camera, view, this.interpolateMode === 'spherical', {ease, duration}, this._popAnimations) await popmotion.animateCameraAsync(camera, view, this.interpolateMode === 'spherical', {ease, duration}, this._popAnimations)
.catch((e)=>{ .catch((e)=>{
// console.error(e) // console.error(e)
// const recorder = this._viewer?.getPluginByType<CanvasRecorderPlugin>('CanvasRecorder') // const recorder = this._viewer?.getPluginByType<CanvasRecorderPlugin>('CanvasRecorder')
// if (!recorder || !recorder.enabled) return // if (!recorder || !recorder.enabled) return
// if (this._cameraViews.length < 1) return // if (this._cameraViews.length < 1) return
// await this.resetToFirstView()
// if (recorder.isRecording()) { // if (recorder.isRecording()) {
// console.error('CanvasRecorderPlugin is already recording') // console.error('CanvasRecorderPlugin is already recording')
// return // return
// } // }
// let looping = false
// if (this.viewLooping) {
// looping = true
// this.viewLooping = false
// }
// await this.resetToFirstView()
// return new Promise<Blob|undefined>((resolve, reject) => { // return new Promise<Blob|undefined>((resolve, reject) => {
// const listener2 = ()=>{ // const listener2 = ()=>{
// recorder.removeEventListener('start', listenerStart) // recorder.removeEventListener('start', listenerStart)
// onStart?.() // onStart?.()
// await this.animateAllViews() // await this.animateAllViews()
// const blob = await recorder.stopRecording() // const blob = await recorder.stopRecording()
// if (looping) this.viewLooping = true
// if (downloadOnEnd) { // if (downloadOnEnd) {
// const name = await this._viewer?.prompt('Canvas Recorder: Save file as', 'recording.mp4') // const name = await this._viewer?.prompt('Canvas Recorder: Save file as', 'recording.mp4')
// if (name !== null && blob) await this._downloadBlob(blob, name || 'recording.mp4') // if (name !== null && blob) await this._downloadBlob(blob, name || 'recording.mp4')

+ 2
- 2
src/plugins/animation/PopmotionPlugin.ts Datei anzeigen

import type {Driver} from 'popmotion/lib/animations/types' import type {Driver} from 'popmotion/lib/animations/types'
import {now} from 'ts-browser-helpers' import {now} from 'ts-browser-helpers'
import {animate, type AnimationOptions} from 'popmotion'
import {animate, type AnimationOptions, KeyframeOptions} from 'popmotion'
import {AViewerPluginSync, ThreeViewer} from '../../viewer' import {AViewerPluginSync, ThreeViewer} from '../../viewer'
import type {FrameFadePlugin} from '../pipeline/FrameFadePlugin' import type {FrameFadePlugin} from '../pipeline/FrameFadePlugin'
import type {ProgressivePlugin} from '../pipeline/ProgressivePlugin' import type {ProgressivePlugin} from '../pipeline/ProgressivePlugin'
animateCameraToViewLinear(camera, view) animateCameraToViewLinear(camera, view)
return this.animate({ return this.animate({
ease: EasingFunctions.linear, ease: EasingFunctions.linear,
duration: 1000,
...anim, ...options, ...anim, ...options,
duration: ((options as KeyframeOptions).duration ?? 1000) * (view.duration ?? 1),
}) })
} }
async animateCameraAsync(camera: ICamera, view: ICameraView, spherical = true, options?: Partial<AnimationOptions<any>>, animations?: AnimationResult[]) { async animateCameraAsync(camera: ICamera, view: ICameraView, spherical = true, options?: Partial<AnimationOptions<any>>, animations?: AnimationResult[]) {

Laden…
Abbrechen
Speichern