abstract-3d 4.0.0-beta.0 → 4.0.0-beta.2
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/README.md +1 -1
- package/lib/renderers/react/react.d.ts.map +1 -1
- package/lib/renderers/react/react.js +4 -3
- package/lib/renderers/react/react.js.map +1 -1
- package/lib/renderers/three/appearance/appearance.d.ts.map +1 -1
- package/lib/renderers/three/appearance/appearance.js +4 -1
- package/lib/renderers/three/appearance/appearance.js.map +1 -1
- package/lib/renderers/three/build/build.js +7 -3
- package/lib/renderers/three/build/build.js.map +1 -1
- package/lib/renderers/three/build/materials.d.ts +7 -3
- package/lib/renderers/three/build/materials.d.ts.map +1 -1
- package/lib/renderers/three/build/materials.js +10 -5
- package/lib/renderers/three/build/materials.js.map +1 -1
- package/lib/renderers/three/quality/quality.d.ts +4 -24
- package/lib/renderers/three/quality/quality.d.ts.map +1 -1
- package/lib/renderers/three/quality/quality.js +6 -43
- package/lib/renderers/three/quality/quality.js.map +1 -1
- package/lib/renderers/three/shadow/shadow.d.ts +15 -0
- package/lib/renderers/three/shadow/shadow.d.ts.map +1 -0
- package/lib/renderers/three/shadow/shadow.js +81 -0
- package/lib/renderers/three/shadow/shadow.js.map +1 -0
- package/lib/renderers/three/viewer/options.d.ts +6 -2
- package/lib/renderers/three/viewer/options.d.ts.map +1 -1
- package/lib/renderers/three/viewer/options.js +2 -0
- package/lib/renderers/three/viewer/options.js.map +1 -1
- package/lib/renderers/three/viewer/viewer.d.ts +3 -2
- package/lib/renderers/three/viewer/viewer.d.ts.map +1 -1
- package/lib/renderers/three/viewer/viewer.js +24 -20
- package/lib/renderers/three/viewer/viewer.js.map +1 -1
- package/package.json +1 -3
- package/src/renderers/react/react.tsx +5 -4
- package/src/renderers/three/appearance/appearance.test.ts +5 -0
- package/src/renderers/three/appearance/appearance.ts +4 -1
- package/src/renderers/three/build/build.ts +6 -3
- package/src/renderers/three/build/materials.ts +14 -8
- package/src/renderers/three/quality/quality.test.ts +11 -4
- package/src/renderers/three/quality/quality.ts +5 -65
- package/src/renderers/three/shadow/shadow.ts +116 -0
- package/src/renderers/three/viewer/options.ts +8 -2
- package/src/renderers/three/viewer/viewer.ts +26 -23
- package/src/custom_typings/n8ao.d.ts +0 -11
|
@@ -46,7 +46,9 @@ export type ViewerOptions<Content> = {
|
|
|
46
46
|
/** Lights faces by which way they turn and gives metal reflections: `studio` by default, `room` for three's RoomEnvironment, or null for none */
|
|
47
47
|
readonly environment?: Texture | "studio" | "room" | null;
|
|
48
48
|
readonly environmentIntensity?: number;
|
|
49
|
-
/**
|
|
49
|
+
/** A soft shadow on the ground under the scene, rendered once per build; on by default */
|
|
50
|
+
readonly groundShadow?: boolean;
|
|
51
|
+
/** The resolution: `low` 1, `medium` up to 1.5 and `high` up to 2 pixels per CSS pixel; `auto` by default, high until moving gets slow */
|
|
50
52
|
readonly quality?: Quality;
|
|
51
53
|
readonly useAlphaTest?: boolean;
|
|
52
54
|
readonly materialStateImages?: Record<string, string>;
|
|
@@ -61,10 +63,12 @@ export type ViewerOptions<Content> = {
|
|
|
61
63
|
readonly onHoverGroup?: (id: string | undefined, rootData: Data, data: Data, event: SceneEvent) => void;
|
|
62
64
|
readonly onContextMenuGroup?: (id: string, rootData: Data, data: Data, left: number, top: number, event: SceneEvent) => void;
|
|
63
65
|
readonly onClickRelation?: (relation: Relation, event: SceneEvent) => void;
|
|
66
|
+
/** A click, not a drag, on nothing clickable, e.g. the background; r3f's Canvas event of the same name */
|
|
67
|
+
readonly onPointerMissed?: (event: MouseEvent) => void;
|
|
64
68
|
};
|
|
65
69
|
|
|
66
70
|
/** What an update has to redo, in the order it's redone */
|
|
67
|
-
export type Change = "compile" | "build" | "camera" | "controls" | "gizmo" | "lights" | "quality" | "paint" | "dimensions" | "overlays";
|
|
71
|
+
export type Change = "compile" | "build" | "shadow" | "camera" | "controls" | "gizmo" | "lights" | "quality" | "paint" | "dimensions" | "overlays";
|
|
68
72
|
|
|
69
73
|
/** What passing each option redoes; callbacks and what's read later need nothing */
|
|
70
74
|
export const effects: { readonly [K in keyof ViewerOptions<unknown>]-?: ReadonlyArray<Change> } = {
|
|
@@ -86,6 +90,7 @@ export const effects: { readonly [K in keyof ViewerOptions<unknown>]-?: Readonly
|
|
|
86
90
|
lights: ["lights"],
|
|
87
91
|
environment: ["lights"],
|
|
88
92
|
environmentIntensity: ["lights"],
|
|
93
|
+
groundShadow: ["shadow"],
|
|
89
94
|
quality: ["quality"],
|
|
90
95
|
popovers: ["overlays"],
|
|
91
96
|
getTooltips: ["overlays"],
|
|
@@ -95,4 +100,5 @@ export const effects: { readonly [K in keyof ViewerOptions<unknown>]-?: Readonly
|
|
|
95
100
|
onHoverGroup: [],
|
|
96
101
|
onContextMenuGroup: [],
|
|
97
102
|
onClickRelation: [],
|
|
103
|
+
onPointerMissed: [],
|
|
98
104
|
};
|
|
@@ -32,8 +32,10 @@ import { configureControls, createControls, setPose } from "../camera/controls.j
|
|
|
32
32
|
import { createGizmo } from "../camera/gizmo.js";
|
|
33
33
|
import type { CompiledScene } from "../compile/compile.js";
|
|
34
34
|
import { compileScene } from "../compile/compile.js";
|
|
35
|
-
import type {
|
|
36
|
-
import {
|
|
35
|
+
import type { TierGovernor } from "../quality/quality.js";
|
|
36
|
+
import { getPixelRatio, recordFrame } from "../quality/quality.js";
|
|
37
|
+
import type { GroundShadow } from "../shadow/shadow.js";
|
|
38
|
+
import { createGroundShadow, disposeGroundShadow } from "../shadow/shadow.js";
|
|
37
39
|
import type { GlyphAtlas } from "../text/text.js";
|
|
38
40
|
import { createGlyphAtlas } from "../text/text.js";
|
|
39
41
|
import type { Change, ViewerOptions } from "./options.js";
|
|
@@ -77,7 +79,7 @@ export type Viewer<Content> = {
|
|
|
77
79
|
compiled?: CompiledScene;
|
|
78
80
|
built?: BuiltScene;
|
|
79
81
|
gizmo?: ViewportGizmo;
|
|
80
|
-
|
|
82
|
+
shadow?: GroundShadow;
|
|
81
83
|
governor?: TierGovernor;
|
|
82
84
|
readonly environments: Partial<Record<"studio" | "room", Texture>>;
|
|
83
85
|
/** The scene is built and its shaders compiled */
|
|
@@ -164,12 +166,12 @@ export function disposeViewer<Content>(v: Viewer<Content>): void {
|
|
|
164
166
|
v.resizeObserver.disconnect();
|
|
165
167
|
v.controls.orbit.dispose();
|
|
166
168
|
v.gizmo?.dispose();
|
|
167
|
-
if (v.path) {
|
|
168
|
-
disposeRenderPath(v.path);
|
|
169
|
-
}
|
|
170
169
|
if (v.built) {
|
|
171
170
|
disposeScene(v.built);
|
|
172
171
|
}
|
|
172
|
+
if (v.shadow) {
|
|
173
|
+
disposeGroundShadow(v.shadow);
|
|
174
|
+
}
|
|
173
175
|
Object.values(v.environments).forEach((e) => e.dispose());
|
|
174
176
|
v.geometries.forEach((g) => g.dispose());
|
|
175
177
|
v.atlas.texture.dispose();
|
|
@@ -191,6 +193,12 @@ function apply<Content>(v: Viewer<Content>, changes: ReadonlySet<Change>): void
|
|
|
191
193
|
v.structure = { activeComponents: options.activeComponents, relationsActive: options.activeRelations !== undefined };
|
|
192
194
|
rebuild(v);
|
|
193
195
|
}
|
|
196
|
+
if (changes.has("shadow") || changes.has("build")) {
|
|
197
|
+
if (v.shadow) {
|
|
198
|
+
disposeGroundShadow(v.shadow);
|
|
199
|
+
}
|
|
200
|
+
v.shadow = v.built && options.groundShadow !== false ? createGroundShadow(v.renderer, v.scene, v.built) : undefined;
|
|
201
|
+
}
|
|
194
202
|
if (changes.has("camera")) {
|
|
195
203
|
const { near = 0.1, far = 2000, ...rest } = options.camera ?? { type: "Perspective" };
|
|
196
204
|
v.camera = v.cameras[rest.type];
|
|
@@ -211,11 +219,9 @@ function apply<Content>(v: Viewer<Content>, changes: ReadonlySet<Change>): void
|
|
|
211
219
|
updateLights(v);
|
|
212
220
|
}
|
|
213
221
|
if (changes.has("quality")) {
|
|
214
|
-
const quality = options.quality ?? "
|
|
215
|
-
v.governor = { quality, tier: quality === "auto" ? "
|
|
216
|
-
|
|
217
|
-
if (changes.has("quality") || changes.has("camera")) {
|
|
218
|
-
updateRenderPath(v);
|
|
222
|
+
const quality = options.quality ?? "auto";
|
|
223
|
+
v.governor = { quality, tier: quality === "auto" ? "high" : quality, sum: 0, count: 0 };
|
|
224
|
+
v.renderer.setPixelRatio(getPixelRatio(v.governor.tier, window.devicePixelRatio));
|
|
219
225
|
}
|
|
220
226
|
if ((changes.has("paint") || changes.has("build")) && v.built) {
|
|
221
227
|
const start = performance.now();
|
|
@@ -284,7 +290,7 @@ function renderFrame<Content>(v: Viewer<Content>, now: number): void {
|
|
|
284
290
|
renderer.info.reset();
|
|
285
291
|
const moving = v.controls.orbit.update(Math.min(interval / 1000, 0.1)) || !!gizmo?.animating;
|
|
286
292
|
if (moving && loop.wasMoving && v.governor && recordFrame(v.governor, interval)) {
|
|
287
|
-
|
|
293
|
+
renderer.setPixelRatio(getPixelRatio(v.governor.tier, window.devicePixelRatio));
|
|
288
294
|
}
|
|
289
295
|
loop.wasMoving = moving;
|
|
290
296
|
const animated = !!built && built.animatedItems.length > 0;
|
|
@@ -296,11 +302,13 @@ function renderFrame<Content>(v: Viewer<Content>, now: number): void {
|
|
|
296
302
|
if (built) {
|
|
297
303
|
cullScene(built, camera.position);
|
|
298
304
|
}
|
|
299
|
-
|
|
305
|
+
if (v.loaded) {
|
|
306
|
+
renderer.render(v.scene, camera);
|
|
307
|
+
}
|
|
300
308
|
gizmo?.render();
|
|
301
309
|
v.overlays.renderer.render(v.overlays.scene, camera);
|
|
302
310
|
Object.assign(v.stats, { frames: v.stats.frames + 1, frameMs: performance.now() - start, drawCalls: renderer.info.render.calls });
|
|
303
|
-
if (moving || animated
|
|
311
|
+
if (moving || animated) {
|
|
304
312
|
invalidate(v);
|
|
305
313
|
} else {
|
|
306
314
|
loop.last = 0;
|
|
@@ -310,7 +318,6 @@ function renderFrame<Content>(v: Viewer<Content>, now: number): void {
|
|
|
310
318
|
function onResize<Content>(v: Viewer<Content>, rect: DOMRectReadOnly): void {
|
|
311
319
|
Object.assign(v.size, { width: rect.width, height: rect.height });
|
|
312
320
|
v.renderer.setSize(rect.width, rect.height, false);
|
|
313
|
-
v.path?.composer?.setSize(rect.width, rect.height);
|
|
314
321
|
v.overlays.renderer.setSize(rect.width, rect.height);
|
|
315
322
|
v.gizmo?.update();
|
|
316
323
|
fitPose(v);
|
|
@@ -369,13 +376,16 @@ function hoverAtPointer<Content>(v: Viewer<Content>): void {
|
|
|
369
376
|
|
|
370
377
|
function onClick<Content>(v: Viewer<Content>, event: MouseEvent): void {
|
|
371
378
|
const { down } = v.pointer;
|
|
372
|
-
const
|
|
379
|
+
const clicked = !!down && Math.hypot(event.clientX - down.x, event.clientY - down.y) <= clickTolerance;
|
|
380
|
+
const hit = clicked ? pick(v, event) : undefined;
|
|
373
381
|
const target = hit && v.compiled!.targets[hit.target];
|
|
374
382
|
const args = hit && getGroupArgs(v, hit);
|
|
375
383
|
if (hit && target?.kind === "relation") {
|
|
376
384
|
v.options.onClickRelation?.(target.relation, { nativeEvent: event, point: hit.point });
|
|
377
385
|
} else if (hit && args) {
|
|
378
386
|
v.options.onClickGroup?.(...args, { nativeEvent: event, point: hit.point });
|
|
387
|
+
} else if (clicked) {
|
|
388
|
+
v.options.onPointerMissed?.(event);
|
|
379
389
|
}
|
|
380
390
|
}
|
|
381
391
|
|
|
@@ -529,12 +539,5 @@ function updateOverlays<Content>(v: Viewer<Content>): void {
|
|
|
529
539
|
setOverlays(v.overlays, overlays, options.onOverlays);
|
|
530
540
|
}
|
|
531
541
|
|
|
532
|
-
function updateRenderPath<Content>(v: Viewer<Content>): void {
|
|
533
|
-
if (v.path) {
|
|
534
|
-
disposeRenderPath(v.path);
|
|
535
|
-
}
|
|
536
|
-
v.path = createRenderPath(v.renderer, v.scene, v.camera, v.governor?.tier ?? "low");
|
|
537
|
-
}
|
|
538
|
-
|
|
539
542
|
const raycaster = new Raycaster();
|
|
540
543
|
const ndc = new Vector2();
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
declare module "n8ao" {
|
|
2
|
-
import type { Camera, Scene, WebGLRenderTarget } from "three";
|
|
3
|
-
import type { Pass } from "three/addons/postprocessing/Pass.js";
|
|
4
|
-
|
|
5
|
-
type AOPass = Pass & {
|
|
6
|
-
readonly configuration: Record<string, unknown> & { intensity: number };
|
|
7
|
-
readonly beautyRenderTarget: WebGLRenderTarget;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const N8AOPass: new (scene: Scene, camera: Camera, width?: number, height?: number) => AOPass;
|
|
11
|
-
}
|