|
1 | 1 |
|
2 | 2 | const float degree_per_px = 0.05; |
3 | | -const float br_limit = 1.0 / (255.0 * 12.92); |
| 3 | +// empirical constants |
| 4 | +const float a = 0.123; |
| 5 | +const float k = 0.0016; |
| 6 | +const float exposure = 1.0; |
4 | 7 |
|
5 | | -varying vec3 v_color; // 12 |
6 | | -varying vec3 v_tetha_k; // 24 |
7 | | -varying float pointSize; // 28 |
| 8 | +// py: max_square_size = 512 # px |
| 9 | +const float max_square_size = 256.0; |
| 10 | +// py: max_br = (degree_per_px * max_square_size / algorithms.a)**2 / (2*np.pi) |
| 11 | +const float max_br = pow((degree_per_px * max_square_size / a), 2.0) / (2.0 * 3.141592653); |
8 | 12 |
|
9 | | -uniform vec2 viewportSize; |
| 13 | +varying vec3 v_color; |
| 14 | +varying float max_theta; |
| 15 | +varying float pointSize; |
| 16 | +varying float br0; |
10 | 17 |
|
11 | 18 | attribute vec4 in_Position; |
12 | 19 | attribute vec3 in_Color; |
13 | | -attribute float in_PointSize; // scaled brightness measured in Vegas |
| 20 | +attribute float in_PointSize; |
14 | 21 |
|
| 22 | +const float color_saturation_limit = 0.1; // The ratio of the minimum color component to the maximum |
| 23 | + |
| 24 | +//! Normalizes the color by its green value and corrects extreme saturation |
| 25 | +// py: def green_normalization(color: np.ndarray): |
| 26 | +vec3 green_normalization(vec3 color) |
| 27 | +{ |
| 28 | + // py: color /= color.max() |
| 29 | + // color /= max(color.r, max(color.g, color.b)); // we do this in XYZRGBConverter::convertUnnormalized() |
| 30 | + |
| 31 | + // py: delta = color_saturation_limit - color.min() |
| 32 | + float delta = color_saturation_limit - min(color.r, min(color.g, color.b)); |
| 33 | + |
| 34 | + // py: if delta > 0: |
| 35 | + if (delta > 0) |
| 36 | + { |
| 37 | + // py: color += delta * (1-color)**2 # desaturating to the saturation limit |
| 38 | + vec3 diff = vec3(1.0) - color; |
| 39 | + color += delta * (diff * diff); // desaturating to the saturation limit |
| 40 | + } |
| 41 | + // py: return color / color[1] |
| 42 | + return color / color.g; |
| 43 | +} |
15 | 44 |
|
16 | 45 | void main(void) |
17 | 46 | { |
18 | | - float linearBr = pow(10.0, 0.4f * in_PointSize) * br_limit; |
19 | | - vec3 color0 = in_Color * (linearBr / in_Color.g); // scaling on brightness and normalizing by green channel |
| 47 | + // py: linear_br = 10**(-0.4 * star_mag) * exposure # scaled brightness measured in Vegas |
| 48 | + // here i use +0.4 because `in_PointSize` is not the actual magnitude but `faintest` - `actual` |
| 49 | + br0 = pow(10.0, 0.4 * in_PointSize) * exposure; |
| 50 | + |
| 51 | + // py: color = auxiliary.green_normalization(color0) |
| 52 | + vec3 color = green_normalization(in_Color); |
| 53 | + |
| 54 | + // py: scaled_color = color * br0 |
| 55 | + vec3 scaled_color = color * br0; |
20 | 56 |
|
21 | | - vec3 check_vec = step(vec3(1.0), color0); // step(edge, x) - For element i of the return value, 0.0 is returned if x[i] < edge[i], and 1.0 is returned otherwise. |
22 | | - float check = check_vec.x + check_vec.y + check_vec.z; |
23 | | - if (check == 0.0) |
| 57 | + // py: if np.all(scaled_color < 1): |
| 58 | + if (all(lessThan(scaled_color, vec3(1.0)))) |
24 | 59 | { |
| 60 | + // we set color in the fragment shader (using v_color) so here we just set point size to 1px |
25 | 61 | pointSize = 1.0; |
26 | | - v_tetha_k = vec3(-1.0); |
| 62 | + // use max_theta == -1 as as signal that the point size is 1px |
| 63 | + max_theta = -1.0; |
27 | 64 | } |
28 | 65 | else |
29 | 66 | { |
30 | | - float max_br = sqrt(max(color0.r, max(color0.g, color0.b))); |
31 | | - float max_theta = 0.2 * sqrt(max_br); // glare radius |
32 | | - float k = 3.3e-5 * pow(max_theta, -2.5); // common constant, depending originally on star brightness |
33 | | - float min_theta = max_theta / (pow(k, -0.5) + 1.0); |
34 | | - pointSize = floor(max_theta / (sqrt(0.5 * br_limit / (k * max_br)) + 1.0) / degree_per_px); |
35 | | - v_tetha_k = vec3(max_theta, min_theta, k); |
| 67 | + // py: br = np.arctan(br0 / max_br) * max_br # dimmed brightness |
| 68 | + float br = atan(br0 / max_br) * max_br; // dimmed brightness |
| 69 | + // py: max_theta = a * np.sqrt(br) # glow radius |
| 70 | + max_theta = a * sqrt(br); // glow radius |
| 71 | + // py: half_sq = floor(max_theta / degree_per_px) |
| 72 | + float half_sq = floor(max_theta / degree_per_px); |
| 73 | + // py: x_min = -min(half_sq, center[0]) |
| 74 | + // py: x_max = min(half_sq+1, width-center[0]) |
| 75 | + // py: y_min = -min(half_sq, center[1]) |
| 76 | + // py: y_max = min(half_sq+1, hight-center[1]) |
| 77 | + // py: x = np.arange(x_min, x_max) |
| 78 | + // py: y = np.arange(y_min, y_max) |
| 79 | + // py: xx, yy = np.meshgrid(x, y) |
| 80 | + // we just set a point size. all iteration over every px is done in the fragment shader |
| 81 | + pointSize = 2.0 * half_sq; |
36 | 82 | } |
37 | 83 |
|
38 | 84 | gl_PointSize = pointSize; |
39 | | - v_color = color0; |
| 85 | + v_color = scaled_color; |
40 | 86 | set_vp(in_Position); |
41 | 87 | } |
0 commit comments