bg2e-js 2.3.11 → 2.3.13
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/dist/bg2e-js.js +356 -326
- package/dist/bg2e-js.js.map +1 -1
- package/package.json +56 -56
- package/src/app/AppController.ts +39 -39
- package/src/app/Bg2KeyboardEvent.ts +54 -54
- package/src/app/Bg2MouseEvent.ts +82 -82
- package/src/app/Bg2TouchEvent.ts +18 -18
- package/src/app/Canvas.ts +108 -108
- package/src/app/EventBase.ts +10 -10
- package/src/app/MainLoop.ts +273 -273
- package/src/app/index.ts +24 -24
- package/src/base/Color.ts +134 -134
- package/src/base/Environment.ts +183 -183
- package/src/base/Light.ts +192 -192
- package/src/base/Material.ts +620 -620
- package/src/base/PolyList.ts +365 -365
- package/src/base/Texture.ts +620 -620
- package/src/base/index.ts +81 -81
- package/src/db/Bg2LoaderPlugin.ts +143 -143
- package/src/db/DBPluginApi.ts +48 -48
- package/src/db/Loader.ts +116 -116
- package/src/db/LoaderPlugin.ts +34 -34
- package/src/db/MtlParser.ts +7 -7
- package/src/db/ObjLoaderPlugin.ts +54 -54
- package/src/db/ObjParser.ts +252 -252
- package/src/db/ObjWriterPlugin.ts +18 -18
- package/src/db/VitscnjLoaderPlugin.ts +112 -112
- package/src/db/Writer.ts +52 -52
- package/src/db/WriterPlugin.ts +22 -22
- package/src/db/index.ts +44 -44
- package/src/debug/DebugRenderer.ts +173 -173
- package/src/debug/WebGLTextureViewer.ts +75 -75
- package/src/debug/index.ts +6 -6
- package/src/index.html +11 -11
- package/src/index.ts +33 -33
- package/src/manipulation/SelectionBuffer.ts +81 -81
- package/src/manipulation/SelectionHighlight.ts +105 -84
- package/src/manipulation/SelectionIdAssignVisitor.ts +96 -96
- package/src/manipulation/SelectionManager.ts +196 -188
- package/src/manipulation/SelectionMode.ts +6 -6
- package/src/math/Mat3.ts +259 -259
- package/src/math/Mat4.ts +710 -710
- package/src/math/MatrixStrategy.ts +25 -25
- package/src/math/Quat.ts +65 -65
- package/src/math/Vec.ts +753 -753
- package/src/math/constants.ts +46 -46
- package/src/math/functions.ts +103 -103
- package/src/math/index.ts +74 -74
- package/src/phsics/joint.ts +137 -137
- package/src/primitives/arrow.ts +57 -57
- package/src/primitives/cone.ts +138 -138
- package/src/primitives/cube.ts +60 -60
- package/src/primitives/cylinder.ts +216 -216
- package/src/primitives/index.ts +13 -13
- package/src/primitives/plane.ts +31 -31
- package/src/primitives/sphere.ts +809 -809
- package/src/react/useBg2e.ts +69 -69
- package/src/render/BRDFIntegrationMap.ts +4 -4
- package/src/render/Environment.ts +135 -135
- package/src/render/FrameBuffer.ts +35 -35
- package/src/render/MaterialRenderer.ts +34 -34
- package/src/render/Pipeline.ts +108 -108
- package/src/render/PolyListRenderer.ts +47 -47
- package/src/render/RenderBuffer.ts +197 -197
- package/src/render/RenderQueue.ts +198 -198
- package/src/render/RenderState.ts +116 -116
- package/src/render/Renderer.ts +248 -248
- package/src/render/SceneAppController.ts +250 -250
- package/src/render/SceneRenderer.ts +387 -387
- package/src/render/Shader.ts +32 -32
- package/src/render/ShadowRenderer.ts +176 -176
- package/src/render/SkyCube.ts +105 -105
- package/src/render/SkySphere.ts +117 -117
- package/src/render/TextureMergerRenderer.ts +70 -70
- package/src/render/TextureRenderer.ts +34 -34
- package/src/render/index.ts +67 -67
- package/src/render/webgl/FrameBuffer.ts +9 -9
- package/src/render/webgl/MaterialRenderer.ts +112 -112
- package/src/render/webgl/Pipeline.ts +88 -88
- package/src/render/webgl/PolyListRenderer.ts +260 -260
- package/src/render/webgl/RenderBuffer.ts +226 -226
- package/src/render/webgl/Renderer.ts +262 -262
- package/src/render/webgl/SceneRenderer.ts +67 -67
- package/src/render/webgl/ShaderProgram.ts +424 -424
- package/src/render/webgl/ShadowRenderer.ts +6 -6
- package/src/render/webgl/SkyCube.ts +15 -15
- package/src/render/webgl/SkySphere.ts +15 -15
- package/src/render/webgl/State.ts +152 -152
- package/src/render/webgl/TextureRenderer.ts +167 -167
- package/src/render/webgl/VertexBuffer.ts +137 -137
- package/src/render/webgl/index.ts +35 -35
- package/src/scene/Camera.ts +458 -458
- package/src/scene/Chain.ts +44 -44
- package/src/scene/ChainJoint.ts +58 -58
- package/src/scene/Component.ts +177 -177
- package/src/scene/ComponentMap.ts +106 -106
- package/src/scene/Drawable.ts +154 -154
- package/src/scene/EnvironmentComponent.ts +141 -141
- package/src/scene/FindNodeVisitor.ts +59 -59
- package/src/scene/LightComponent.ts +154 -154
- package/src/scene/MatrixState.ts +46 -46
- package/src/scene/Node.ts +328 -328
- package/src/scene/NodeVisitor.ts +15 -15
- package/src/scene/OrbitCameraController.ts +450 -450
- package/src/scene/SmoothOrbitCameraController.ts +99 -99
- package/src/scene/Transform.ts +73 -73
- package/src/scene/index.ts +60 -60
- package/src/shaders/BasicDiffuseColorShader.ts +111 -111
- package/src/shaders/BasicPBRLightShader.ts +276 -276
- package/src/shaders/DebugRenderShader.ts +97 -97
- package/src/shaders/DepthRenderShader.ts +127 -127
- package/src/shaders/IrradianceMapCubeShader.ts +115 -115
- package/src/shaders/PBRLightIBLShader.ts +486 -486
- package/src/shaders/PickSelectionShader.ts +101 -101
- package/src/shaders/PresentDebugFramebufferShader.ts +118 -118
- package/src/shaders/PresentTextureShader.ts +99 -99
- package/src/shaders/SelectionHighlightShader.ts +143 -127
- package/src/shaders/ShaderFunction.ts +318 -318
- package/src/shaders/SkyCubeShader.ts +93 -93
- package/src/shaders/SkySphereShader.ts +102 -102
- package/src/shaders/SpecularMapCubeShader.ts +164 -164
- package/src/shaders/TextureMergerShader.ts +171 -171
- package/src/shaders/index.ts +36 -36
- package/src/shaders/webgl/color_correction.glsl +47 -47
- package/src/shaders/webgl/constants.glsl +6 -6
- package/src/shaders/webgl/index.ts +70 -70
- package/src/shaders/webgl/normal_map.glsl +9 -9
- package/src/shaders/webgl/pbr.glsl +173 -173
- package/src/shaders/webgl/uniforms.glsl +91 -91
- package/src/shaders/webgl_shader_lib.ts +213 -213
- package/src/tools/BinaryResourceProvider.ts +14 -14
- package/src/tools/ImageResourceProvider.ts +66 -66
- package/src/tools/MaterialModifier.ts +446 -446
- package/src/tools/Resource.ts +203 -203
- package/src/tools/ResourceProvider.ts +69 -69
- package/src/tools/TextResourceProvider.ts +24 -24
- package/src/tools/TextureCache.ts +51 -51
- package/src/tools/TextureResourceDatabase.ts +100 -100
- package/src/tools/UserAgent.ts +362 -362
- package/src/tools/VideoResourceProvider.ts +50 -50
- package/src/tools/WriteStrategy.ts +22 -22
- package/src/tools/base64.ts +11 -11
- package/src/tools/crypto.ts +19 -19
- package/src/tools/endiantess.ts +13 -13
- package/src/tools/image.ts +18 -18
- package/src/tools/index.ts +41 -41
- package/src/tools/processType.ts +39 -39
- package/src/vite-env.d.ts +12 -12
package/src/scene/Camera.ts
CHANGED
|
@@ -1,458 +1,458 @@
|
|
|
1
|
-
import Mat4 from "../math/Mat4";
|
|
2
|
-
import Vec from "../math/Vec";
|
|
3
|
-
import Component from "./Component";
|
|
4
|
-
import MatrixStrategy from "../math/MatrixStrategy";
|
|
5
|
-
import { radiansToDegrees } from "../math/functions";
|
|
6
|
-
import NodeVisitor from "./NodeVisitor";
|
|
7
|
-
import Node from "./Node";
|
|
8
|
-
|
|
9
|
-
type ProjectionStrategyType = "PerspectiveProjectionMethod" | "OpticalProjectionMethod" | "OrthographicProjectionStrategy";
|
|
10
|
-
|
|
11
|
-
interface ProjectionStrategyBaseConfig {
|
|
12
|
-
type?: ProjectionStrategyType;
|
|
13
|
-
near?: number;
|
|
14
|
-
far?: number;
|
|
15
|
-
viewport?: number[] | Vec;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
interface PerspectiveProjectionConfig extends ProjectionStrategyBaseConfig {
|
|
19
|
-
type?: "PerspectiveProjectionMethod";
|
|
20
|
-
fov?: number;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
interface OpticalProjectionConfig extends ProjectionStrategyBaseConfig {
|
|
24
|
-
type?: "OpticalProjectionMethod";
|
|
25
|
-
frameSize?: number;
|
|
26
|
-
focalLength?: number;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
interface OrthographicProjectionConfig extends ProjectionStrategyBaseConfig {
|
|
30
|
-
type?: "OrthographicProjectionStrategy";
|
|
31
|
-
viewWidth?: number;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
type ProjectionStrategyConfig =
|
|
35
|
-
| PerspectiveProjectionConfig
|
|
36
|
-
| OpticalProjectionConfig
|
|
37
|
-
| OrthographicProjectionConfig
|
|
38
|
-
| ProjectionStrategyBaseConfig;
|
|
39
|
-
|
|
40
|
-
interface CameraSceneData {
|
|
41
|
-
focusDistance?: number;
|
|
42
|
-
isMain?: boolean;
|
|
43
|
-
projectionMethod?: ProjectionStrategyConfig;
|
|
44
|
-
[key: string]: unknown;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export abstract class ProjectionStrategy extends MatrixStrategy {
|
|
48
|
-
protected _near: number;
|
|
49
|
-
protected _far: number;
|
|
50
|
-
protected _viewport: Vec;
|
|
51
|
-
|
|
52
|
-
static Factory(jsonData?: ProjectionStrategyConfig | null): ProjectionStrategy | null {
|
|
53
|
-
if (!jsonData) {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const create = (): ProjectionStrategy | null => {
|
|
58
|
-
switch (jsonData?.type) {
|
|
59
|
-
case "PerspectiveProjectionMethod":
|
|
60
|
-
return new PerspectiveProjectionStrategy();
|
|
61
|
-
case "OpticalProjectionMethod":
|
|
62
|
-
return new OpticalProjectionStrategy();
|
|
63
|
-
case "OrthographicProjectionStrategy":
|
|
64
|
-
return new OrthographicProjectionStrategy();
|
|
65
|
-
default:
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const result = create();
|
|
71
|
-
if (result) {
|
|
72
|
-
result.deserialize(jsonData);
|
|
73
|
-
}
|
|
74
|
-
return result;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
constructor(target: Mat4 | null = null) {
|
|
78
|
-
super(target);
|
|
79
|
-
|
|
80
|
-
this._near = 0.1;
|
|
81
|
-
this._far = 1000.0;
|
|
82
|
-
this._viewport = new Vec([0, 0, 512, 512]);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
abstract clone(): ProjectionStrategy;
|
|
86
|
-
|
|
87
|
-
assign(other: ProjectionStrategy): void {
|
|
88
|
-
this.near = other.near;
|
|
89
|
-
this.far = other.far;
|
|
90
|
-
this.viewport = new Vec(other.viewport);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
set near(v: number) { this._near = v; this.apply(); }
|
|
94
|
-
get near(): number { return this._near; }
|
|
95
|
-
set far(v: number) { this._far = v; this.apply(); }
|
|
96
|
-
get far(): number { return this._far; }
|
|
97
|
-
set viewport(v: Vec) { this._viewport = v; this.apply(); }
|
|
98
|
-
get viewport(): Vec { return this._viewport; }
|
|
99
|
-
|
|
100
|
-
get fov(): number { return 0; }
|
|
101
|
-
|
|
102
|
-
serialize(jsonData: ProjectionStrategyConfig): void {
|
|
103
|
-
jsonData.near = this.near;
|
|
104
|
-
jsonData.far = this.far;
|
|
105
|
-
jsonData.viewport = this.viewport;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
deserialize(jsonData: ProjectionStrategyConfig = {}): void {
|
|
109
|
-
this.near = jsonData.near ?? this.near;
|
|
110
|
-
this.far = jsonData.far ?? this.far;
|
|
111
|
-
if (Array.isArray(jsonData.viewport)) {
|
|
112
|
-
this.viewport = new Vec(jsonData.viewport);
|
|
113
|
-
}
|
|
114
|
-
else if (jsonData.viewport instanceof Vec) {
|
|
115
|
-
this.viewport = new Vec(jsonData.viewport);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export class PerspectiveProjectionStrategy extends ProjectionStrategy {
|
|
121
|
-
private _fov: number;
|
|
122
|
-
|
|
123
|
-
constructor(target: Mat4 | null = null) {
|
|
124
|
-
super(target);
|
|
125
|
-
this._fov = 60;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
set fov(f: number) { this._fov = f; this.apply(); }
|
|
129
|
-
get fov(): number { return this._fov; }
|
|
130
|
-
|
|
131
|
-
clone(): PerspectiveProjectionStrategy {
|
|
132
|
-
const other = new PerspectiveProjectionStrategy(this.target);
|
|
133
|
-
other.assign(this);
|
|
134
|
-
return other;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
assign(other: PerspectiveProjectionStrategy): void {
|
|
138
|
-
super.assign(other);
|
|
139
|
-
this.fov = other.fov;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
apply(): void {
|
|
143
|
-
if (this.target) {
|
|
144
|
-
this.target.perspective(this.fov, this.viewport.aspectRatio, this.near, this.far);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
serialize(jsonData: PerspectiveProjectionConfig): void {
|
|
149
|
-
jsonData.type = "PerspectiveProjectionMethod";
|
|
150
|
-
jsonData.fov = this.fov;
|
|
151
|
-
super.serialize(jsonData);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
deserialize(jsonData: PerspectiveProjectionConfig = {}): void {
|
|
155
|
-
super.deserialize(jsonData);
|
|
156
|
-
this.fov = jsonData.fov ?? this.fov;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export class OpticalProjectionStrategy extends ProjectionStrategy {
|
|
161
|
-
private _focalLength: number;
|
|
162
|
-
private _frameSize: number;
|
|
163
|
-
|
|
164
|
-
constructor(target: Mat4 | null = null) {
|
|
165
|
-
super(target);
|
|
166
|
-
this._focalLength = 50;
|
|
167
|
-
this._frameSize = 35;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
set focalLength(v: number) { this._focalLength = v; this.apply(); }
|
|
171
|
-
get focalLength(): number { return this._focalLength; }
|
|
172
|
-
set frameSize(v: number) { this._frameSize = v; this.apply(); }
|
|
173
|
-
get frameSize(): number { return this._frameSize; }
|
|
174
|
-
|
|
175
|
-
get fov(): number {
|
|
176
|
-
return 2 * Math.atan((this.frameSize / 2.0) / this.focalLength);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
clone(): OpticalProjectionStrategy {
|
|
180
|
-
const other = new OpticalProjectionStrategy(this.target);
|
|
181
|
-
other.assign(this);
|
|
182
|
-
return other;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
assign(other: OpticalProjectionStrategy): void {
|
|
186
|
-
super.assign(other);
|
|
187
|
-
this.focalLength = other.focalLength;
|
|
188
|
-
this.frameSize = other.frameSize;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
apply(): void {
|
|
192
|
-
if (this.target) {
|
|
193
|
-
const fov = radiansToDegrees(this.fov);
|
|
194
|
-
this.target.perspective(fov, this.viewport.aspectRatio, this.near, this.far);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
serialize(jsonData: OpticalProjectionConfig): void {
|
|
199
|
-
super.serialize(jsonData);
|
|
200
|
-
jsonData.type = "OpticalProjectionMethod";
|
|
201
|
-
jsonData.frameSize = this.frameSize;
|
|
202
|
-
jsonData.focalLength = this.focalLength;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
deserialize(jsonData: OpticalProjectionConfig = {}): void {
|
|
206
|
-
super.deserialize(jsonData);
|
|
207
|
-
this.frameSize = jsonData.frameSize ?? this.frameSize;
|
|
208
|
-
this.focalLength = jsonData.focalLength ?? this.focalLength;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
export class OrthographicProjectionStrategy extends ProjectionStrategy {
|
|
213
|
-
private _viewWidth: number;
|
|
214
|
-
|
|
215
|
-
constructor(target: Mat4 | null = null) {
|
|
216
|
-
super(target);
|
|
217
|
-
this._viewWidth = 100;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
set viewWidth(v: number) { this._viewWidth = v; this.apply(); }
|
|
221
|
-
get viewWidth(): number { return this._viewWidth; }
|
|
222
|
-
|
|
223
|
-
clone(): OrthographicProjectionStrategy {
|
|
224
|
-
const other = new OrthographicProjectionStrategy(this.target);
|
|
225
|
-
other.assign(this);
|
|
226
|
-
return other;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
asign(other: OrthographicProjectionStrategy): void {
|
|
230
|
-
super.assign(other);
|
|
231
|
-
this.viewWidth = other.viewWidth;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
apply(): void {
|
|
235
|
-
if (this.target) {
|
|
236
|
-
const height = this.viewWidth / this.viewport.aspectRatio;
|
|
237
|
-
const x = this.viewWidth / 2;
|
|
238
|
-
const y = height / 2;
|
|
239
|
-
this.target.ortho(-x, x, -y, y, -this._far, this._far);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
serialize(jsonData: OrthographicProjectionConfig): void {
|
|
244
|
-
jsonData.type = "OrthographicProjectionStrategy";
|
|
245
|
-
jsonData.viewWidth = this.viewWidth;
|
|
246
|
-
super.serialize(jsonData);
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
deserialize(jsonData: OrthographicProjectionConfig = {}): void {
|
|
250
|
-
this.viewWidth = jsonData.viewWidth ?? this.viewWidth;
|
|
251
|
-
super.deserialize(jsonData);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
class SetMainCameraVisitor extends NodeVisitor {
|
|
256
|
-
private readonly _mainCamera: Camera;
|
|
257
|
-
|
|
258
|
-
constructor(mainCamera: Camera) {
|
|
259
|
-
super();
|
|
260
|
-
if (!mainCamera) {
|
|
261
|
-
throw Error("Set main camera: invalid parameter. The camera paremeter is null.")
|
|
262
|
-
}
|
|
263
|
-
if (!(mainCamera instanceof Camera)) {
|
|
264
|
-
throw Error("Set main camera: invalid parameter. The object is not an instance of Camera class.")
|
|
265
|
-
}
|
|
266
|
-
this._mainCamera = mainCamera;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
visit(node: Node): void {
|
|
270
|
-
const cam = node.camera;
|
|
271
|
-
if (!(cam instanceof Camera)) {
|
|
272
|
-
return;
|
|
273
|
-
}
|
|
274
|
-
cam._isMain = cam === this._mainCamera;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
class GetMainCameraVisitor extends NodeVisitor {
|
|
279
|
-
private _mainCamera: Camera | null;
|
|
280
|
-
private _firstCameraFound: Camera | null;
|
|
281
|
-
|
|
282
|
-
constructor() {
|
|
283
|
-
super();
|
|
284
|
-
this._mainCamera = null;
|
|
285
|
-
this._firstCameraFound = null;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
get mainCamera(): Camera | null {
|
|
289
|
-
return this._mainCamera;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
get firstCameraFound(): Camera | null {
|
|
293
|
-
return this._firstCameraFound;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
clear(): void {
|
|
297
|
-
this._mainCamera = null;
|
|
298
|
-
this._firstCameraFound = null;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
visit(node: Node): void {
|
|
302
|
-
// Note: The _isMain flag is set in Camera.SetMain() function
|
|
303
|
-
const cam = node.camera;
|
|
304
|
-
if (!(cam instanceof Camera)) {
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
if (cam.isMain) {
|
|
309
|
-
cam._isMain = false;
|
|
310
|
-
if (this._mainCamera) {
|
|
311
|
-
console.warn("More than one main cameras found in the scene");
|
|
312
|
-
}
|
|
313
|
-
this._mainCamera = cam;
|
|
314
|
-
}
|
|
315
|
-
else if (!this._firstCameraFound) {
|
|
316
|
-
cam._isMain = false;
|
|
317
|
-
this._firstCameraFound = cam;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
export default class Camera extends Component {
|
|
323
|
-
private _projectionStrategy: ProjectionStrategy | null;
|
|
324
|
-
public _isMain: boolean;
|
|
325
|
-
private _projectionMatrix: Mat4;
|
|
326
|
-
private _viewport: Vec;
|
|
327
|
-
private _focusDistance: number;
|
|
328
|
-
|
|
329
|
-
static SetMain(sceneRoot: Node, camera: Camera): void {
|
|
330
|
-
const isNode = sceneRoot instanceof Node;
|
|
331
|
-
if (!isNode || sceneRoot.parent !== null) {
|
|
332
|
-
throw Error("Camera.setMain(): invalid parameter. Object is not a scene root");
|
|
333
|
-
}
|
|
334
|
-
const visitor = new SetMainCameraVisitor(camera);
|
|
335
|
-
sceneRoot.accept(visitor);
|
|
336
|
-
const rootWithMain = sceneRoot as Node & { __mainCamera__?: Camera | null };
|
|
337
|
-
rootWithMain.__mainCamera__ = camera;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
static GetMain(sceneRoot: Node): Camera | null {
|
|
341
|
-
const rootWithMain = sceneRoot as Node & { __mainCamera__?: Camera | null };
|
|
342
|
-
if (!rootWithMain.__mainCamera__) {
|
|
343
|
-
const visitor = new GetMainCameraVisitor();
|
|
344
|
-
sceneRoot.accept(visitor);
|
|
345
|
-
rootWithMain.__mainCamera__ = visitor.mainCamera || visitor.firstCameraFound || null;
|
|
346
|
-
if (rootWithMain.__mainCamera__) {
|
|
347
|
-
rootWithMain.__mainCamera__._isMain = true;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
return rootWithMain.__mainCamera__ ?? null;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
setMain(sceneRoot: Node): void {
|
|
354
|
-
Camera.SetMain(sceneRoot, this);
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
constructor() {
|
|
358
|
-
super("Camera");
|
|
359
|
-
|
|
360
|
-
this._projectionStrategy = null;
|
|
361
|
-
this._isMain = false;
|
|
362
|
-
|
|
363
|
-
this._projectionMatrix = Mat4.MakePerspective(45.0, 1, 0.1, 100.0);
|
|
364
|
-
this._viewport = new Vec(0, 0, 512, 512);
|
|
365
|
-
|
|
366
|
-
this._focusDistance = 5;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
clone(): Camera {
|
|
370
|
-
const other = new Camera();
|
|
371
|
-
other.assign(this);
|
|
372
|
-
return other;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
assign(other: Camera): void {
|
|
376
|
-
other._projectionStrategy = this._projectionStrategy?.clone() || null;
|
|
377
|
-
// This attribute cannot be assigned, because there can only be one main camera.
|
|
378
|
-
other._isMain = false;
|
|
379
|
-
other._projectionMatrix = new Mat4(this._projectionMatrix);
|
|
380
|
-
other._viewport = new Vec(this._viewport);
|
|
381
|
-
other._focusDistance = this._focusDistance;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
get isMain(): boolean {
|
|
385
|
-
return this._isMain;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
get projectionMatrix(): Mat4 {
|
|
389
|
-
return this._projectionMatrix;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
set projectionMatrix(p: Mat4) {
|
|
393
|
-
this._projectionStrategy = null;
|
|
394
|
-
this._projectionMatrix = p;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
get viewport(): Vec {
|
|
398
|
-
return this._viewport;
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
set viewport(vp: Vec) {
|
|
402
|
-
this._viewport = vp;
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
get projectionStrategy(): ProjectionStrategy | null {
|
|
406
|
-
return this._projectionStrategy;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
set projectionStrategy(ps: ProjectionStrategy | null) {
|
|
410
|
-
this._projectionStrategy = ps;
|
|
411
|
-
if (this._projectionStrategy) {
|
|
412
|
-
this._projectionStrategy.target = this._projectionMatrix;
|
|
413
|
-
this._projectionStrategy.viewport = this._viewport;
|
|
414
|
-
this._projectionStrategy.apply();
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
get focusDistance(): number {
|
|
419
|
-
return this._focusDistance;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
set focusDistance(fd: number) {
|
|
423
|
-
this._focusDistance = fd;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
// This function regenerate the projection matrix with the new
|
|
427
|
-
// aspect ratio, if the projectionStrategy is set.
|
|
428
|
-
resize(width: number, height: number): void {
|
|
429
|
-
this._viewport = new Vec([0, 0, width, height]);
|
|
430
|
-
if (this._projectionStrategy) {
|
|
431
|
-
this._projectionStrategy.viewport = this._viewport;
|
|
432
|
-
this._projectionStrategy.apply();
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
async deserialize(sceneData: CameraSceneData = {}, loader: unknown): Promise<void> {
|
|
437
|
-
await super.deserialize(sceneData, loader);
|
|
438
|
-
this.focusDistance = sceneData.focusDistance ?? this._focusDistance;
|
|
439
|
-
if (sceneData.projectionMethod) {
|
|
440
|
-
const strategy = ProjectionStrategy.Factory(sceneData.projectionMethod);
|
|
441
|
-
if (strategy) {
|
|
442
|
-
this.projectionStrategy = strategy;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
async serialize(sceneData: CameraSceneData = {}, writer: unknown): Promise<void> {
|
|
448
|
-
await super.serialize(sceneData, writer);
|
|
449
|
-
sceneData.isMain = this._isMain;
|
|
450
|
-
sceneData.focusDistance = this._focusDistance;
|
|
451
|
-
if (this.projectionStrategy) {
|
|
452
|
-
const projMethod: ProjectionStrategyConfig = {};
|
|
453
|
-
this.projectionStrategy.serialize(projMethod);
|
|
454
|
-
sceneData.projectionMethod = projMethod;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
1
|
+
import Mat4 from "../math/Mat4";
|
|
2
|
+
import Vec from "../math/Vec";
|
|
3
|
+
import Component from "./Component";
|
|
4
|
+
import MatrixStrategy from "../math/MatrixStrategy";
|
|
5
|
+
import { radiansToDegrees } from "../math/functions";
|
|
6
|
+
import NodeVisitor from "./NodeVisitor";
|
|
7
|
+
import Node from "./Node";
|
|
8
|
+
|
|
9
|
+
type ProjectionStrategyType = "PerspectiveProjectionMethod" | "OpticalProjectionMethod" | "OrthographicProjectionStrategy";
|
|
10
|
+
|
|
11
|
+
interface ProjectionStrategyBaseConfig {
|
|
12
|
+
type?: ProjectionStrategyType;
|
|
13
|
+
near?: number;
|
|
14
|
+
far?: number;
|
|
15
|
+
viewport?: number[] | Vec;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface PerspectiveProjectionConfig extends ProjectionStrategyBaseConfig {
|
|
19
|
+
type?: "PerspectiveProjectionMethod";
|
|
20
|
+
fov?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface OpticalProjectionConfig extends ProjectionStrategyBaseConfig {
|
|
24
|
+
type?: "OpticalProjectionMethod";
|
|
25
|
+
frameSize?: number;
|
|
26
|
+
focalLength?: number;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface OrthographicProjectionConfig extends ProjectionStrategyBaseConfig {
|
|
30
|
+
type?: "OrthographicProjectionStrategy";
|
|
31
|
+
viewWidth?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type ProjectionStrategyConfig =
|
|
35
|
+
| PerspectiveProjectionConfig
|
|
36
|
+
| OpticalProjectionConfig
|
|
37
|
+
| OrthographicProjectionConfig
|
|
38
|
+
| ProjectionStrategyBaseConfig;
|
|
39
|
+
|
|
40
|
+
interface CameraSceneData {
|
|
41
|
+
focusDistance?: number;
|
|
42
|
+
isMain?: boolean;
|
|
43
|
+
projectionMethod?: ProjectionStrategyConfig;
|
|
44
|
+
[key: string]: unknown;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export abstract class ProjectionStrategy extends MatrixStrategy {
|
|
48
|
+
protected _near: number;
|
|
49
|
+
protected _far: number;
|
|
50
|
+
protected _viewport: Vec;
|
|
51
|
+
|
|
52
|
+
static Factory(jsonData?: ProjectionStrategyConfig | null): ProjectionStrategy | null {
|
|
53
|
+
if (!jsonData) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const create = (): ProjectionStrategy | null => {
|
|
58
|
+
switch (jsonData?.type) {
|
|
59
|
+
case "PerspectiveProjectionMethod":
|
|
60
|
+
return new PerspectiveProjectionStrategy();
|
|
61
|
+
case "OpticalProjectionMethod":
|
|
62
|
+
return new OpticalProjectionStrategy();
|
|
63
|
+
case "OrthographicProjectionStrategy":
|
|
64
|
+
return new OrthographicProjectionStrategy();
|
|
65
|
+
default:
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const result = create();
|
|
71
|
+
if (result) {
|
|
72
|
+
result.deserialize(jsonData);
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
constructor(target: Mat4 | null = null) {
|
|
78
|
+
super(target);
|
|
79
|
+
|
|
80
|
+
this._near = 0.1;
|
|
81
|
+
this._far = 1000.0;
|
|
82
|
+
this._viewport = new Vec([0, 0, 512, 512]);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
abstract clone(): ProjectionStrategy;
|
|
86
|
+
|
|
87
|
+
assign(other: ProjectionStrategy): void {
|
|
88
|
+
this.near = other.near;
|
|
89
|
+
this.far = other.far;
|
|
90
|
+
this.viewport = new Vec(other.viewport);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
set near(v: number) { this._near = v; this.apply(); }
|
|
94
|
+
get near(): number { return this._near; }
|
|
95
|
+
set far(v: number) { this._far = v; this.apply(); }
|
|
96
|
+
get far(): number { return this._far; }
|
|
97
|
+
set viewport(v: Vec) { this._viewport = v; this.apply(); }
|
|
98
|
+
get viewport(): Vec { return this._viewport; }
|
|
99
|
+
|
|
100
|
+
get fov(): number { return 0; }
|
|
101
|
+
|
|
102
|
+
serialize(jsonData: ProjectionStrategyConfig): void {
|
|
103
|
+
jsonData.near = this.near;
|
|
104
|
+
jsonData.far = this.far;
|
|
105
|
+
jsonData.viewport = this.viewport;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
deserialize(jsonData: ProjectionStrategyConfig = {}): void {
|
|
109
|
+
this.near = jsonData.near ?? this.near;
|
|
110
|
+
this.far = jsonData.far ?? this.far;
|
|
111
|
+
if (Array.isArray(jsonData.viewport)) {
|
|
112
|
+
this.viewport = new Vec(jsonData.viewport);
|
|
113
|
+
}
|
|
114
|
+
else if (jsonData.viewport instanceof Vec) {
|
|
115
|
+
this.viewport = new Vec(jsonData.viewport);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export class PerspectiveProjectionStrategy extends ProjectionStrategy {
|
|
121
|
+
private _fov: number;
|
|
122
|
+
|
|
123
|
+
constructor(target: Mat4 | null = null) {
|
|
124
|
+
super(target);
|
|
125
|
+
this._fov = 60;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
set fov(f: number) { this._fov = f; this.apply(); }
|
|
129
|
+
get fov(): number { return this._fov; }
|
|
130
|
+
|
|
131
|
+
clone(): PerspectiveProjectionStrategy {
|
|
132
|
+
const other = new PerspectiveProjectionStrategy(this.target);
|
|
133
|
+
other.assign(this);
|
|
134
|
+
return other;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
assign(other: PerspectiveProjectionStrategy): void {
|
|
138
|
+
super.assign(other);
|
|
139
|
+
this.fov = other.fov;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
apply(): void {
|
|
143
|
+
if (this.target) {
|
|
144
|
+
this.target.perspective(this.fov, this.viewport.aspectRatio, this.near, this.far);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
serialize(jsonData: PerspectiveProjectionConfig): void {
|
|
149
|
+
jsonData.type = "PerspectiveProjectionMethod";
|
|
150
|
+
jsonData.fov = this.fov;
|
|
151
|
+
super.serialize(jsonData);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
deserialize(jsonData: PerspectiveProjectionConfig = {}): void {
|
|
155
|
+
super.deserialize(jsonData);
|
|
156
|
+
this.fov = jsonData.fov ?? this.fov;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export class OpticalProjectionStrategy extends ProjectionStrategy {
|
|
161
|
+
private _focalLength: number;
|
|
162
|
+
private _frameSize: number;
|
|
163
|
+
|
|
164
|
+
constructor(target: Mat4 | null = null) {
|
|
165
|
+
super(target);
|
|
166
|
+
this._focalLength = 50;
|
|
167
|
+
this._frameSize = 35;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
set focalLength(v: number) { this._focalLength = v; this.apply(); }
|
|
171
|
+
get focalLength(): number { return this._focalLength; }
|
|
172
|
+
set frameSize(v: number) { this._frameSize = v; this.apply(); }
|
|
173
|
+
get frameSize(): number { return this._frameSize; }
|
|
174
|
+
|
|
175
|
+
get fov(): number {
|
|
176
|
+
return 2 * Math.atan((this.frameSize / 2.0) / this.focalLength);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
clone(): OpticalProjectionStrategy {
|
|
180
|
+
const other = new OpticalProjectionStrategy(this.target);
|
|
181
|
+
other.assign(this);
|
|
182
|
+
return other;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
assign(other: OpticalProjectionStrategy): void {
|
|
186
|
+
super.assign(other);
|
|
187
|
+
this.focalLength = other.focalLength;
|
|
188
|
+
this.frameSize = other.frameSize;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
apply(): void {
|
|
192
|
+
if (this.target) {
|
|
193
|
+
const fov = radiansToDegrees(this.fov);
|
|
194
|
+
this.target.perspective(fov, this.viewport.aspectRatio, this.near, this.far);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
serialize(jsonData: OpticalProjectionConfig): void {
|
|
199
|
+
super.serialize(jsonData);
|
|
200
|
+
jsonData.type = "OpticalProjectionMethod";
|
|
201
|
+
jsonData.frameSize = this.frameSize;
|
|
202
|
+
jsonData.focalLength = this.focalLength;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
deserialize(jsonData: OpticalProjectionConfig = {}): void {
|
|
206
|
+
super.deserialize(jsonData);
|
|
207
|
+
this.frameSize = jsonData.frameSize ?? this.frameSize;
|
|
208
|
+
this.focalLength = jsonData.focalLength ?? this.focalLength;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export class OrthographicProjectionStrategy extends ProjectionStrategy {
|
|
213
|
+
private _viewWidth: number;
|
|
214
|
+
|
|
215
|
+
constructor(target: Mat4 | null = null) {
|
|
216
|
+
super(target);
|
|
217
|
+
this._viewWidth = 100;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
set viewWidth(v: number) { this._viewWidth = v; this.apply(); }
|
|
221
|
+
get viewWidth(): number { return this._viewWidth; }
|
|
222
|
+
|
|
223
|
+
clone(): OrthographicProjectionStrategy {
|
|
224
|
+
const other = new OrthographicProjectionStrategy(this.target);
|
|
225
|
+
other.assign(this);
|
|
226
|
+
return other;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
asign(other: OrthographicProjectionStrategy): void {
|
|
230
|
+
super.assign(other);
|
|
231
|
+
this.viewWidth = other.viewWidth;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
apply(): void {
|
|
235
|
+
if (this.target) {
|
|
236
|
+
const height = this.viewWidth / this.viewport.aspectRatio;
|
|
237
|
+
const x = this.viewWidth / 2;
|
|
238
|
+
const y = height / 2;
|
|
239
|
+
this.target.ortho(-x, x, -y, y, -this._far, this._far);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
serialize(jsonData: OrthographicProjectionConfig): void {
|
|
244
|
+
jsonData.type = "OrthographicProjectionStrategy";
|
|
245
|
+
jsonData.viewWidth = this.viewWidth;
|
|
246
|
+
super.serialize(jsonData);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
deserialize(jsonData: OrthographicProjectionConfig = {}): void {
|
|
250
|
+
this.viewWidth = jsonData.viewWidth ?? this.viewWidth;
|
|
251
|
+
super.deserialize(jsonData);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
class SetMainCameraVisitor extends NodeVisitor {
|
|
256
|
+
private readonly _mainCamera: Camera;
|
|
257
|
+
|
|
258
|
+
constructor(mainCamera: Camera) {
|
|
259
|
+
super();
|
|
260
|
+
if (!mainCamera) {
|
|
261
|
+
throw Error("Set main camera: invalid parameter. The camera paremeter is null.")
|
|
262
|
+
}
|
|
263
|
+
if (!(mainCamera instanceof Camera)) {
|
|
264
|
+
throw Error("Set main camera: invalid parameter. The object is not an instance of Camera class.")
|
|
265
|
+
}
|
|
266
|
+
this._mainCamera = mainCamera;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
visit(node: Node): void {
|
|
270
|
+
const cam = node.camera;
|
|
271
|
+
if (!(cam instanceof Camera)) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
cam._isMain = cam === this._mainCamera;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
class GetMainCameraVisitor extends NodeVisitor {
|
|
279
|
+
private _mainCamera: Camera | null;
|
|
280
|
+
private _firstCameraFound: Camera | null;
|
|
281
|
+
|
|
282
|
+
constructor() {
|
|
283
|
+
super();
|
|
284
|
+
this._mainCamera = null;
|
|
285
|
+
this._firstCameraFound = null;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
get mainCamera(): Camera | null {
|
|
289
|
+
return this._mainCamera;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
get firstCameraFound(): Camera | null {
|
|
293
|
+
return this._firstCameraFound;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
clear(): void {
|
|
297
|
+
this._mainCamera = null;
|
|
298
|
+
this._firstCameraFound = null;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
visit(node: Node): void {
|
|
302
|
+
// Note: The _isMain flag is set in Camera.SetMain() function
|
|
303
|
+
const cam = node.camera;
|
|
304
|
+
if (!(cam instanceof Camera)) {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (cam.isMain) {
|
|
309
|
+
cam._isMain = false;
|
|
310
|
+
if (this._mainCamera) {
|
|
311
|
+
console.warn("More than one main cameras found in the scene");
|
|
312
|
+
}
|
|
313
|
+
this._mainCamera = cam;
|
|
314
|
+
}
|
|
315
|
+
else if (!this._firstCameraFound) {
|
|
316
|
+
cam._isMain = false;
|
|
317
|
+
this._firstCameraFound = cam;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export default class Camera extends Component {
|
|
323
|
+
private _projectionStrategy: ProjectionStrategy | null;
|
|
324
|
+
public _isMain: boolean;
|
|
325
|
+
private _projectionMatrix: Mat4;
|
|
326
|
+
private _viewport: Vec;
|
|
327
|
+
private _focusDistance: number;
|
|
328
|
+
|
|
329
|
+
static SetMain(sceneRoot: Node, camera: Camera): void {
|
|
330
|
+
const isNode = sceneRoot instanceof Node;
|
|
331
|
+
if (!isNode || sceneRoot.parent !== null) {
|
|
332
|
+
throw Error("Camera.setMain(): invalid parameter. Object is not a scene root");
|
|
333
|
+
}
|
|
334
|
+
const visitor = new SetMainCameraVisitor(camera);
|
|
335
|
+
sceneRoot.accept(visitor);
|
|
336
|
+
const rootWithMain = sceneRoot as Node & { __mainCamera__?: Camera | null };
|
|
337
|
+
rootWithMain.__mainCamera__ = camera;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
static GetMain(sceneRoot: Node): Camera | null {
|
|
341
|
+
const rootWithMain = sceneRoot as Node & { __mainCamera__?: Camera | null };
|
|
342
|
+
if (!rootWithMain.__mainCamera__) {
|
|
343
|
+
const visitor = new GetMainCameraVisitor();
|
|
344
|
+
sceneRoot.accept(visitor);
|
|
345
|
+
rootWithMain.__mainCamera__ = visitor.mainCamera || visitor.firstCameraFound || null;
|
|
346
|
+
if (rootWithMain.__mainCamera__) {
|
|
347
|
+
rootWithMain.__mainCamera__._isMain = true;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return rootWithMain.__mainCamera__ ?? null;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
setMain(sceneRoot: Node): void {
|
|
354
|
+
Camera.SetMain(sceneRoot, this);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
constructor() {
|
|
358
|
+
super("Camera");
|
|
359
|
+
|
|
360
|
+
this._projectionStrategy = null;
|
|
361
|
+
this._isMain = false;
|
|
362
|
+
|
|
363
|
+
this._projectionMatrix = Mat4.MakePerspective(45.0, 1, 0.1, 100.0);
|
|
364
|
+
this._viewport = new Vec(0, 0, 512, 512);
|
|
365
|
+
|
|
366
|
+
this._focusDistance = 5;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
clone(): Camera {
|
|
370
|
+
const other = new Camera();
|
|
371
|
+
other.assign(this);
|
|
372
|
+
return other;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
assign(other: Camera): void {
|
|
376
|
+
other._projectionStrategy = this._projectionStrategy?.clone() || null;
|
|
377
|
+
// This attribute cannot be assigned, because there can only be one main camera.
|
|
378
|
+
other._isMain = false;
|
|
379
|
+
other._projectionMatrix = new Mat4(this._projectionMatrix);
|
|
380
|
+
other._viewport = new Vec(this._viewport);
|
|
381
|
+
other._focusDistance = this._focusDistance;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
get isMain(): boolean {
|
|
385
|
+
return this._isMain;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
get projectionMatrix(): Mat4 {
|
|
389
|
+
return this._projectionMatrix;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
set projectionMatrix(p: Mat4) {
|
|
393
|
+
this._projectionStrategy = null;
|
|
394
|
+
this._projectionMatrix = p;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
get viewport(): Vec {
|
|
398
|
+
return this._viewport;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
set viewport(vp: Vec) {
|
|
402
|
+
this._viewport = vp;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
get projectionStrategy(): ProjectionStrategy | null {
|
|
406
|
+
return this._projectionStrategy;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
set projectionStrategy(ps: ProjectionStrategy | null) {
|
|
410
|
+
this._projectionStrategy = ps;
|
|
411
|
+
if (this._projectionStrategy) {
|
|
412
|
+
this._projectionStrategy.target = this._projectionMatrix;
|
|
413
|
+
this._projectionStrategy.viewport = this._viewport;
|
|
414
|
+
this._projectionStrategy.apply();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
get focusDistance(): number {
|
|
419
|
+
return this._focusDistance;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
set focusDistance(fd: number) {
|
|
423
|
+
this._focusDistance = fd;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// This function regenerate the projection matrix with the new
|
|
427
|
+
// aspect ratio, if the projectionStrategy is set.
|
|
428
|
+
resize(width: number, height: number): void {
|
|
429
|
+
this._viewport = new Vec([0, 0, width, height]);
|
|
430
|
+
if (this._projectionStrategy) {
|
|
431
|
+
this._projectionStrategy.viewport = this._viewport;
|
|
432
|
+
this._projectionStrategy.apply();
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
async deserialize(sceneData: CameraSceneData = {}, loader: unknown): Promise<void> {
|
|
437
|
+
await super.deserialize(sceneData, loader);
|
|
438
|
+
this.focusDistance = sceneData.focusDistance ?? this._focusDistance;
|
|
439
|
+
if (sceneData.projectionMethod) {
|
|
440
|
+
const strategy = ProjectionStrategy.Factory(sceneData.projectionMethod);
|
|
441
|
+
if (strategy) {
|
|
442
|
+
this.projectionStrategy = strategy;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async serialize(sceneData: CameraSceneData = {}, writer: unknown): Promise<void> {
|
|
448
|
+
await super.serialize(sceneData, writer);
|
|
449
|
+
sceneData.isMain = this._isMain;
|
|
450
|
+
sceneData.focusDistance = this._focusDistance;
|
|
451
|
+
if (this.projectionStrategy) {
|
|
452
|
+
const projMethod: ProjectionStrategyConfig = {};
|
|
453
|
+
this.projectionStrategy.serialize(projMethod);
|
|
454
|
+
sceneData.projectionMethod = projMethod;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|