Я реализовал этот урок в 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-буфера пространства камеры.