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
|
#ifndef __MATH_INC
#define __MATH_INC
#define PI 3.14159265358979323846264f
#define TAU (2.0f * PI)
#define HALF_PI (PI * 0.5f)
#define RCP_PI (1.0f / PI)
#define RCP_TAU (1.0f / TAU)
#define PHI 1.618033989f
#define RCP_PHI 0.618033989f
#define SQRT_2 1.414213562f
#define SQRT_2_RCP 0.707106781f
#define RCP_SQRT_2 0.707106781f
#define RCP_SQRT_3 0.577350269f
#define TWO_OVER_THREE 0.6666666666666666f
#define SQRT_3 1.73205081f
#define SQRT_3_OVER_2 0.8660254037844386f
#define EULERS_CONSTANT 2.718281828f
float sin_noise_3d(float3 uvw) {
return sin(uvw[0]) * sin(uvw[1]) * sin(uvw[2]);
}
float sin_noise_3d_fbm(float3 uvw, uint octaves, float k, float strength) {
float result = 0;
float factor = 1.0f;
for (uint i = 0; i < octaves; i++) {
result += sin_noise_3d(uvw) * factor * strength;
uvw *= k;
factor /= k;
}
return result;
}
// Wrap a dot product. Assume it's already clamped.
// At k=0, you get standard lambertian shading.
// At k=0.5, you get half-lambertian shading.
// At k=1.0, you get flat shading.
// k must be on [0, 1].
// Energy preserving, within some small bound.
float wrapDotProduct(float XoY, float k) {
float lambertian = XoY;
float half_lambertian = pow(max(1e-4, (XoY + 0.5f) / (1.0f + 0.5f)), 2);
float flat = RCP_PI;
if (k < 0.5) {
return lerp(lambertian, half_lambertian, k * 2.0f);
} else {
return lerp(half_lambertian, flat, k * 2.0f - 1.0f);
}
}
// Vector rotation with a quaternion
// https://blog.molecular-matters.com/2013/05/24/a-faster-quaternion-vector-multiplication/
float3 rotate_vector(float3 v, float4 q)
{
float3 t = 2.0 * cross(q.xyz, v);
return v + q.w * t + cross(q.xyz, t);
}
// Cartesian to cube hexagonal coordinates.
// Based on this: https://backdrifting.net/post/064_hex_grids
float3 cart_to_hex(float2 cart) {
float p = cart.x;
float q = dot(cart, float2(0.5f, SQRT_3_OVER_2));
float r = dot(cart, float2(0.5f, -SQRT_3_OVER_2));
return float3(p, q, r) * 0.5f;
}
float2 hex_to_cart(float3 cart) {
return float2(
cart[0] + (cart[1] + cart[2]) * 0.5f,
(cart[1] - cart[2]) * SQRT_3_OVER_2);
}
float3 round_hex(float3 hex_coord) {
float3 rounded = round(hex_coord);
float3 diff = abs(rounded - hex_coord);
float error = rounded.x - rounded.y - rounded.z;
float3 max_mask = float3(
diff.x > diff.y && diff.x > diff.z,
diff.y > diff.x && diff.y > diff.z,
diff.z > diff.x && diff.z > diff.y);
rounded += error * float3(-1, 1, 1) * max_mask;
return rounded;
}
// Reoriented normal mapping
// https://blog.selfshadow.com/publications/blending-in-detail/
// Inputs are in tangent space.
float3 blendNormalsHill12(float3 n0, float3 n1) {
n0.z += 1.0;
n1.xy = -n1.xy;
return normalize(n0 * dot(n0, n1) - n1 * n0.z);
}
#endif // __MATH_INC
|