@volter/editor-threejs 0.5.192 → 0.5.194
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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@volter/editor-threejs",
|
|
3
3
|
"author": "Volter AI, Inc.",
|
|
4
|
-
"version": "0.5.
|
|
4
|
+
"version": "0.5.194",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
@@ -135,12 +135,12 @@
|
|
|
135
135
|
"serving": "./dist-node/serving.mjs"
|
|
136
136
|
},
|
|
137
137
|
"dependencies": {
|
|
138
|
-
"@volter/editor-project": "0.5.
|
|
138
|
+
"@volter/editor-project": "0.5.194",
|
|
139
139
|
"@sparkjsdev/spark": "^2.1.0",
|
|
140
140
|
"three.quarks": "^0.16.0",
|
|
141
141
|
"zod": "^4.3.6",
|
|
142
142
|
"typescript": "5.9.3",
|
|
143
|
-
"@volter/editor-sdk": "0.5.
|
|
143
|
+
"@volter/editor-sdk": "0.5.194",
|
|
144
144
|
"postprocessing": "6.38.3",
|
|
145
145
|
"quarks.core": "0.16.0",
|
|
146
146
|
"@fortawesome/free-solid-svg-icons": "^7.2.0"
|
package/src/capture/scene.ts
CHANGED
|
@@ -12,6 +12,9 @@ export interface SceneCaptureOptions {
|
|
|
12
12
|
transparent?: boolean;
|
|
13
13
|
toneMapping?: THREE.ToneMapping;
|
|
14
14
|
exposure?: number;
|
|
15
|
+
/** Caller-owned draw resources for this renderer/camera. The returned
|
|
16
|
+
* cleanup runs after success or failure, before releasing the renderer. */
|
|
17
|
+
prepareDraw?: (renderer:THREE.WebGLRenderer,camera:THREE.Camera)=>void|(()=>void);
|
|
15
18
|
/** Integration-owned GPU display resolve, shared with its live viewport. */
|
|
16
19
|
displayTransform?: DocumentDisplayTransform;
|
|
17
20
|
/** Caller-owned scene-linear effect. The input carries a depth texture;
|
|
@@ -75,6 +78,7 @@ function capture(
|
|
|
75
78
|
let display: THREE.WebGLRenderTarget | undefined;
|
|
76
79
|
let displayInput: THREE.WebGLRenderTarget | undefined;
|
|
77
80
|
let completed = false;
|
|
81
|
+
let finishDraw:(()=>void)|void=undefined;
|
|
78
82
|
try {
|
|
79
83
|
hdr = new THREE.WebGLRenderTarget(renderWidth, renderHeight, { type: THREE.HalfFloatType });
|
|
80
84
|
if (options.effect) hdr.depthTexture = new THREE.DepthTexture(renderWidth, renderHeight);
|
|
@@ -86,6 +90,7 @@ function capture(
|
|
|
86
90
|
renderer.setClearColor(0, options.transparent ? 0 : 1);
|
|
87
91
|
if (options.transparent) scene.background = null;
|
|
88
92
|
renderer.setRenderTarget(hdr);
|
|
93
|
+
finishDraw=options.prepareDraw?.(renderer,camera);
|
|
89
94
|
renderer.clear();
|
|
90
95
|
renderer.render(scene, camera);
|
|
91
96
|
const resolved = options.effect?.render(renderer, hdr, scene, camera) ?? hdr;
|
|
@@ -128,18 +133,20 @@ function capture(
|
|
|
128
133
|
completed = true;
|
|
129
134
|
return imageUrl;
|
|
130
135
|
} finally {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
try {finishDraw?.();} finally {
|
|
137
|
+
scene.background = previous.background;
|
|
138
|
+
renderer.setRenderTarget(previous.target);
|
|
139
|
+
renderer.toneMapping = previous.toneMapping;
|
|
140
|
+
renderer.toneMappingExposure = previous.exposure;
|
|
141
|
+
renderer.outputColorSpace = previous.colorSpace;
|
|
142
|
+
renderer.shadowMap.enabled = previous.shadows;
|
|
143
|
+
renderer.shadowMap.type = previous.shadowType;
|
|
144
|
+
renderer.setClearColor(previous.clearColor, previous.clearAlpha);
|
|
145
|
+
display?.dispose();
|
|
146
|
+
displayInput?.dispose();
|
|
147
|
+
hdr?.dispose();
|
|
148
|
+
lease.release({ discard: !completed });
|
|
149
|
+
}
|
|
143
150
|
}
|
|
144
151
|
}
|
|
145
152
|
|
|
@@ -1534,7 +1534,6 @@ export class Object3DDocumentSession {
|
|
|
1534
1534
|
const target = new THREE.WebGLRenderTarget(transform ? outputWidth : renderWidth, transform ? outputHeight : renderHeight);
|
|
1535
1535
|
let resolved: THREE.WebGLRenderTarget | null = null;
|
|
1536
1536
|
const previousTarget = this.renderer.getRenderTarget();
|
|
1537
|
-
const previousPixelRatio = this.renderer.getPixelRatio();
|
|
1538
1537
|
const perspective = this.viewport.camera;
|
|
1539
1538
|
const previousAspect = perspective.aspect;
|
|
1540
1539
|
try {
|
|
@@ -1545,7 +1544,6 @@ export class Object3DDocumentSession {
|
|
|
1545
1544
|
perspective.aspect = outputWidth / outputHeight;
|
|
1546
1545
|
perspective.updateProjectionMatrix();
|
|
1547
1546
|
}
|
|
1548
|
-
this.renderer.setPixelRatio(1);
|
|
1549
1547
|
this.renderer.setRenderTarget(sceneTarget);
|
|
1550
1548
|
this.renderCapture(
|
|
1551
1549
|
(camera) => this.renderSolidForCapture(camera, sceneTarget, renderWidth, renderHeight),
|
|
@@ -1586,21 +1584,11 @@ export class Object3DDocumentSession {
|
|
|
1586
1584
|
perspective.aspect = previousAspect;
|
|
1587
1585
|
perspective.updateProjectionMatrix();
|
|
1588
1586
|
this.renderer.setRenderTarget(previousTarget);
|
|
1589
|
-
this.renderer.setPixelRatio(previousPixelRatio);
|
|
1590
|
-
// THE COMPOSER IS SIZED AGAIN AT THE DISPLAY'S RATIO. The capture's own draw restores the
|
|
1591
|
-
// composer's size while the ratio is still 1 (`renderSolidForCapture`), and the composer
|
|
1592
|
-
// sizes its buffers from the renderer's drawing buffer: every capture (a selection's
|
|
1593
|
-
// preview takes one) left the view and its outline mask at CSS resolution until the next
|
|
1594
|
-
// resize. Measured on the stage: a crisp outline stating 4 device px drew 10 right after a
|
|
1595
|
-
// selection and 4 after a repaint that resized.
|
|
1596
|
-
this.composer?.setSize(this.renderWidth, this.renderHeight, false);
|
|
1597
1587
|
target.dispose();
|
|
1598
1588
|
resolved?.dispose();
|
|
1599
1589
|
sceneTarget.dispose();
|
|
1600
|
-
//
|
|
1601
|
-
//
|
|
1602
|
-
// (Save Screenshot, an agent's get_viewport_screenshot) left the viewport a flat grey until the
|
|
1603
|
-
// pointer next moved over it (measured 2026-09-28: stddev 0 across the view, restored on hover).
|
|
1590
|
+
// Refresh any draw-time state after the offscreen photograph. Neither
|
|
1591
|
+
// renderer pixel ratio nor canvas dimensions change during capture.
|
|
1604
1592
|
invalidateStages();
|
|
1605
1593
|
}
|
|
1606
1594
|
}
|
|
@@ -1780,21 +1768,30 @@ export class Object3DDocumentSession {
|
|
|
1780
1768
|
const composer = this.composer;
|
|
1781
1769
|
const outlined = (this.selectionOutline?.selection.size ?? 0) > 0;
|
|
1782
1770
|
if (!composer || !outlined || !this.sceneRenderPass || !this.selectionOutlinePass) {
|
|
1783
|
-
this.
|
|
1771
|
+
this.renderLinearScene(camera, target);
|
|
1784
1772
|
return;
|
|
1785
1773
|
}
|
|
1786
|
-
const
|
|
1787
|
-
const previousHeight = this.renderHeight;
|
|
1774
|
+
const previousSize = this.renderer.getDrawingBufferSize(new THREE.Vector2());
|
|
1788
1775
|
try {
|
|
1789
|
-
|
|
1776
|
+
this.resizeComposerBuffers(width, height);
|
|
1790
1777
|
this.renderLinearScene(camera, target);
|
|
1791
1778
|
} finally {
|
|
1792
|
-
|
|
1779
|
+
this.resizeComposerBuffers(previousSize.x, previousSize.y);
|
|
1793
1780
|
this.syncComposerOutput();
|
|
1794
1781
|
this.renderer.setRenderTarget(target);
|
|
1795
1782
|
}
|
|
1796
1783
|
}
|
|
1797
1784
|
|
|
1785
|
+
/** Offscreen sizing must not call EffectComposer.setSize: it also resizes
|
|
1786
|
+
* the renderer's visible canvas, clearing the frame a human is watching. */
|
|
1787
|
+
private resizeComposerBuffers(width: number, height: number): void {
|
|
1788
|
+
const composer = this.composer;
|
|
1789
|
+
if (!composer) return;
|
|
1790
|
+
composer.inputBuffer.setSize(width, height);
|
|
1791
|
+
composer.outputBuffer.setSize(width, height);
|
|
1792
|
+
for (const pass of composer.passes) pass.setSize(width, height);
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1798
1795
|
/** Live HDR draw at the renderer's CURRENT size. Resizing the composer with
|
|
1799
1796
|
* device pixels here would resize the canvas and multiply HiDPI twice on
|
|
1800
1797
|
* every frame. Only an offscreen photograph changes its sizing. */
|
|
@@ -1802,10 +1799,20 @@ export class Object3DDocumentSession {
|
|
|
1802
1799
|
const composer = this.composer;
|
|
1803
1800
|
const outlined = (this.selectionOutline?.selection.size ?? 0) > 0;
|
|
1804
1801
|
if (!composer || !outlined || !this.sceneRenderPass || !this.selectionOutlinePass) {
|
|
1802
|
+
// EffectComposer disables renderer.autoClear when it is created. This
|
|
1803
|
+
// direct path owns a whole scene frame too, including an unselected HDR
|
|
1804
|
+
// viewport and plain photographs, so it must clear its previous depth.
|
|
1805
|
+
this.renderer.setRenderTarget(target);
|
|
1806
|
+
this.renderer.clear(true, true, false);
|
|
1805
1807
|
this.renderer.render(this.scene, camera);
|
|
1806
1808
|
return;
|
|
1807
1809
|
}
|
|
1808
1810
|
try {
|
|
1811
|
+
// These passes are driven directly rather than by composer.render().
|
|
1812
|
+
// Update both passes to the drawing camera, including native camera views
|
|
1813
|
+
// and offscreen captures; the composer's previous free camera can differ.
|
|
1814
|
+
composer.setMainScene(this.scene);
|
|
1815
|
+
composer.setMainCamera(camera);
|
|
1809
1816
|
this.sceneRenderPass.renderToScreen = false;
|
|
1810
1817
|
this.selectionOutlinePass.renderToScreen = false;
|
|
1811
1818
|
this.sceneRenderPass.render(this.renderer, composer.inputBuffer, composer.outputBuffer, 0);
|