Welcome to mirror list, hosted at ThFree Co, Russian Federation.

common_math_geom_lib.glsl « shaders « intern « draw « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 71460c392859f6e2bdc4bd46d852f471ddc0ceaf (plain)
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

#pragma BLENDER_REQUIRE(common_math_lib.glsl)

/* ---------------------------------------------------------------------- */
/** \name Math intersection & projection functions.
 * \{ */

vec4 plane_from_quad(vec3 v0, vec3 v1, vec3 v2, vec3 v3)
{
  vec3 nor = normalize(cross(v2 - v1, v0 - v1) + cross(v0 - v3, v2 - v3));
  return vec4(nor, -dot(nor, v2));
}

vec4 plane_from_tri(vec3 v0, vec3 v1, vec3 v2)
{
  vec3 nor = normalize(cross(v2 - v1, v0 - v1));
  return vec4(nor, -dot(nor, v2));
}

float point_plane_projection_dist(vec3 line_origin, vec3 plane_origin, vec3 plane_normal)
{
  return dot(plane_normal, plane_origin - line_origin);
}

float point_line_projection_dist(vec2 point, vec2 line_origin, vec2 line_normal)
{
  return dot(line_normal, line_origin - point);
}

float line_plane_intersect_dist(vec3 line_origin,
                                vec3 line_direction,
                                vec3 plane_origin,
                                vec3 plane_normal)
{
  return dot(plane_normal, plane_origin - line_origin) / dot(plane_normal, line_direction);
}

float line_plane_intersect_dist(vec3 line_origin, vec3 line_direction, vec4 plane)
{
  vec3 plane_co = plane.xyz * (-plane.w / len_squared(plane.xyz));
  vec3 h = line_origin - plane_co;
  return -dot(plane.xyz, h) / dot(plane.xyz, line_direction);
}

vec3 line_plane_intersect(vec3 line_origin,
                          vec3 line_direction,
                          vec3 plane_origin,
                          vec3 plane_normal)
{
  float dist = line_plane_intersect_dist(line_origin, line_direction, plane_origin, plane_normal);
  return line_origin + line_direction * dist;
}

vec3 line_plane_intersect(vec3 line_origin, vec3 line_direction, vec4 plane)
{
  float dist = line_plane_intersect_dist(line_origin, line_direction, plane);
  return line_origin + line_direction * dist;
}

float line_aligned_plane_intersect_dist(vec3 line_origin, vec3 line_direction, vec3 plane_origin)
{
  /* aligned plane normal */
  vec3 L = plane_origin - line_origin;
  float disk_dist = length(L);
  vec3 plane_normal = -normalize(L);
  return -disk_dist / dot(plane_normal, line_direction);
}

vec3 line_aligned_plane_intersect(vec3 line_origin, vec3 line_direction, vec3 plane_origin)
{
  float dist = line_aligned_plane_intersect_dist(line_origin, line_direction, plane_origin);
  if (dist < 0) {
    /* if intersection is behind we fake the intersection to be
     * really far and (hopefully) not inside the radius of interest */
    dist = 1e16;
  }
  return line_origin + line_direction * dist;
}

/**
 * Returns intersection distance between the unit sphere and the line
 * with the assumption that \a line_origin is contained in the unit sphere.
 * It will always returns the farthest intersection.
 */
float line_unit_sphere_intersect_dist(vec3 line_origin, vec3 line_direction)
{
  float a = dot(line_direction, line_direction);
  float b = dot(line_direction, line_origin);
  float c = dot(line_origin, line_origin) - 1;

  float dist = 1e15;
  float determinant = b * b - a * c;
  if (determinant >= 0) {
    dist = (sqrt(determinant) - b) / a;
  }

  return dist;
}

/**
 * Returns minimum intersection distance between the unit box and the line
 * with the assumption that \a line_origin is contained in the unit box.
 * In other words, it will always returns the farthest intersection.
 */
float line_unit_box_intersect_dist(vec3 line_origin, vec3 line_direction)
{
  /* https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
   */
  vec3 first_plane = (vec3(1.0) - line_origin) / line_direction;
  vec3 second_plane = (vec3(-1.0) - line_origin) / line_direction;
  vec3 farthest_plane = max(first_plane, second_plane);

  return min_v3(farthest_plane);
}

float line_unit_box_intersect_dist_safe(vec3 line_origin, vec3 line_direction)
{
  vec3 safe_line_direction = max(vec3(1e-8), abs(line_direction)) *
                             select(vec3(1.0), -vec3(1.0), lessThan(line_direction, vec3(0.0)));
  return line_unit_box_intersect_dist(line_origin, safe_line_direction);
}

/**
 * Same as line_unit_box_intersect_dist but for 2D case.
 */
float line_unit_square_intersect_dist(vec2 line_origin, vec2 line_direction)
{
  vec2 first_plane = (vec2(1.0) - line_origin) / line_direction;
  vec2 second_plane = (vec2(-1.0) - line_origin) / line_direction;
  vec2 farthest_plane = max(first_plane, second_plane);

  return min_v2(farthest_plane);
}

float line_unit_square_intersect_dist_safe(vec2 line_origin, vec2 line_direction)
{
  vec2 safe_line_direction = max(vec2(1e-8), abs(line_direction)) *
                             select(vec2(1.0), -vec2(1.0), lessThan(line_direction, vec2(0.0)));
  return line_unit_square_intersect_dist(line_origin, safe_line_direction);
}

/**
 * Returns clipping distance (intersection with the nearest plane) with the given axis-aligned
 * bound box along \a line_direction.
 * Safe even if \a line_direction is degenerate.
 * It assumes that an intersection exists (i.e: that \a line_direction points towards the AABB).
 */
float line_aabb_clipping_dist(vec3 line_origin, vec3 line_direction, vec3 aabb_min, vec3 aabb_max)
{
  vec3 safe_dir = select(line_direction, vec3(1e-5), lessThan(abs(line_direction), vec3(1e-5)));
  vec3 dir_inv = 1.0 / safe_dir;

  vec3 first_plane = (aabb_min - line_origin) * dir_inv;
  vec3 second_plane = (aabb_max - line_origin) * dir_inv;
  vec3 nearest_plane = min(first_plane, second_plane);
  return max_v3(nearest_plane);
}

/** \} */

/* ---------------------------------------------------------------------- */
/** \name Other useful functions.
 * \{ */

void make_orthonormal_basis(vec3 N, out vec3 T, out vec3 B)
{
  vec3 up_vector = abs(N.z) < 0.99999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
  T = normalize(cross(up_vector, N));
  B = cross(N, T);
}

/* ---- Encode / Decode Normal buffer data ---- */
/* From http://aras-p.info/texts/CompactNormalStorage.html
 * Using Method #4: Spheremap Transform */
vec2 normal_encode(vec3 n, vec3 view)
{
  float p = sqrt(n.z * 8.0 + 8.0);
  return n.xy / p + 0.5;
}

vec3 normal_decode(vec2 enc, vec3 view)
{
  vec2 fenc = enc * 4.0 - 2.0;
  float f = dot(fenc, fenc);
  float g = sqrt(1.0 - f / 4.0);
  vec3 n;
  n.xy = fenc * g;
  n.z = 1 - f / 2;
  return n;
}

vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B)
{
  return T * vector.x + B * vector.y + N * vector.z;
}

vec3 world_to_tangent(vec3 vector, vec3 N, vec3 T, vec3 B)
{
  return vec3(dot(T, vector), dot(B, vector), dot(N, vector));
}

/** \} */