Отражение пространства экрана всегда дает dQ.z - PullRequest
0 голосов
/ 06 декабря 2018

Я реализовал этот урок в Vulkan, но я не получил ожидаемого результата, затем я понял, что в моем шейдере я всегда обнуляю dQ.z, я не знаю, почему это происходит, this - моя грязная, отлаженная, неоптимизированная реализация.

Итак, у вас есть идеи, что не так?

Это мой код GLSL

vec3 dir = normalize(p - vpos); // world-space direction
if(is_zero(dir.z)) {
    return false;
}
vec3 tmpv3 = dir * dis + vpos;
if(tmpv3.z < scene_ubo.s.camera.position_far.w) {
    dis = abs((scene_ubo.s.camera.position_far.w - vpos.z) / dir.z);
    if(dis < SMALL_EPSILON) {
        return false;
    }
    tmpv3 = dir * dis + vpos;
} else if (tmpv3.z > scene_ubo.s.camera.near_reserved.x) {
    dis = abs((scene_ubo.s.camera.near_reserved.x - vpos.z) / dir.z);
    if(dis < SMALL_EPSILON) {
        return false;
    }
    tmpv3 = dir * dis + vpos;
}
const vec3 end = tmpv3;

const mat4 proj = mat4(
    half_screen_width, 0.0, 0.0, 0.0,
    0.0, -half_screen_height, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    half_screen_width, half_screen_height, 0.0, 1.0
    ) * scene_ubo.s.camera.projection; // Vulkan form of projection

const vec4 h0 = proj * vec4(vpos, 1.0); // vpos is view-space-position (view * position)
const vec4 h1 = proj * vec4(end, 1.0);

const float k0 = 1.0 / h0.w;
const float k1 = 1.0 / h1.w;

const vec3 q0 = vpos * k0;
const vec3 q1 = end * k1;

const vec2 p0 = h0.xy * k0;
const vec2 p1 = h1.xy * k1;

vec4 tmpv4 = vec4(p1 - p0, q1.z - q0.z, k1 - k0);
if(is_zero(tmpv4.x) && is_zero(tmpv4.y)) {
    return false;
}
float endx = screen_width;
bool permute = false;
{
    vec2 ad = abs(tmpv4.xy);
    float coef;
    if(ad.x > ad.y) {
        coef = 1.0 / ad.x;
    } else {
        endx = screen_height;
        permute = true;
        tmpv4.xy = tmpv4.yx;
        coef = 1.0 / ad.y;
    }
    tmpv4 *= coef;
}
const vec4 dpqk = tmpv4;
vec4 pqk = vec4(permute? p0.yx: p0, q0.z, k0);
pqk += dpqk * 0.2;

float prev_z_max_estimate = pqk.z / pqk.w; // I think this is better than vpos.z (?)
float ray_z_max = prev_z_max_estimate, ray_z_min = prev_z_max_estimate;
float scene_z_max = ray_z_max + 10000;
const float z_thickness = 0.1;

float step_index = 0;
for(;
    (step_index < steps) &&
        (pqk.x < endx && pqk.x > 0.0) && // debug
        !is_zero(scene_z_max) &&
        ((ray_z_max < (scene_z_max - z_thickness)) || (ray_z_min > scene_z_max));
    ++step_index, pqk += dpqk
) {
    ray_z_min = prev_z_max_estimate;
    ray_z_max = -abs((dpqk.z * 0.5 + pqk.z) / (dpqk.w * 0.5 + pqk.w));
    prev_z_max_estimate = ray_z_max;
    if (ray_z_min > ray_z_max) {
        float tmp = ray_z_min;
        ray_z_min = ray_z_max;
        ray_z_max = tmp;
    }
    // todo it can be replaced with something much better
    hituv = (permute? pqk.yx: pqk.xy) *  deferred_ubo.s.pixel_step.xy;
    hituv.y = 1 - hituv.y;
    if(hituv.x < 0.0 || hituv.x > 1.0 || hituv.y < 0.0 || hituv.y > 1.0) {
        return false;
    }
    scene_z_max = -abs((scene_ubo.s.camera.view * vec4(texture(position, hituv).xyz, 1.0)).z);

}
return (ray_z_max >= scene_z_max - z_thickness) && (scene_z_max >= ray_z_min);

Это в основном похоже на оригинальный код, за исключением того, что я использую позицию в мировом пространстве вместо z-буфера пространства камеры.

...