2023-08-24 10:54:59 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2022 Blender Authors
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2022-05-14 20:29:28 +02:00
|
|
|
|
2024-10-04 15:48:22 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
2025-09-25 10:57:02 +02:00
|
|
|
#include "infos/eevee_common_infos.hh"
|
2024-12-02 21:26:15 +01:00
|
|
|
|
2022-05-14 20:29:28 +02:00
|
|
|
/**
|
|
|
|
|
* Camera projection / uv functions and utils.
|
2023-08-19 17:13:05 +10:00
|
|
|
*/
|
2022-05-14 20:29:28 +02:00
|
|
|
|
2024-10-04 15:48:22 +02:00
|
|
|
#include "gpu_shader_math_base_lib.glsl"
|
2025-09-15 12:07:26 +02:00
|
|
|
#include "gpu_shader_math_matrix_transform_lib.glsl"
|
|
|
|
|
#include "gpu_shader_math_safe_lib.glsl"
|
|
|
|
|
#include "gpu_shader_math_vector_lib.glsl"
|
2022-05-14 20:29:28 +02:00
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Panoramic Projections
|
|
|
|
|
*
|
|
|
|
|
* Adapted from Cycles to match EEVEE's coordinate system.
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 camera_equirectangular_from_direction(CameraData cam, float3 dir)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
|
|
|
|
float phi = atan(-dir.z, dir.x);
|
|
|
|
|
float theta = acos(dir.y / length(dir));
|
2025-04-14 13:46:41 +02:00
|
|
|
return (float2(phi, theta) - cam.equirect_bias) * cam.equirect_scale_inv;
|
2022-05-14 20:29:28 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 camera_equirectangular_to_direction(CameraData cam, float2 uv)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
|
|
|
|
uv = uv * cam.equirect_scale + cam.equirect_bias;
|
|
|
|
|
float phi = uv.x;
|
|
|
|
|
float theta = uv.y;
|
|
|
|
|
float sin_theta = sin(theta);
|
2025-04-14 13:46:41 +02:00
|
|
|
return float3(sin_theta * cos(phi), cos(theta), -sin_theta * sin(phi));
|
2022-05-14 20:29:28 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 camera_fisheye_from_direction(CameraData cam, float3 dir)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
|
|
|
|
float r = atan(length(dir.xy), -dir.z) / cam.fisheye_fov;
|
|
|
|
|
float phi = atan(dir.y, dir.x);
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 uv = r * float2(cos(phi), sin(phi)) + 0.5f;
|
2022-05-14 20:29:28 +02:00
|
|
|
return (uv - cam.uv_bias) / cam.uv_scale;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 camera_fisheye_to_direction(CameraData cam, float2 uv)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
|
|
|
|
uv = uv * cam.uv_scale + cam.uv_bias;
|
2025-04-11 18:28:45 +02:00
|
|
|
uv = (uv - 0.5f) * 2.0f;
|
2022-05-14 20:29:28 +02:00
|
|
|
float r = length(uv);
|
2025-04-11 18:28:45 +02:00
|
|
|
if (r > 1.0f) {
|
2025-04-14 13:46:41 +02:00
|
|
|
return float3(0.0f);
|
2022-05-14 20:29:28 +02:00
|
|
|
}
|
|
|
|
|
float phi = safe_acos(uv.x * safe_rcp(r));
|
2025-04-11 18:28:45 +02:00
|
|
|
float theta = r * cam.fisheye_fov * 0.5f;
|
|
|
|
|
if (uv.y < 0.0f) {
|
2022-05-14 20:29:28 +02:00
|
|
|
phi = -phi;
|
|
|
|
|
}
|
2025-04-14 13:46:41 +02:00
|
|
|
return float3(cos(phi) * sin(theta), sin(phi) * sin(theta), -cos(theta));
|
2022-05-14 20:29:28 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 camera_mirror_ball_from_direction(CameraData cam, float3 dir)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
|
|
|
|
dir = normalize(dir);
|
2025-04-11 18:28:45 +02:00
|
|
|
dir.z -= 1.0f;
|
|
|
|
|
dir *= safe_rcp(2.0f * safe_sqrt(-0.5f * dir.z));
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 uv = 0.5f * dir.xy + 0.5f;
|
2022-05-14 20:29:28 +02:00
|
|
|
return (uv - cam.uv_bias) / cam.uv_scale;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 camera_mirror_ball_to_direction(CameraData cam, float2 uv)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
|
|
|
|
uv = uv * cam.uv_scale + cam.uv_bias;
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 dir;
|
2025-04-11 18:28:45 +02:00
|
|
|
dir.xy = uv * 2.0f - 1.0f;
|
|
|
|
|
if (length_squared(dir.xy) > 1.0f) {
|
2025-04-14 13:46:41 +02:00
|
|
|
return float3(0.0f);
|
2022-05-14 20:29:28 +02:00
|
|
|
}
|
2025-04-11 18:28:45 +02:00
|
|
|
dir.z = -safe_sqrt(1.0f - square(dir.x) - square(dir.y));
|
2025-04-15 11:36:53 +02:00
|
|
|
constexpr float3 I = float3(0.0f, 0.0f, 1.0f);
|
2022-05-14 20:29:28 +02:00
|
|
|
return reflect(I, dir);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name Regular projections
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 camera_view_from_uv(float4x4 projmat, float2 uv)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
2025-04-14 13:46:41 +02:00
|
|
|
return project_point(projmat, float3(uv * 2.0f - 1.0f, 0.0f));
|
2022-05-14 20:29:28 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 camera_uv_from_view(float4x4 projmat, bool is_persp, float3 vV)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
2025-04-14 13:46:41 +02:00
|
|
|
float4 tmp = projmat * float4(vV, 1.0f);
|
2025-04-11 18:28:45 +02:00
|
|
|
if (is_persp && tmp.w <= 0.0f) {
|
2022-05-14 20:29:28 +02:00
|
|
|
/* Return invalid coordinates for points behind the camera.
|
|
|
|
|
* This can happen with panoramic projections. */
|
2025-04-14 13:46:41 +02:00
|
|
|
return float2(-1.0f);
|
2022-05-14 20:29:28 +02:00
|
|
|
}
|
2025-04-11 18:28:45 +02:00
|
|
|
return (tmp.xy / tmp.w) * 0.5f + 0.5f;
|
2022-05-14 20:29:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
/** \name General functions handling all projections
|
|
|
|
|
* \{ */
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 camera_view_from_uv(CameraData cam, float2 uv)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 vV;
|
2022-05-14 20:29:28 +02:00
|
|
|
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:
|
2023-09-25 16:56:17 +10:00
|
|
|
// ATTR_FALLTHROUGH;
|
2022-05-14 20:29:28 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 camera_uv_from_view(CameraData cam, float3 vV)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
|
|
|
|
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:
|
2023-09-25 16:56:17 +10:00
|
|
|
// ATTR_FALLTHROUGH;
|
2022-05-14 20:29:28 +02:00
|
|
|
case CAMERA_PANO_EQUIDISTANT:
|
|
|
|
|
return camera_fisheye_from_direction(cam, vV);
|
|
|
|
|
case CAMERA_PANO_MIRROR:
|
|
|
|
|
return camera_mirror_ball_from_direction(cam, vV);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-14 13:46:41 +02:00
|
|
|
float2 camera_uv_from_world(CameraData cam, float3 P)
|
2022-05-14 20:29:28 +02:00
|
|
|
{
|
2025-04-14 13:46:41 +02:00
|
|
|
float3 vV = transform_direction(cam.viewmat, normalize(P));
|
2022-07-13 17:31:04 +02:00
|
|
|
return camera_uv_from_view(cam, vV);
|
2022-05-14 20:29:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** \} */
|