- C++ 79.7%
- GLSL 10.5%
- Python 8.7%
- CMake 0.8%
- PowerShell 0.3%
- MATERIAL_COVERAGE.md + FEATURE_COVERAGE.md -> COVERAGE.md (shared vocabulary and maintenance rule); stale rows fixed (dome tilt gap, graded ghost lights, mip rule since 0.1.1.87, ground plane matte lights since 0.1.1.91, scalar colour maps) - VALIDATION entries 0.1.0.97-0.1.1.23 moved to archive/ (1,720 -> 1,146 lines) - HANDOFF: resume-after-a-break checklist for hardware changes, status condensed, scene numbers from the 0.1.1.91 host check, duplicate road item removed - README current release 0.1.1.91; ARCHITECTURE ground-plane technique Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|---|---|---|
| archive | ||
| cmake | ||
| shaders | ||
| src | ||
| tests | ||
| tools | ||
| .gitattributes | ||
| .gitignore | ||
| AGENTS.md | ||
| ARCHITECTURE.md | ||
| CMakeLists.txt | ||
| COVERAGE.md | ||
| HANDOFF.md | ||
| LEARNINGS.md | ||
| MATERIALS.md | ||
| README.md | ||
| SCOPE.md | ||
| VALIDATION.md | ||
Vulkan Offline for Daz Studio 6
Experimental Windows x64 offline renderer for Daz Studio 6 using Vulkan compute, hardware ray queries and a progressive path tracer. The goal is a drop-in replacement for Iray on GPUs Iray cannot use; the target is "similar enough" to Iray, not identical (SCOPE.md). The current implementation is not yet production-ready.
Target and current state
- Windows 11, AMD Radeon RX 7900 XTX, 24 GB VRAM (vendor-neutral Vulkan; other GPUs untested).
- Daz Studio 6.25.2026.14722; compile against SDK 6.25.2026.13900 in Daz Studio 6.25+ BETA SDK.
- Daz Studio 6.25+ BETA SDK Latest is reference-only: its SDK 6.25.2026.19400 requires a newer host. Its existing Qt development installation can be used without compiling against its SDK.
- Qt 6.10.3 MSVC 2022 x64, including Core5Compat. Vendor SDKs are unchanged.
- Current release: 0.1.1.91 (November 4, 2026). Against Iray (whole image): two-character scene 1.00, emissive-lit living room 1.00, render_test4 (strand hair, PBRSkin makeup, ghost lights) face 1.05 / body 1.00, render_test5 (night street: instances, area lights, Matte Fog, twilight Sun-Sky; six cameras) 0.97-1.00, render_test6 (geografts, sunlit room; two cameras) 0.99, render_test7 (pool room with large windows; four cameras) 0.96-1.01; visible noise at or below Iray's in the living room, 1.0–1.5× in the character scene at equal samples. Sampling at 512² 512 spp: characters 19.2 s, render_test4 face with dense strand hair ~59 s (host check 0.1.1.82, bounce limit 32). Renders are bit-identical run to run (render_test6's varying Daz hair aside). Status, out-of-bar regions and next steps: HANDOFF.md. Host tests run through the harness in ../../daz tools (headless Daz, Iray reference cache).
Milestones (details in VALIDATION.md and its archive):
| Release | Change |
|---|---|
| 0.1.0.19–20 | Refractive light connections (manifold NEE) through solid glass |
| 0.1.0.21 | Learned path guiding (off by default; never a host gain; removed in 0.1.0.87) |
| 0.1.0.23–28 | Iray-style tone mapping, PFM output, Iray brightness/dome calibration, Draw Dome |
| 0.1.0.29 | Iray Uber glossy layering; final continuation ray traced (path length N ≈ Iray N+1) |
| 0.1.0.30–31 | Owen-scrambled Sobol sampling (always on) |
| 0.1.0.32–35 | Paged and grayscale-packed textures; PBRSkin with subsurface scattering |
| 0.1.0.36 | Glossy anisotropy; PBR-mode refraction reflection weight (eyes) |
| 0.1.0.37–38 | Adaptive GPU batching, cached readback, parallel texture decoding |
| 0.1.0.39–40 | Non-thin-walled Iray Uber translucency (hair cards) |
| 0.1.0.41–42 | Texture mipmaps with camera-driven resolution selection |
| 0.1.0.43–46 | Iray simple_glossy lobe, Iray curve-layer layering, Top Coat, Dual Lobe Specular, weighted lobe selection |
| 0.1.0.47 | Faster subsurface random walks (3.3× on a skin benchmark) |
| 0.1.0.48–51 | Iray Uber PBR Specular/Glossiness (layered base, coats, Glossy Specular as F0) |
| 0.1.0.52 | Emission blackbody temperature; map-less Iray dome renders black |
| 0.1.0.53–54 | Open Image Denoise (HIP GPU); DAZ Script access to render settings |
| 0.1.0.55–56 | Per-object geometry log; in-session texture cache (repeat renders ~2× faster) |
| 0.1.0.57 | Iray-calibrated photometric efficacy (emitter probe 1.000) |
| 0.1.0.58–60 | Review fixes; adaptive (learned, visibility-aware) light selection; emitter-guided paths default off |
| 0.1.0.61–63 | Iray MDL bump (file_bump_texture); Iray Uber Base Color Effect and SSS Mode bindings |
| 0.1.0.64–65 | Per-channel display firefly filter (red skin speckles); albedo-weighted subsurface channels |
| 0.1.0.66 | Daz gamma 2.2 colour decoding; mapped Iray Uber metal tint; Daz light units (point-light probes) |
| 0.1.0.67 | Iray flux-unit emission (lm, W): luminance = flux / area per side |
| 0.1.0.68 | Iray Visible to Primary Rays and Ghost Light Factor per node |
| 0.1.0.69 | Strand hair as tapered tubes (provisional material) |
| 0.1.0.70–71 | Chiang hair BSDF (MDL SDK port, OmniHair inputs); GPU memory log; Visible-off nodes skipped |
| 0.1.0.72 | Strand hair as procedural curve segments (4x faster, hair memory ~2.3 -> 0.4 GB) |
| 0.1.0.73 | PBRSkin makeup layer |
| 0.1.0.76 | Render subdivision of cage meshes (SDK Catmull-Clark of a copy; no HD morph detail) |
| 0.1.0.77–78 | Render failure cleanup; shader specialization and index medium stack (1.3–3.3x on benchmarks) |
| 0.1.0.80 | Iray Uber Dual Lobe Specular Reflectivity map (living-room skin 1.21 -> 1.00) |
| 0.1.0.81–85 | Daz camera headlamp as Iray renders it (render_test4 body view 0.81 -> 1.01) |
| 0.1.0.86 | Full-resolution unfiltered textures for metallic materials with normal/roughness maps (glitter top 0.80 -> 1.00) |
| 0.1.0.87 | Learned path guiding and emitter-guided paths removed (no host gain) |
| 0.1.0.88 | Material self-reporting ("Not translated [...]" log lines); PBRSkin Bump Enable honoured |
| 0.1.0.89 | First-hit material map beside the PFM; per-material host-check regions |
| 0.1.0.90 | Canonical material layout in the shader (M1 step 1; images bit-identical) |
| 0.1.0.91 | Canonical offline::Material in core, plugin and tests (M1 step 2a; bit-identical) |
| 0.1.0.92 | Translators write the canonical material; former layout deleted (exported materials byte-identical) |
| 0.1.0.93 | Material translators split per shader family on ChannelReader (byte-identical) |
| 0.1.0.94 | Translator golden tests from captured material snapshots |
| 0.1.0.95 | Iray Uber top-coat reflectivity read (was always the default); M1 complete |
| 0.1.0.96 | Makeup maps in texture footprints; OmniHair opacity per its MDL |
| 0.1.0.97 | PBRSkin second specular lobe, top coat and detail maps |
| 0.1.0.98 | Diffuse roughness (libbsdf Oren-Nayar), Iray Uber and PBRSkin (probe-verified) |
| 0.1.0.99 | Iray Uber Diffuse Overlay (probe-verified) |
| 0.1.1.0 | Iray Uber Backscattering, libbsdf lobe ported (probe-verified) |
| 0.1.1.1 | Thin-walled dielectrics as one Fresnel event (eye-moisture catchlights) |
| 0.1.1.4 | Metal-detail texture rule only for metallic maps with metal content |
| 0.1.1.5 | libbsdf diffuse normalization for tilted shading normals (normal-mapped surfaces) |
| 0.1.1.6 | MDL anisotropy conversion without a cap (card hair) |
| 0.1.1.7 | Camera headlamp scales with Focal Distance² as in Iray (large rooms) |
| 0.1.1.8 | Iray's Gaussian pixel filter (radius 1.5 px); Crush Blacks tone-mapping setting |
| 0.1.1.10 | Depth of field, aperture blades, orthographic cameras, crop windows; vertical field of view (non-square framing fixed) |
| 0.1.1.13 | Iray Sun-Sky (base::sun_and_sky port, Daz's solar position) |
| 0.1.1.17 | Environment and sun light through flat glass panes (thick and zero-thickness) with MIS |
| 0.1.1.20 | Daz spot lights (Iray cone profile and intensity), photometric lights (flux, colour temperature) |
| 0.1.1.21 | Code-review fixes: spot lights selected by flux; texture footprints for orthographic and lens-shifted cameras |
| 0.1.1.22 | Photometric lights honour Intensity; a dome without a map renders Iray's Sun-Sky |
| 0.1.1.23 | Iray Environment Tint on dome and Sun-Sky environments |
| 0.1.1.24 | Daz instance nodes (flattened copies, nested instances, instance groups) |
| 0.1.1.26 | Iray Matte Fog (distance fog on every path segment, in-scatter relative to the environment) |
| 0.1.1.29 | Daz area lights: photometric rectangle, disc and sphere lights with the spot profile, visible in reflections |
| 0.1.1.30 | Code-review fixes: mirrored instance copies keep outward winding; instance transforms read exactly |
| 0.1.1.34-0.1.1.38 | Previews on a worker thread, preview denoise interval, path diagnostics off by default, texture cache without copies |
| 0.1.1.41-0.1.1.42 | Sun-Sky follows Dome Rotation; dome tilt (Dome Orientation X/Y/Z) |
| 0.1.1.47 | Iray ground plane / shadow catcher (Draw Ground) |
| 0.1.1.51 | Geografts (the follow target's assembly mesh) |
| 0.1.1.52 | Default bounce limit 32 |
| 0.1.1.54 | Window sheet pairs crossed as one pane |
| 0.1.1.56 | Matte Fog under map domes |
| 0.1.1.57 | Ground-plane sun shadows |
| 0.1.1.58 | EXR / floating-point textures |
| 0.1.1.60 | Window sheet pairs at oblique angles, passed as two thin-walled sheets |
| 0.1.1.61 | White Point tone-mapping setting |
| 0.1.1.62 | Dome Only / Sun-Sky Only drop Daz light nodes, as in Iray |
| 0.1.1.63 | Base-colour texture alpha no longer used as cutout |
| 0.1.1.71 | Faster render setup (re-render of the street scene 4.77 -> 3.43 s) |
| 0.1.1.72-74 | Shader displacement (Displacement Strength map, Min/Max, SubD Displacement Level; probe silhouettes equal to Iray's) |
| 0.1.1.75-77 | Deterministic renders (learned light selection in fixed point); persistent GPU context and on-disk pipeline cache |
| 0.1.1.78 | Image series / animation renders; renderer core split into prepare / sample / diagnostics phases |
| 0.1.1.79 | Scene exporter split into per-family files (src/daz/export/), renders unchanged |
| 0.1.1.80 | Cutout coverage independent of the GPU's traversal order (run-to-run exact unless Daz's input varies) |
| 0.1.1.81 | Graded Ghost Light Factor (glossy highlights fade as in Iray); coloured Glossy Specular per channel |
| 0.1.1.82 | Colour images on scalar channels read as Iray does (RGB average); glass roughness maps applied |
| 0.1.1.83 | Glossy materials keep full-resolution normal maps (highlight glints as in Iray) |
| 0.1.1.84 | Geometry export 1.7-3.2x faster (identical output) |
| 0.1.1.85 | Glossy Reflectivity maps |
| 0.1.1.86 | Deterministic ray-hit tie-break |
| 0.1.1.87 | Glossy materials with normal maps keep all maps at full resolution (brick and stucco walls as in Iray) |
| 0.1.1.88 | Repeat renders skip the closed-volume check (session cache) |
| 0.1.1.91 | Iray ground plane: only sky, sun and directional lights cast its shadow (sunlit interiors as in Iray) |
Project map
- src/daz: plugin registration, native render properties, render lifecycle, GUI-thread scene export and progressive Daz handler output.
- src/core: value-only scene data, materials, lighting preparation and Vulkan resource/BLAS/TLAS ownership. GPU workers never access live Daz scene objects.
- shaders/pathtrace.comp: the path tracer (
path(),main()), including shaders/pathtrace in dependency order: texture filtering, strand-curve intersection, layered surface BSDFs (diffuse, GGX, Iraysimple_glossy, top coat, dual lobe), the Chiang hair BSDF, dielectrics and media, subsurface walks, emission, direct lighting and light selection, refractive connections and MIS (layout: ARCHITECTURE.md). - tests: CPU invariants, native SDK/runtime checks and synthetic GPU fixtures. These do not replace testing inside Daz.
- tools: build and user-operated installation helpers;
tools/analysis: Iray comparison and asset-inspection scripts, and
harness suites in
tools/analysis/suites; tools/probes: headless DAZ Script helpers (scene inspection: environment, lights, instances, tone mapping, camera, hair) and probe scenes (probe_metal_point.duf,probe_lights.duf, render_test4 with Iray canvases).
Documents:
- SCOPE.md: goal, fidelity bar, in/out of scope, roadmap and the user's decision log.
- HANDOFF.md: current status and next steps.
- AGENTS.md: how agents work on this project (reading order, working style, documents, build, release, host check).
- ARCHITECTURE.md: data flow, modules, invariants, debt, the target material model and the techniques as implemented.
- COVERAGE.md: which shaders content uses and per channel what is verified, derived, assumed, approximated or missing (with usage counts from the content library); the same for geometry, lights, environment, camera, output, animation and scale, with scope tiers.
- MATERIALS.md: Iray Uber/PBRSkin/OmniHair channel bindings and units.
- LEARNINGS.md: lessons by topic.
- VALIDATION.md: chronological commands, results and caveats from October 19 (0.1.0.74 onward).
- archive: historical only. Validation for 0.1.0.1–0.1.0.18, 0.1.0.19–0.1.0.47, 0.1.0.47–0.1.0.57, 0.1.0.58–0.1.0.65 and 0.1.0.66–0.1.0.73, RELEASE_HISTORY.md (releases through 0.1.0.14) and NOISE_REVIEW.md (an October 1 independent review, mostly addressed).
Build
Prerequisites: Python 3, CMake 3.22+, MSVC 2022 Build Tools with Windows SDK,
Vulkan SDK with glslc (local: 1.4.357; the renderer needs Vulkan 1.2 with ray queries and 64-bit buffer atomics), the matching Qt development installation, and the Intel
Open Image Denoise 2.5.1 Windows release extracted to
../../.build-tools/oidn/oidn-2.5.1.x64.windows (override with -DOIDN_DIR). Use
Release or RelWithDebInfo, never a Qt-debug DLL in Daz.
From this plugin directory:
python .\tools\Build.py --sdk-dir '..\..\Daz Studio 6.25+ BETA SDK' --test
The helper also defaults to that older sibling SDK, never Latest.
Qt is located independently, checking the selected SDK, workspace .build-tools
and the reference SDK's .build-tools. Override it if needed:
python .\tools\Build.py --sdk-dir '..\..\Daz Studio 6.25+ BETA SDK' --qt-dir 'C:\Qt\6.10.3\msvc2022_64\lib\cmake\Qt6' --test
New builds use build/current (or build-core/current for --core-only).
build/releases/<version> holds every released DLL and shader (experiment builds
pruned; PDBs from 0.1.1.17; one shared denoiser runtime in build/releases/denoiser-runtime) and build/fixtures the real-asset
test fixtures. --build-dir overrides the output folder;
a cache from another source location is rejected with a recovery instruction.
The helper normalizes Windows environment-key casing before launching tools.
python .\tools\Build.py --core-only --test
python .\tools\Build.py --test --gpu-test
--test runs build-helper regressions, CPU CTest and, for a plugin build, native
settings, optics, emission-color and loader checks against the installed runtime.
--daz-dir overrides the runtime directory. --gpu-test runs the full synthetic
GPU suite serially; it is not a Daz GUI render. Shader validation is recorded
separately in VALIDATION.md.
Default DLL: build/current/plugin/RelWithDebInfo/dsp_vulkan_offline.dll.
Install and host testing
Close Daz first. The user's account owns the installed plugin DLL and PDB, so the helper runs without elevation (agents may run it: AGENTS.md); a first install, or a changed denoiser runtime, needs an elevated PowerShell:
.\tools\Install.ps1 -DazDir 'C:\Program Files\DAZ 3D\DAZStudio6'
The helper backs up the existing DLL to build/install-backups (last five kept), overwrites only the plugin
DLL/PDB (not Qt libraries), copies the denoiser runtime only when it changed, and prints the installed SHA-256. -Release 0.1.0.73 installs an
archived release from build/releases (never 0.1.0.39 or 0.1.0.41); -BuildDir selects a nondefault build
folder. Never copy development
Qt DLLs into Daz. Restart Daz and select Vulkan Offline (Experimental).
Host renders and Iray comparisons run headless through the harness in
../../daz tools (runs and the Iray reference cache live
there); GUI renders are for what the harness cannot do (host checks: build/host-checks). Use the host-check instructions in AGENTS.md,
not historical pending requests in the archive. Daz's host log is
%APPDATA%\DAZ 3D\Studio6\log.txt, not in the installation directory.
Scripting (DAZ Script)
Settings are properties of the renderer's settings element, reachable from the active renderer (0.1.0.54):
var renderer = App.getRenderMgr().getActiveRenderer(); // Vulkan Offline (Experimental)
print(renderer.getRenderSettingNames());
renderer.setRenderSetting("SamplesPerPixel", 128);
renderer.setRenderSetting("Denoiser", "Final image"); // or 0, 1, 2
renderer.setRenderSetting("WriteLinearImage", true);
print(renderer.getRenderSetting("SamplesPerPixel"));
Changes apply to the next render and persist like pane edits (registry
HKCU\Software\VulkanOffline\DazStudio6; set the environment variable
VULKAN_OFFLINE_SETTINGS_FILE to an INI path to use a separate file). When a
render goes to a file (render options DirectToFile with a filename), the linear
PFM is written next to it with the same base name.
Features and limitations
What is implemented, approximated or missing: COVERAGE.md; how it works: ARCHITECTURE.md.