File size: 7,631 Bytes
585c960 381a806 138026f 381a806 06457e8 453ac5c 06457e8 453ac5c a5cda22 06457e8 6203801 453ac5c a5cda22 6203801 06457e8 453ac5c d9ce18e 2c580ef a02d987 2c580ef ed18a0a 8269864 585c960 ae92738 585c960 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | # WorldGen Vulkan validation
## Environment
```text
Windows 11
AMD Radeon RX 6900 XT 16GB
Vulkan 1.4 (AMD proprietary driver)
No CUDA
```
## Pipeline
```text
t2s:
prompt
-> FLUX.1-dev Q4_K_S + WorldGen text2scene LoRA
(stable-diffusion.cpp, SD_VULKAN=ON)
-> 1024x512 equirectangular panorama
-> DA-2 depth (ncnn Vulkan, fp32)
-> worldgen-vk (Rust): RGBD -> 3DGS PLY + mesh PLY
i2s:
image
-> 90-degree full-height band -> cond/mask
-> FLUX.1-Fill-dev Q4_K (official safetensors converted with sd-cli)
+ WorldGen img2scene LoRA
-> Fill pano, composite original image region back
-> DA-2 depth (ncnn Vulkan)
-> worldgen-vk (Rust): RGBD -> 3DGS PLY + mesh PLY
```
## Verified runs
### t2s
```text
prompt: a cozy wooden bedroom with warm lamps
1024x512, 20 steps
output: output/t2s-ncnn-clean/
524,288 splats
1,046,528 triangles
```
### i2s
```text
input: assets/rainforest/photo.jpg
1024x512, 20 steps
output: output/i2s-ncnn-clean/
524,288 splats
1,046,528 triangles
```
### i2s seam blending
The Fill output and the original input band are composited with
`cv2.seamlessClone` (NORMAL_CLONE). Without OpenCV, a 24 px feathered alpha
blend is used. This removes the visible vertical band boundary; it does not
remove Fill object repetition.
### 1600x800
```text
t2s, 1600x800, 10 steps: 739 s
output: 1,280,000 splats, 1600x800 pano
DA-2 native 1600x800 trace:
graph da2_trace_1600.ncnn.param/.bin
time 6.29 s (Vulkan f32)
max abs 0.144
mean abs 0.0041
cosine 0.99954
full 50 steps: roughly 1 hour on this GPU
```
### Open3D / TSDF mesh
Default mesh is now a **voxel signed-distance field + marching cubes**
(`worldgen_mesh.py --method voxel`):
```text
voxel-res 0.25, voxel-stride 4, median 5, trim-poles 0.02, voxel-smooth 2.5
50k verts / 98k tris
~3.3 s at 1024x512
i2s end-to-end 20 steps: ~70 s (vs 61.5 s shell)
```
Median filtering, pole trimming and a 2.5-voxel Gaussian smoothing remove the
top tab and reduce the left fold. The left crescent is still visible, so this
is a large improvement over the needle shell but not a perfect reconstruction.
Poisson/Ball/Alpha are available but were not better:
```text
Poisson: 537,145 verts / 1,067,522 tris, 6.8 s, crescent fold + ripples
Ball: 985,990 tris, shell-equivalent
Alpha: noisy surface with holes
```
The voxel TSDF still shows a fold at the left depth discontinuity and a small
pole tab, but it removes the needle-like shell stretching. `--mesh-shell`
keeps the old Rust mesh (`mesh_shell.ply`).
### GPU 3DGS renderer
`gpu-splat/` is a wgpu/Vulkan splat renderer. The camera was fixed to
inside-out and the projection now matches the CPU reference; increasing the
splat radius 2x and raising opacity removes the earlier wash/blue-dome.
```text
gpu-splat.exe gaussians14.ply 0 out.png 0.2
```
It renders the official painting scene on the RX 6900 XT; it is not identical
to the official demo camera (the GPU view is closer/lower), but it is a real
Vulkan GPU 3DGS image.
### 3DGS render / official comparison
`render_splat_points.py --equirect` projects all 524,288 gaussians back to a
1024x512 equirect image and reconstructs the panorama (colors/geometry intact).
An inside-out 90-degree perspective point render also produces a coherent
scene:
```text
ply: 524,288 gaussians
inside 90 deg: 39,976 projected points
```

