| … | … | @@ -1573,6 +1573,11 @@ void SceneShaderRaytracing::init(const String p_defines) { |
| 1573 | 1573 | // behind the RT define. |
| 1574 | 1574 | actions.renames["BOUNCE_INDEX"] = "rt_bounce_index"; |
| 1575 | 1575 | actions.renames["PRIMARY_HIT"] = "rt_primary_hit"; |
| 1576 | // Ray-differential stand-in for dFdx/dFdy(WORLD_POSITION), which cannot | |
| 1577 | // exist in a hit shader. Feed these to textureGrad instead of taking | |
| 1578 | // derivatives, or the sampler falls back to LOD 0 and aliases. | |
| 1579 | actions.renames["RAY_FOOTPRINT_X"] = "rt_footprint_x"; | |
| 1580 | actions.renames["RAY_FOOTPRINT_Y"] = "rt_footprint_y"; | |
| 1576 | 1581 | |
| 1577 | 1582 | actions.renames["NODE_POSITION_WORLD"] = "read_model_matrix[3].xyz"; |
| 1578 | 1583 | actions.renames["CAMERA_POSITION_WORLD"] = "inv_view_matrix[3].xyz"; |
| … | … | @@ -62,6 +62,32 @@ rt_front_facing = rt_front_face; |
| 62 | 62 | rt_screen_uv = vec2(gl_LaunchIDEXT.xy) / vec2(gl_LaunchSizeEXT.xy); |
| 63 | 63 | rt_frag_coord = vec4(gl_LaunchIDEXT.xy, 0.0, 1.0); |
| 64 | 64 | |
| 65 | // Per-pixel world-space footprint at the hit (ray differentials). The camera's | |
| 66 | // right/up axes, scaled by the world size of one pixel at this distance, then | |
| 67 | // slid along the ray onto the surface plane so grazing angles stretch the | |
| 68 | // footprint the way real derivatives would. | |
| 69 | // | |
| 70 | // projection_matrix[1][1] is 1/tan(fovy/2), so 2*t/(that * viewport_height) is the | |
| 71 | // world height of a pixel at distance t. On secondary bounces gl_HitTEXT is that | |
| 72 | // bounce's length rather than a camera distance, which makes this an | |
| 73 | // approximation there -- still far better than the zero derivative it replaces. | |
| 74 | { | |
| 75 | float rt_t = gl_HitTEXT; | |
| 76 | vec3 rt_dir = gl_WorldRayDirectionEXT; | |
| 77 | float rt_px = 2.0 * rt_t / max(projection_matrix[1][1] * read_viewport_size.y, 1e-6); | |
| 78 | vec3 rt_fx = inv_view_matrix[0].xyz * rt_px; | |
| 79 | vec3 rt_fy = inv_view_matrix[1].xyz * rt_px; | |
| 80 | vec3 rt_n = normalize(rt_normal); | |
| 81 | float rt_ndotd = dot(rt_n, rt_dir); | |
| 82 | if (abs(rt_ndotd) > 1e-4) { | |
| 83 | rt_footprint_x = rt_fx - rt_dir * (dot(rt_fx, rt_n) / rt_ndotd); | |
| 84 | rt_footprint_y = rt_fy - rt_dir * (dot(rt_fy, rt_n) / rt_ndotd); | |
| 85 | } else { | |
| 86 | rt_footprint_x = rt_fx; | |
| 87 | rt_footprint_y = rt_fy; | |
| 88 | } | |
| 89 | } | |
| 90 | ||
| 65 | 91 | // Run vertex shader (computes varyings, may modify built-ins). |
| 66 | 92 | /* RT_CUSTOM_VERTEX_CALL */ |
| 67 | 93 |
| … | … | @@ -30,6 +30,18 @@ vec4 color_interp = vec4(1.0); |
| 30 | 30 | uint rt_bounce_index = 0u; |
| 31 | 31 | bool rt_primary_hit = true; |
| 32 | 32 | |
| 33 | // World-space size of one pixel's footprint at this hit, along screen X and Y, | |
| 34 | // projected onto the surface. This is the ray-differential replacement for | |
| 35 | // dFdx/dFdy(WORLD_POSITION) -- which cannot exist in a hit shader, there being no | |
| 36 | // 2x2 quad -- and it is what a textureGrad needs to pick a sane mip. | |
| 37 | // | |
| 38 | // Exposed to GDShader as RAY_FOOTPRINT_X / RAY_FOOTPRINT_Y. Deliberately NOT | |
| 39 | // wired into dFdx() itself: dFdx of a world position is exactly this, but dFdx of | |
| 40 | // anything else is not, and silently returning a position footprint for an | |
| 41 | // arbitrary expression would be wrong in a way nothing would catch. | |
| 42 | vec3 rt_footprint_x = vec3(0.0); | |
| 43 | vec3 rt_footprint_y = vec3(0.0); | |
| 44 | ||
| 33 | 45 | vec4 custom0_attrib = vec4(0.0); |
| 34 | 46 | vec4 custom1_attrib = vec4(0.0); |
| 35 | 47 | vec4 custom2_attrib = vec4(0.0); |