Unravel Engine C++ Reference
Loading...
Searching...
No Matches
math.h
Go to the documentation of this file.
1#pragma once
2
3#include "bbox.h"
4#include "bsphere.h"
5#include "frustum.h"
6#include "math_types.h"
7#include "plane.h"
8#include "transform.hpp"
9#include "color.h"
10#include "gradient.h"
11#include <algorithm>
12#include <cmath>
13#include <functional>
14
15namespace math
16{
17
18static inline std::vector<float> log_space(std::size_t start, std::size_t end, std::size_t count)
19{
20 std::vector<float> result;
21 result.reserve(count);
22 for(std::size_t i = 0; i <= count; ++i)
23 {
24 float f = start * glm::pow(float(end) / float(start), float(i) / float(count));
25 result.push_back(f);
26 }
27
28 return result;
29}
30
31// inline bool is_negative_float(const float& A)
32// {
33// return ((*(const std::uint32_t*)&A) >= std::uint32_t(0x80000000)); // Detects sign bit.
34// }
35
36// template<typename T>
37// inline T square(const T& t)
38// {
39// return t * t;
40// }
41
47// inline bool compute_projected_sphere_shaft(float light_x,
48// float light_z,
49// float radius,
50// const transform& proj,
51// const vec3& axis,
52// float axis_sign,
53// std::int32_t& in_out_min_x,
54// std::int32_t& in_out_max_x)
55// {
56// auto view_x = float(in_out_min_x);
57// auto view_size_x = float(in_out_max_x - in_out_min_x);
58
59// // Vertical planes: T = <Nx, 0, Nz, 0>
60// float discriminant = (square(light_x) - square(radius) + square(light_z)) * square(light_z);
61// if(discriminant >= 0)
62// {
63// float sqrt_discriminant = glm::sqrt(discriminant);
64// float inv_light_square = 1.0f / (square(light_x) + square(light_z));
65
66// float Nxa = (radius * light_x - sqrt_discriminant) * inv_light_square;
67// float Nxb = (radius * light_x + sqrt_discriminant) * inv_light_square;
68// float Nza = (radius - Nxa * light_x) / light_z;
69// float Nzb = (radius - Nxb * light_x) / light_z;
70// float Pza = light_z - radius * Nza;
71// float Pzb = light_z - radius * Nzb;
72
73// // Tangent a
74// if(Pza > 0)
75// {
76// float Pxa = -Pza * Nza / Nxa;
77// vec4 P = proj * vec4(axis.x * Pxa, axis.y * Pxa, Pza, 1);
78// float X = (dot(vec3(P), axis) / P.w + 1.0f * axis_sign) / 2.0f * axis_sign;
79// if(is_negative_float(Nxa) ^ is_negative_float(axis_sign))
80// {
81// in_out_max_x = glm::min<std::int32_t>(std::int32_t(glm::ceil(view_size_x * X + view_x)), in_out_max_x);
82// }
83// else
84// {
85// in_out_min_x = glm::max<std::int32_t>(std::int32_t(glm::floor(view_size_x * X + view_x)), in_out_min_x);
86// }
87// }
88
89// // Tangent b
90// if(Pzb > 0)
91// {
92// float Pxb = -Pzb * Nzb / Nxb;
93// vec4 P = proj * vec4(axis.x * Pxb, axis.y * Pxb, Pzb, 1);
94// float X = (dot(vec3(P), axis) / P.w + 1.0f * axis_sign) / 2.0f * axis_sign;
95// if(is_negative_float(Nxb) ^ is_negative_float(axis_sign))
96// {
97// in_out_max_x = glm::min<std::int32_t>(std::int32_t(glm::ceil(view_size_x * X + view_x)), in_out_max_x);
98// }
99// else
100// {
101// in_out_min_x = glm::max<std::int32_t>(std::int32_t(glm::floor(view_size_x * X + view_x)), in_out_min_x);
102// }
103// }
104// }
105
106// return in_out_min_x <= in_out_max_x;
107// }
108
109// //@return 0: not visible, 1:use scissor rect, 2: no scissor rect needed
110// inline std::uint32_t compute_projected_sphere_rect(std::int32_t& left,
111// std::int32_t& right,
112// std::int32_t& top,
113// std::int32_t& bottom,
114// const vec3& sphere_center,
115// float radius,
116// const math::vec3& view_origin,
117// const transform& view,
118// const transform& proj)
119// {
120// // Calculate a screen rectangle for the sphere's radius.
121// if(math::length2(sphere_center - view_origin) > math::square(radius))
122// {
123// math::vec3 lv = view.transform_coord(sphere_center);
124
125// if(!compute_projected_sphere_shaft(lv.x, lv.z, radius, proj, vec3(1.0f, 0.0f, 0.0f), 1.0f, left, right))
126// {
127// return 0;
128// }
129
130// if(!compute_projected_sphere_shaft(lv.y, lv.z, radius, proj, vec3(0.0f, 1.0f, 0.0f), -1.0f, top, bottom))
131// {
132// return 0;
133// }
134
135// return 1;
136// }
137// else
138// {
139// return 2;
140// }
141// }
142
143inline bool is_negative_float(const float& A)
144{
145 union {
146 float f;
147 std::uint32_t i;
148 } u;
149 u.f = A;
150 return (u.i & 0x80000000) != 0; // Detects sign bit.
151}
152
153template<typename T>
154inline T square(const T& t)
155{
156 return t * t;
157}
158
164inline bool compute_projected_sphere_shaft(float light_x,
165 float light_z,
166 float radius,
167 const glm::mat4& proj,
168 const glm::vec3& axis,
169 float axis_sign,
170 std::int32_t& in_out_min_x,
171 std::int32_t& in_out_max_x)
172{
173 auto view_x = float(in_out_min_x);
174 auto view_size_x = float(in_out_max_x - in_out_min_x);
175
176 // Vertical planes: T = <Nx, 0, Nz, 0>
177 float discriminant = (square(light_x) - square(radius) + square(light_z)) * square(light_z);
178 if(discriminant >= 0)
179 {
180 float sqrt_discriminant = glm::sqrt(discriminant);
181 float inv_light_square = 1.0f / (square(light_x) + square(light_z));
182
183 float Nxa = (radius * light_x - sqrt_discriminant) * inv_light_square;
184 float Nxb = (radius * light_x + sqrt_discriminant) * inv_light_square;
185 float Nza = (radius - Nxa * light_x) / light_z;
186 float Nzb = (radius - Nxb * light_x) / light_z;
187 float Pza = light_z - radius * Nza;
188 float Pzb = light_z - radius * Nzb;
189
190 // Tangent a
191 if(Pza > 0)
192 {
193 float Pxa = -Pza * Nza / Nxa;
194 glm::vec4 P = proj * glm::vec4(axis.x * Pxa, axis.y * Pxa, Pza, 1);
195 float X = (glm::dot(glm::vec3(P), axis) / P.w + 1.0f * axis_sign) / 2.0f * axis_sign;
196 if(is_negative_float(Nxa) ^ is_negative_float(axis_sign))
197 {
198 in_out_max_x = std::min<std::int32_t>(std::int32_t(glm::ceil(view_size_x * X + view_x)), in_out_max_x);
199 }
200 else
201 {
202 in_out_min_x = std::max<std::int32_t>(std::int32_t(glm::floor(view_size_x * X + view_x)), in_out_min_x);
203 }
204 }
205
206 // Tangent b
207 if(Pzb > 0)
208 {
209 float Pxb = -Pzb * Nzb / Nxb;
210 glm::vec4 P = proj * glm::vec4(axis.x * Pxb, axis.y * Pxb, Pzb, 1);
211 float X = (glm::dot(glm::vec3(P), axis) / P.w + 1.0f * axis_sign) / 2.0f * axis_sign;
212 if(is_negative_float(Nxb) ^ is_negative_float(axis_sign))
213 {
214 in_out_max_x = std::min<std::int32_t>(std::int32_t(glm::ceil(view_size_x * X + view_x)), in_out_max_x);
215 }
216 else
217 {
218 in_out_min_x = std::max<std::int32_t>(std::int32_t(glm::floor(view_size_x * X + view_x)), in_out_min_x);
219 }
220 }
221 }
222
223 return in_out_min_x <= in_out_max_x;
224}
225
226//@return 0: not visible, 1:use scissor rect, 2: no scissor rect needed
227inline std::uint32_t compute_projected_sphere_rect(std::int32_t& left,
228 std::int32_t& right,
229 std::int32_t& top,
230 std::int32_t& bottom,
231 const glm::vec3& sphere_center,
232 float radius,
233 const glm::vec3& view_origin,
234 const glm::mat4& view,
235 const glm::mat4& proj)
236{
237 // Calculate a screen rectangle for the sphere's radius.
238 if(glm::length2(sphere_center - view_origin) > square(radius))
239 {
240 glm::vec3 lv = glm::vec3(view * glm::vec4(sphere_center, 1.0f));
241
242 if(!compute_projected_sphere_shaft(lv.x, lv.z, radius, proj, glm::vec3(1.0f, 0.0f, 0.0f), 1.0f, left, right))
243 {
244 return 0;
245 }
246
247 if(!compute_projected_sphere_shaft(lv.y, lv.z, radius, proj, glm::vec3(0.0f, 1.0f, 0.0f), -1.0f, top, bottom))
248 {
249 return 0;
250 }
251
252 return 1;
253 }
254 else
255 {
256 return 2;
257 }
258}
259
260inline float halton(std::uint32_t Index, std::uint32_t Base)
261{
262 float Result = 0.0f;
263 float InvBase = 1.0f / Base;
264 float Fraction = InvBase;
265 while(Index > 0)
266 {
267 Result += (Index % Base) * Fraction;
268 Index /= Base;
269 Fraction *= InvBase;
270 }
271 return Result;
272}
273
285inline void taa_subpixel_offset_progressive(std::uint32_t frame,
286 float& offset_x,
287 float& offset_y,
288 float temporal_phase_scale = 1.0f)
289{
290 const float s =
291 temporal_phase_scale < 0.03f ? 0.03f : (temporal_phase_scale > 4.0f ? 4.0f : temporal_phase_scale);
292 constexpr float inv_phi = 0.61803398874989484820459f;
293 const float f = static_cast<float>(frame) * s;
294 float u = std::fmod(0.5f + f * inv_phi, 1.0f);
295 float v = std::fmod(0.5f + f * (inv_phi * inv_phi), 1.0f);
296 if(u < 0.0f)
297 {
298 u += 1.0f;
299 }
300 if(v < 0.0f)
301 {
302 v += 1.0f;
303 }
304 offset_x = u - 0.5f;
305 offset_y = v - 0.5f;
306}
307
309inline void taa_subpixel_offset_halton(std::uint32_t frame,
310 float& offset_x,
311 float& offset_y,
312 float temporal_phase_scale = 1.0f)
313{
314 const float s =
315 temporal_phase_scale < 0.03f ? 0.03f : (temporal_phase_scale > 4.0f ? 4.0f : temporal_phase_scale);
316 // Larger effective index steps when s<1 so Halton visits similar to "slower phase" golden/R2.
317 const float inv_s = 1.0f / s;
318 const std::uint32_t i = std::max(1u, static_cast<std::uint32_t>(static_cast<float>(frame) * inv_s) + 1u);
319 offset_x = halton(i, 2u) - 0.5f;
320 offset_y = halton(i, 3u) - 0.5f;
321}
322
324inline void taa_subpixel_offset_r2(std::uint32_t frame,
325 float& offset_x,
326 float& offset_y,
327 float temporal_phase_scale = 1.0f)
328{
329 const float s =
330 temporal_phase_scale < 0.03f ? 0.03f : (temporal_phase_scale > 4.0f ? 4.0f : temporal_phase_scale);
331 constexpr float a1 = 0.75487766624669276f;
332 constexpr float a2 = 0.56984029099805327f;
333 const float f = static_cast<float>(frame) * s;
334 float u = std::fmod(0.5f + f * a1, 1.0f);
335 float v = std::fmod(0.5f + f * a2, 1.0f);
336 if(u < 0.0f)
337 {
338 u += 1.0f;
339 }
340 if(v < 0.0f)
341 {
342 v += 1.0f;
343 }
344 offset_x = u - 0.5f;
345 offset_y = v - 0.5f;
346}
347
348inline std::uint32_t power_of_n_round_down(std::uint32_t val, std::uint32_t n)
349{
350 std::uint32_t currentVal = n;
351 std::uint32_t iter = 1;
352 while(currentVal < val)
353 {
354 currentVal *= n;
355 ++iter;
356 }
357
358 return iter;
359}
360
361} // namespace math
uint16_t view
uint32_t frame
Definition graphics.cpp:23
Definition bbox.cpp:5
std::uint32_t compute_projected_sphere_rect(std::int32_t &left, std::int32_t &right, std::int32_t &top, std::int32_t &bottom, const glm::vec3 &sphere_center, float radius, const glm::vec3 &view_origin, const glm::mat4 &view, const glm::mat4 &proj)
Definition math.h:227
std::uint32_t power_of_n_round_down(std::uint32_t val, std::uint32_t n)
Definition math.h:348
T square(const T &t)
Definition math.h:154
static std::vector< float > log_space(std::size_t start, std::size_t end, std::size_t count)
Definition math.h:18
float halton(std::uint32_t Index, std::uint32_t Base)
Definition math.h:260
void taa_subpixel_offset_progressive(std::uint32_t frame, float &offset_x, float &offset_y, float temporal_phase_scale=1.0f)
2D subpixel jitter in [-0.5, 0.5] for temporal AA (Kronecker / golden-ratio sequence).
Definition math.h:285
void taa_subpixel_offset_halton(std::uint32_t frame, float &offset_x, float &offset_y, float temporal_phase_scale=1.0f)
Definition math.h:309
bool compute_projected_sphere_shaft(float light_x, float light_z, float radius, const glm::mat4 &proj, const glm::vec3 &axis, float axis_sign, std::int32_t &in_out_min_x, std::int32_t &in_out_max_x)
Definition math.h:164
bool is_negative_float(const float &A)
Definition math.h:143
void taa_subpixel_offset_r2(std::uint32_t frame, float &offset_x, float &offset_y, float temporal_phase_scale=1.0f)
Definition math.h:324
uint32_t count
std::vector< math::vec3 > start