mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-07 12:31:56 +00:00
383 lines
25 KiB
Markdown
383 lines
25 KiB
Markdown
# Integrated Render workspace (R3)
|
||
|
||
The native image panel offers CPU raster, optional CPU ray tracing and
|
||
[GPU path tracing](render-path.md) as explicit image methods. All three methods can be edited and saved offline. Check and Start are enabled
|
||
only when the selected method has an installed supporting host; an unavailable method never falls back.
|
||
|
||
R4a builds on this viewport contract with a separately advertised CPU product-image
|
||
executor and Check/Start/Cancel/Export controls. See [render jobs](render-jobs.md) for
|
||
the asynchronous protocol, image limits, captured revisions and PNG export. The legacy
|
||
`ui.render` snapshot remains a separate route.
|
||
|
||
Choose **Render** in the workspace switcher after finishing a modelling operation.
|
||
The current integrated GPU renderer shows a separate product scene. Return to Design
|
||
restores its camera, projection preference and existing viewport drawing policy.
|
||
The live product preview remains independent of the selected image method.
|
||
|
||
## Stage bar and floating docks
|
||
|
||
Render has no ribbon. A shared 88 pt two-row stage bar sits 8 pt to the right of
|
||
the 104 × 88 pt workspace card, with matching top and bottom edges. The icon sits
|
||
above the Render label and Workspace caption. The header is 36 pt; the remaining
|
||
52 pt contains the tools, centred vertically below a 1 pt divider. Numbered **Look**, **Light**, **Frame** and **Output** chips
|
||
run `view.render_stage {stage: look|light|frame|output}`. The selection belongs to the
|
||
open document tab's view state; it is not saved in the design. Opening a stage never
|
||
applies or saves settings or starts an image job. It focuses the existing Inspector
|
||
page, while every Inspector page and registered Render command remains reachable.
|
||
The headless command validates and echoes the request without changing the document.
|
||
|
||
Render, Cancel and the shared command search (S) occupy the top row. The Pick control's
|
||
icon-text Body/Face/Component segments, Paint/Pick Up actions and direct-light
|
||
preview information chip occupy Look's second row with 8 pt side padding. Changing the
|
||
light coordinate frame remains disabled with its reason in this checkout. Frame
|
||
uses the existing explicit camera command for projection; Output shows the current
|
||
size/format and directs edits to the Output Inspector. No completion ticks are inferred.
|
||
|
||
The Browser and Inspector float in both shell layouts, share top and bottom edges,
|
||
and clear the bar and Shots strip by 8 pt. Their default outer widths are 266 pt and 305 pt, with the shared resize bounds.
|
||
The 48 pt Shots strip has an 8 pt gap from the docks. The 110 pt compass uses the
|
||
free canvas beside the Inspector and the navigation bar keeps its shared navigation handler. Narrow
|
||
rows scroll horizontally; docks shrink together or disappear if no usable space
|
||
remains. The Shots strip's independent `view.shots_strip` preference is unchanged.
|
||
The current model/library Browser can reveal model bodies for Look; scene-specific
|
||
Lights, Shots and Output expansion awaits the scene Browser change.
|
||
|
||
`view.render_focus {on: true}` hides the Browser, Inspector and Shots strip and
|
||
releases their canvas reservations. Tab toggles focus while Render is active and
|
||
no text field has focus; the **Exit focus** chip sits at the Browser's remembered
|
||
side below the stage bar. The workspace card, stage bar, compass and view bar
|
||
remain available. Focus belongs to the window, is never saved in a design or
|
||
preferences, and retains the docks' sides, widths and folded state.
|
||
|
||
Below 1100 pt, or with `view.layout {mode: compact}`, the docks use their shared
|
||
minimum width without overwriting the remembered width. Below 800 pt the Browser
|
||
folds into a chip. Its floating card opens through
|
||
`view.render_browser {open: true}` and closes through **Fold Browser**; it shields
|
||
navigation beneath the card without reserving a canvas column. Neither command
|
||
edits or evaluates the design, moves the camera or creates an undo step.
|
||
|
||
## Image methods and controls
|
||
|
||
**CPU raster** produces the existing preview PNG with approximate transparency.
|
||
**CPU ray tracing** requires a native worker and the `raytrace-cpu` build feature.
|
||
Its panel offers **Single image** with 1, 4 or 16 spatial samples per pixel, or
|
||
**CPU progressive** with 1–64 accumulated samples and a separate seed. Both use
|
||
Neutral / Warm and cool / Key and rim lighting, cast shadows and exposure from
|
||
−16 to +16 EV. Progressive sampling has a 1,048,576-pixel and 16,777,216 pixel × sample
|
||
limit; the UI proposes a smaller size only as an explicit action. It requires an
|
||
opaque background; the panel explains the incompatibility and lets the user clear
|
||
Transparent background. Additional collapsible sections expose body reflections,
|
||
captured HDR or constant environments, directional lights and point lights. Reflection
|
||
bindings require explicit confirmation after a document change; reusing a name cannot
|
||
redirect them to another body. Check and the current job display their separate HDR
|
||
capture metadata. See [CPU workspace controls](render-cpu-workspace.md) for units,
|
||
limits and the immutable capture contract. CPU glass, emission, surface effects,
|
||
anisotropy, area lights and spot cones remain API capabilities without panel editors.
|
||
|
||
**GPU path tracing** preserves asynchronous shader preparation and its timing display.
|
||
Its independent image device requires Vulkan; the live viewport may use another backend.
|
||
When no compatible Vulkan device is available, GPU settings remain editable and
|
||
saveable, while Check and Start explain why GPU execution is unavailable.
|
||
The panel exposes progressive sample counts from 1 to 4096 and an Advanced section
|
||
for maximum path depth (1–16), random seed and exposure (−32 to +32 EV). One setup
|
||
exposure field controls the selected image method. Switching methods retains their
|
||
local numeric drafts while submitting and saving only the active method. Reloading
|
||
or choosing another setup replaces those drafts with the saved numeric intent.
|
||
The live product preview keeps its fixed studio response and does not apply image
|
||
exposure, environments, lens or material overrides.
|
||
|
||
The GPU Advanced section also exposes Reinhard / ACES fitted tone mapping, optional
|
||
final edge-aware denoising, and a thin-lens depth-of-field control. Positive aperture
|
||
requires a perspective product camera. Denoising preserves raw accumulation but can
|
||
soften detail; glass and sharp specular first hits bypass its final spatial filter.
|
||
|
||
The Environment section selects no map, an original artistic sky gradient, or a local
|
||
Radiance `.hdr` panorama. HDR input is bounded to 16 MiB, 2048 × 1024, 2:1, and linear
|
||
sRGB/D65 primaries; unspecified primaries require the explicit interpretation checkbox.
|
||
EXR is not supported. Rotation and intensity affect illumination, while the saved
|
||
background remains the camera backplate. Selecting a file runs the bounded public
|
||
`render.hdr.inspect` command; a typed path has an explicit **Check HDR file** action.
|
||
The picker belongs to the originating document revision, setup, method and input
|
||
selection. A cancelled or stale answer never replaces a newer selection.
|
||
|
||
The panel distinguishes a pending file, a checked file and **HDR saved inside this
|
||
design**. It shows dimensions, declared colour primaries and intensity; the source
|
||
digest is available in a collapsed details section. Check, Start and Save use the
|
||
checked file's expected SHA-256, rejecting changed bytes until an explicit recheck.
|
||
An already captured image retains its immutable source independently of later edits.
|
||
|
||
Custom studio lighting exposes constant linear-RGB environment radiance, a finite-radius sun,
|
||
and up to four one-sided rectangular emitters. World-space centers and orthogonal
|
||
half-edge vectors specify their geometry in millimetres; radiance is linear RGB.
|
||
An environment map replaces the constant environment term. The path integrator uses
|
||
the published emitter/BSDF MIS contract.
|
||
|
||
### GPU image materials
|
||
|
||
The GPU image materials section assigns runtime optics to whole visible scene bodies.
|
||
Refresh the authoritative body list, explicitly choose a body, and add its assignment.
|
||
The captured ordinal and exact name must match; a document identity or revision change
|
||
requires explicit revalidation. A removed, renamed or reordered body cannot silently
|
||
receive another body's settings. The editor uses weak document identity references, so
|
||
stale assignments do not retain historical documents. The normal Appearance and material
|
||
library dialogs keep their existing behavior.
|
||
|
||
Glass, clear coat and planar maps have separate collapsible controls. Six original glass
|
||
recipes come directly from the starter pack: linear transmittance over the recipe's
|
||
reference distance becomes absorption per millimetre via `-ln(T) / distance`. Selecting
|
||
one never changes saved opacity or assigns a scalar appearance. The swatch shows the
|
||
recipe's transmittance, not a rendered preview. Manual IOR, RGB absorption, thin-sheet
|
||
thickness and straight-shadow transmission are available. Closed solids derive optical
|
||
distance from geometry; full topology, orientation, overlap and optical-boundary checks
|
||
run during GPU preparation. Successful Check does not certify those geometric properties.
|
||
|
||
Clear coat exposes weight, roughness and IOR over the existing opaque base. Runtime maps
|
||
accept bounded local PNG/JPEG base-color sRGB and OpenGL +Y normal images, normal strength,
|
||
and orthogonal world-space origin/U/V vectors in millimetres. Each vector spans one full
|
||
repeat. The backend's 1024×1024 per-map, 16 MiB encoded-total and 128-repeat bounds remain.
|
||
Glass cannot share one body with coat or maps. Limits are eight glass bodies, 64 coat
|
||
bodies and 16 mapped bodies, within a maximum of 64 editor assignments.
|
||
|
||
All these controls are temporary per-document-tab state, explicitly labelled in the UI.
|
||
They are not saved in the design, render setup or portable material library. Disable the
|
||
overrides before choosing a CPU method; active GPU assignments cause Check/Start to
|
||
refuse a CPU request. Both buttons submit the same freshly validated runtime parameters,
|
||
and file contents are captured by the engine at that boundary. File-picker completion
|
||
checks the original document, revision and body identity before accepting the path.
|
||
|
||
Check and Start build the same request from the current product camera, size and
|
||
selected method, including when Render Result is open. Every click revalidates host
|
||
availability and scene readiness. The engine checks resource admission at Start;
|
||
an earlier successful Check does not reserve a queue slot or memory.
|
||
|
||
## Product scene
|
||
|
||
`engine::product_scene::extract` consumes authoritative evaluated geometry, reusing
|
||
the document's world/occurrence placement and mesh Arcs. Body, component, material,
|
||
face and imported appearances retain their existing precedence and opacity. Source
|
||
geometry is never transformed a second time or altered to serve a renderer.
|
||
|
||
The shared L1 `ProductScene`/`ProductMesh` contract contains world-space meshes,
|
||
resolved sRGB colours, opacity and face appearance overrides. Face indices are the
|
||
existing mesh-to-B-rep mapping, resolved through document appearance references;
|
||
they are not new persistent names or triangle-derived face identities.
|
||
|
||
There are no grid/axis/edge lines, sketches, construction objects, section cuts,
|
||
analysis shading, active-component fading, canvases or decals in the product scene. Browser visibility still controls which bodies appear.
|
||
The existing Design viewport and CPU snapshot routes keep their current policies.
|
||
|
||
Extraction refuses a stale live-drag model. The explicit model-reading `render.scene {}`
|
||
command follows the normal engine evaluation boundary, then returns bounded metadata:
|
||
body names, triangle counts, resolved colours/opacity, face-override counts and bounds.
|
||
It does not return mesh payloads, change the document or add an undo step. Product
|
||
extraction admits at most 16,384 visible bodies.
|
||
|
||
## Image result canvas
|
||
|
||
The image panel switches between **Live Preview** (the product camera) and
|
||
**Render Result** (the current CPU checkpoint or last completed PNG). Clicking the
|
||
small image preview also opens the result on the main canvas. Check, Start, Cancel and Export
|
||
remain available in the same panel. An empty result explains how to start a job;
|
||
it never substitutes the live preview for an exported image.
|
||
|
||
**Fit Image** frames the complete image and follows window resizing. **100%**
|
||
maps one image pixel to one physical display pixel, including on high-DPI screens.
|
||
Pan, wheel, trackpad and Space + drag use the shared Navigation preferences with
|
||
orbit disabled. Ctrl + arrow keys pan the image; Fit/Home frame it. Image navigation
|
||
does not move the product or Design camera and does not change the saved setup.
|
||
|
||
The canvas shows the image dimensions, executor, full job identity and captured
|
||
model revision. A visible warning identifies an earlier captured revision when the
|
||
document has changed. A CPU progressive checkpoint is explicitly provisional and
|
||
shows its samples per pixel and sequence. Its texture is cached by job identity
|
||
and sequence, separately from the last completed image. **Export final PNG** keeps
|
||
using that completed image even while a checkpoint is shown. Cancelling or failing
|
||
the active job clears its preview and returns to the retained final image.
|
||
Transparency is shown over a checker
|
||
background; display scaling and navigation never modify the PNG bytes.
|
||
|
||
Canvas selection, framing and pan/zoom are local to each open document tab. Switching
|
||
tabs never displays another document's texture. A new image starts fitted; later
|
||
checkpoints and transitions to final/cancelled state preserve pan/zoom. Final
|
||
publication is checked directly after the preview read so a stale status reply
|
||
cannot briefly select an older frame and reset the next frame's zoom. The canvas
|
||
itself adds no document fields; CPU sampling intent is saved with the job below.
|
||
|
||
## Settings and product camera
|
||
|
||
The right panel stages a named setup's camera, background, output and active image
|
||
method. **Save Setup** records the complete numerical `RenderSetup.job` and the current
|
||
product `Camera` through `render.settings.set`, with one undo step. A new checked HDR
|
||
uses `render.settings.capture_hdr` to save both source bytes and setup in that same
|
||
atomic step. Editing the name
|
||
is Save As; choosing an existing name from the picker loads that setup. **Reload Saved
|
||
Settings** replaces the numeric draft with the saved values. Drafts remain separate
|
||
for each open document, and loading a setup preserves completed images and result framing.
|
||
|
||
| Active method | Saved numeric intent |
|
||
| --- | --- |
|
||
| CPU raster | Transparency, with zero exposure |
|
||
| CPU ray tracing | Single-image AA or progressive SPP/seed, preset or custom directional lights, point/spot lights, area lights and their samples/seed, shadows, constant RGB environment or embedded HDR with rotation/intensity/samples, setup exposure |
|
||
| GPU path tracing | Transparency, samples/depth/seed, tone map, denoise, lens, RGB studio lighting/sun/area lights, procedural sky or embedded HDR with rotation/intensity/explicit colour assumption, setup exposure |
|
||
|
||
The CPU panel preserves existing area-light and spot-cone fields even though it does
|
||
not yet edit every field. Opening a GPU setup retains non-power-of-two sample counts,
|
||
RGB environment values, exact sky gradients and radians. Explicit empty light lists,
|
||
black environments and absent settings remain distinct. The only exposure authority
|
||
is `RenderSetup.exposure_ev`: CPU requests lower it to their raytrace options with zero
|
||
outer exposure; GPU jobs use the same value in their job options. Choosing raster
|
||
explicitly selects its zero-exposure response.
|
||
|
||
Saving uses pure numeric validation and does not require an installed renderer or a
|
||
current evaluated scene. New HDR capture reads and validates the bounded source through
|
||
the engine; failure leaves the document, resource table and local file selection intact.
|
||
After success, the draft changes to the embedded resource and contains no source path.
|
||
Saving that setup again, Save As, Reload and design reopen use the included bytes, even
|
||
when the original file has been removed. CPU/GPU setups may share the same immutable
|
||
payload. The engine limits each source to 16 MiB and the design to 64 resources/64 MiB.
|
||
|
||
Check and Start use the same complete typed setup and then perform normal host, scene
|
||
and capture admission. Temporary bindings can still use an embedded HDR through the
|
||
runtime resource selector. GPU maps and all body bindings, including disabled
|
||
assignments, cannot yet be saved as a complete job.
|
||
The panel explains the limitation and refuses Save before changing the document.
|
||
Those inputs can still execute through the existing transient request route. Older
|
||
setups with nondefault legacy environment rotation/intensity are also retained and
|
||
refused for full-job saving until explicitly converted; their values are never erased.
|
||
|
||
**Restore Saved Camera** runs `render.settings.apply {name}`, preserving target,
|
||
distance, yaw, pitch, roll, FOV and up axis as view state. It neither edits the document
|
||
nor settles a stale model. The UI honours its up axis in Render; the Design camera
|
||
is restored when returning. The camera moves exactly as in Design: the navigation preset,
|
||
Orbit around, zoom to the cursor, the SpaceMouse, the middle double-click, F6 and the axis
|
||
view or navigation cube all work and
|
||
**Fit Product** frames visible product bodies without including sketches or selection.
|
||
|
||
Preview drafts do not make the document dirty until saved. Unknown backend preferences
|
||
and unsupported modes remain saved intent: the strict resolver reports the unsupported
|
||
viewport request. **Use Integrated Preview** is an explicit draft change, never an
|
||
automatic fallback. The method selector describes the desired image execution independently of the
|
||
installed host. It does not claim support for a saved final-mode or external-engine
|
||
preference. Saved image settings do not change the fixed live product preview.
|
||
|
||
## Host capabilities and resources
|
||
|
||
`render.backends` always retains the built-in `cpu-raster` preview/PNG image executor.
|
||
An installed CPU image host adds `cpu-product`; a native host with `raytrace-cpu`
|
||
also advertises `cpu-raytrace`, with its bounded PBR/HDRI/refraction profile. Discovery
|
||
does not select that method automatically or enable native workers in the browser.
|
||
Only an installed UI GPU host adds `gpu-viewport`, advertising **Preview / Viewport**
|
||
with no image formats or HDRI/refraction/progressive features. The installed
|
||
[opaque PBR consumer](render-opaque-pbr.md) adds the `pbr` feature. The host reports
|
||
effective limits from its created device and depth attachment: at most 4096 pixels
|
||
per dimension and 4,194,304 pixels, within the 256 MiB pixel scratch admission policy.
|
||
The estimate includes the selected MSAA colour/depth cost; it excludes scene geometry,
|
||
driver overhead and cached source meshes. It is not a measurement of total GPU memory.
|
||
|
||
The preview never refuses a frame because of the screen size. When the viewport's physical
|
||
size is past those limits (a maximised 4K or 5K window is 8–15 million pixels), the preview
|
||
draws at the largest size of the same aspect the executor admits (`RenderLimits::fit`, both
|
||
axes scaled by one factor, scratch included) and filters it up into the viewport. A viewport
|
||
within the limits draws at full size.
|
||
|
||
PNG images keep the saved-setup limits above. A setup past them is refused with the limits and
|
||
the largest size at its aspect (for example `4096 × 4096` → `2048 × 2048`), and the image panel
|
||
offers to use that size.
|
||
|
||
Pure capability metadata lives in the session/host, outside persistence and history,
|
||
surviving document replacement, scratch sessions and document-tab switches. No wgpu
|
||
types enter the engine or document crates. A host without an installed GPU/depth buffer
|
||
reports that product viewport preview is unavailable, rather than silently using the
|
||
opaque CPU snapshot path to approximate transparent appearances.
|
||
|
||
GPU product batches are separate from Design batches while sharing the installed
|
||
device and pipelines. Model/visibility/appearance changes update the product scene;
|
||
camera movement updates uniforms without rebuilding vertices. Selection and section
|
||
state do not change the product buffers. Vertex uploads are bounded to 128 MiB and
|
||
checked before allocation; malformed/non-finite triangles and invalid opacity fail.
|
||
Reinstalling the host invalidates product uploads. This is not a general device-loss,
|
||
render-job or cancellation protocol; those ownership mechanisms belong to R4.
|
||
|
||
Transparency uses the existing raster far/near alpha-blending approximation, without
|
||
refraction or HDR illumination. Opaque PBR uses a separate surface batch in the
|
||
same installed renderer. R3 itself added no export job; R4a supplies CPU product
|
||
PNG jobs. There is no result gallery or Bevy dependency. Saved setups were added
|
||
in format 21, alongside opt-in optical parameters on existing looks.
|
||
`ui.render` remains the existing Design snapshot API, using its installed renderer;
|
||
`ui.screenshot` captures
|
||
the actual integrated Render workspace. Product-image export uses `render.start`
|
||
and `render.export`, rather than the Design snapshot API.
|
||
|
||
## Reproduce
|
||
|
||
Run the original procedural `examples/render-studio.json` through the engine/CLI and
|
||
open its saved design in the app. Select Render, adjust its background or camera and
|
||
save a setup. The fixture uses original boxes/cylinders and simple colour/opacity
|
||
assignments; no commercial CAD files, artwork or materials are used. Actual Windows
|
||
Vulkan/MSAA evidence is attached to [#673](https://github.com/bherbruck/solidcraft/issues/673).
|
||
|
||
## Explicit Render camera and the Design view contract
|
||
|
||
`render.camera.set {camera}` applies a complete camera snapshot as transient view
|
||
state. It uses the saved-render camera's strict decoder and finite mm/radian
|
||
limits, preserves its explicit roll and up axis, and does not evaluate geometry,
|
||
change a saved shot, modify the design or add an undo step. Omitted roll/up use
|
||
zero/Z defaults; all other camera fields are required. Unknown fields, invalid
|
||
axes, nonfinite values and out-of-bounds numbers refuse atomically.
|
||
|
||
The Render inspector uses this command for numerical edits and before Frame
|
||
Subject. Design's `view.apply` retains upstream's independent policy: it accepts
|
||
finite roll (clamped to +/-pi) and refuses an explicit up axis. Render does not
|
||
reintroduce the former fork-specific extension to that Design command. Saving
|
||
or restoring a shot still uses the existing render-settings commands.
|
||
|
||
The camera pitch label is explicitly **Camera pitch**, so the legacy English
|
||
label adapter does not replace mechanical screw pitch translations. Material
|
||
axis conventions have stable catalog IDs; the numerical/wood conventions and
|
||
engineering data remain unchanged.
|
||
|
||
The legacy English-label adapter gives explicit catalog IDs precedence and, for
|
||
an ambiguous source label, retains a translation already present in the chosen
|
||
locale before falling back to English. Adding an untranslated Render alias no
|
||
longer hides existing Library, Appearance or Checkpoint translations. Contextual
|
||
Render labels still use their own stable IDs rather than borrowing a different
|
||
feature's meaning.
|
||
|
||
## Picking in the product view
|
||
|
||
The Look stage bar's second-row **Pick** control selects Body, Face or Component granularity,
|
||
using Design’s selection filter state through the `select.filter` command. Component
|
||
picks use the Browser’s exact occurrence path, including nested and repeated
|
||
placements; a body at the design root retains its body identity. Face picks use the
|
||
existing mesh-to-B-rep mapping and connected-surface selection rules.
|
||
|
||
Hover highlights the target; clicking selects it. Clicking empty space clears the
|
||
selection. Shift and Ctrl/Cmd follow Design’s add/toggle behavior and the Shift
|
||
add-only preference. Browser row selections and product picks share the same
|
||
selection commands and state, retained across Design/Render switches. Picking works
|
||
with the Shots strip shown or hidden. Render picking never starts a geometry edit.
|
||
|
||
Selection and hover use Design’s highlight drawing and theme tokens in a separate
|
||
GPU overlay on the live product view. The product scene and its upload stay unchanged.
|
||
CPU image jobs, exported PNGs, retained images and the Render Result canvas never
|
||
contain this overlay; the Pick control is disabled on the result canvas.
|
||
|
||
## Browser scene focus
|
||
|
||
The shared Browser lists Environment (with its source), Lights, saved Shots,
|
||
Objects and Output (with image dimensions and format). Shots **+** opens the
|
||
existing Shots manager; Lights **+**, Solo and Mute remain faded with an explicit
|
||
reason until named light commands exist. Existing light entries describe the
|
||
current numerical image setup, without inventing a saved rig.
|
||
|
||
`ViewState.selection` exposes `RenderSelection` for Nothing, Object (the existing
|
||
engine selection), Environment, Light, Shot and Output. It belongs to each document
|
||
view and is never saved in a design. `view.render_select` validates semantic focus
|
||
requests without opening dialogs or editing/evaluating a design. Object picks and
|
||
Browser selections keep the existing selection commands. Inspector routing stays
|
||
as before; the focus state is available to a later Inspector change.
|
||
|
||
Look expands Objects, Light expands Lights and Environment, and Frame expands
|
||
Shots. Output leaves expansion unchanged. Stages preserve selection and never
|
||
lock rows or prevent manual expansion.
|