Skip to content

Commit 11ed2a0

Browse files
committed
wip
1 parent 6036e69 commit 11ed2a0

File tree

3 files changed

+102
-34
lines changed

3 files changed

+102
-34
lines changed

shaders/star_frag.glsl

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,61 @@
11
const float degree_per_px = 0.05;
22
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;
36

47
varying vec3 v_color;
5-
varying vec3 v_tetha_k;
8+
varying float max_theta;
69
varying float pointSize;
10+
varying float br0;
711

8-
float psf_square(float theta, float min_theta, float max_theta, float k)
12+
// py: def PSF_Bounded(theta: float, max_theta: float, br_center: float):
13+
// max_theta is common for all pixels so it's set via `varying` in the vertex shader
14+
float psf_bounded(float theta, float br_center)
915
{
10-
// Human eye's point source function, optimized to fit a square.
11-
// Lower limit on brightness and angular size: 1 Vega and 0.05 degrees per pixel.
12-
// No upper limits.
16+
// Human eye's point source function from the research by Greg Spencer et al., optimized to fit a square.
17+
// Lower limit on brightness and angular size: 1 Vega and 0.05 degrees per pixel. No upper limits.
1318

14-
if (theta < min_theta)
15-
return 1.0; // overexposed
19+
// py: if theta == 0:
20+
if (theta == 0)
21+
// py: return br_center
22+
return br_center; // the center is always overexposed (zero division error)
1623

24+
// py: elif theta < max_theta:
1725
if (theta < max_theta)
1826
{
27+
// py: brackets = max_theta / theta - 1
1928
float brackets = max_theta / theta - 1.0;
29+
// py: return k * brackets * brackets
2030
return k * brackets * brackets;
2131
}
2232

23-
return 0.0;
33+
// py: return 0. # after max_theta function starts to grow again
34+
return 0.0; // after max_theta function starts to grow again
2435
}
2536

2637
void main(void)
2738
{
28-
float max_theta = v_tetha_k.x;
39+
vec3 glow_colored;
2940
if (max_theta == -1.0)
3041
{
31-
gl_FragColor = vec4(v_color, 1.0);
42+
// just a one pixel star
43+
glow_colored = v_color;
44+
// py: arr[center[1], center[0]] += scaled_color
45+
gl_FragColor = vec4(glow_colored, 1.0);
3246
}
3347
else
3448
{
35-
float min_theta = v_tetha_k.y;
36-
float k = v_tetha_k.z;
3749
// Option 2: glare square render
50+
// py: theta = np.sqrt(xx*xx + yy*yy) * degree_per_px # array of distances to the center
51+
// in fragment shader all points have virtual dimension 1x1, so gl_PointCoord has a value from [0; 1]
3852
vec2 offset = (gl_PointCoord.xy - vec2(0.5)) * pointSize;
39-
float theta = length(offset) * degree_per_px;
40-
41-
gl_FragColor = vec4(v_color * psf_square(theta, min_theta, max_theta, k), 1.0);
53+
float theta = length(offset) * degree_per_px;
54+
// py: glow_bw = PSF_Bounded(theta, max_theta, br0) # in the [0, 1] range, like in Celestia
55+
float glow_bw = psf_bounded(theta, br0);
56+
// py: glow_colored = color * np.repeat(np.expand_dims(glow_bw, axis=2), 3, axis=2) # scaling
57+
glow_colored = v_color * glow_bw;
58+
// py: arr[center[1]+y_min:center[1]+y_max, center[0]+x_min:center[0]+x_max] += glow_colored
59+
gl_FragColor = vec4(glow_colored, 1.0);
4260
}
4361
}

shaders/star_vert.glsl

Lines changed: 65 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,87 @@
11

22
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;
47

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);
812

9-
uniform vec2 viewportSize;
13+
varying vec3 v_color;
14+
varying float max_theta;
15+
varying float pointSize;
16+
varying float br0;
1017

1118
attribute vec4 in_Position;
1219
attribute vec3 in_Color;
13-
attribute float in_PointSize; // scaled brightness measured in Vegas
20+
attribute float in_PointSize;
1421

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+
}
1544

1645
void main(void)
1746
{
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;
2056

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))))
2459
{
60+
// we set color in the fragment shader (using v_color) so here we just set point size to 1px
2561
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;
2764
}
2865
else
2966
{
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;
3682
}
3783

3884
gl_PointSize = pointSize;
39-
v_color = color0;
85+
v_color = scaled_color;
4086
set_vp(in_Position);
4187
}

src/celengine/pointstarrenderer.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ PointStarRenderer::PointStarRenderer() :
3737
{
3838
}
3939

40+
//const float br_limit = 1.0f / (255.0f * 12.92f);
41+
const float br_limit = 1.0f / 255.0f;
42+
const float exposure = 1.0f;
43+
4044
void PointStarRenderer::process(const Star& star, float distance, float appMag)
4145
{
4246
if (distance > distanceLimit)

0 commit comments

Comments
 (0)