1 /*
2 * Stellarium
3 * Copyright (C) 2002 Fabien Chereau
4 * Copyright (C) 2014 Georg Zotti (extinction parts)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
19 */
20
21 #include "MilkyWay.hpp"
22 #include "StelFader.hpp"
23 #include "StelTexture.hpp"
24 #include "StelUtils.hpp"
25 #include "StelFileMgr.hpp"
26
27 #include "StelProjector.hpp"
28 #include "StelToneReproducer.hpp"
29 #include "StelApp.hpp"
30 #include "StelTextureMgr.hpp"
31 #include "StelCore.hpp"
32 #include "StelSkyDrawer.hpp"
33 #include "StelPainter.hpp"
34 #include "StelTranslator.hpp"
35 #include "StelModuleMgr.hpp"
36 #include "LandscapeMgr.hpp"
37 #include "StelMovementMgr.hpp"
38 #include "Planet.hpp"
39
40 #include <QDebug>
41 #include <QSettings>
42
43 // Class which manages the displaying of the Milky Way
MilkyWay()44 MilkyWay::MilkyWay()
45 : color(1.f, 1.f, 1.f)
46 , intensity(1.)
47 , intensityFovScale(1.0)
48 , intensityMinFov(0.25) // when zooming in further, MilkyWay is no longer visible.
49 , intensityMaxFov(2.5) // when zooming out further, MilkyWay is fully visible (when enabled).
50 , vertexArray()
51 , vertexArrayNoAberration()
52 {
53 setObjectName("MilkyWay");
54 fader = new LinearFader();
55 }
56
~MilkyWay()57 MilkyWay::~MilkyWay()
58 {
59 delete fader;
60 fader = Q_NULLPTR;
61
62 delete vertexArray;
63 vertexArray = Q_NULLPTR;
64 delete vertexArrayNoAberration;
65 vertexArrayNoAberration = Q_NULLPTR;
66 }
67
init()68 void MilkyWay::init()
69 {
70 QSettings* conf = StelApp::getInstance().getSettings();
71 Q_ASSERT(conf);
72
73 tex = StelApp::getInstance().getTextureManager().createTexture(StelFileMgr::getInstallationDir()+"/textures/milkyway.png");
74 setFlagShow(conf->value("astro/flag_milky_way").toBool());
75 setIntensity(conf->value("astro/milky_way_intensity",1.).toDouble());
76 setSaturation(conf->value("astro/milky_way_saturation", 1.).toDouble());
77
78 // A new texture was provided by Fabien. Better resolution, but in equatorial coordinates. I had to enhance it a bit, and shift it by 90 degrees.
79 // We must create a constant array to take and derive possibly aberrated positions into the vertexArray
80 vertexArrayNoAberration = new StelVertexArray(StelPainter::computeSphereNoLight(1.,1.,45,15,1, true)); // GZ orig: slices=stacks=20.
81 vertexArray = new StelVertexArray(StelPainter::computeSphereNoLight(1.,1.,45,15,1, true)); // GZ orig: slices=stacks=20.
82 vertexArray->colors.resize(vertexArray->vertex.length());
83 vertexArray->colors.fill(color);
84
85 QString displayGroup = N_("Display Options");
86 addAction("actionShow_MilkyWay", displayGroup, N_("Milky Way"), "flagMilkyWayDisplayed", "M");
87 }
88
89
update(double deltaTime)90 void MilkyWay::update(double deltaTime)
91 {
92 fader->update(static_cast<int>(deltaTime*1000));
93 //calculate FOV fade value, linear fade between intensityMaxFov and intensityMinFov
94 double fov = StelApp::getInstance().getCore()->getMovementMgr()->getCurrentFov();
95 intensityFovScale = qBound(0.0,(fov - intensityMinFov) / (intensityMaxFov - intensityMinFov),1.0);
96 }
97
98 /*************************************************************************
99 Reimplementation of the getCallOrder method
100 *************************************************************************/
getCallOrder(StelModuleActionName actionName) const101 double MilkyWay::getCallOrder(StelModuleActionName actionName) const
102 {
103 if (actionName==StelModule::ActionDraw)
104 return 1;
105 return 0;
106 }
107
setFlagShow(bool b)108 void MilkyWay::setFlagShow(bool b)
109 {
110 if (*fader != b)
111 {
112 *fader = b;
113 emit milkyWayDisplayedChanged(b);
114 }
115 }
116
getFlagShow() const117 bool MilkyWay::getFlagShow() const {return *fader;}
118
draw(StelCore * core)119 void MilkyWay::draw(StelCore* core)
120 {
121 if (!fader->getInterstate())
122 return;
123
124 // Apply annual aberration. We take original vertices, and put the aberrated positions into the vertexArray which we draw.
125 // prepare for aberration: Explan. Suppl. 2013, (7.38)
126 if (core->getUseAberration())
127 {
128 Vec3d vel=core->getCurrentPlanet()->getHeliocentricEclipticVelocity();
129 vel=StelCore::matVsop87ToJ2000*vel;
130 vel*=core->getAberrationFactor() * (AU/(86400.0*SPEED_OF_LIGHT));
131 for (int i=0; i<vertexArrayNoAberration->vertex.size(); ++i)
132 {
133 Vec3d vert=vertexArrayNoAberration->vertex.at(i);
134 Q_ASSERT_X(fabs(vert.lengthSquared()-1.0)<0.0001, "Milky Way aberration", "vertex length not unity");
135 vert+=vel;
136 vert.normalize();
137
138 vertexArray->vertex[i]=vert;
139 }
140 }
141 else
142 {
143 // for (int i=0; i<vertexArrayNoAberration->vertex.size(); ++i)
144 // vertexArray->vertex[i]=vertexArrayNoAberration->vertex.at(i);
145 vertexArray->vertex=vertexArrayNoAberration->vertex;
146 }
147
148 StelProjector::ModelViewTranformP transfo = core->getJ2000ModelViewTransform();
149
150 const StelProjectorP prj = core->getProjection(transfo); // GZ: Maybe this can now be simplified?
151 StelToneReproducer* eye = core->getToneReproducer();
152 StelSkyDrawer *drawer=core->getSkyDrawer();
153
154 Q_ASSERT(tex); // A texture must be loaded before calling this
155
156 // This RGB color corresponds to the night blue scotopic color = 0.25, 0.25 in xyY mode.
157 // since milky way is always seen white RGB value in the texture (1.0,1.0,1.0)
158 // Vec3f c = Vec3f(0.34165f, 0.429666f, 0.63586f);
159 // This is the same color, just brighter to have Blue=1.
160 //Vec3f c = Vec3f(0.53730381f, .675724216f, 1.0f);
161 // The new texture (V0.13.1) is quite blue to start with. It is better to apply white color for it.
162 //Vec3f c = Vec3f(1.0f, 1.0f, 1.0f);
163 // Still better: Re-activate the configurable color!
164 Vec3f c = color;
165
166 // We must also adjust milky way to light pollution.
167 // Is there any way to calibrate this?
168 // We compute a float 1..9 from Bortle index and atmosphere display value (allows smooth fade when switching)
169 float atmFadeIntensity = GETSTELMODULE(LandscapeMgr)->getAtmosphereFadeIntensity();
170 int bortle=drawer->getBortleScaleIndex();
171 float bortleIntensity = 1.f+ (bortle-1)*atmFadeIntensity; // Bortle index moderated by atmosphere fader.
172 //aLum*=(11.0f-bortle)*0.1f;
173
174 float lum = drawer->surfaceBrightnessToLuminance(12.f+0.15f*bortleIntensity); // was 11.5; Source? How to calibrate the new texture?
175
176 // Get the luminance scaled between 0 and 1
177 float aLum =eye->adaptLuminanceScaled(lum*fader->getInterstate());
178
179 // Bound a maximum luminance. GZ: Is there any reference/reason, or just trial and error?
180 aLum = qMin(0.38f, aLum*2.f);
181
182
183 // intensity of 1.0 is "proper", but allow boost for dim screens
184 c*=aLum*static_cast<float>(intensity*intensityFovScale);
185
186
187 // TODO: Find an even better balance with sky brightness, MW should be hard to see during Full Moon and at least somewhat reduced in smaller phases.
188 // adapt brightness by atmospheric brightness. This block developed for ZodiacalLight, hopefully similarly applicable...
189 const float atmLum = GETSTELMODULE(LandscapeMgr)->getAtmosphereAverageLuminance();
190 // 10cd/m^2 at sunset, 3.3 at civil twilight (sun at -6deg). 0.0145 sun at -12, 0.0004 sun at -18, 0.01 at Full Moon!?
191 //qDebug() << "AtmLum: " << atmLum;
192 float atmFactor=qMax(0.35f, 50.0f*(0.02f-atmLum)); // keep visible in twilight, but this is enough for some effect with the moon.
193 c*=atmFactor*atmFactor;
194
195 if (c[0]<0) c[0]=0;
196 if (c[1]<0) c[1]=0;
197 if (c[2]<0) c[2]=0;
198
199 const bool withExtinction=(drawer->getFlagHasAtmosphere() && drawer->getExtinction().getExtinctionCoefficient()>=0.01f);
200 if (withExtinction)
201 {
202 // We must process the vertices to find geometric altitudes in order to compute vertex colors.
203 // Note that there is a visible boost of extinction for higher Bortle indices. I must reflect that as well.
204 const Extinction& extinction=drawer->getExtinction();
205 vertexArray->colors.clear();
206
207 for (int i=0; i<vertexArray->vertex.size(); ++i)
208 {
209 Vec3d vertAltAz=core->j2000ToAltAz(vertexArray->vertex.at(i), StelCore::RefractionOn);
210 Q_ASSERT(fabs(vertAltAz.lengthSquared()-1.0) < 0.001);
211
212 float mag=0.0f;
213 extinction.forward(vertAltAz, &mag);
214 float extinctionFactor=std::pow(0.3f, mag) * (1.1f-bortleIntensity*0.1f); // drop of one magnitude: should be factor 2.5 or 40%. We take 30%, it looks more realistic.
215 vertexArray->colors.append(c*extinctionFactor);
216 }
217 }
218 else
219 vertexArray->colors.fill(c);
220
221 StelPainter sPainter(prj);
222 sPainter.setCullFace(true);
223 sPainter.setBlending(true, GL_ONE, GL_ONE); // allow colored sky background
224 tex->bind();
225 sPainter.setSaturation(static_cast<float>(saturation));
226 sPainter.drawStelVertexArray(*vertexArray);
227 sPainter.setCullFace(false);
228 }
229