3d-sky-rays

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

3D Sky Rays

3D天空光束

Make the light appear to travel through gaps in the scene. Roof edges and foliage should shape the shafts as the camera moves.
模拟光线穿过场景缝隙的效果。当相机移动时,屋顶边缘和植被应当能塑造光束的形态。

Fit the existing renderer

适配现有渲染器

Inspect the renderer version, render targets, alpha usage, depth path, tone mapping, and post-processing order. Keep the existing WebGL or WebGPU backend. The shader recipe below describes a WebGL screen-space effect; implement the equivalent in the project's node/render pipeline when using WebGPU.
Use one normalized world-space direction pointing toward the sun for the sky, ray source, and directional lighting. If the art direction deliberately offsets the visible sun from the lighting sun, document and control that offset in one place.
检查渲染器版本、渲染目标、alpha通道使用方式、深度路径、色调映射(tone mapping)以及后处理顺序。保留现有的WebGL或WebGPU后端。以下着色器方案描述的是WebGL屏幕空间效果;若使用WebGPU,请在项目的节点/渲染管线中实现等效效果。
天空、光源和方向光统一使用一个指向太阳方向的归一化世界空间向量。如果美术方向有意让可见太阳与光照太阳的位置存在偏移,需在统一位置记录并控制该偏移量。

Build an occlusion-aware ray pass

构建支持遮挡感知的光束渲染通道

  1. Render scene color in linear HDR. Obtain a mask identifying open sky: white for sky, black for opaque occluders. Match foliage alpha cutouts and vertex motion in the mask pass so leaves do not become solid rectangles.
  2. A dedicated sky mask is the portable default. Reusing scene alpha is an optimization only when every preceding pass preserves its meaning: sky alpha 0, opaque geometry alpha 1. Transparent glass, particles, canvas compositing, and AO can break that convention; inspect the mask directly.
  3. Project a point along the sun direction from the camera. Reject a source behind the camera before using projected coordinates. Convert NDC to UV with
    uv = ndc.xy * 0.5 + 0.5
    ; account for the pipeline's texture orientation.
  4. For each ray-buffer pixel, march toward the sun UV. Sample sky visibility multiplied by sky brightness above an HDR threshold. Accumulate decaying samples and divide by the sum of weights so sample-count changes do not change exposure.
  5. Reject UVs outside the mask texture. Fade the effect as the sun moves far off-screen; clamping samples to the edge creates bright bands. A small overscan margin is useful for a sun just outside the frame.
  6. Composite the ray color additively into linear scene color before the final tone-map/output transform. Preserve the input alpha if later passes need it.
Core accumulation, expressed as pseudocode:
text
step = (pixelUV - sunUV) * density / sampleCount
sampleUV = pixelUV - step * jitter
sum = 0; weightSum = 0; weight = 1
repeat sampleCount times:
    sampleUV -= step
    if sampleUV is inside the texture:
        energy = max(luminance(scene(sampleUV)) - threshold, 0)
        sum += min(energy, energyCap) * skyMask(sampleUV) * weight
    weightSum += weight
    weight *= decay
rays = sum / max(weightSum, epsilon)
Use aspect-correct distance from the source for radial falloff. Keep any angular variation broad and subtle; the scene occlusion should provide most of the structure. On opaque foreground surfaces, attenuate the screen-space overlay strongly so wood and stone retain contrast. This is an artistic approximation, not a substitute for depth-integrated volumetric scattering.
  1. 以线性HDR格式渲染场景颜色。获取用于识别开阔天空的遮罩:白色代表天空,黑色代表不透明遮挡物。在遮罩渲染通道中匹配植被的alpha裁剪与顶点运动效果,避免树叶变成实心矩形。
  2. 专用天空遮罩是通用性最佳的默认方案。仅当所有前置渲染通道都遵循alpha语义约定(天空alpha为0,不透明几何体alpha为1)时,复用场景alpha才是可行的优化方案。透明玻璃、粒子、画布合成以及AO都可能破坏该约定;请直接检查遮罩效果。
  3. 从相机出发沿太阳方向投影一个点。在使用投影坐标前,需排除位于相机后方的光源。使用公式
    uv = ndc.xy * 0.5 + 0.5
    将NDC转换为UV;需考虑管线的纹理方向。
  4. 对光束缓冲区的每个像素,向太阳UV方向步进采样。采样天空可见度值,并乘以高于HDR阈值的天空亮度。对衰减的采样结果进行累加,再除以权重总和,这样采样数量的变化不会影响曝光度。
  5. 排除遮罩纹理外的UV坐标。当太阳移动到远离屏幕的位置时,逐渐减弱效果;将采样钳制到边缘会产生亮带。设置少量过扫描边距有助于处理太阳刚好在画面外的情况。
  6. 在最终色调映射/输出变换之前,将光束颜色以加法方式合成到线性场景颜色中。如果后续通道需要输入alpha,请保留该值。
