1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
/**
* 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 P)
{
vec3 vV = transform_direction(cam.viewmat, normalize(P));
return camera_uv_from_view(cam, vV);
}
/** \} */
|