     return ray_forward;
 }
 vec2 viewDirectionToUV_prevFrame(vec3 dir) {
+    vec3 P = mat3(uboPerFrame.prevViewTransform) * dir;
+
+#if 1
     float zOnPlane = -(1.0 / tan(uboPerFrame.zRange.z * 0.5));
-
-    vec3 P = mat3(uboPerFrame.prevViewTransform) * dir;
     P.xy *= zOnPlane / P.z;
     P.x *= uboPerFrame.screenResolution.y / uboPerFrame.screenResolution.x;
     return 0.5 * (P.xy + vec2(1.0));
+#else
+    float a = P.x;
+    float b = P.y;
+    float c = P.z;
+    float z = -(1.0 / tan(uboPerFrame.zRange.z * 0.5));
+    float k = uboPerFrame.screenResolution.y / uboPerFrame.screenResolution.x;
+    float m = z * sqrt(1.0 - c*c) / (c * sqrt(a*a + b*b));
+    float u = 0.5 * (1.0 + a*m*k);
+    float v = 0.5 * (1.0 + b*m);
+    return vec2(u, v);
+#endif
 }
 
 void main() {


	vec3 impact = ray.origin + ray.direction * t0;

	hit.t = t0;
	hit.origin = impact;
	hit.normal = (impact - sphere.origin) / sphere.radius;
}

bool isInvalidHit(hit_t hit) {

        imageStore(renderTarget, currentTexel, prevResult);
        return;
    }
#endif // REPROJECTION_METHOD
#endif // TEMPORAL_REPROJECTION

	ray_t eye_ray;
    eye_ray.origin = uboPerFrame.ws_eyePosition;
	eye_ray.direction = viewDir;

    // Raymarching is broken if eye is too close to the interface of cloud layers
    if (abs(eye_ray.origin.y - getCloudLayerMin()) <= 1.5 || abs(eye_ray.origin.y - getCloudLayerMax()) <= 1.5) {
