diff --git a/data/shaders/planet.frag b/data/shaders/planet.frag index fe30196a6233bf..d760c9e53fdcb8 100644 --- a/data/shaders/planet.frag +++ b/data/shaders/planet.frag @@ -24,6 +24,8 @@ VARYING mediump vec2 texc; //texture coord VARYING highp vec3 P; //original vertex pos in model space +const highp float PI = 3.14159265; + uniform sampler2D tex; uniform mediump vec2 poleLat; //latitudes of pole caps, in terms of texture coordinate. x>0...north, y<1...south. uniform mediump vec3 ambientLight; @@ -63,6 +65,7 @@ VARYING highp vec4 shadowCoord; uniform sampler2D earthShadow; uniform mediump float eclipsePush; uniform sampler2D normalMap; + uniform sampler2D horizonMap; VARYING highp vec3 normalX; VARYING highp vec3 normalY; @@ -263,6 +266,53 @@ void main() mediump vec3 normal = texture2D(normalMap, texc).rgb-vec3(0.5, 0.5, 0); normal = normalize(normalX*normal.x+normalY*normal.y+normalZ*normal.z); // normal now contains the real surface normal taking normal map into account + + mediump float horizonShadowCoefficient = 1; + { + // Check whether the fragment is in the shadow of surrounding mountains or the horizon + mediump vec3 lonDir = normalX; + mediump vec3 northDir = normalY; + mediump vec3 zenith = normalZ; + mediump float sunAzimuth = atan(dot(lightDirection,lonDir), dot(lightDirection,northDir)); + mediump float sinSunElevation = dot(zenith, lightDirection); + mediump vec4 horizonElevSample = (texture2D(horizonMap, texc) - 0.5) * 2.; + mediump vec4 sinHorizElevs = sign(horizonElevSample) * horizonElevSample * horizonElevSample; + mediump float sinHorizElevLeft, sinHorizElevRight; + mediump float alpha; + if(sunAzimuth >= PI/2) + { + // Sun is between East and South + sinHorizElevLeft = sinHorizElevs[1]; + sinHorizElevRight = sinHorizElevs[2]; + alpha = (sunAzimuth - PI/2) / (PI/2); + } + else if(sunAzimuth >= 0) + { + // Sun is between North and East + sinHorizElevLeft = sinHorizElevs[0]; + sinHorizElevRight = sinHorizElevs[1]; + alpha = sunAzimuth / (PI/2); + } + else if(sunAzimuth <= -PI/2) + { + // Sun is between South and West + sinHorizElevLeft = sinHorizElevs[2]; + sinHorizElevRight = sinHorizElevs[3]; + alpha = (sunAzimuth + PI) / (PI/2); + } + else + { + // Sun is between West and North + sinHorizElevLeft = sinHorizElevs[3]; + sinHorizElevRight = sinHorizElevs[0]; + alpha = (sunAzimuth + PI/2) / (PI/2); + } + mediump float horizElevLeft = asin(sinHorizElevLeft); + mediump float horizElevRight = asin(sinHorizElevRight); + mediump float horizElev = horizElevLeft + (horizElevRight-horizElevLeft)*alpha; + if(sinSunElevation < sin(horizElev)) + horizonShadowCoefficient = 0; + } #else // important to normalize here again mediump vec3 normal = normalize(normalVS); @@ -271,6 +321,9 @@ void main() // Use an Oren-Nayar model for rough surfaces // Ref: http://content.gpwiki.org/index.php/D3DBook:(Lighting)_Oren-Nayar lum = orenNayar(normal, lightDirection, eyeDirection, orenNayarParameters.x, orenNayarParameters.y, orenNayarParameters.z, orenNayarParameters.w); +#endif +#ifdef IS_MOON + lum *= horizonShadowCoefficient; #endif //calculate pseudo-outgassing/rim-lighting effect lowp float outgas = 0.0; diff --git a/data/ssystem_major.ini b/data/ssystem_major.ini index f9c8e4a5637753..cd711f77c84ba5 100644 --- a/data/ssystem_major.ini +++ b/data/ssystem_major.ini @@ -1089,6 +1089,7 @@ coord_func=lunar_special landscape=moon name=Moon normals_map=moon_normals.png +horizon_map=moon_horizon.png orbit_visualization_period=27.321582 parent=Earth radius=1737.4 diff --git a/src/core/StelObserver.cpp b/src/core/StelObserver.cpp index f68c3fb52187e4..9b90a15744b1ea 100644 --- a/src/core/StelObserver.cpp +++ b/src/core/StelObserver.cpp @@ -52,7 +52,7 @@ class ArtificialPlanet : public Planet }; ArtificialPlanet::ArtificialPlanet(const PlanetP& orig) : - Planet("art", 0, 0, Vec3f(0,0,0), 0, 0, "", "", "", Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, false, true, false, false, "artificial"), + Planet("art", 0, 0, Vec3f(0,0,0), 0, 0, "", "", "", "", Q_NULLPTR, Q_NULLPTR, Q_NULLPTR, false, true, false, false, "artificial"), dest(Q_NULLPTR), orig_name(orig->getEnglishName()), orig_name_i18n(orig->getNameI18n()) { // set parent = sun: diff --git a/src/core/modules/Comet.cpp b/src/core/modules/Comet.cpp index 497cb9a4e0d01d..c4c85c663d2466 100644 --- a/src/core/modules/Comet.cpp +++ b/src/core/modules/Comet.cpp @@ -75,6 +75,7 @@ Comet::Comet(const QString& englishName, roughness, atexMapName, "", // no normalmap. + "", // no horizon map aobjModelName, coordFunc, orbitPtr, diff --git a/src/core/modules/MinorPlanet.cpp b/src/core/modules/MinorPlanet.cpp index 669c468714604d..520868d83a836c 100644 --- a/src/core/modules/MinorPlanet.cpp +++ b/src/core/modules/MinorPlanet.cpp @@ -36,6 +36,7 @@ MinorPlanet::MinorPlanet(const QString& englishName, float roughness, const QString& atexMapName, const QString& anormalMapName, + const QString& ahorizonMapName, const QString& aobjModelName, posFuncType coordFunc, KeplerOrbit* orbitPtr, @@ -51,6 +52,7 @@ MinorPlanet::MinorPlanet(const QString& englishName, roughness, atexMapName, anormalMapName, + ahorizonMapName, aobjModelName, coordFunc, orbitPtr, diff --git a/src/core/modules/MinorPlanet.hpp b/src/core/modules/MinorPlanet.hpp index 0472e0f82ed768..87d488909795ec 100644 --- a/src/core/modules/MinorPlanet.hpp +++ b/src/core/modules/MinorPlanet.hpp @@ -46,6 +46,7 @@ class MinorPlanet : public Planet float roughness, const QString& texMapName, const QString& normalMapName, + const QString& horizonMapName, const QString& objModelName, posFuncType _coordFunc, KeplerOrbit *orbitPtr, diff --git a/src/core/modules/Planet.cpp b/src/core/modules/Planet.cpp index 9532ba838c1f3c..bb5e50a04f3dc7 100644 --- a/src/core/modules/Planet.cpp +++ b/src/core/modules/Planet.cpp @@ -208,6 +208,7 @@ Planet::Planet(const QString& englishName, float roughness, const QString& atexMapName, const QString& anormalMapName, + const QString& ahorizonMapName, const QString& aobjModelName, posFuncType coordFunc, Orbit* anOrbitPtr, @@ -226,6 +227,7 @@ Planet::Planet(const QString& englishName, nativeName(""), texMapName(atexMapName), normalMapName(anormalMapName), + horizonMapName(ahorizonMapName), siderealPeriod(0.), equatorialRadius(radius), oneMinusOblateness(1.0-oblateness), @@ -297,6 +299,16 @@ Planet::Planet(const QString& englishName, normalMapFileOrig = normalMapFile; } } + if(!horizonMapName.isEmpty()) + { + // TODO: use StelFileMgr::findFileInAllPaths() after introducing an Add-On Manager + QString horizonMapFile = StelFileMgr::findFile("textures/"+horizonMapName, StelFileMgr::File); + if (!horizonMapFile.isEmpty()) + { + horizonMap = StelApp::getInstance().getTextureManager().createTextureThread(horizonMapFile, StelTexture::StelTextureParams(true, GL_LINEAR, GL_REPEAT)); + horizonMapFileOrig = horizonMapFile; + } + } //the OBJ is lazily loaded when first required if(!aobjModelName.isEmpty()) { @@ -354,6 +366,9 @@ void Planet::resetTextures() // restore normal map if (!normalMapFileOrig.isEmpty()) normalMap = StelApp::getInstance().getTextureManager().createTextureThread(normalMapFileOrig, StelTexture::StelTextureParams(true, GL_LINEAR, GL_REPEAT)); + + if (!horizonMapFileOrig.isEmpty()) + horizonMap = StelApp::getInstance().getTextureManager().createTextureThread(horizonMapFileOrig, StelTexture::StelTextureParams(true, GL_LINEAR, GL_REPEAT)); } void Planet::replaceTexture(const QString &texName) @@ -2968,6 +2983,7 @@ void Planet::PlanetShaderVars::initLocations(QOpenGLShaderProgram* p) GL(earthShadow = p->uniformLocation("earthShadow")); GL(eclipsePush = p->uniformLocation("eclipsePush")); GL(normalMap = p->uniformLocation("normalMap")); + GL(horizonMap = p->uniformLocation("horizonMap")); // Rings-specific variables GL(isRing = p->uniformLocation("isRing")); @@ -3979,6 +3995,8 @@ void Planet::drawSphere(StelPainter* painter, float screenRd, bool drawOnlyRing) GL(moonShaderProgram->setUniformValue(moonShaderVars.eclipsePush, push)); // constant for now... } + GL(horizonMap->bind(4)); + GL(moonShaderProgram->setUniformValue(moonShaderVars.horizonMap, 4)); } if (englishName=="Mars") diff --git a/src/core/modules/Planet.hpp b/src/core/modules/Planet.hpp index 4738d537da297f..dc5254776b5d48 100644 --- a/src/core/modules/Planet.hpp +++ b/src/core/modules/Planet.hpp @@ -165,6 +165,7 @@ class Planet : public StelObject float roughness, const QString& texMapName, const QString& normalMapName, + const QString& ahorizonMapName, const QString& objModelName, posFuncType _coordFunc, Orbit *anOrbitPtr, @@ -698,6 +699,7 @@ class Planet : public StelObject QString nativeNameMeaningI18n; // Can be used in a skyculture QString texMapName; // Texture file path QString normalMapName; // Texture file path + QString horizonMapName; // Texture file path RotationElements re; // Rotation and axis orientation parameters double siderealPeriod; // sidereal period (Planet year or a moon's sidereal month) [earth days] double equatorialRadius; // Planet's equatorial radius in AU @@ -732,6 +734,7 @@ class Planet : public StelObject // i.e. angle between ascending node of body equator w.r.t. ICRF equator and its prime meridian. StelTextureSP texMap; // Planet map texture StelTextureSP normalMap; // Planet normal map texture + StelTextureSP horizonMap; // Planet horizon map texture PlanetOBJModel* objModel; // Planet model (when it has been loaded) QFuture* objModelLoader;// For async loading of the OBJ file @@ -782,6 +785,7 @@ class Planet : public StelObject // File path for texture and normal map; both variables used for saving original names of files QString texMapFileOrig; QString normalMapFileOrig; + QString horizonMapFileOrig; std::unique_ptr sphereVAO; std::unique_ptr ringsVAO; @@ -823,6 +827,7 @@ class Planet : public StelObject int earthShadow; int eclipsePush; // apparent brightness push for partial Lunar Eclipse (make bright rim overbright) int normalMap; + int horizonMap; // Rings-specific variables int isRing; diff --git a/src/core/modules/SolarSystem.cpp b/src/core/modules/SolarSystem.cpp index f6b34c4ad837c6..fe61ed1b666c64 100644 --- a/src/core/modules/SolarSystem.cpp +++ b/src/core/modules/SolarSystem.cpp @@ -984,6 +984,7 @@ bool SolarSystem::loadPlanets(const QString& filePath) const bool hidden = pd.value(secname+"/hidden", false).toBool(); const QString normalMapName = ( hidden ? "" : englishName.toLower().append("_normals.png")); // no normal maps for invisible objects! + const QString horizonMapName = ( hidden ? "" : englishName.toLower().append("_normals.png")); // no normal maps for invisible objects! newP = PlanetP(new MinorPlanet(englishName, pd.value(secname+"/radius", 1.0).toDouble()/AU, @@ -993,6 +994,7 @@ bool SolarSystem::loadPlanets(const QString& filePath) pd.value(secname+"/roughness",0.9f).toFloat(), pd.value(secname+"/tex_map", "nomap.png").toString(), pd.value(secname+"/normals_map", normalMapName).toString(), + pd.value(secname+"/horizon_map", horizonMapName).toString(), pd.value(secname+"/model").toString(), posfunc, static_cast(orbitPtr), // the KeplerOrbit object created previously @@ -1072,6 +1074,7 @@ bool SolarSystem::loadPlanets(const QString& filePath) pd.value(secname+"/roughness",0.9f).toFloat(), pd.value(secname+"/tex_map", "nomap.png").toString(), pd.value(secname+"/normals_map", englishName.toLower().append("_normals.png")).toString(), + pd.value(secname+"/horizon_map", englishName.toLower().append("_horizon.png")).toString(), pd.value(secname+"/model").toString(), posfunc, static_cast(orbitPtr), // This remains Q_NULLPTR for the major planets, or has a KeplerOrbit for planet moons. diff --git a/textures/moon_horizon.png b/textures/moon_horizon.png new file mode 100644 index 00000000000000..81926d796b92b3 Binary files /dev/null and b/textures/moon_horizon.png differ diff --git a/textures/moon_normals.png b/textures/moon_normals.png index 1ddd86cbfe98b7..c5cbfb730f171b 100644 Binary files a/textures/moon_normals.png and b/textures/moon_normals.png differ