diff options
Diffstat (limited to 'source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl')
-rw-r--r-- | source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl new file mode 100644 index 00000000000..f79e9102d76 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_camera_lib.glsl @@ -0,0 +1,166 @@ + +/** + * Camera projection / uv functions and utils. + **/ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + +/* -------------------------------------------------------------------- */ +/** \name Panoramic Projections + * + * Adapted from Cycles to match EEVEE's coordinate system. + * \{ */ + +vec2 camera_equirectangular_from_direction(CameraData cam, vec3 dir) +{ + float phi = atan(-dir.z, dir.x); + float theta = acos(dir.y / length(dir)); + return (vec2(phi, theta) - cam.equirect_bias) * cam.equirect_scale_inv; +} + +vec3 camera_equirectangular_to_direction(CameraData cam, vec2 uv) +{ + uv = uv * cam.equirect_scale + cam.equirect_bias; + float phi = uv.x; + float theta = uv.y; + float sin_theta = sin(theta); + return vec3(sin_theta * cos(phi), cos(theta), -sin_theta * sin(phi)); +} + +vec2 camera_fisheye_from_direction(CameraData cam, vec3 dir) +{ + float r = atan(length(dir.xy), -dir.z) / cam.fisheye_fov; + float phi = atan(dir.y, dir.x); + vec2 uv = r * vec2(cos(phi), sin(phi)) + 0.5; + return (uv - cam.uv_bias) / cam.uv_scale; +} + +vec3 camera_fisheye_to_direction(CameraData cam, vec2 uv) +{ + uv = uv * cam.uv_scale + cam.uv_bias; + uv = (uv - 0.5) * 2.0; + float r = length(uv); + if (r > 1.0) { + return vec3(0.0); + } + float phi = safe_acos(uv.x * safe_rcp(r)); + float theta = r * cam.fisheye_fov * 0.5; + if (uv.y < 0.0) { + phi = -phi; + } + return vec3(cos(phi) * sin(theta), sin(phi) * sin(theta), -cos(theta)); +} + +vec2 camera_mirror_ball_from_direction(CameraData cam, vec3 dir) +{ + dir = normalize(dir); + dir.z -= 1.0; + dir *= safe_rcp(2.0 * safe_sqrt(-0.5 * dir.z)); + vec2 uv = 0.5 * dir.xy + 0.5; + return (uv - cam.uv_bias) / cam.uv_scale; +} + +vec3 camera_mirror_ball_to_direction(CameraData cam, vec2 uv) +{ + uv = uv * cam.uv_scale + cam.uv_bias; + vec3 dir; + dir.xy = uv * 2.0 - 1.0; + if (len_squared(dir.xy) > 1.0) { + return vec3(0.0); + } + dir.z = -safe_sqrt(1.0 - sqr(dir.x) - sqr(dir.y)); + const vec3 I = vec3(0.0, 0.0, 1.0); + return reflect(I, dir); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Regular projections + * \{ */ + +vec3 camera_view_from_uv(mat4 projmat, vec2 uv) +{ + return project_point(projmat, vec3(uv * 2.0 - 1.0, 0.0)); +} + +vec2 camera_uv_from_view(mat4 projmat, bool is_persp, vec3 vV) +{ + vec4 tmp = projmat * vec4(vV, 1.0); + if (is_persp && tmp.w <= 0.0) { + /* Return invalid coordinates for points behind the camera. + * This can happen with panoramic projections. */ + return vec2(-1.0); + } + return (tmp.xy / tmp.w) * 0.5 + 0.5; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name General functions handling all projections + * \{ */ + +vec3 camera_view_from_uv(CameraData cam, vec2 uv) +{ + vec3 vV; + switch (cam.type) { + default: + case CAMERA_ORTHO: + case CAMERA_PERSP: + return camera_view_from_uv(cam.wininv, uv); + case CAMERA_PANO_EQUIRECT: + vV = camera_equirectangular_to_direction(cam, uv); + break; + case CAMERA_PANO_EQUIDISTANT: + /* ATTR_FALLTHROUGH; */ + case CAMERA_PANO_EQUISOLID: + vV = camera_fisheye_to_direction(cam, uv); + break; + case CAMERA_PANO_MIRROR: + vV = camera_mirror_ball_to_direction(cam, uv); + break; + } + return vV; +} + +vec2 camera_uv_from_view(CameraData cam, vec3 vV) +{ + switch (cam.type) { + default: + case CAMERA_ORTHO: + return camera_uv_from_view(cam.winmat, false, vV); + case CAMERA_PERSP: + return camera_uv_from_view(cam.winmat, true, vV); + case CAMERA_PANO_EQUIRECT: + return camera_equirectangular_from_direction(cam, vV); + case CAMERA_PANO_EQUISOLID: + /* ATTR_FALLTHROUGH; */ + case CAMERA_PANO_EQUIDISTANT: + return camera_fisheye_from_direction(cam, vV); + case CAMERA_PANO_MIRROR: + return camera_mirror_ball_from_direction(cam, vV); + } +} + +vec2 camera_uv_from_world(CameraData cam, vec3 V) +{ + vec3 vV = transform_point(cam.viewmat, V); + switch (cam.type) { + default: + case CAMERA_ORTHO: + return camera_uv_from_view(cam.persmat, false, V); + case CAMERA_PERSP: + return camera_uv_from_view(cam.persmat, true, V); + case CAMERA_PANO_EQUIRECT: + return camera_equirectangular_from_direction(cam, vV); + case CAMERA_PANO_EQUISOLID: + /* ATTR_FALLTHROUGH; */ + case CAMERA_PANO_EQUIDISTANT: + return camera_fisheye_from_direction(cam, vV); + case CAMERA_PANO_MIRROR: + return camera_mirror_ball_from_direction(cam, vV); + } +} + +/** \} */ |