优化体积渲染:使用 HDDA 树遍历器

改进内容:
1. 添加 get_hdda_hit 函数,使用 pnanovdb_hdda_tree_marcher
2. 添加 get_dim_coord 函数,检测空区域维度
3. 优化 ray marching:
   - 先用 HDDA 找到第一个有数据的点
   - 遍历中检测 dim,跳过空区域
   - 回溯机制避免跳过有效数据

效果:体积云渲染更完整,不再是只有框表面有数据
This commit is contained in:
2026-03-11 22:11:04 +08:00
parent fa50179d00
commit 79ee8d0492

View File

@@ -59,6 +59,31 @@ float get_value_coord(inout pnanovdb_readaccessor_t acc, float3 pos)
return pnanovdb_read_float(buf, address);
}
uint get_dim_coord(inout pnanovdb_readaccessor_t acc, float3 pos)
{
pnanovdb_vec3_t p = pos;
pnanovdb_coord_t ijk = pnanovdb_hdda_pos_to_ijk(p);
return pnanovdb_readaccessor_get_dim(PNANOVDB_GRID_TYPE_FLOAT, buf, acc, ijk);
}
bool get_hdda_hit(inout pnanovdb_readaccessor_t acc, inout float tmin, float3 origin, float3 direction, float tmax, out float valueAtHit)
{
pnanovdb_vec3_t p_origin = origin;
pnanovdb_vec3_t p_direction = direction;
float thit;
bool hit = pnanovdb_hdda_tree_marcher(
PNANOVDB_GRID_TYPE_FLOAT,
buf,
acc,
p_origin, tmin,
p_direction, tmax,
thit,
valueAtHit
);
tmin = thit;
return hit;
}
PSInput MainVS(VSInput input)
{
PSInput output;
@@ -100,19 +125,45 @@ float4 MainPS(PSInput input) : SV_TARGET
float3 color = float3(0, 0, 0);
float transmittance = 1.0;
float not_used;
bool hit = get_hdda_hit(volume.acc, tmin, _CameraPos, rayDir, tmax, not_used);
if (!hit) { return float4(0, 0, 0, 0); }
float skip = 0;
for (uint i = 0; i < _MaxSteps; i++) {
float t = tmin + i * _StepSize;
if (t > tmax || transmittance < 0.01) break;
if (tmin >= tmax || transmittance < 0.01) break;
float3 worldPos = _CameraPos + rayDir * t;
float3 worldPos = _CameraPos + rayDir * tmin;
uint dim = get_dim_coord(volume.acc, worldPos);
if (dim > 1) {
float skip_step = 15.0;
tmin += skip_step;
skip = skip_step;
continue;
}
float density = get_value_coord(volume.acc, worldPos) * _DensityScale;
if (density > 0.001) {
float3 S = density * float3(1, 1, 1);
color += transmittance * S * _StepSize;
transmittance *= exp(-density * _StepSize);
if (density < 0.001) {
float skip_step = 5.0;
tmin += skip_step;
skip = skip_step;
continue;
}
if (skip > 0) {
tmin -= skip * 0.8;
worldPos = _CameraPos + rayDir * tmin;
skip = 0;
}
float3 S = density * float3(1, 1, 1);
color += transmittance * S * _StepSize;
transmittance *= exp(-density * _StepSize);
tmin += _StepSize;
}
float alpha = 1.0 - transmittance;