核心累加逻辑的伪代码如下:
text
step = (pixelUV - sunUV) * density / sampleCount
sampleUV = pixelUV - step * jitter
sum = 0; weightSum = 0; weight = 1
repeat sampleCount times:
    sampleUV -= step
    if sampleUV is inside the texture:
        energy = max(luminance(scene(sampleUV)) - threshold, 0)
        sum += min(energy, energyCap) * skyMask(sampleUV) * weight
    weightSum += weight
    weight *= decay
rays = sum / max(weightSum, epsilon)
使用与光源的宽高比校正距离实现径向衰减。角度变化应保持平缓且细微;光束的主要形态应由场景遮挡决定。对于不透明的前景表面,需大幅减弱屏幕空间叠加效果,以保留木材、石材等材质的对比度。这是一种艺术化的近似实现,不能替代深度积分的体积散射效果。

Tune appearance before cost

优先调优效果,再考虑性能成本

Start with a low sun, warm neutral tint, visible gaps, and restrained intensity. View from behind a roofline and through a canopy. Whiteout usually means excessive intensity or a bad mask, not insufficient bloom.
Use roughly 24–48 samples and a half-resolution ray buffer as a starting experiment; increase only when visible banding warrants it. Seijaku's reference uses 72 samples, which is a reference choice rather than a required quality floor. Smooth noise jitter can reduce bands, but animated jitter can shimmer; use stable noise for still or reduced-motion views unless temporal accumulation is available.
Skip the pass when its contribution is zero. Resize its buffers with the drawing buffer, dispose replaced targets, and measure its incremental GPU/frame cost with rays enabled and disabled. Avoid synchronous GPU readback in the render loop.
初始调试可采用低角度太阳、暖中性色调、可见缝隙以及适中的强度。从屋顶线后方和树冠下方观察效果。画面发白通常是强度过高或遮罩质量差导致的,而非bloom效果不足。
初始实验可采用约24-48个采样以及半分辨率的光束缓冲区;仅当出现可见条带效应时再增加采样数。Seijaku的参考实现使用了72个采样,这只是参考选择,而非最低质量要求。平滑噪声抖动可以减少条带,但动态抖动会产生闪烁效果;对于静态或低运动画面,请使用稳定噪声,除非支持时序累加。
当光束效果贡献为零时,跳过该渲染通道。随绘制缓冲区调整光束缓冲区的大小,释放被替换的渲染目标,并分别在开启和关闭光束效果的情况下测量其每帧GPU增量开销。避免在渲染循环中进行同步GPU回读。

Verify

验证项

  • Roofs and leaf silhouettes visibly interrupt shafts; no rectangular foliage halos.
  • Turning away from the sun removes the effect without a mirrored source or flash.
  • Entering an interior preserves surface contrast; unrelated emissive objects do not become suns.
  • Camera orbit, portrait resize, dusk, and a static reduced-motion frame remain stable.
  • Desktop and mobile checks include shader errors, frame time, and the actual ray-buffer size.
  • 屋顶和树叶轮廓能明显阻断光束,不会出现矩形植被光晕。
  • 转向背离太阳的方向时效果会消失,不会出现镜像光源或闪光。
  • 进入室内场景时表面对比度保持正常;无关的自发光物体不会被误判为太阳。
  • 相机环绕、竖屏尺寸调整、黄昏场景以及静态低运动画面均保持稳定。
  • 桌面端和移动端的检查项包括着色器错误、帧耗时以及实际光束缓冲区大小。

Reference

参考资料

Read REFERENCES.md for the source and renderer documentation. In Seijaku, inspect
GodRayShader
,
makePost
, and the projected-source update. Its alpha-mask convention depends on its complete render pipeline; do not transplant that assumption alone.
阅读REFERENCES.md获取源码与渲染器文档。在Seijaku项目中,可查看
GodRayShader
、
makePost
以及投影光源更新逻辑。其alpha遮罩约定依赖于完整的渲染管线,请勿单独移植该假设。