X Tutup
Skip to content

Commit d145e18

Browse files
authored
calculate star colors using Planck's law (#6210)
* calculate star colors using Planck's law * apply CIE to RGB matrix * generate star color once * Move color generation to SystemBodyData * fix generating color for lua-defined systems
1 parent 8a20b44 commit d145e18

File tree

7 files changed

+125
-5
lines changed

7 files changed

+125
-5
lines changed

src/Camera.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ static void position_system_lights(Frame *camFrame, Frame *frame, std::vector<Ca
139139
if (body && !frame->IsRotFrame() && (body->GetSuperType() == SystemBody::SUPERTYPE_STAR)) {
140140
vector3d lpos = frame->GetPositionRelTo(camFrame->GetId());
141141

142-
const Color &col = StarSystem::starRealColors[body->GetType()];
142+
const Color &col = body->GetStarColor();
143143

144144
const Color lightCol(col[0], col[1], col[2], 0);
145145
vector3f lightpos(lpos.x, lpos.y, lpos.z);
@@ -205,7 +205,7 @@ void Camera::Update()
205205
// limit the minimum billboard size for planets so they're always a little visible
206206
attrs.billboardSize = std::max(1.0f, pixSize);
207207
if (b->IsType(ObjectType::STAR)) {
208-
attrs.billboardColor = StarSystem::starRealColors[b->GetSystemBody()->GetType()];
208+
attrs.billboardColor = b->GetSystemBody()->GetStarColor();
209209
} else if (b->IsType(ObjectType::PLANET)) {
210210
// XXX this should incorporate some lighting effect
211211
// (ie, colour of the illuminating star(s))

src/GeoSphere.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ void GeoSphere::Render(Graphics::Renderer *renderer, const matrix4x4d &modelView
446446
// stars should emit light and terrain should be visible from distance
447447
ambient.r = ambient.g = ambient.b = 51;
448448
ambient.a = 255;
449-
emission = StarSystem::starRealColors[GetSystemBody()->GetType()];
449+
emission = GetSystemBody()->GetStarColor();
450450
emission.a = 255;
451451
} else {
452452
// give planet some ambient lighting if the viewer is close to it

src/Star.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ void Star::BuildHaloBuffer(Graphics::Renderer *renderer, double rad)
5757
// build halo vertex buffer
5858
Random rand;
5959
Graphics::VertexArray va(Graphics::ATTRIB_POSITION | Graphics::ATTRIB_DIFFUSE);
60-
const Color bright(StarSystem::starRealColors[GetSystemBody()->GetType()]);
60+
const Color bright(GetSystemBody()->GetStarColor());
6161
const Color dark(Color::BLANK);
6262

6363
va.Add(vector3f(0.f), bright);

src/galaxy/CustomSystem.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ static double *getDoubleOrFixed(lua_State *L, int which)
135135

136136
CSB_FIELD_SETTER_FIXED(radius, bodyData.m_radius)
137137
CSB_FIELD_SETTER_FIXED(mass, bodyData.m_mass)
138-
CSB_FIELD_SETTER_INT(temp, bodyData.m_averageTemp)
139138
CSB_FIELD_SETTER_FIXED(semi_major_axis, bodyData.m_semiMajorAxis)
140139
CSB_FIELD_SETTER_FIXED(eccentricity, bodyData.m_eccentricity)
141140
CSB_FIELD_SETTER_FIXED(rotation_period, bodyData.m_rotationPeriod)
@@ -153,6 +152,16 @@ CSB_FIELD_SETTER_STRING(space_station_type, bodyData.m_spaceStationType)
153152
#undef CSB_FIELD_SETTER_FLOAT
154153
#undef CSB_FIELD_SETTER_INT
155154

155+
static int l_csb_temp(lua_State *L)
156+
{
157+
CustomSystemBody *csb = l_csb_check(L, 1);
158+
int value = luaL_checkinteger(L, 2);
159+
csb->bodyData.m_averageTemp = value;
160+
csb->bodyData.GenerateStarColor();
161+
lua_settop(L, 1);
162+
return 1;
163+
}
164+
156165
static int l_csb_radius_km(lua_State *L)
157166
{
158167
CustomSystemBody *csb = l_csb_check(L, 1);

src/galaxy/StarSystemGenerator.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ void StarSystemRandomGenerator::PickPlanetType(SystemBody *sbody, Random &rand)
720720
//Radius is too high as it now uses the planetary calculations to work out radius (Cube root of mass)
721721
// So tell it to use the star data instead:
722722
sbody->m_radius = fixed(rand.Int32(starTypeInfo[sbody->GetType()].radius[0], starTypeInfo[sbody->GetType()].radius[1]), 100);
723+
sbody->GenerateStarColor();
723724
} else if (sbody->GetMassAsFixed() > 6) {
724725
sbody->m_type = SystemBody::TYPE_PLANET_GAS_GIANT;
725726
// Generate a random "surface" density for gas giants roughly fitted to real-life estimation of Jupiter at "cloud deck" level
@@ -1207,6 +1208,7 @@ void StarSystemRandomGenerator::MakeStarOfType(SystemBody *sbody, SystemBody::Bo
12071208
}
12081209
sbody->m_mass = fixed(rand.Int32(starTypeInfo[type].mass[0], starTypeInfo[type].mass[1]), 100);
12091210
sbody->m_averageTemp = rand.Int32(starTypeInfo[type].tempMin, starTypeInfo[type].tempMax);
1211+
sbody->GenerateStarColor();
12101212
}
12111213

12121214
void StarSystemRandomGenerator::MakeRandomStar(SystemBody *sbody, Random &rand)

src/galaxy/SystemBody.cpp

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ SystemBodyData::SystemBodyData() :
2323
m_averageTemp(0),
2424
m_heightMapFractal(0)
2525
{
26+
m_starColor = Color(255, 0, 255, 255);
2627
}
2728

2829
void SystemBodyData::SaveToJson(Json &out)
@@ -98,6 +99,7 @@ void SystemBodyData::LoadFromJson(const Json &obj)
9899
m_inclination = obj.value<fixed>("inclination", 0);
99100
m_argOfPeriapsis = obj.value<fixed>("argOfPeriapsis", 0);
100101
m_averageTemp = obj.value<uint32_t>("averageTemp", 0);
102+
GenerateStarColor();
101103

102104
m_metallicity = obj.value<fixed>("metallicity", 0);
103105
m_volcanicity = obj.value<fixed>("volcanicity", 0);
@@ -129,6 +131,108 @@ void SystemBodyData::LoadFromJson(const Json &obj)
129131
m_heightMapFractal = std::min(m_heightMapFractal, uint32_t(1));
130132
}
131133

134+
double GetPlanckBrightness(const double wavelength_nm, const int temperature)
135+
{
136+
// Planck's constant
137+
const double h = 6.62607015e-34; // kg*m^2*s^-1 (J*s)
138+
139+
// speed of light
140+
const double c = 299792458; // m*s^2
141+
142+
// Boltzmann's constant
143+
const double k = 1.380649e-23; // J/K
144+
145+
double wavelength = wavelength_nm * 1e-9;
146+
147+
double exponent = exp((h*c) / (wavelength * k * temperature));
148+
return 2 * h * pow(c, 2) / (pow(wavelength, 5) * exponent);
149+
}
150+
151+
const vector3d nm_to_rgb[48] = {
152+
vector3d( 0.000000f, 0.000000f, 0.000001f ), // 360 nm
153+
vector3d( 0.000006f, 0.000001f, 0.000026f ), // 370 nm
154+
vector3d( 0.000160f, 0.000017f, 0.000705f ), // 380 nm
155+
vector3d( 0.002362f, 0.000253f, 0.010482f ), // 390 nm
156+
vector3d( 0.019110f, 0.002004f, 0.086011f ), // 400 nm
157+
vector3d( 0.084736f, 0.008756f, 0.389366f ), // 410 nm
158+
vector3d( 0.204492f, 0.021391f, 0.972542f ), // 420 nm
159+
vector3d( 0.314679f, 0.038676f, 1.553480f ), // 430 nm
160+
vector3d( 0.383734f, 0.062077f, 1.967280f ), // 440 nm
161+
vector3d( 0.370702f, 0.089456f, 1.994800f ), // 450 nm
162+
vector3d( 0.302273f, 0.128201f, 1.745370f ), // 460 nm
163+
vector3d( 0.195618f, 0.185190f, 1.317560f ), // 470 nm
164+
vector3d( 0.080507f, 0.253589f, 0.772125f ), // 480 nm
165+
vector3d( 0.016172f, 0.339133f, 0.415254f ), // 490 nm
166+
vector3d( 0.003816f, 0.460777f, 0.218502f ), // 500 nm
167+
vector3d( 0.037465f, 0.606741f, 0.112044f ), // 510 nm
168+
vector3d( 0.117749f, 0.761757f, 0.060709f ), // 520 nm
169+
vector3d( 0.236491f, 0.875211f, 0.030451f ), // 530 nm
170+
vector3d( 0.376772f, 0.961988f, 0.013676f ), // 540 nm
171+
vector3d( 0.529826f, 0.991761f, 0.003988f ), // 550 nm
172+
vector3d( 0.705224f, 0.997340f, 0.000000f ), // 560 nm
173+
vector3d( 0.878655f, 0.955552f, 0.000000f ), // 570 nm
174+
vector3d( 1.014160f, 0.868934f, 0.000000f ), // 580 nm
175+
vector3d( 1.118520f, 0.777405f, 0.000000f ), // 590 nm
176+
vector3d( 1.123990f, 0.658341f, 0.000000f ), // 600 nm
177+
vector3d( 1.030480f, 0.527963f, 0.000000f ), // 610 nm
178+
vector3d( 0.856297f, 0.398057f, 0.000000f ), // 620 nm
179+
vector3d( 0.647467f, 0.283493f, 0.000000f ), // 630 nm
180+
vector3d( 0.431567f, 0.179828f, 0.000000f ), // 640 nm
181+
vector3d( 0.268329f, 0.107633f, 0.000000f ), // 650 nm
182+
vector3d( 0.152568f, 0.060281f, 0.000000f ), // 660 nm
183+
vector3d( 0.081261f, 0.031800f, 0.000000f ), // 670 nm
184+
vector3d( 0.040851f, 0.015905f, 0.000000f ), // 680 nm
185+
vector3d( 0.019941f, 0.007749f, 0.000000f ), // 690 nm
186+
vector3d( 0.009577f, 0.003718f, 0.000000f ), // 700 nm
187+
vector3d( 0.004553f, 0.001768f, 0.000000f ), // 710 nm
188+
vector3d( 0.002175f, 0.000846f, 0.000000f ), // 720 nm
189+
vector3d( 0.001045f, 0.000407f, 0.000000f ), // 730 nm
190+
vector3d( 0.000508f, 0.000199f, 0.000000f ), // 740 nm
191+
vector3d( 0.000251f, 0.000098f, 0.000000f ), // 750 nm
192+
vector3d( 0.000126f, 0.000050f, 0.000000f ), // 760 nm
193+
vector3d( 0.000065f, 0.000025f, 0.000000f ), // 770 nm
194+
vector3d( 0.000033f, 0.000013f, 0.000000f ), // 780 nm
195+
vector3d( 0.000018f, 0.000007f, 0.000000f ), // 790 nm
196+
vector3d( 0.000009f, 0.000004f, 0.000000f ), // 800 nm
197+
vector3d( 0.000005f, 0.000002f, 0.000000f ), // 810 nm
198+
vector3d( 0.000003f, 0.000001f, 0.000000f ), // 820 nm
199+
vector3d( 0.000002f, 0.000001f, 0.000000f ) // 830 nm
200+
};
201+
202+
void SystemBodyData::GenerateStarColor()
203+
{
204+
// https://www.shadertoy.com/view/NlGXzz
205+
206+
// [360-830 nm]
207+
vector3d rgb = vector3d(0.f);
208+
209+
const matrix3x3d xyz2rgb = matrix3x3d::FromVectors(
210+
vector3d( 3.2404542,-0.9692660, 0.0556434),
211+
vector3d(-1.5371385, 1.8760108,-0.2040259),
212+
vector3d(-0.4985314, 0.0415560, 1.0572252)
213+
);
214+
215+
for (int i = 0; i < 48; i++) {
216+
double wavelength = 360 + (10 * i);
217+
218+
rgb += GetPlanckBrightness(wavelength, m_averageTemp) * (xyz2rgb * nm_to_rgb[i]);
219+
}
220+
221+
// normalize
222+
double max = std::max(std::max(rgb.x, rgb.y), rgb.z);
223+
// black color
224+
if (max == 0.f) {
225+
rgb = vector3d(0.f);
226+
} else {
227+
rgb /= (max / 255);
228+
}
229+
rgb.x = std::max(rgb.x, 0.0);
230+
rgb.y = std::max(rgb.y, 0.0);
231+
rgb.z = std::max(rgb.z, 0.0);
232+
233+
m_starColor = Color(rgb.x, rgb.y, rgb.z, 255);
234+
}
235+
132236
SystemBody::SystemBody(const SystemPath &path, StarSystem *system) :
133237
m_parent(nullptr),
134238
m_system(system),

src/galaxy/SystemBody.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ class SystemBodyData {
9292

9393
void SaveToJson(Json &out);
9494
void LoadFromJson(const Json &obj);
95+
void GenerateStarColor();
9596

9697
std::string m_name;
9798
SystemBodyType::BodyType m_type = SystemBodyType::TYPE_GRAVPOINT;
@@ -132,6 +133,9 @@ class SystemBodyData {
132133
unsigned int m_heightMapFractal;
133134

134135
std::string m_spaceStationType;
136+
137+
// star color
138+
Color m_starColor;
135139
};
136140

137141
class SystemBody : public RefCounted, public SystemBodyType, protected SystemBodyData {
@@ -271,6 +275,7 @@ class SystemBody : public RefCounted, public SystemBodyType, protected SystemBod
271275
// which is rendered when the body has a small screen size
272276
return Color(200, 200, 200, 255);
273277
}
278+
Color GetStarColor() const { return m_starColor; };
274279

275280
// Returns color, density in kg/m^3 at sea level
276281
void GetAtmosphereFlavor(Color *outColor, double *outDensity) const

0 commit comments

Comments
 (0)
X Tutup