diff --git a/CMakeLists.txt b/CMakeLists.txt index e3fa40e3..24f9f68c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -150,6 +150,7 @@ owds_add_ros_library(overworld_utility_lib src/Utils/YamlReader.cpp src/Utils/Ontology.cpp src/Utils/XmlTokenize.cpp + src/Utils/SolarAzEl.cpp # src/Utils/RosFiles.cpp src/Utils/Wavefront.cpp) diff --git a/include/overworld/Engine/Common/Lights/AmbientLight.h b/include/overworld/Engine/Common/Lights/AmbientLight.h index 0aae01df..a4550228 100644 --- a/include/overworld/Engine/Common/Lights/AmbientLight.h +++ b/include/overworld/Engine/Common/Lights/AmbientLight.h @@ -1,8 +1,16 @@ #ifndef OWDS_COMMON_AMBIENT_LIGHT_H #define OWDS_COMMON_AMBIENT_LIGHT_H +#include +#include +#include +#include #include #include +#include +#include + +#include "overworld/Utils/SolarAzEl.h" namespace owds { @@ -24,11 +32,54 @@ namespace owds { computeSpecular(); } + AmbientLight(const std::array& lat_long_alt, + const glm::vec3& color = glm::vec3(1.0), + float ambient_strength = 1.0f, + float diffuse_strength = 1.0f, + float specular_strength = 1.0f) : color_(glm::vec4(color, 1.0f)), + ambient_strength_(ambient_strength), + diffuse_strength_(diffuse_strength), + specular_strength_(specular_strength), + latitude_(lat_long_alt[0]), + longitude_(lat_long_alt[1]), + altitude_(lat_long_alt[2]) + + { + double el = 0., az = 0.; + solarAzEl(time(0), latitude_, longitude_, altitude_, &az, &el); + setElevationAndAzimuth(glm::radians(el), glm::radians(az)); + computeAmbient(); + computeDiffuse(); + computeSpecular(); + } + void setDirection(const glm::vec3& direction) { direction_ = glm::vec4(direction, 1.0f); } + void setElevationAndAzimuth(float elevation, float azimuth) + { + float x = std::cos(elevation) * std::sin(azimuth); + float y = std::cos(elevation) * std::cos(azimuth); + float z = std::sin(elevation); + setDirection(glm::vec3(y, -x, -z)); + + if(z < 0) + { + diffuse_strength_ = 0.; + specular_strength_ = 0.; + color_ = glm::vec4(0.31, 0.435f, 0.78f, 1.f); + } + else if(z < 1.) + { + auto night_color = glm::vec4(0.31, 0.435f, 0.78f, 1.f); + color_ = z * color_ + night_color * (1.f - z); + diffuse_strength_ = z; + specular_strength_ = z; + } + } + void setColor(const glm::vec3& color) { color_ = glm::vec4(color, 1.0f); @@ -68,6 +119,10 @@ namespace owds { float diffuse_strength_; float specular_strength_; + float latitude_; + float longitude_; + float altitude_; + glm::vec4 ambient_; glm::vec4 diffuse_; glm::vec4 specular_; diff --git a/include/overworld/Utils/SolarAzEl.h b/include/overworld/Utils/SolarAzEl.h new file mode 100644 index 00000000..445f607c --- /dev/null +++ b/include/overworld/Utils/SolarAzEl.h @@ -0,0 +1,8 @@ +#ifndef OWDS_SOLARAZEL_H +#define OWDS_SOLARAZEL_H + +#include + +void solarAzEl(time_t utc_time_point, double Lat, double Lon, double Alt, double* Az, double* El); + +#endif // OWDS_SOLARAZEL_H \ No newline at end of file diff --git a/src/Engine/Common/World.cpp b/src/Engine/Common/World.cpp index 23bd6a46..3f6dc756 100755 --- a/src/Engine/Common/World.cpp +++ b/src/Engine/Common/World.cpp @@ -250,7 +250,7 @@ namespace owds { float diffuse_strength, float specular_strength) { - ambient_light_ = AmbientLight(glm::vec3(direction[0], direction[1], direction[2]), + ambient_light_ = AmbientLight(direction, glm::vec3(color[0], color[1], color[2]), ambient_strength, diffuse_strength, specular_strength); } diff --git a/src/Nodes/TestOpengl.cpp b/src/Nodes/TestOpengl.cpp index d28388ab..8e1e2a7b 100644 --- a/src/Nodes/TestOpengl.cpp +++ b/src/Nodes/TestOpengl.cpp @@ -60,7 +60,7 @@ void worldThread(const std::string& world_name, owds::Window* window) { std::cout << world_name << std::endl; auto& cam = window->getCamera(); - cam.setFieldOfView(80.f); + cam.setFieldOfView(60.f); cam.setOutputAA(owds::ViewAntiAliasing_e::msaa_x4); cam.setOutputResolution({640, 480}); cam.setPositionAndLookAt({6, 6, 1.7}, {0, 0, 0}); @@ -74,7 +74,7 @@ void worldThread(const std::string& world_name, owds::Window* window) std::cout << "================== WORLD " << world_name << " CREATED ! ================" << std::endl; - world.setAmbientLight({0.5f, 0.2f, -0.3f}, + world.setAmbientLight({48.f, -2.f, 0.f}, {1.0f, 0.976f, 0.898f}, 0.25, 0.4, 0.8); diff --git a/src/Utils/SolarAzEl.cpp b/src/Utils/SolarAzEl.cpp new file mode 100644 index 00000000..a7503230 --- /dev/null +++ b/src/Utils/SolarAzEl.cpp @@ -0,0 +1,146 @@ +/* +Copyright(c) 2010, Darin Koblick +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met : + +*Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "overworld/Utils/SolarAzEl.h" + +#include +#include +#include + +#ifndef M_PI +#define M_PI (3.14159265358979323846264338327950288) +#endif /* M_PI */ + +double julian_day(time_t utc_time_point); + +void solarAzEl(time_t utc_time_point, double Lat, double Lon, double Alt, double* Az, double* El) +{ + double jd = julian_day(utc_time_point); + + double d = jd - 2451543.5; + + // Keplerian Elements for the Sun(geocentric) + double w = 282.9404 + 4.70935e-5 * d; // (longitude of perihelion degrees) + // a = 1.000000; % (mean distance, a.u.) + double e = 0.016709 - 1.151e-9 * d; // (eccentricity) + double M = fmod(356.0470 + 0.9856002585 * d, 360.0); // (mean anomaly degrees) + + double L = w + M; // (Sun's mean longitude degrees) + + double oblecl = 23.4393 - 3.563e-7 * d; // (Sun's obliquity of the ecliptic) + + // auxiliary angle + double E = M + (180 / M_PI) * e * sin(M * (M_PI / 180)) * (1 + e * cos(M * (M_PI / 180))); + + // rectangular coordinates in the plane of the ecliptic(x axis toward perhilion) + double x = cos(E * (M_PI / 180)) - e; + double y = sin(E * (M_PI / 180)) * sqrt(1 - pow(e, 2)); + + // find the distance and true anomaly + double r = sqrt(pow(x, 2) + pow(y, 2)); + double v = atan2(y, x) * (180 / M_PI); + + // find the longitude of the sun + double lon = v + w; + + // compute the ecliptic rectangular coordinates + double xeclip = r * cos(lon * (M_PI / 180)); + double yeclip = r * sin(lon * (M_PI / 180)); + double zeclip = 0.0; + // rotate these coordinates to equitorial rectangular coordinates + double xequat = xeclip; + + double yequat = yeclip * cos(oblecl * (M_PI / 180)) + zeclip * sin(oblecl * (M_PI / 180)); + + double zequat = yeclip * sin(23.4406 * (M_PI / 180)) + zeclip * cos(oblecl * (M_PI / 180)); + // convert equatorial rectangular coordinates to RA and Decl: + r = sqrt(pow(xequat, 2) + pow(yequat, 2) + pow(zequat, 2)) - (Alt / 149598000); // roll up the altitude correction + double RA = atan2(yequat, xequat) * (180 / M_PI); + + double delta = asin(zequat / r) * (180 / M_PI); + + // Following the RA DEC to Az Alt conversion sequence explained here : + // http ://www.stargazing.net/kepler/altaz.html + // Find the J2000 value + // J2000 = jd - 2451545.0; + // hourvec = datevec(UTC); + // UTH = hourvec(:, 4) + hourvec(:, 5) / 60 + hourvec(:, 6) / 3600; + + // Get UTC representation of time / C++ Specific + tm* ptm; + ptm = gmtime(&utc_time_point); + double UTH = (double)ptm->tm_hour + (double)ptm->tm_min / 60 + (double)ptm->tm_sec / 3600; + + // Calculate local siderial time + double GMST0 = fmod(L + 180, 360.0) / 15; + + double SIDTIME = GMST0 + UTH + Lon / 15; + + // Replace RA with hour angle HA + double HA = (SIDTIME * 15 - RA); + + // convert to rectangular coordinate system + x = cos(HA * (M_PI / 180)) * cos(delta * (M_PI / 180)); + + y = sin(HA * (M_PI / 180)) * cos(delta * (M_PI / 180)); + double z = sin(delta * (M_PI / 180)); + + // rotate this along an axis going east - west. + double xhor = x * cos((90 - Lat) * (M_PI / 180)) - z * sin((90 - Lat) * (M_PI / 180)); + + double yhor = y; + double zhor = x * sin((90 - Lat) * (M_PI / 180)) + z * cos((90 - Lat) * (M_PI / 180)); + + // Find the h and AZ + *Az = atan2(yhor, xhor) * (180 / M_PI) + 180; + *El = asin(zhor) * (180 / M_PI); +} + +double julian_day(time_t utc_time_point) +{ + // Extract UTC Time + struct tm* tm = gmtime(&utc_time_point); + + double year = tm->tm_year + 1900; + double month = tm->tm_mon + 1; + double day = tm->tm_mday; + double hour = tm->tm_hour; + double min = tm->tm_min; + double sec = tm->tm_sec; + + if(month <= 2) + { + year -= 1; + month += 12; + } + + double jd = floor(365.25 * (year + 4716.0)) + floor(30.6001 * (month + 1.0)) + 2.0 - + floor(year / 100.0) + floor(floor(year / 100.0) / 4.0) + day - 1524.5 + + (hour + min / 60 + sec / 3600) / 24; + + return jd; +}