* wip(render): reconcile completed material and image pipeline source with 0.20 (#5493) Source-only integration reference for staged review, not a merge-ready aggregate. Donor: 0xlillith/solidcraft@aea20b0115. Upstream:858e5995d6. Retain original CPU/material contracts and explicit GPU donor provenance in docs/render-materials-lab.md (#2067, #2191, #2780, #3306). Preserve released format migrations and current navigation/startup/shell behavior. New saved records use pending descriptors. The physical-card descriptor follows the maintainer's material-engineering-cards naming request, with a legacy-lab format-29 regression. Replace raw new panel hosts with shared containers. Repository checks, complete workspace/all-target Clippy, and the independent physical/resource authoring checks pass for this source. The fresh full local CI invocation has reached test compilation and is not yet complete. Do not transfer donor native output or prior test totals to this integration. Generated review screenshots, video, package ZIP and machine logs remain at the immutable personal evidence pin. Uncommitted geometric displacement is backed up separately, not silently included. No kernel/vendor change, direct main write, release or independent contributor-branch rewrite. Co-authored-by: Christian Svensson <blue@cmd.nu> * test(cli): pin the Compact camera-sample admission diagnostic (#5493) The bounded request still refuses 1024x1024x64 samples before host initialization and writes no output. Update only the stale expected diagnostic to the existing Compact budget wording; production limits and code are unchanged. Exact-tree CLI regression suite: 14 passed, 0 failed. The full repository gate has been invoked separately and is not yet complete. * Normalize UI container violation paths across platforms Report repository-relative paths with forward slashes so diagnostics and the existing nested-package regression assertions agree on Windows and Unix. Keep the container detection rules unchanged. Validation: official ui-containers gate and all seven focused xtask tests passed; rustfmt and diff checks passed. Only xtask/dependencies were compiled; no application build or heavy tests. (cherry picked from commit44b58d8e10) * fix(render): preserve camera contracts and correct acceptance regressions (#5493) Preserve Design view.apply semantics with a separate strict Render camera command. Retain existing translations when English-only aliases collide; add material-axis entries and camera-specific pitch labels. Compare complete validated engineering cards and retain job handles before cancellation. Focused and native acceptance is pinned to treef8a423b21f. Full CI has been invoked separately and is not claimed green. Landing follows the render integration policy in #5493. * fix(render): resolve showcase licence and upstream resource hygiene (#5493) Record SychPL's explicit MIT OR Apache-2.0 grant, retaining source/model bytes and the Ubuntu lettering notice. Remove 80 absent attribution rows, personal fork records, dead delivery attributes and three fork/resource-only workflows. Existing xtask assets now performs bounded offline hash checks and rejects orphan render attribution; no parallel draft CI or package installation. Original authoring reproduction remains explicit. Scoped xtask tests, assets, Clippy, formatting and prepared SELENE validation pass; no application or renderer-wide result is inferred. * fix(render): align saved bounds and progressive sample resolution (#5493) Address review r4364211669/r4364211677/r4364211681/r4364211691/r4364211695. Persisted light/frame domains respect the existing 1e9 document bound; related LED/rectangle/direction cases use the same bound. Workstation primary resolve shares the 4096 admission cap and film counters use checked conversions. Exact candidate: 485 CPU render tests, 21 render document tests and strict scoped Clippy pass, including positive boundary round trips and 2048/4096 end-to-end checkpoints. No released format/migration edits, relaxed test limits or full-stack acceptance claim. * wip(render): isolate optional resources and harden sample handling (#5493) Review work in progress: opt-in encoded render library with reproducible runtime catalog exports; native-only robust dependency through the workspace; checked bloom slices; per-sample point-light diagnostics; independent area-light spatial/film keys. Resource-module binaries in both configurations, generation, Cargo production feature graphs and attribution checks pass. Full engine/render regression and combined acceptance are pending: do not merge this donor as a constituent or treat scoped resource proof as runtime acceptance. * fix(gpu): preserve donor allocations through the scope-safety repair (#5722) Port the native-validated #5723 scope-cleanup correction into the experimental donor, retaining its adaptive, volume, aging, photographic and bloom allocations. Same reverse-drain helper and regression cases; the donor combination still needs its own compile/test gate and is not covered retroactively by render-base results. * claim: #1369 * Reject unknown pending concepts after format folding (#1369) * test(render): close bounded sampling and bloom review regressions (#5493) Validate the optional-resource/lighting/dependency donor at its exact tree. Required Vulkan GPU 127/0/3; CPU renderer 487/0; engine Render 72/0; document render 21/0; lean library 7/0; strict scoped Clippy, assets/layers/lists/containers and lean-engine WASM pass. Preserve original failed controller/typing attempts. This is the draft donor/disposition source, not a replacement for constituent render PRs or final main acceptance. * wip(render): preserve stable aging target validation candidate Exact staged source from prior review work on donor3b892eab5e. This is a recovery/review checkpoint, NOT accepted delivery. An actual command-path regression currently fails because the selected executor refuses ordered surface aging. No assertion, capability or admission limit is weakened. Native/UI/full combination acceptance remains pending. Saved/runtime split adds one pending descriptor and retains original file scope; no main/render branch is changed. * test(render): preserve numeric setup intent at the admitted coordinate bound Follow up jyviko review on #5494 without weakening the corrected saved-coordinate contract. The positive clicked fixture uses 1e9 instead of inadmissible 2e9; explicit out-of-range cases still refuse, and the full saved setup round-trips through JSON and the native container. Exact-source Render workspace 95/0 and strict all-target UI Clippy pass. This does not incorporate the separately failing stable-aging candidate or claim full current-render acceptance. * test(render): use the real GPU executor for saved aging Move successful native cold-reopen Check/Start coverage from the CPU-backed protocol fixture into the production GPU executor tests. Verify capture-index changes preserve the stable target and that enabling aging changes both PNG and raw EXR output. Retain explicit, allocation-free refusal coverage for executors without aging support. Production capabilities and admission checks are unchanged. * fix(render): persist stable identities for targeted aging (#5493) Separate saved RenderBodyTarget identities from captured mesh ordinals. Reject legacy ambiguous targets, resolve Check/Start after visibility changes and preserve native reopening, copies and undo. Unsupported executors still refuse; real AMD Vulkan regression completes saved aging after reordered capture. Source tree6b84c8adpasses document 23, engine Render 75, GPU effects 5 and Render UI 95 with no failures; scoped strict Clippy, WASM and repository gates pass. Fresh CLI/native reopen and clean/aged GPU exports pass with identical physical totals and inspected actual images. Whole current-render integration is separate. * fix(render): reconcile combined CPU/GPU contracts on current upstream Unify captured resources/status and CPU-vs-GPU request schemas after the real two-parent integration; remove obsolete duplicate Vulkan selector and retain combined platform-filter regression. Deduplicate only identical or superseded test definitions, retaining the stronger card metadata and reserved-executor assertions. No assertions, admission limits or feature refusals are weakened. All targets of render dependencies, GPU, engine, UI, CLI and native app pass cargo check with raytrace-cpu and bundled-render-library at treec70d00d1. Native executable tests and full current-source acceptance remain pending. This is a private integration rehearsal for subsequent constituent PRs, not an aggregate official render/main merge. * test(render): retain one complete host lifetime regression set Deduplicate byte-identical DropProbe/task-lifetime tests and retain the adapted environment/texture ownership regressions with every assertion and complete memory estimate. Keep the registered-geometry admission regression once; only struct field order differed. Replace a one-element diagnostic loop with its equivalent block, preserving all wrap/width assertions. Test-only integration repair. Formatting and diff checks pass; refreshed executable validation is required. No production behavior, limits, assertions or ignores changed. * fix(doc): recognize the proven format-29 card descriptor alias Normalize only the historical format-29 physical-material-cards spelling, and only when material-engineering-cards is registered. Admission and migration de-duplication use the same identity. Unknown concepts, wrong versions and incapable readers still refuse before mutation. Six controlled-history Rust regressions and actual CLI migration/no-clobber acceptance pass. No version, released migration or CI changes. Refs #5793, #1369, #5493. * test(render): preserve grounding refusal before explicit instance moves Update the two Render binding fixtures for upstream first-occurrence grounding. Verify grounded movement refuses without changing document/history, then explicitly unground through the public command before the intended move. Retain every target, resource, copy and persistence assertion. Refs #5493. --------- Co-authored-by: Christian Svensson <blue@cmd.nu> Co-authored-by: Victor Santos Oliveira <56417388+Vittuu@users.noreply.github.com> Co-authored-by: cfaulkingham <colin.faulkingham@gmail.com>
20 KiB
Integrated Render workspace (R3)
The native image panel offers CPU raster, optional CPU ray tracing and GPU path tracing 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 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.
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 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, selection or hover colours, section cuts, analysis shading, active-component fading, canvases or decals in this initial product policy. 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 (nothing is picked or selected here), 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 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.
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.