Files
2025-09-18 17:55:52 -04:00

193 lines
8.2 KiB
C++

/*
@file LightingParameters.cpp
@maintainer Morgan McGuire, matrix@graphics3d.com
@created 2002-10-05
@edited 2006-06-28
*/
#include "G3D/LightingParameters.h"
#include "G3D/Matrix3.h"
#include "G3D/spline.h"
#include "G3D/GLight.h"
#ifdef RBX_PLATFORM_ANDROID
#include <G3D/android_time.h>
#else
#include <sys/timeb.h>
#endif
#include <sys/types.h>
#ifndef _MSC_VER
#define _timeb timeb
#define _ftime ftime
#endif
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4305)
#endif
namespace G3D {
static const double sunRiseAndSetTime = HOUR / 2;
static const double solarYear = 365.2564*DAY;
static const double halfSolarYear = 182.6282;
static const double moonPhaseInterval = DAY*29.53;
// Tilt amount from the ecliptic
static const double earthTilt = toRadians(23.5);
static const double moonTilt = toRadians(5);
// (very rough) Initial star offset on Jan 1 1970 midnight
static const double initialStarRot = 1;
// Initial moon phase on Jan 1 1970 midnight
static const double initialMoonPhase = 0.75;
LightingParameters::LightingParameters() {
physicallyCorrect = true;
setLatitude(BROWN_UNIVERSITY_LATITUDE);
setTime(0);
}
LightingParameters::LightingParameters(
const GameTime _time,
bool _physicallyCorrect,
float _latitude) {
physicallyCorrect = _physicallyCorrect;
setLatitude(_latitude);
setTime(_time);
}
void LightingParameters::setLatitude(float _latitude) {
geoLatitude = _latitude;
}
void LightingParameters::setTime(const GameTime _time) {
// wrap to a 1 day interval
double time = _time - floor(_time / DAY) * DAY;
// Calculate starfield coordinate frame
double starRot = initialStarRot - (2*G3D::pi()*(_time - (_time*floor(_time / SIDEREAL_DAY)))/SIDEREAL_DAY);
float aX, aY, aZ;
starVec.x = cos(starRot);
starVec.y = 0;
starVec.z = sin(starRot);
starFrame.lookAt(starVec, Vector3::unitY());
trueStarFrame.lookAt(starVec, Vector3::unitY());
trueStarFrame.rotation.toEulerAnglesXYZ(aX, aY, aZ);
aX -= geoLatitude;
trueStarFrame.rotation = Matrix3::fromEulerAnglesXYZ(aX, aY, aZ);
// sunAngle = 0 at midnight
float sourceAngle = 2 * (float)G3D::pi() * time / DAY;
// Calculate fake solar and lunar positions
sunPosition.x = sin(sourceAngle);
sunPosition.y = -cos(sourceAngle);
sunPosition.z = 0;
moonPosition.x = sin(sourceAngle + (float)G3D::pi());
moonPosition.y = -cos(sourceAngle + (float)G3D::pi());
moonPosition.z = 0;
// Calculate "true" solar and lunar positions
// These positions will always be somewhat wrong
// unless _time is equal to real world GMT time,
// and the current longitude is equal to zero. Also,
// I'm assuming that the equinox-solstice interval
// occurs exactly every 90 days, which isn't exactly
// correct.
// In addition, the precession of the moon's orbit is
// not taken into account, but this should only account
// for a 5 degree margin of error at most.
float dayOfYearOffset = (_time - (_time*floor(_time / solarYear)))/DAY;
moonPhase = floor(_time / moonPhaseInterval) + initialMoonPhase;
float latRad = toRadians(geoLatitude);
float sunOffset = -earthTilt*cos(G3D::pi()*(dayOfYearOffset-halfSolarYear)/halfSolarYear) - latRad;
float moonOffset = ((-earthTilt+moonTilt)*sin(moonPhase*4)) - latRad;
float curMoonPhase = (moonPhase*G3D::pi()*2);
Matrix3 rotMat = Matrix3::fromAxisAngle(Vector3::unitZ().cross(sunPosition), sunOffset);
trueSunPosition = rotMat * sunPosition;
Vector3 trueMoon = Vector3(sin(curMoonPhase + sourceAngle),
-cos(curMoonPhase + sourceAngle),
0);
rotMat = Matrix3::fromAxisAngleFast(Vector3::unitZ().cross(trueMoon), moonOffset);
trueMoonPosition = rotMat * trueMoon;
// Determine which light source we observe.
if (!physicallyCorrect) {
if ((sourceAngle < (G3D::pi() / 2)) || (sourceAngle > (3 * G3D::pi() / 2))) {
source = MOON;
sourceAngle += (float)G3D::pi();
} else {
source = SUN;
}
lightDirection.x = sin(sourceAngle);
lightDirection.y = -cos(sourceAngle);
lightDirection.z = 0;
} else if (trueSunPosition.y > -.3f) {
// The sun is always the stronger light source. When using
// physically correct parameters, the sun and moon will
// occasionally be in the visible sky at the same time.
source = SUN;
lightDirection = trueSunPosition;
} else {
source = MOON;
lightDirection = trueMoonPosition;
}
const Color3 dayAmbient = Color3::white() * .40f;
const Color3 dayDiffuse = Color3::white() * .75f;
{
static const double times[] = {MIDNIGHT, SUNRISE - HOUR, SUNRISE, SUNRISE + sunRiseAndSetTime / 4, SUNRISE + sunRiseAndSetTime, SUNSET - sunRiseAndSetTime, SUNSET - sunRiseAndSetTime / 2, SUNSET, SUNSET + HOUR/2, DAY};
static const Color3 color[] = {Color3(.2f, .2f, .2f), Color3(.1f, .1, .1), Color3(0,0,0), Color3(.6, .6, 0), dayDiffuse, dayDiffuse, Color3(.1, .1, .075), Color3(.1, .05, .05), Color3(.1, .1, .1), Color3(.2, .2, .2)};
lightColor = linearSpline(time, times, color, 10);
}
{
static const double times[] = {MIDNIGHT, SUNRISE - HOUR, SUNRISE, SUNRISE + sunRiseAndSetTime / 4, SUNRISE + sunRiseAndSetTime, SUNSET - sunRiseAndSetTime, SUNSET - sunRiseAndSetTime / 2, SUNSET, SUNSET + HOUR/2, DAY};
static const Color3 color[] = {Color3(0, .1, .3), Color3(0, .0, .1), Color3(0,0,0), Color3(0,0,0), dayAmbient, dayAmbient, Color3(.5, .2, .2), Color3(.05, .05, .1), Color3(0, .0, .1), Color3(0, .1, .3)};
ambient = linearSpline(time, times, color, 10);
}
{
static const double times[] = {MIDNIGHT, SUNRISE - HOUR, SUNRISE, SUNRISE + sunRiseAndSetTime / 2, SUNRISE + sunRiseAndSetTime, SUNSET - sunRiseAndSetTime, SUNSET - sunRiseAndSetTime / 2, SUNSET, SUNSET + HOUR/2, DAY };
static const Color3 color[] = {Color3(.1, .1, .17), Color3(.05, .06, .07), Color3(.08, .08, .01), Color3(1,1,1) *.75, Color3(1,1,1) * .75, Color3(1,1,1) * .35, Color3(.5, .2, .2), Color3(.05, .05, .1), Color3(.06, .06, .07), Color3(.1, .1, .17)};
diffuseAmbient = linearSpline(time, times, color, 10);
}
{
static const double times[] = {MIDNIGHT, SUNRISE - 2*HOUR, SUNRISE - HOUR, SUNRISE - HOUR/2, SUNRISE, SUNRISE + sunRiseAndSetTime, SUNSET - sunRiseAndSetTime, SUNSET, SUNSET + HOUR/3, DAY};
static const Color3 color[] = {Color3(0,0,0), Color3(0,0,0), Color3(.07,.07,.1), Color3(.2, .15, .01), Color3(.2, .15, .01), Color3(1,1,1), Color3(1,1,1), Color3(.4, .2, .05), Color3(0,0,0), Color3(0,0,0)};
skyAmbient = linearSpline(time, times, color, sizeof(times)/sizeof(times[0]));
}
{
static const double times[] = {MIDNIGHT, SUNRISE - 3 * HOUR, SUNRISE - 2*HOUR, SUNRISE - HOUR/2, SUNRISE, SUNRISE + sunRiseAndSetTime, SUNSET - sunRiseAndSetTime, SUNSET, SUNSET + HOUR/3, SUNSET + 2*HOUR, SUNSET + 3*HOUR, DAY};
static const Color3 color[] = {Color3(0.0,0.0,0.0), 0.7f*Color3(0.0,0.0,0.0), 0.7f*Color3(0.3,0.3,0.4), Color3(0.4, 0.3, 0.3), Color3(0.3, 0.2, 0.3), Color3(1,1,1), Color3(1,1,1), Color3(.4, .3, .2), Color3(0.3,0.2,0.3), Color3(0.3,0.2,0.3), Color3(0,0,0), Color3(0,0,0) };
skyAmbient2 = linearSpline(time, times, color, sizeof(times)/sizeof(times[0]));
}
emissiveScale = Color3::white();
}
GLight LightingParameters::directionalLight() const {
return GLight::directional(lightDirection, lightColor);
}
}
#ifdef _MSC_VER
# pragma warning(pop)
#endif