forked from aya/aya
Initial commit
This commit is contained in:
207
engine/3d/src/LightingParameters.cpp
Normal file
207
engine/3d/src/LightingParameters.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
@file LightingParameters.cpp
|
||||
|
||||
@maintainer Morgan McGuire, matrix@graphics3d.com
|
||||
@created 2002-10-05
|
||||
@edited 2006-06-28
|
||||
*/
|
||||
|
||||
#include "LightingParameters.hpp"
|
||||
#include "Matrix3.hpp"
|
||||
#include "spline.hpp"
|
||||
#include "GLight.hpp"
|
||||
#include <sys/timeb.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
} // namespace G3D
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
Reference in New Issue
Block a user