`render_splat_gaussian.py` adds 3D covariance + alpha compositing for an
equirect image. `render_splat_perspective.py` projects the same covariance
through a 90-degree pinhole camera; at 832x480 it produces a scene close to the
official demo viewpoint. `--scale-factor 0.7` is the current best balance
between blur (1.0) and holes (0.3).
The existing `vulkan-splat` viewer still frames a full panorama badly (washed
or tiny orbit view); this is a viewer camera issue, not a PLY/numeric issue.
The 3DGS center/scale/quaternion formula is validated at ~1e-7 against the
WorldGen Python reference.
### Fill foreground cleaning
By default `worldgen_i2s_prep.py` writes `cond_clean.png`: GrabCut foreground
is removed from the Fill condition with OpenCV inpaint, while the original
band (`cond.png`) is composited back after Fill. This stops Fill from repeating
the foreground object on both sides. Use `--keep-fg` to disable.
The official painting demo now produces a clean panorama with the house once
(no duplicated foreground) and no visible band edge.
### inpaint_bg (simplified)
`worldgen_i2s.py --inpaint-bg`:
```text
GrabCut foreground mask
-> OpenCV Telea background inpaint
-> DA-2 depth on background
-> worldgen-vk splat
-> merge foreground splats + background splats in the foreground mask
```
Test: 1024x512, 5 steps, 524,288 base splats + 20,529 background splats
= 544,817 merged vertices. This is not the official OneFormer + FLUX Fill
branch; it is a CPU/OpenCV approximation.
### Clean builds from source
Tested with local source checkouts (same scripts also clone when `-Source` is
omitted):
```text
build_sd.ps1 -Source <stable-diffusion.cpp> -> build-sd/bin/Release/sd-cli.exe
build_da2.ps1 -Source <ncnn> -> tools/da2-ncnn/da2ncnn.exe + ncnn.dll
build_rust.ps1 -> tools/worldgen-vk/worldgen-vk.exe
```
`sd-cli.exe --list-devices` reports `Vulkan0 AMD Radeon RX 6900 XT`; the
freshly built DA-2 runner reproduces the 1024x512 output on the same GPU.
### DA-2 numeric and performance
ncnn Vulkan vs PyTorch, 1024x512:
```text
max abs 0.0161
mean abs 0.0027
cosine 0.9999994
time 3.05 s (f32 Vulkan)
```
The ncnn graph has **0 custom layers and 0 CPU-fallback layers**: the final
`Squeeze` was replaced by a `Reshape` (`0=1024 1=512`, or `1600 800` for the
1600 trace). The runner must be compiled with `-DNCNN_VULKAN` and call
`net.set_vulkan_device(0)`; otherwise ncnn silently falls back to CPU.
### Latency (1024x512, 20 steps, RX 6900 XT)
```text
t2s total 56.7 s
i2s total 61.5 s
FLUX sampling ~100% GPU 3D utilization
VAE decode 9.0 s untiled -> 1.35 s with --vae-tiling --vae-tile-size 512x512
DA-2 3.05 s
Rust RGBD->3DGS 0.29 s
```
### RGBD -> 3DGS math
Compared with the WorldGen Python formula on synthetic panorama/depth:
```text
center ~1e-7
scale ~1e-7
quaternion ~1e-7
```
### FLUX
- stable-diffusion.cpp built with `SD_VULKAN=ON`
- `Vulkan0 = AMD Radeon RX 6900 XT`
- FLUX.1-dev Q4_K_S SHA256 `962d536a...` matches
- FLUX.1-Fill-dev official safetensors SHA256 `03e289f5...` matches
- converted q4_K: 780 tensors
- text2scene LoRA: 312/312 applied
- img2scene LoRA: 456/684 applied (228 incompatible keys skipped)
## No PyTorch at inference
`worldgen_t2s.py`, `worldgen_i2s.py`, `worldgen_i2s_prep.py` and
`worldgen_da2.py` do not import torch. Model inference is:
```text
FLUX/Fill -> sd-cli (C++/Vulkan)
DA-2 -> ncnn (C++/Vulkan)
3DGS/mesh -> worldgen-vk (Rust, CPU geometry + PLY)
```
## Known gaps
- Not byte/quality-equivalent to official WorldGen:
- Fill repeats objects and has a visible band boundary.
- Mesh has some stretching from depth discontinuities.
- Optional `use_sharp=True` and `inpaint_bg=True` branches are not wired.
- Official WorldGen visual/numeric comparison of the full FLUX stage is not done;
only component-level validation (DA-2, 3DGS math, weights, pipeline runs).
- Default validation resolution is 1024x512; 1600x800 is supported by
resampling but is much slower (~1 h per 50-step panorama).
- ncnn/pnnx toolchain is C++, not Rust; Rust covers RGBD->3DGS/mesh.
|