@realsee/vreo 1.0.0-alpha.2 → 1.0.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -1
- package/README.md +46 -36
- package/lib/PlayController/index.js +1 -1
- package/lib/Player/Controller.d.ts +4 -4
- package/lib/Player/Controller.js +30 -17
- package/lib/Player/index.js +4 -1
- package/lib/Player/modules/VideoAgent/VideoAgentMesh.d.ts +2 -2
- package/lib/Player/modules/VideoAgent/VideoAgentMesh.js +3 -3
- package/lib/Player/modules/VideoAgent/index.js +1 -1
- package/lib/Player/modules/Wave/index.js +174 -25
- package/lib/Player/modules/keyframes/BgMusic/index.js +54 -35
- package/lib/Player/modules/keyframes/PanoTag/index.js +3 -3
- package/lib/shared-utils/{AduioLike.d.ts → AudioLike.d.ts} +0 -0
- package/lib/shared-utils/{AduioLike.js → AudioLike.js} +4 -6
- package/lib/typings/VreoUnit.d.ts +6 -6
- package/package.json +2 -4
- package/stylesheets/default.css +11 -4
- package/docs/.nojekyll +0 -1
- package/docs/assets/custom.css +0 -78
- package/docs/assets/highlight.css +0 -127
- package/docs/assets/icons.css +0 -1043
- package/docs/assets/icons.png +0 -0
- package/docs/assets/icons@2x.png +0 -0
- package/docs/assets/main.js +0 -52
- package/docs/assets/search.js +0 -1
- package/docs/assets/style.css +0 -1414
- package/docs/assets/widgets.png +0 -0
- package/docs/assets/widgets@2x.png +0 -0
- package/docs/classes/Player.AudioLike.html +0 -52
- package/docs/classes/Player.Controller.html +0 -54
- package/docs/classes/Player.Player-1.html +0 -50
- package/docs/classes/Player.VideoAgentMesh.html +0 -142
- package/docs/classes/Player.VideoAgentScene.html +0 -1
- package/docs/demo/assets/AppReact.d0ee843a.js +0 -1
- package/docs/demo/assets/default.63925584.js +0 -3984
- package/docs/demo/assets/default.f3f3ca8c.css +0 -1
- package/docs/demo/assets/dynamic.76506c2c.js +0 -1
- package/docs/demo/assets/examples.3d8323db.js +0 -25
- package/docs/demo/assets/examples.dac4a6fe.css +0 -1
- package/docs/demo/assets/index.7e31122c.js +0 -1
- package/docs/demo/assets/index.9331038f.css +0 -1
- package/docs/demo/assets/main.79b11b9d.js +0 -1
- package/docs/demo/assets/react.2ee8565f.css +0 -1
- package/docs/demo/assets/react.c1c07c14.js +0 -25
- package/docs/demo/assets/znRoyv06SZQeqA7m.0057e8ae.js +0 -1
- package/docs/demo/examples.html +0 -17
- package/docs/demo/index-react-dynamic.html +0 -20
- package/docs/demo/index-react.html +0 -20
- package/docs/demo/index.html +0 -19
- package/docs/enums/Player.InfoPanelStyleEnum.html +0 -1
- package/docs/enums/Player.InfoPanelTypeEnum.html +0 -3
- package/docs/enums/Player.PanoEffectEnum.html +0 -5
- package/docs/enums/Player.PanoTagEnum.html +0 -3
- package/docs/enums/Player.PanoTagStyleEnum.html +0 -7
- package/docs/enums/Player.VreoKeyframeEnum.html +0 -25
- package/docs/enums/fivePlugins.CameraMovementEffect.html +0 -1
- package/docs/enums/fivePlugins.Rotation.html +0 -1
- package/docs/index.html +0 -245
- package/docs/interfaces/Player.CustomVreoKeyframeProps.html +0 -1
- package/docs/interfaces/Player.PlayerConfigs.html +0 -7
- package/docs/interfaces/Player.Vertex.html +0 -3
- package/docs/interfaces/Player.VideoAgentMeshOptions.html +0 -8
- package/docs/interfaces/Player.VreoKeyframe.html +0 -3
- package/docs/interfaces/Player.VreoUnit.html +0 -3
- package/docs/interfaces/Player.VreoVideo.html +0 -3
- package/docs/interfaces/fivePlugins.CSS3DRenderPluginExportType.html +0 -4
- package/docs/interfaces/fivePlugins.CameraMovementOptsCallback.html +0 -1
- package/docs/interfaces/fivePlugins.CameraMovementPluginExportType.html +0 -7
- package/docs/interfaces/fivePlugins.CameraMovementPluginParameterType.html +0 -1
- package/docs/interfaces/fivePlugins.ModelTVVideoPluginData.html +0 -1
- package/docs/interfaces/fivePlugins.ModelTVVideoPluginExportType.html +0 -1
- package/docs/interfaces/fivePlugins.ModelTVVideoPluginParameterType.html +0 -1
- package/docs/interfaces/fivePlugins.Vector3Position.html +0 -3
- package/docs/interfaces/react.VreoActionCallbacks.html +0 -23
- package/docs/interfaces/react.VreoProviderProps.html +0 -1
- package/docs/modules/Player.html +0 -37
- package/docs/modules/custom.html +0 -3
- package/docs/modules/fivePlugins.html +0 -6
- package/docs/modules/react.html +0 -1
- package/docs/modules.html +0 -1
- package/resources/PlayController/createHTMLAudioElement.ts +0 -53
- package/resources/PlayController/index.ts +0 -154
- package/resources/Player/App.tsx +0 -66
- package/resources/Player/Controller.ts +0 -297
- package/resources/Player/custom/SpatialScenePanel/index.tsx +0 -264
- package/resources/Player/hooks.ts +0 -26
- package/resources/Player/index.tsx +0 -225
- package/resources/Player/modules/Drawer/index.tsx +0 -40
- package/resources/Player/modules/PopUp/index.tsx +0 -26
- package/resources/Player/modules/ResizeObserver/index.tsx +0 -23
- package/resources/Player/modules/VideoAgent/VideoAgentMesh.ts +0 -302
- package/resources/Player/modules/VideoAgent/VideoAgentScene.ts +0 -56
- package/resources/Player/modules/VideoAgent/index.tsx +0 -53
- package/resources/Player/modules/Wave/index.tsx +0 -18
- package/resources/Player/modules/keyframes/BgMusic/index.tsx +0 -66
- package/resources/Player/modules/keyframes/CameraMovement/index.tsx +0 -37
- package/resources/Player/modules/keyframes/InfoPanel/index.tsx +0 -165
- package/resources/Player/modules/keyframes/ModelVideo/index.tsx +0 -77
- package/resources/Player/modules/keyframes/PanoEffect/index.tsx +0 -99
- package/resources/Player/modules/keyframes/PanoEffect/lineAnime.ts +0 -31
- package/resources/Player/modules/keyframes/PanoTag/index.tsx +0 -83
- package/resources/Player/modules/keyframes/PanoTextLabel/index.tsx +0 -117
- package/resources/Player/modules/keyframes/Prompter/index.tsx +0 -56
- package/resources/Player/modules/keyframes/UpdateVRPanorama/index.tsx +0 -99
- package/resources/Player/modules/keyframes/VideoEffect/index.tsx +0 -115
- package/resources/Player/typings.ts +0 -49
- package/resources/fivePlugins/CSS3DRenderPlugin/centerPoint.ts +0 -5
- package/resources/fivePlugins/CSS3DRenderPlugin/createResizeObserver.ts +0 -17
- package/resources/fivePlugins/CSS3DRenderPlugin/evenNumber.ts +0 -4
- package/resources/fivePlugins/CSS3DRenderPlugin/index.ts +0 -254
- package/resources/fivePlugins/CSS3DRenderPlugin/transformPositionToVector3.ts +0 -5
- package/resources/fivePlugins/CameraMovementPlugin/index.ts +0 -226
- package/resources/fivePlugins/CameraMovementPlugin/typings.ts +0 -59
- package/resources/fivePlugins/ModelTVVideoPlugin/index.ts +0 -278
- package/resources/index.ts +0 -1
- package/resources/react/index.tsx +0 -121
- package/resources/shared-utils/AduioLike.ts +0 -109
- package/resources/shared-utils/Preloader.ts +0 -35
- package/resources/shared-utils/addResizeListener.ts +0 -46
- package/resources/shared-utils/animationFrame/BetterTween.ts +0 -33
- package/resources/shared-utils/animationFrame/index.ts +0 -48
- package/resources/shared-utils/animationFrame/tween.ts +0 -51
- package/resources/shared-utils/createTransMatrix.ts +0 -12
- package/resources/shared-utils/getFileExpandedName.ts +0 -6
- package/resources/shared-utils/getMediaInfo.ts +0 -52
- package/resources/shared-utils/setElementDataset.ts +0 -18
- package/resources/typings/VreoUnit.ts +0 -314
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import { Five, MovePanoOptions } from '@realsee/five'
|
|
2
|
-
import type { FivePlugin } from '@realsee/five'
|
|
3
|
-
import * as TWEEN from '@tweenjs/tween.js'
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
CameraMovementPluginParameterType,
|
|
7
|
-
CameraMovementPluginExportType,
|
|
8
|
-
MoveArgs,
|
|
9
|
-
MoveOpts,
|
|
10
|
-
RotateArgs,
|
|
11
|
-
RotateOpts,
|
|
12
|
-
Rotation,
|
|
13
|
-
} from './typings'
|
|
14
|
-
|
|
15
|
-
import { Easing, tweenProgress } from '../../shared-utils/animationFrame/tween'
|
|
16
|
-
|
|
17
|
-
const PI = Math.PI
|
|
18
|
-
const PI_2 = PI * 2
|
|
19
|
-
|
|
20
|
-
function formatLatitude(rad: number) {
|
|
21
|
-
return rad % PI_2
|
|
22
|
-
}
|
|
23
|
-
function formatLongitude(rad: number) {
|
|
24
|
-
return rad % PI_2
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const getLongitudeParams = (from: number, to: number, rotation: Rotation): { from: number; to: number } => {
|
|
28
|
-
from = formatLongitude(from)
|
|
29
|
-
to = formatLongitude(to)
|
|
30
|
-
|
|
31
|
-
// 逆时针旋转,初始值必须是较大的值
|
|
32
|
-
if (rotation === Rotation.Anticlockwise && from > to) to += PI_2
|
|
33
|
-
|
|
34
|
-
// 顺时针旋转,结束值必须是较大值
|
|
35
|
-
else if (rotation === Rotation.Clockwise && to > from) from += PI_2
|
|
36
|
-
|
|
37
|
-
// Loop 旋转,找锐角旋转
|
|
38
|
-
// 如果 to 比 from 大 180°,逆时针转
|
|
39
|
-
// 如果 from 比 to 大 180°,顺时针转
|
|
40
|
-
else if (rotation !== Rotation.Anticlockwise && rotation !== Rotation.Clockwise && to - from > PI) return getLongitudeParams(from, to, Rotation.Clockwise)
|
|
41
|
-
else if (rotation !== Rotation.Anticlockwise && rotation !== Rotation.Clockwise && from - to > PI) return getLongitudeParams(from, to, Rotation.Anticlockwise)
|
|
42
|
-
return { from, to }
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function progressNumber(from: number, to: number, pst: number) {
|
|
46
|
-
return from + (to - from) * pst
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* **运镜插件** 模拟类似于电影运镜效果。
|
|
51
|
-
*/
|
|
52
|
-
export const CameraMovementPlugin: FivePlugin<CameraMovementPluginParameterType, CameraMovementPluginExportType> = (
|
|
53
|
-
five: Five,
|
|
54
|
-
) => {
|
|
55
|
-
|
|
56
|
-
const move = (args: Partial<MoveArgs>, duration: number, opts: MoveOpts = { preload: true }) => {
|
|
57
|
-
return new Promise<boolean>(async (resolve, reject) => {
|
|
58
|
-
|
|
59
|
-
if (opts.asyncStartCallback) {
|
|
60
|
-
opts.asyncStartCallback()
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (five.panoIndex === undefined) {
|
|
64
|
-
return reject(false)
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (args.mode && args.mode !== five.currentMode) {
|
|
68
|
-
await new Promise((resolve) => {
|
|
69
|
-
if (!args.mode) return
|
|
70
|
-
five.once('modeChange', (mode) => {
|
|
71
|
-
five.once('initAnimationEnded', () => {
|
|
72
|
-
if (mode === args.mode) {
|
|
73
|
-
resolve(true)
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
})
|
|
77
|
-
five.changeMode(args.mode, {
|
|
78
|
-
fov: args.fov || undefined,
|
|
79
|
-
latitude: args.latitude || undefined,
|
|
80
|
-
longitude: args.longitude || undefined,
|
|
81
|
-
panoIndex: args.panoIndex || undefined,
|
|
82
|
-
})
|
|
83
|
-
})
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (args.mode === Five.Mode.Floorplan) {
|
|
87
|
-
return resolve(true)
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (opts.preload && args.panoIndex !== undefined && args.panoIndex !== five.panoIndex) {
|
|
91
|
-
await five.preloadPano(args.panoIndex)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (opts.asyncEndCallback) {
|
|
95
|
-
opts.asyncEndCallback()
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
args.panoIndex === undefined &&
|
|
100
|
-
args.fov === undefined &&
|
|
101
|
-
args.latitude === undefined &&
|
|
102
|
-
args.longitude === undefined
|
|
103
|
-
) {
|
|
104
|
-
return resolve(true)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const panoIndex = args.panoIndex !== undefined ? args.panoIndex : five.panoIndex
|
|
109
|
-
|
|
110
|
-
if (panoIndex !== undefined) {
|
|
111
|
-
const movePanoOptions: MovePanoOptions = Object.assign(args, {
|
|
112
|
-
duration, // 移动耗时
|
|
113
|
-
moveEndCallback: () => resolve(true), // 移动结束
|
|
114
|
-
moveCancelCallback: () => {
|
|
115
|
-
resolve(true)
|
|
116
|
-
}, // 移动开始
|
|
117
|
-
// effect: args.transEffect || 'fade',
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
await five.moveToPano(
|
|
121
|
-
panoIndex,
|
|
122
|
-
movePanoOptions,
|
|
123
|
-
)
|
|
124
|
-
} else {
|
|
125
|
-
reject(false)
|
|
126
|
-
}
|
|
127
|
-
})
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const getAnimeParams = (args: RotateArgs) => {
|
|
131
|
-
const currentFiveState = five.state
|
|
132
|
-
// latitude
|
|
133
|
-
const fromLatitude = formatLatitude(currentFiveState.latitude)
|
|
134
|
-
const toLatitude = formatLatitude(args.latitude)
|
|
135
|
-
// longitude
|
|
136
|
-
const { from: fromLongitude, to: toLongitude } = getLongitudeParams(
|
|
137
|
-
currentFiveState.longitude,
|
|
138
|
-
args.longitude,
|
|
139
|
-
args.rotation || Rotation.Loop,
|
|
140
|
-
)
|
|
141
|
-
// fov
|
|
142
|
-
const fromFov = currentFiveState.fov
|
|
143
|
-
const toFov = args.fov
|
|
144
|
-
return {
|
|
145
|
-
from: { latitude: fromLatitude, longitude: fromLongitude, fov: fromFov },
|
|
146
|
-
to: { latitude: toLatitude, longitude: toLongitude, fov: toFov },
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const rotate = async (args: RotateArgs, duration: number, opts: RotateOpts = {}) => {
|
|
151
|
-
if (opts.asyncStartCallback) {
|
|
152
|
-
opts.asyncStartCallback()
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// 先切换模型再出旋转效果
|
|
156
|
-
if (args.mode && five.currentMode !== args.mode) {
|
|
157
|
-
await five.changeMode(args.mode)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// 全景状态下,需要点位对齐
|
|
161
|
-
if (args.mode === Five.Mode.Panorama &&
|
|
162
|
-
five.currentMode === Five.Mode.Panorama &&
|
|
163
|
-
args.panoIndex !== undefined &&
|
|
164
|
-
args.panoIndex !== five.panoIndex) {
|
|
165
|
-
if (opts.preload) await five.preloadPano(args.panoIndex)
|
|
166
|
-
await new Promise((resolve, reject) => {
|
|
167
|
-
five.moveToPano(args.panoIndex, {
|
|
168
|
-
moveEndCallback: () => resolve(true), // 移动结束
|
|
169
|
-
moveCancelCallback: () => reject(false), // 移动开始
|
|
170
|
-
effect: 'fade',
|
|
171
|
-
})
|
|
172
|
-
})
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (opts.asyncEndCallback) {
|
|
176
|
-
opts.asyncEndCallback()
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const { from, to } = getAnimeParams(args)
|
|
180
|
-
return await new Promise<boolean>((resolve, reject) => {
|
|
181
|
-
const onUpdate = ({ progress }: { progress: number }) => {
|
|
182
|
-
const state: Record<string, number> = {}
|
|
183
|
-
state.longitude = progressNumber(from.longitude, to.longitude, progress) % PI_2
|
|
184
|
-
state.latitude = progressNumber(from.latitude, to.latitude, progress)
|
|
185
|
-
state.fov = progressNumber(from.fov, to.fov, progress)
|
|
186
|
-
five.setState(state, true)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const onComplete = () => {
|
|
190
|
-
resolve(true)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const onDestroy = () => {
|
|
194
|
-
resolve(false)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
let animeDuration = duration
|
|
198
|
-
|
|
199
|
-
if (args.rotation === Rotation.Loop) {
|
|
200
|
-
animeDuration = args.rotateSpeed
|
|
201
|
-
? Math.ceil((Math.abs(to.longitude - from.longitude) / args.rotateSpeed) * 1000)
|
|
202
|
-
: duration
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
type _Tween = TWEEN.Tween<{ progress: number }> & { onDestroy: (p: any) => _Tween; destroy: () => void }
|
|
206
|
-
|
|
207
|
-
const tween = (tweenProgress(animeDuration, Easing.Linear.None) as _Tween)
|
|
208
|
-
.onUpdate(onUpdate)
|
|
209
|
-
.onComplete(onComplete)
|
|
210
|
-
.onDestroy(onDestroy)
|
|
211
|
-
if (args.rotation === Rotation.Loop) {
|
|
212
|
-
tween.repeat(Infinity).yoyo(true)
|
|
213
|
-
}
|
|
214
|
-
setTimeout(() => {
|
|
215
|
-
// 总时间到了之后强制结束,同时也是 Loop 模式的结束方式
|
|
216
|
-
tween.destroy()
|
|
217
|
-
resolve(true)
|
|
218
|
-
}, duration)
|
|
219
|
-
})
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return {
|
|
223
|
-
move,
|
|
224
|
-
rotate,
|
|
225
|
-
}
|
|
226
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/* eslint-disable prettier/prettier */
|
|
2
|
-
import { Mode, MovePanoOptions, Pose } from '@realsee/five'
|
|
3
|
-
|
|
4
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
|
5
|
-
export interface CameraMovementPluginParameterType { }
|
|
6
|
-
|
|
7
|
-
export interface CameraMovementPluginExportType {
|
|
8
|
-
/**
|
|
9
|
-
* 运镜:移动
|
|
10
|
-
* @param moveArgs
|
|
11
|
-
* @param duration
|
|
12
|
-
* @param opts
|
|
13
|
-
*/
|
|
14
|
-
move(moveArgs: Partial<MoveArgs>, duration: number, opts?: MoveOpts): Promise<boolean>
|
|
15
|
-
/**
|
|
16
|
-
* 运镜:旋转
|
|
17
|
-
* @param args
|
|
18
|
-
* @param duration
|
|
19
|
-
* @param opts
|
|
20
|
-
*/
|
|
21
|
-
rotate(args: RotateArgs, duration: number, opts?: RotateOpts): Promise<boolean>
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export enum CameraMovementEffect {
|
|
25
|
-
Move = 'Move',
|
|
26
|
-
Rotate = 'Rotate',
|
|
27
|
-
}
|
|
28
|
-
export enum Rotation {
|
|
29
|
-
Clockwise = 'Clockwise',
|
|
30
|
-
Anticlockwise = 'Anticlockwise',
|
|
31
|
-
Loop = 'Loop',
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export interface CameraMovementOptsCallback {
|
|
35
|
-
asyncStartCallback?: () => void
|
|
36
|
-
asyncEndCallback?: () => void
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export type MoveArgs = {
|
|
40
|
-
mode: Mode
|
|
41
|
-
panoIndex: number
|
|
42
|
-
transEffect?: "fly" | "fade" | "instant"
|
|
43
|
-
} & Pose
|
|
44
|
-
|
|
45
|
-
export type MoveOpts = {
|
|
46
|
-
preload?: boolean
|
|
47
|
-
} & CameraMovementOptsCallback
|
|
48
|
-
|
|
49
|
-
export type RotateArgs = {
|
|
50
|
-
mode?: Mode
|
|
51
|
-
panoIndex: number
|
|
52
|
-
loop: boolean
|
|
53
|
-
rotateSpeed: number
|
|
54
|
-
rotation: Rotation
|
|
55
|
-
} & Pose
|
|
56
|
-
|
|
57
|
-
export type RotateOpts = {
|
|
58
|
-
preload?: boolean
|
|
59
|
-
} & CameraMovementOptsCallback
|
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import * as THREE from 'three'
|
|
2
|
-
import type { FivePlugin } from '@realsee/five'
|
|
3
|
-
|
|
4
|
-
export interface ModelTVVideoPluginData {
|
|
5
|
-
enable?: boolean
|
|
6
|
-
video_src: string
|
|
7
|
-
video_poster_src: string
|
|
8
|
-
points: { x: number; y: number; z: number }[][]
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface ModelTVVideoPluginParameterType {
|
|
12
|
-
videoElement?: HTMLVideoElement
|
|
13
|
-
}
|
|
14
|
-
export interface ModelTVVideoPluginExportType {
|
|
15
|
-
enable: () => void
|
|
16
|
-
disable: () => void
|
|
17
|
-
load: (data: ModelTVVideoPluginData, videoElement?: HTMLVideoElement) => Promise<void>
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type ModelTVVideoPluginPoints = THREE.Vector3[][]
|
|
21
|
-
|
|
22
|
-
type ModelTVVideoPluginState = {
|
|
23
|
-
videoMeshes: THREE.Mesh<THREE.BufferGeometry, THREE.MeshBasicMaterial>[]
|
|
24
|
-
videoTextureEnabled: boolean
|
|
25
|
-
videoSource: string
|
|
26
|
-
rectPoints: ModelTVVideoPluginPoints
|
|
27
|
-
enabled: boolean
|
|
28
|
-
imageTexture?: THREE.Texture
|
|
29
|
-
videoTexture?: THREE.VideoTexture
|
|
30
|
-
videoElement?: HTMLVideoElement
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const ModelTVVideoPlugin: FivePlugin<ModelTVVideoPluginParameterType, ModelTVVideoPluginExportType> = (
|
|
34
|
-
five,
|
|
35
|
-
{ videoElement },
|
|
36
|
-
) => {
|
|
37
|
-
const state: ModelTVVideoPluginState = {
|
|
38
|
-
videoMeshes: [],
|
|
39
|
-
videoTextureEnabled: false,
|
|
40
|
-
videoSource: '',
|
|
41
|
-
rectPoints: [],
|
|
42
|
-
enabled: false,
|
|
43
|
-
videoElement: videoElement,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const setMuted = (muted: boolean) => {
|
|
47
|
-
if (state.videoTexture) {
|
|
48
|
-
state.videoTexture.image.muted = muted
|
|
49
|
-
state.videoTexture.image.play()
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
const getMuted = () => {
|
|
53
|
-
if (state.videoTexture) return state.videoTexture.image.muted
|
|
54
|
-
else return true
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const enable = () => {
|
|
58
|
-
if (state.enabled) return
|
|
59
|
-
if (!state.videoTexture) return
|
|
60
|
-
|
|
61
|
-
state.enabled = true
|
|
62
|
-
state.videoMeshes = createPanoVideoMeshes()
|
|
63
|
-
state.videoMeshes.forEach((mesh) => five.scene.add(mesh))
|
|
64
|
-
|
|
65
|
-
const play = () => {
|
|
66
|
-
if (!state.videoTexture) return
|
|
67
|
-
|
|
68
|
-
const timeupdate = () => {
|
|
69
|
-
if (!state.videoTexture) return
|
|
70
|
-
state.videoTexture?.image.removeEventListener('timeupdate', timeupdate)
|
|
71
|
-
state.videoTextureEnabled = true
|
|
72
|
-
state.videoMeshes.forEach((mesh) => {
|
|
73
|
-
if (mesh.material.map !== state.videoTexture) mesh.material.map = state.videoTexture!
|
|
74
|
-
})
|
|
75
|
-
five.needsRender = true
|
|
76
|
-
}
|
|
77
|
-
state.videoTexture.image.addEventListener('timeupdate', timeupdate)
|
|
78
|
-
if (state.videoTexture && state.videoMeshes.length) {
|
|
79
|
-
state.videoTexture.image.play()
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (five.model.loaded) play()
|
|
84
|
-
else {
|
|
85
|
-
return five.once('modelLoaded', () => play())
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const disable = () => {
|
|
90
|
-
if (!state.enabled) return
|
|
91
|
-
state.enabled = false
|
|
92
|
-
state.videoMeshes.forEach((mesh) => {
|
|
93
|
-
mesh.geometry.dispose()
|
|
94
|
-
mesh.material.dispose()
|
|
95
|
-
five.scene.remove(mesh)
|
|
96
|
-
if (state.videoTexture) state.videoTexture.image.pause()
|
|
97
|
-
})
|
|
98
|
-
state.videoMeshes = []
|
|
99
|
-
five.needsRender = true
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
const createPanoVideoMeshes = () => {
|
|
103
|
-
return state.rectPoints.map((points, index) => {
|
|
104
|
-
const geometry = new THREE.BufferGeometry()
|
|
105
|
-
const segments = 128
|
|
106
|
-
|
|
107
|
-
const verticesArray: number[] = []
|
|
108
|
-
verticesArray.push(points[0].x, points[0].y, points[0].z)
|
|
109
|
-
for (let i = 1; i < segments; i++) {
|
|
110
|
-
verticesArray.push(
|
|
111
|
-
points[0].x + ((points[1].x - points[0].x) * i) / segments,
|
|
112
|
-
points[0].y + ((points[1].y - points[0].y) * i) / segments,
|
|
113
|
-
points[0].z + ((points[1].z - points[0].z) * i) / segments,
|
|
114
|
-
)
|
|
115
|
-
}
|
|
116
|
-
verticesArray.push(points[1].x, points[1].y, points[1].z)
|
|
117
|
-
verticesArray.push(points[2].x, points[2].y, points[2].z)
|
|
118
|
-
for (let i = 1; i < segments; i++) {
|
|
119
|
-
verticesArray.push(
|
|
120
|
-
points[2].x + ((points[3].x - points[2].x) * i) / segments,
|
|
121
|
-
points[2].y + ((points[3].y - points[2].y) * i) / segments,
|
|
122
|
-
points[2].z + ((points[3].z - points[2].z) * i) / segments,
|
|
123
|
-
)
|
|
124
|
-
}
|
|
125
|
-
verticesArray.push(points[3].x, points[3].y, points[3].z)
|
|
126
|
-
|
|
127
|
-
const uvArray: number[] = []
|
|
128
|
-
uvArray.push(0, 1)
|
|
129
|
-
for (let i = 1; i < segments; i++) {
|
|
130
|
-
uvArray.push(0, 1 - i / segments)
|
|
131
|
-
}
|
|
132
|
-
uvArray.push(0, 0)
|
|
133
|
-
uvArray.push(1, 0)
|
|
134
|
-
for (let i = 1; i < segments; i++) {
|
|
135
|
-
uvArray.push(1, i / segments)
|
|
136
|
-
}
|
|
137
|
-
uvArray.push(1, 1)
|
|
138
|
-
|
|
139
|
-
const indicesArray: number[] = []
|
|
140
|
-
for (let i = 0; i < segments; i++) {
|
|
141
|
-
indicesArray.push(i, i + 1, segments * 2 - i, i, segments * 2 - i, segments * 2 + 1 - i)
|
|
142
|
-
}
|
|
143
|
-
geometry.setAttribute('position', new THREE.BufferAttribute(new Float32Array(verticesArray), 3))
|
|
144
|
-
geometry.setAttribute('uv', new THREE.BufferAttribute(new Float32Array(uvArray), 2))
|
|
145
|
-
geometry.setIndex(new THREE.BufferAttribute(new Uint32Array(indicesArray), 1))
|
|
146
|
-
const material = new THREE.MeshBasicMaterial({
|
|
147
|
-
map: state.videoTextureEnabled ? state.videoTexture : state.imageTexture,
|
|
148
|
-
side: THREE.DoubleSide,
|
|
149
|
-
})
|
|
150
|
-
const mesh = new THREE.Mesh(geometry, material)
|
|
151
|
-
mesh.renderOrder = 1
|
|
152
|
-
mesh.name = `video-${index}-${performance.now()}`
|
|
153
|
-
return mesh
|
|
154
|
-
})
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const getImageTexture = (source: string) => {
|
|
158
|
-
const texture = new THREE.TextureLoader().load(source)
|
|
159
|
-
texture.minFilter = THREE.LinearFilter
|
|
160
|
-
texture.magFilter = THREE.LinearFilter
|
|
161
|
-
texture.format = THREE.RGBFormat
|
|
162
|
-
return texture
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const getVideoTexture = (
|
|
166
|
-
source: string,
|
|
167
|
-
video?: HTMLVideoElement,
|
|
168
|
-
): Promise<THREE.VideoTexture & { videoSource: string }> => {
|
|
169
|
-
return new Promise((resolve, reject) => {
|
|
170
|
-
const xhr = new XMLHttpRequest()
|
|
171
|
-
xhr.onreadystatechange = () => {
|
|
172
|
-
if (xhr.readyState == 4) {
|
|
173
|
-
if (xhr.status == 200) {
|
|
174
|
-
const url = window.URL || window.webkitURL
|
|
175
|
-
video = video || document.createElement('video')
|
|
176
|
-
video.crossOrigin = 'anonymous'
|
|
177
|
-
video.autoplay = true
|
|
178
|
-
video.muted = true
|
|
179
|
-
video.loop = true
|
|
180
|
-
video.playsInline = true
|
|
181
|
-
video.src = url.createObjectURL(xhr.response)
|
|
182
|
-
const texture = new THREE.VideoTexture(video)
|
|
183
|
-
texture.minFilter = THREE.LinearFilter
|
|
184
|
-
texture.magFilter = THREE.LinearFilter
|
|
185
|
-
texture.format = THREE.RGBFormat
|
|
186
|
-
resolve(Object.assign(texture, { videoSource: source }))
|
|
187
|
-
} else {
|
|
188
|
-
reject(new Error('Video download Error: ' + xhr.status))
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
xhr.onerror = (error) => reject(error)
|
|
193
|
-
xhr.open('GET', source)
|
|
194
|
-
xhr.responseType = 'blob'
|
|
195
|
-
xhr.send()
|
|
196
|
-
})
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const load = async (data: ModelTVVideoPluginData, videoElement?: HTMLVideoElement) => {
|
|
200
|
-
const { video_src, video_poster_src, points } = data
|
|
201
|
-
state.videoSource = video_src
|
|
202
|
-
state.rectPoints = points.map((items) => items.map(({ x, y, z }) => new THREE.Vector3(x, y, z)))
|
|
203
|
-
state.imageTexture = getImageTexture(video_poster_src)
|
|
204
|
-
|
|
205
|
-
if (videoElement) {
|
|
206
|
-
state.videoElement = videoElement
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
state.videoTexture = await getVideoTexture(state.videoSource, state.videoElement)
|
|
210
|
-
|
|
211
|
-
state.enabled = !!data.enable
|
|
212
|
-
if (state.enabled) enable()
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
five.on('modeChange', () => setMuted(true))
|
|
216
|
-
|
|
217
|
-
five.on('wantsTapGesture', (raycaster) => {
|
|
218
|
-
if (!state.enabled) return
|
|
219
|
-
const [intersect] = raycaster.intersectObjects(five.scene.children, true)
|
|
220
|
-
if (!!intersect && /^video/.test(intersect.object.name)) {
|
|
221
|
-
if (state.videoTexture) setMuted(!state.videoTexture.image.muted)
|
|
222
|
-
return false
|
|
223
|
-
}
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
five.on('panoArrived', () => {
|
|
227
|
-
if (!state.enabled) return
|
|
228
|
-
if (getMuted()) return
|
|
229
|
-
const cameraPosition = five.camera.position
|
|
230
|
-
|
|
231
|
-
const visible = state.rectPoints.find((points) => {
|
|
232
|
-
const centerVector = points.reduce(
|
|
233
|
-
(total, curr) =>
|
|
234
|
-
new THREE.Vector3(
|
|
235
|
-
total.x + curr.x / points.length,
|
|
236
|
-
total.y + curr.y / points.length,
|
|
237
|
-
total.z + curr.z / points.length,
|
|
238
|
-
),
|
|
239
|
-
new THREE.Vector3(),
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
return (
|
|
243
|
-
points
|
|
244
|
-
.map(
|
|
245
|
-
(point) =>
|
|
246
|
-
new THREE.Vector3(
|
|
247
|
-
(point.x + centerVector.x) / 2,
|
|
248
|
-
(point.y + centerVector.y) / 2,
|
|
249
|
-
(point.z + centerVector.z) / 2,
|
|
250
|
-
),
|
|
251
|
-
)
|
|
252
|
-
.filter((vector) => {
|
|
253
|
-
vector = vector.clone().sub(cameraPosition).normalize()
|
|
254
|
-
const raycaster = new THREE.Raycaster(cameraPosition, vector)
|
|
255
|
-
const [intersect] = raycaster.intersectObjects(five.scene.children, true)
|
|
256
|
-
return !!intersect && /^video/.test(intersect.object.name)
|
|
257
|
-
}).length >= 2
|
|
258
|
-
)
|
|
259
|
-
})
|
|
260
|
-
if (!visible) setMuted(true)
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
five.on('renderFrame', () => {
|
|
264
|
-
state.videoMeshes.forEach((meshes) => {
|
|
265
|
-
if (meshes)
|
|
266
|
-
//@ts-ignore
|
|
267
|
-
meshes.needsRender = true
|
|
268
|
-
})
|
|
269
|
-
})
|
|
270
|
-
|
|
271
|
-
five.on('load', (input) => {
|
|
272
|
-
if (input.modelTVVideoData) {
|
|
273
|
-
load(input.modelTVVideoData)
|
|
274
|
-
}
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
return { enable, disable, load }
|
|
278
|
-
}
|
package/resources/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { Player } from './Player'
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { unsafe__useFiveInstance } from '@realsee/five/react'
|
|
2
|
-
import * as React from 'react'
|
|
3
|
-
import { Player } from '../Player'
|
|
4
|
-
import { PlayerConfigs } from '../Player/typings'
|
|
5
|
-
import { VreoKeyframeEvent, VreoUnit } from '../typings/VreoUnit'
|
|
6
|
-
|
|
7
|
-
const VreoContext = React.createContext<Player | null>(null)
|
|
8
|
-
|
|
9
|
-
export interface VreoProviderProps {
|
|
10
|
-
configs?: Partial<PlayerConfigs>
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export const VreoProvider: React.FC<VreoProviderProps> = (props ) => {
|
|
14
|
-
const five = unsafe__useFiveInstance()
|
|
15
|
-
|
|
16
|
-
const [player, setPlayer] = React.useState<Player | null>(null)
|
|
17
|
-
const playerRef = React.useRef<Player | null>(null)
|
|
18
|
-
|
|
19
|
-
React.useEffect(() => {
|
|
20
|
-
playerRef.current = new Player(five, props.configs || {})
|
|
21
|
-
setPlayer(playerRef.current)
|
|
22
|
-
|
|
23
|
-
return () => {
|
|
24
|
-
playerRef.current?.dispose()
|
|
25
|
-
}
|
|
26
|
-
}, [])
|
|
27
|
-
|
|
28
|
-
if (!player) return <></>
|
|
29
|
-
|
|
30
|
-
return <VreoContext.Provider value={player}>{props.children}</VreoContext.Provider>
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function useVreoInstance() {
|
|
34
|
-
const context = React.useContext(VreoContext)
|
|
35
|
-
if (!context) {
|
|
36
|
-
throw new Error('VreoProvider never found.')
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return context
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* VreoPlayer 命令集合。
|
|
44
|
-
*/
|
|
45
|
-
export interface VreoActionCallbacks {
|
|
46
|
-
/**
|
|
47
|
-
* 载入剧本数据。
|
|
48
|
-
* @param vreoUnit 剧本数据
|
|
49
|
-
* @param currentTime 开始时间戳
|
|
50
|
-
* @param preload 是否开启预载
|
|
51
|
-
* @param force 是否强制载入
|
|
52
|
-
*/
|
|
53
|
-
load: (vreoUnit: VreoUnit, currentTime?: number, preload?: boolean, force?: boolean) => Promise<boolean>
|
|
54
|
-
/**
|
|
55
|
-
* 播放。
|
|
56
|
-
*/
|
|
57
|
-
play: (currentTime?: number) => void
|
|
58
|
-
/**
|
|
59
|
-
* 暂停。
|
|
60
|
-
*/
|
|
61
|
-
pause: () => void
|
|
62
|
-
/**
|
|
63
|
-
* 显示 UI 面板。
|
|
64
|
-
*/
|
|
65
|
-
show: () => void
|
|
66
|
-
/**
|
|
67
|
-
* 隐藏 UI 面板。
|
|
68
|
-
*/
|
|
69
|
-
hide: () => void
|
|
70
|
-
/**
|
|
71
|
-
* 销毁数据及部分定时任务。
|
|
72
|
-
*/
|
|
73
|
-
dispose: () => void
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function useVreoAction() {
|
|
77
|
-
const player = useVreoInstance()
|
|
78
|
-
|
|
79
|
-
const load = React.useCallback(
|
|
80
|
-
(vreoUnit: VreoUnit, currentTime?: number) => player.load(vreoUnit, currentTime),
|
|
81
|
-
[player]
|
|
82
|
-
)
|
|
83
|
-
|
|
84
|
-
const play = React.useCallback((currentTime?: number) => player.play(currentTime || 0), [player])
|
|
85
|
-
const pause = React.useCallback(() => player.pause(), [player])
|
|
86
|
-
const show = React.useCallback(() => player.show(), [player])
|
|
87
|
-
const hide = React.useCallback(() => player.hide(), [player])
|
|
88
|
-
const dispose = React.useCallback(() => player.dispose(), [player])
|
|
89
|
-
|
|
90
|
-
return { load, pause, show, play, hide, dispose }
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function useVreoEventCallback<T extends keyof VreoKeyframeEvent>(
|
|
94
|
-
name: T,
|
|
95
|
-
callback: VreoKeyframeEvent[T],
|
|
96
|
-
deps?: React.DependencyList | undefined
|
|
97
|
-
) {
|
|
98
|
-
const player = useVreoInstance()
|
|
99
|
-
let dependencyList: React.DependencyList = [player, name]
|
|
100
|
-
if (deps !== undefined) {
|
|
101
|
-
dependencyList = dependencyList.concat(deps)
|
|
102
|
-
}
|
|
103
|
-
React.useEffect(() => {
|
|
104
|
-
// @ts-ignore
|
|
105
|
-
player.on(name, callback)
|
|
106
|
-
return () => {
|
|
107
|
-
// @ts-ignore
|
|
108
|
-
player.off(name, callback)
|
|
109
|
-
}
|
|
110
|
-
}, dependencyList)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function useVreoPausedState() {
|
|
114
|
-
const player = useVreoInstance()
|
|
115
|
-
const [state, setState] = React.useState(player.paused)
|
|
116
|
-
|
|
117
|
-
useVreoEventCallback('paused', () => setState(true))
|
|
118
|
-
useVreoEventCallback('playing', () => setState(false))
|
|
119
|
-
|
|
120
|
-
return state
|
|
121
|
-
}
|