✦ SPIELWELTENMoto Racer - Rampage ↗

HDRI radiance, half-float storage and GGX termination

Read-only CPU/source review, 17 September 2026. No GPU workload, import or asset edit. The proposed simple chain “AlpineDay is bright, therefore an infinity makes GGX loop forever” is not supported by the inspected data and shaders.

Original source values

The existing Assets/Rampage/Resources/Skies/AlpineDay.hdr was decoded on CPU as Radiance RGBE scanline RLE, with RGB = channel * 2^(exponent-136), zero for exponent zero. No third-party image transformation, exposure adjustment or write to the asset was performed.

Quantity Result
SHA-256 462a3cc63bfcd9fe0299137a0f33f4ade84e237f4cb6115fe46f5ab400693fe6
Size 2048 x 1024
All source RGB values finite / nonnegative true / true
Maximum R / G / B 114176 / 110592 / 104960
Maximum Rec.709 luminance 110947.328
Runtime lux multiplier 78654.18 / 5.45773304 = 14411.511047451304
Largest source component times multiplier 1645448685.3538, finite in float32
Original panorama pixels above 65504 after this multiplication 1252 of 2097152

These are original panorama measurements, not the BC6H-compressed, resampled cubemap or a GPU readback. They reproduce the prior maximum-luminance measurement in Docs/ALPINE-SKY-DIAGNOSIS.md. SkyImportSettings.cs imports linear BC6H cubemaps with 512-pixel faces and mipmaps; the source is not CPU-readable after Unity import. Import compression/resampling and sky-cube sampling may change which texels saturate.

Where the actual path limits radiance

Pinned HDRP 17.3 Runtime/Sky/HDRISky/HDRISky.shader:213–218 uses an explicitly float3 product of cubemap color, intensity and exposure, then ClampToFloat16Max(skyColor) before returning the fragment output. Core Common.hlsl:1700 defines this as min(value, HALF_MAX); HALF_MAX is 65504.

The cubemap baking fragment at lines 265–268 calls RenderSky with exposure 1.0. The camera fragment instead uses GetCurrentExposureMultiplier(). Camera EV13 therefore does not rescue the unexposed lighting cube; the explicit shader clamp is the relevant protection. SkyRenderingContext.cs:37,41 and SkyManager.cs:933 allocate the sky and GGX intermediate resources as R16G16B16A16_SFloat, not packed R11G11B10. For the measured finite, nonnegative source and finite multiplier, the shown arithmetic does not create infinity before the clamp and cannot overflow half storage merely because of the source radiance.

Bright-sun saturation can alter lighting fidelity. That is different from observing non-finite GPU values or proving a TDR mechanism. This review does not inspect every downstream renderer computation and does not claim general shader memory safety.

GGX loops: distinguish filtering from sample-table preparation

Exact lifetime of the unbounded preparation loop

HDRenderPipeline.cs:658–669 constructs one IBLFilterGGX for the pipeline and passes the same filter array to SkyManager. During rendering, HDRenderPipeline.cs:2913–2916 calls Initialize only if IsInitialized is false. IBLFilterGGX.cs:38–40 defines initialized as a non-null lookup RenderTexture; lines 63–74 allocate that 89x6 texture and dispatch ComputeGgxIblSampleData once. Lines 92–95 bind only its output texture and dispatch exactly one group. There are no caller-supplied sky-lux, HDRI-color, sample-count or roughness constant-buffer values for this kernel: mip and sample counts derive from thread indices and compile-time functions in the shader.

Subsequent Realtime sky updates use that existing lookup. FilterCubemapCommon:161–165 redispatches preparation only when the existing RenderTexture reports IsCreated()==false, after recreating it. Pipeline cleanup destroys the lookup (HDRenderPipeline.cs:1046–1048, IBLFilterGGX.cs:133–136). Normal scene replacement does not construct another filter or deliberately release this texture in the inspected application code.

Thus “the while(true) runs afresh on every one-second sky update” is false. Startup/reinitialization is the relevant scope. A successfully rendered garage and multiple alps loads before failure lower the priority of an ordinary deterministic LUT-initialization hang. A device/resource loss could cause the reinitialization branch, but that can be a consequence of the reset; no evidence shows it initiating the current incident. No loop patch is justified.

17.3 versus 17.6 and next action

SHA-256 comparisons show byte-identical copies of HDRISky.shader, GGXConvolve.shader, AmbientProbeConvolution.compute and ComputeGgxIblSampleData.compute between the current 17.3 package and the installed 6.6 Editor's 17.6 package. The fresh engine port may still change native submission or other package code; these particular shaders do not supply a claimed overflow fix.

Do not add a NaN guard, reduce the HDRI multiplier or alter the sky asset on this evidence. The separate periodic sky/ambient/convolution lifetime hypothesis remains testable by changing indirect-sky updates alone after the current-content engine comparison. That experiment targets recurring work/resource behavior, not a demonstrated numeric overflow.