16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-17 23:39:18 +02:00

minor refactoring, shadows colour influenced by sun/moon positions

This commit is contained in:
tmj-fstate
2017-08-03 16:00:48 +02:00
parent c8a70e5280
commit 238ea7547d
9 changed files with 162 additions and 150 deletions

View File

@@ -3493,18 +3493,6 @@ void
TGround::Update_Lights() {
m_lights.update();
// arrange the light array from closest to farthest from current position of the camera
auto const camera = Global::pCameraPosition;
std::sort(
m_lights.data.begin(),
m_lights.data.end(),
[&]( light_array::light_record const &Left, light_array::light_record const &Right ) {
// move lights which are off at the end...
if( Left.intensity == 0.0f ) { return false; }
if( Right.intensity == 0.0f ) { return true; }
// ...otherwise prefer closer and/or brigher light sources
return ((camera - Left.position).LengthSquared() * (1.0f - Left.intensity)) < ((camera - Right.position).LengthSquared() * (1.0f - Right.intensity));
} );
}
// Winger 170204 - szukanie trakcji nad pantografami

View File

@@ -2220,10 +2220,12 @@ world_environment::update() {
m_sun.update();
m_moon.update();
// ...determine source of key light and adjust global state accordingly...
auto const sunlightlevel = m_sun.getIntensity();
// diffuse (sun) intensity goes down after twilight, and reaches minimum 18 degrees below horizon
float twilightfactor = clamp( -m_sun.getAngle(), 0.0f, 18.0f ) / 18.0f;
// NOTE: sun light receives extra padding to prevent moon from kicking in too soon
auto const sunlightlevel = m_sun.getIntensity() + 0.05f * ( 1.f - twilightfactor );
auto const moonlightlevel = m_moon.getIntensity() * 0.65f; // scaled down by arbitrary factor, it's pretty bright otherwise
float keylightintensity;
float twilightfactor;
glm::vec3 keylightcolor;
if( moonlightlevel > sunlightlevel ) {
// rare situations when the moon is brighter than the sun, typically at night
@@ -2241,8 +2243,7 @@ world_environment::update() {
Global::DayLight.set_position( m_sun.getPosition() );
Global::DayLight.direction = -1.0f * m_sun.getDirection();
keylightintensity = sunlightlevel;
// diffuse (sun) intensity goes down after twilight, and reaches minimum 18 degrees below horizon
twilightfactor = clamp( -Global::SunAngle, 0.0f, 18.0f ) / 18.0f;
// include 'golden hour' effect in twilight lighting
float const duskfactor = 1.0f - clamp( Global::SunAngle, 0.0f, 18.0f ) / 18.0f;
keylightcolor = interpolate(
glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ),

View File

@@ -83,14 +83,6 @@ cFrustum::calculate( glm::mat4 const &Projection, glm::mat4 const &Modelview ) {
m_frustum[ side_FRONT ][ plane_C ] = clip[ 11 ] + clip[ 10 ];
m_frustum[ side_FRONT ][ plane_D ] = clip[ 15 ] + clip[ 14 ];
normalize_plane( side_FRONT );
m_inversetransformation = glm::inverse( Projection * glm::mat4{ glm::mat3{ Modelview } } );
// calculate frustum corners
m_frustumpoints = ndcfrustumshapepoints;
transform_to_world(
std::begin( m_frustumpoints ),
std::end( m_frustumpoints ) );
}
bool
@@ -177,19 +169,6 @@ cFrustum::cube_inside( float const X, float const Y, float const Z, float const
return true;
}
std::vector<std::size_t> const frustumshapepoinstorder{ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 };
// debug helper, draws shape of frustum in world space
void
cFrustum::draw( glm::vec3 const &Offset ) const {
::glBegin( GL_LINES );
for( auto const pointindex : frustumshapepoinstorder ) {
::glVertex3fv( glm::value_ptr( glm::vec3{ m_frustumpoints[ pointindex ] } - Offset ) );
}
::glEnd();
}
void cFrustum::normalize_plane( cFrustum::side const Side ) {
float magnitude =

View File

@@ -12,10 +12,12 @@ http://mozilla.org/MPL/2.0/.
#include "float3d.h"
#include "dumb3d.h"
std::vector<glm::vec4> const ndcfrustumshapepoints = {
std::vector<glm::vec4> const ndcfrustumshapepoints {
{ -1, -1, -1, 1 },{ 1, -1, -1, 1 },{ 1, 1, -1, 1 },{ -1, 1, -1, 1 }, // z-near
{ -1, -1, 1, 1 },{ 1, -1, 1, 1 },{ 1, 1, 1, 1 },{ -1, 1, 1, 1 } }; // z-far
std::vector<std::size_t> const frustumshapepoinstorder { 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 };
// generic frustum class. used to determine if objects are inside current view area
class cFrustum {
@@ -65,23 +67,6 @@ public:
cube_inside( Math3D::vector3 const &Center, float const Size ) const { return cube_inside( static_cast<float>( Center.x ), static_cast<float>( Center.y ), static_cast<float>( Center.z ), Size ); }
bool
cube_inside( float const X, float const Y, float const Z, float const Size ) const;
// transforms provided set of clip space points to world space
template <class Iterator_>
void
transform_to_world( Iterator_ First, Iterator_ Last ) const {
std::for_each(
First, Last,
[this]( glm::vec4 &point ) {
// transform each point using the cached matrix...
point = this->m_inversetransformation * point;
// ...and scale by transformed w
point = glm::vec4{ glm::vec3{ point } / point.w, 1.f }; } ); }
// debug helper, draws shape of frustum in world space
void
draw( glm::vec3 const &Offset ) const;
// members:
std::vector<glm::vec4> m_frustumpoints; // coordinates of corners for defined frustum, in world space
private:
// types:
@@ -96,5 +81,4 @@ private:
// members:
float m_frustum[6][4]; // holds the A B C and D values (normal & distance) for each side of the frustum.
glm::mat4 m_inversetransformation; // cached inverse transformation matrix
};

View File

@@ -60,10 +60,10 @@ light_array::update() {
if( ( true == light.owner->MoverParameters->Battery ) || ( true == light.owner->MoverParameters->ConverterFlag ) ) {
// with power on, the intensity depends on the state of activated switches
auto const &lightbits = light.owner->iLights[ light.index ];
light.count = 0 +
( ( lightbits & 1 ) ? 1 : 0 ) +
( ( lightbits & 4 ) ? 1 : 0 ) +
( ( lightbits & 16 ) ? 1 : 0 );
light.count = 0
+ ( ( lightbits & TMoverParameters::light::headlight_left ) ? 1 : 0 )
+ ( ( lightbits & TMoverParameters::light::headlight_right ) ? 1 : 0 )
+ ( ( lightbits & TMoverParameters::light::headlight_upper ) ? 1 : 0 );
if( light.count > 0 ) {
// TODO: intensity can be affected further by dim switch or other factors

View File

@@ -19,9 +19,9 @@ public:
TDynamicObject const *owner; // the object in world which 'carries' the light
int index{ -1 }; // 0: front lights, 1: rear lights
Math3D::vector3 position; // position of the light in 3d scene
glm::dvec3 position; // position of the light in 3d scene
glm::vec3 direction; // direction of the light in 3d scene
float3 color{ 255.0f / 255.0f, 241.0f / 255.0f, 224.0f / 255.0f }; // color of the light, default is halogen light
glm::vec3 color{ 255.0f / 255.0f, 241.0f / 255.0f, 224.0f / 255.0f }; // color of the light, default is halogen light
float intensity{ 0.0f }; // (combined) intensity of the light(s)
int count{ 0 }; // number (or pattern) of active light(s)
};

View File

@@ -34,6 +34,20 @@ glm::vec4 const white{ 1.f, 1.f, 1.f, 1.f };
} // namespace colors
void
opengl_camera::update_frustum( glm::mat4 const &Projection, glm::mat4 const &Modelview ) {
m_frustum.calculate( Projection, Modelview );
// cache inverse tranformation matrix
// NOTE: transformation is done only to camera-centric space
m_inversetransformation = glm::inverse( Projection * glm::mat4{ glm::mat3{ Modelview } } );
// calculate frustum corners
m_frustumpoints = ndcfrustumshapepoints;
transform_to_world(
std::begin( m_frustumpoints ),
std::end( m_frustumpoints ) );
}
// returns true if specified object is within camera frustum, false otherwise
bool
opengl_camera::visible( bounding_area const &Area ) const {
@@ -55,6 +69,17 @@ opengl_camera::visible( TDynamicObject const *Dynamic ) const {
return ( m_frustum.sphere_inside( Dynamic->GetPosition(), radius ) > 0.0f );
}
// debug helper, draws shape of frustum in world space
void
opengl_camera::draw( glm::vec3 const &Offset ) const {
::glBegin( GL_LINES );
for( auto const pointindex : frustumshapepoinstorder ) {
::glVertex3fv( glm::value_ptr( glm::vec3{ m_frustumpoints[ pointindex ] } - Offset ) );
}
::glEnd();
}
bool
opengl_renderer::Init( GLFWwindow *Window ) {
@@ -251,15 +276,16 @@ opengl_renderer::Render() {
m_drawtime = std::max( 20.f, 0.95f * m_drawtime + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - m_drawstart ) ).count() / 1000.f );
}
m_drawstart = std::chrono::steady_clock::now();
auto const drawstartcolor = m_drawstart;
auto const drawstartcolorpass = m_drawstart;
m_renderpass.draw_mode = rendermode::none; // force setup anew
m_debuginfo.clear();
Render_pass( rendermode::color );
m_drawcount = m_drawqueue.size();
// accumulate last 20 frames worth of render time (cap at 1000 fps to prevent calculations going awry)
m_drawtimecolor = std::max( 20.f, 0.95f * m_drawtimecolor + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - drawstartcolor ) ).count() / 1000.f );
m_debuginfo += " frame total: " + to_string( m_drawtimecolor / 20.f, 2 ) + " msec (" + std::to_string( m_drawqueue.size() ) + " sectors)";
m_drawtimecolorpass = std::max( 20.f, 0.95f * m_drawtimecolorpass + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - drawstartcolorpass ) ).count() / 1000.f );
m_debuginfo += "frame total: " + to_string( m_drawtimecolorpass / 20.f, 2 ) + " msec (" + std::to_string( m_drawqueue.size() ) + " sectors) ";
glfwSwapBuffers( m_window );
@@ -270,25 +296,26 @@ opengl_renderer::Render() {
void
opengl_renderer::Render_pass( rendermode const Mode ) {
m_renderpass.setup( Mode, m_framebuffersupport );
setup_pass( m_renderpass, Mode );
switch( m_renderpass.draw_mode ) {
case rendermode::color: {
opengl_camera shadowcamera; // temporary helper, remove once ortho shadowmap code is done
if( Global::RenderShadows && World.InitPerformed() ) {
if( ( true == Global::RenderShadows )
&& ( true == World.InitPerformed() )
&& ( m_shadowcolor != colors::white ) ) {
// run shadowmap pass before color
Render_pass( rendermode::shadows );
#ifdef EU07_USE_DEBUG_SHADOWMAP
UILayer.set_texture( m_shadowdebugtexture );
#endif
shadowcamera = m_renderpass.camera; // cache shadow camera placement for visualization
m_renderpass.setup( rendermode::color, m_framebuffersupport ); // restore draw mode. TBD, TODO: render mode stack
setup_pass( m_renderpass, Mode ); // restore draw mode. TBD, TODO: render mode stack
#ifdef EU07_USE_DEBUG_CAMERA
m_worldcamera.setup(
setup_pass(
m_worldcamera,
rendermode::color,
m_framebuffersupport,
0.f,
std::min(
1.f,
@@ -337,10 +364,10 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
::glColor4f( 1.f, 0.9f, 0.8f, 1.f );
::glDisable( GL_LIGHTING );
::glDisable( GL_TEXTURE_2D );
shadowcamera.frustum().draw( m_renderpass.camera.position() - shadowcamera.position() );
shadowcamera.draw( m_renderpass.camera.position() - shadowcamera.position() );
if( DebugCameraFlag ) {
::glColor4f( 0.8f, 1.f, 0.9f, 1.f );
m_worldcamera.camera.frustum().draw( m_renderpass.camera.position() - m_worldcamera.camera.position() );
m_worldcamera.camera.draw( m_renderpass.camera.position() - m_worldcamera.camera.position() );
}
::glLineWidth( 1.f );
::glEnable( GL_LIGHTING );
@@ -397,8 +424,8 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
::glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 ); // switch back to primary render target
m_drawtimeshadows = 0.95f * m_drawtimeshadows + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - shadowdrawstart ) ).count() / 1000.f;
m_debuginfo = "shadows: " + to_string( m_drawtimeshadows / 20.f, 2 ) + " msec (" + std::to_string( m_drawqueue.size() ) + " sectors)";
m_drawtimeshadowpass = 0.95f * m_drawtimeshadowpass + std::chrono::duration_cast<std::chrono::microseconds>( ( std::chrono::steady_clock::now() - shadowdrawstart ) ).count() / 1000.f;
m_debuginfo += "shadows: " + to_string( m_drawtimeshadowpass / 20.f, 2 ) + " msec (" + std::to_string( m_drawqueue.size() ) + " sectors) ";
}
break;
}
@@ -453,27 +480,29 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
}
void
opengl_renderer::renderpass_config::setup( rendermode const Mode, bool const Framebuffersupport, float const Znear, float const Zfar, bool const Ignoredebug ) {
opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, float const Znear, float const Zfar, bool const Ignoredebug ) {
draw_mode = Mode;
Config.draw_mode = Mode;
if( false == World.InitPerformed() ) { return; }
switch( draw_mode ) {
case rendermode::color: { draw_range = Global::BaseDrawRange; break; }
case rendermode::shadows: { draw_range = Global::BaseDrawRange * 0.5f; break; }
case rendermode::pickcontrols: { draw_range = 50.f; break; }
case rendermode::pickscenery: { draw_range = Global::BaseDrawRange * 0.5f; break; }
default: { draw_range = 0.f; break; }
// setup draw range
switch( Mode ) {
case rendermode::color: { Config.draw_range = Global::BaseDrawRange; break; }
case rendermode::shadows: { Config.draw_range = Global::BaseDrawRange * 0.5f; break; }
case rendermode::pickcontrols: { Config.draw_range = 50.f; break; }
case rendermode::pickscenery: { Config.draw_range = Global::BaseDrawRange * 0.5f; break; }
default: { Config.draw_range = 0.f; break; }
}
// setup camera
auto &camera = Config.camera;
camera.projection() = glm::mat4( 1.f );
glm::dmat4 viewmatrix( 1.0 );
switch( draw_mode ) {
switch( Mode ) {
case rendermode::color: {
// projection
auto const zfar = draw_range * Global::fDistanceFactor * Zfar;
auto const zfar = Config.draw_range * Global::fDistanceFactor * Zfar;
auto const znear = (
Znear > 0.f ?
Znear * zfar :
@@ -498,33 +527,29 @@ opengl_renderer::renderpass_config::setup( rendermode const Mode, bool const Fra
case rendermode::shadows: {
// calculate lightview boundaries based on relevant area of the world camera frustum:
// setup chunk of frustum we're interested in...
// ...setup chunk of frustum we're interested in...
auto const znear = 0.f;
auto const zfar = std::min( 1.f, Global::shadowtune.depth / ( Global::BaseDrawRange * Global::fDistanceFactor ) * std::max( 1.f, Global::ZoomFactor * 0.5f ) );
renderpass_config worldview;
worldview.setup( rendermode::color, Framebuffersupport, znear, zfar, true );
// ...transform frustum shape to camera-centric world space...
auto frustumchunkshapepoints = ndcfrustumshapepoints;
worldview.camera.frustum().transform_to_world( std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) );
// ...determine the centre of frustum chunk in world space...
setup_pass( worldview, rendermode::color, znear, zfar, true );
auto &frustumchunkshapepoints = worldview.camera.frustum_points();
// ...modelview matrix: determine the centre of frustum chunk in world space...
glm::vec3 frustumchunkmin, frustumchunkmax;
bounding_box( frustumchunkmin, frustumchunkmax, std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) );
auto const frustumchunkcentre = ( frustumchunkmin + frustumchunkmax ) * 0.5f;
auto const lighttarget = worldview.camera.position() + glm::dvec3{ frustumchunkcentre };
// ...cap the vertical angle to keep shadows from getting too long...
auto const lightvector =
glm::normalize( glm::vec3{
-Global::DayLight.direction.x,
std::max( -Global::DayLight.direction.y, 0.15f ),
-Global::DayLight.direction.z } );
// ...place the light source at the calculated centre...
camera.position() = lighttarget;// -glm::dvec3{ lightvector };
// ...setup world space light view matrix...
Global::DayLight.direction.x,
std::min( Global::DayLight.direction.y, -0.15f ),
Global::DayLight.direction.z } );
// ...place the light source at the calculated centre and setup world space light view matrix...
camera.position() = worldview.camera.position() + glm::dvec3{ frustumchunkcentre };
viewmatrix *= glm::lookAt(
camera.position(),
camera.position() - glm::dvec3{ lightvector },
camera.position() + glm::dvec3{ lightvector },
glm::dvec3{ 0.f, 1.f, 0.f } );
// ...calculate boundaries of the frustum chunk in light space...
// ...projection matrix: calculate boundaries of the frustum chunk in light space...
auto const lightviewmatrix =
glm::translate(
glm::mat4{ glm::mat3{ viewmatrix } },
@@ -547,7 +572,7 @@ opengl_renderer::renderpass_config::setup( rendermode const Mode, bool const Fra
case rendermode::pickscenery: {
// TODO: scissor test for pick modes
// projection
if( true == Framebuffersupport ) {
if( true == m_framebuffersupport ) {
auto const angle = Global::FieldOfView / Global::ZoomFactor;
auto const height = std::max( 1.0f, (float)Global::iWindowWidth ) / std::max( 1.0f, (float)Global::iWindowHeight ) / ( Global::iWindowWidth / EU07_PICKBUFFERSIZE );
camera.projection() *=
@@ -555,7 +580,7 @@ opengl_renderer::renderpass_config::setup( rendermode const Mode, bool const Fra
glm::radians( Global::FieldOfView / Global::ZoomFactor ),
std::max( 1.f, (float)Global::iWindowWidth ) / std::max( 1.0f, (float)Global::iWindowHeight ) / ( Global::iWindowWidth / EU07_PICKBUFFERSIZE ),
0.1f * Global::ZoomFactor,
draw_range * Global::fDistanceFactor );
Config.draw_range * Global::fDistanceFactor );
}
else {
camera.projection() *=
@@ -563,7 +588,7 @@ opengl_renderer::renderpass_config::setup( rendermode const Mode, bool const Fra
glm::radians( Global::FieldOfView / Global::ZoomFactor ),
std::max( 1.f, (float)Global::iWindowWidth ) / std::max( 1.f, (float)Global::iWindowHeight ),
0.1f * Global::ZoomFactor,
draw_range * Global::fDistanceFactor );
Config.draw_range * Global::fDistanceFactor );
}
// modelview
camera.position() = Global::pCameraPosition;
@@ -681,7 +706,9 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
// shadow texture unit.
// interpolates between primary colour and the previous unit, which should hold darkened variant of the primary colour
if( m_shadowtextureunit >= 0 ) {
if( ( true == Global::RenderShadows ) && ( true == Shadows ) ) {
if( ( true == Global::RenderShadows )
&& ( true == Shadows )
&& ( m_shadowcolor != colors::white ) ) {
::glActiveTexture( m_shadowtextureunit );
::glBindTexture( GL_TEXTURE_2D, m_shadowtexture );
@@ -756,7 +783,9 @@ void
opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool const Reflections ) {
// helper texture unit.
if( m_helpertextureunit >= 0 ) {
if( ( true == Global::RenderShadows ) && ( true == Shadows ) ) {
if( ( true == Global::RenderShadows )
&& ( true == Shadows )
&& ( m_shadowcolor != colors::white ) ) {
::glActiveTexture( m_helpertextureunit );
::glEnable( GL_TEXTURE_2D );
}
@@ -804,6 +833,17 @@ opengl_renderer::setup_shadow_color( glm::vec4 const &Shadowcolor ) {
bool
opengl_renderer::Render( world_environment *Environment ) {
// calculate shadow tone, based on positions of celestial bodies
m_shadowcolor = interpolate(
glm::vec4{ 0.5f, 0.5f, 0.5f, 1.f },
glm::vec4{ colors::white },
clamp( -Environment->m_sun.getAngle(), 0.f, 6.f ) / 6.f );
if( ( Environment->m_sun.getAngle() < -18.f )
&& ( Environment->m_moon.getAngle() > 0.f ) ) {
// turn on moon shadows after nautical twilight, if the moon is actually up
m_shadowcolor = glm::vec4{ 0.5f, 0.5f, 0.5f, 1.f };
}
if( Global::bWireFrame ) {
// bez nieba w trybie rysowania linii
return false;
@@ -888,7 +928,10 @@ opengl_renderer::Render( world_environment *Environment ) {
::glLoadIdentity(); // macierz jedynkowa
::glTranslatef( moonposition.x, moonposition.y, moonposition.z );
float const size = 0.02f; // TODO: expose distance/scale factor from the moon object
float const size = interpolate( // TODO: expose distance/scale factor from the moon object
0.0175f,
0.015f,
clamp( Environment->m_moon.getAngle(), 0.f, 90.f ) / 90.f );
// choose the moon appearance variant, based on current moon phase
// NOTE: implementation specific, 8 variants are laid out in 3x3 arrangement
// from new moon onwards, top left to right bottom (last spot is left for future use, if any)
@@ -2628,7 +2671,7 @@ opengl_renderer::Update( double const Deltatime ) {
m_framerate = 1000.f / ( m_drawtime / 20.f );
// adjust draw ranges etc, based on recent performance
auto const framerate = 1000.0f / (m_drawtimecolor / 20.0f);
auto const framerate = 1000.0f / (m_drawtimecolorpass / 20.0f);
float targetfactor;
if( framerate > 90.0 ) { targetfactor = 3.0f; }
@@ -2697,7 +2740,18 @@ opengl_renderer::Info() const {
}
void
opengl_renderer::Update_Lights( light_array const &Lights ) {
opengl_renderer::Update_Lights( light_array &Lights ) {
// arrange the light array from closest to farthest from current position of the camera
auto const camera = m_renderpass.camera.position();
std::sort(
std::begin( Lights.data ),
std::end( Lights.data ),
[&camera]( light_array::light_record const &Left, light_array::light_record const &Right ) {
// move lights which are off at the end...
if( Left.intensity == 0.f ) { return false; }
if( Right.intensity == 0.f ) { return true; }
// ...otherwise prefer closer and/or brigher light sources
return ( glm::length2( camera - Left.position ) * ( 1.f - Left.intensity ) ) < ( glm::length2( camera - Right.position ) * ( 1.f - Right.intensity ) ); } );
size_t const count = std::min( m_lights.size(), Lights.data.size() );
if( count == 0 ) { return; }
@@ -2710,40 +2764,35 @@ opengl_renderer::Update_Lights( light_array const &Lights ) {
// we ran out of lights to assign
break;
}
if( scenelight.intensity == 0.0f ) {
if( scenelight.intensity == 0.f ) {
// all lights past this one are bound to be off
break;
}
if( ( m_renderpass.camera.position() - scenelight.position ).Length() > 1000.0f ) {
auto const lightoffset = glm::vec3{ scenelight.position - camera };
if( glm::length( lightoffset ) > 1000.f ) {
// we don't care about lights past arbitrary limit of 1 km.
// but there could still be weaker lights which are closer, so keep looking
continue;
}
// if the light passed tests so far, it's good enough
renderlight->set_position( glm::make_vec3( (scenelight.position - m_renderpass.camera.position()).readArray() ) );
renderlight->set_position( lightoffset );
renderlight->direction = scenelight.direction;
auto luminance = Global::fLuminance; // TODO: adjust this based on location, e.g. for tunnels
auto luminance = static_cast<float>( Global::fLuminance );
// adjust luminance level based on vehicle's location, e.g. tunnels
auto const environment = scenelight.owner->fShade;
if( environment > 0.0f ) {
if( environment > 0.f ) {
luminance *= environment;
}
renderlight->diffuse[ 0 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.x - luminance ) );
renderlight->diffuse[ 1 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.y - luminance ) );
renderlight->diffuse[ 2 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.z - luminance ) );
renderlight->ambient[ 0 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.x * scenelight.intensity - luminance) );
renderlight->ambient[ 1 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.y * scenelight.intensity - luminance ) );
renderlight->ambient[ 2 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.z * scenelight.intensity - luminance ) );
/*
// NOTE: we have no simple way to determine whether the lights are falling on objects located in darker environment
// until this issue is resolved we're disabling reduction of light strenght based on the global luminance
renderlight->diffuse[ 0 ] = std::max( 0.0f, scenelight.color.x );
renderlight->diffuse[ 1 ] = std::max( 0.0f, scenelight.color.y );
renderlight->diffuse[ 2 ] = std::max( 0.0f, scenelight.color.z );
renderlight->ambient[ 0 ] = std::max( 0.0f, scenelight.color.x * scenelight.intensity );
renderlight->ambient[ 1 ] = std::max( 0.0f, scenelight.color.y * scenelight.intensity );
renderlight->ambient[ 2 ] = std::max( 0.0f, scenelight.color.z * scenelight.intensity );
*/
renderlight->diffuse =
glm::vec4{
glm::max( glm::vec3{ colors::none }, scenelight.color - glm::vec3{ luminance } ),
renderlight->diffuse[ 3 ] };
renderlight->ambient =
glm::vec4{
glm::max( glm::vec3{ colors::none }, scenelight.color * glm::vec3{ scenelight.intensity } - glm::vec3{ luminance } ),
renderlight->ambient[ 3 ] };
::glLightf( renderlight->id, GL_LINEAR_ATTENUATION, static_cast<GLfloat>( (0.25 * scenelight.count) / std::pow( scenelight.count, 2 ) * (scenelight.owner->DimHeadlights ? 1.25 : 1.0) ) );
::glEnable( renderlight->id );

View File

@@ -87,10 +87,9 @@ public:
// methods:
inline
void
update_frustum() { m_frustum.calculate( m_projection, m_modelview ); }
inline
update_frustum() { update_frustum( m_projection, m_modelview ); }
void
update_frustum(glm::mat4 const &Projection, glm::mat4 const &Modelview) { m_frustum.calculate(Projection, Modelview); }
update_frustum( glm::mat4 const &Projection, glm::mat4 const &Modelview );
bool
visible( bounding_area const &Area ) const;
bool
@@ -114,15 +113,31 @@ public:
glm::mat4 &
modelview() { return m_modelview; }
inline
cFrustum const &
frustum() { return m_frustum; }
std::vector<glm::vec4> &
frustum_points() { return m_frustumpoints; }
// transforms provided set of clip space points to world space
template <class Iterator_>
void
transform_to_world( Iterator_ First, Iterator_ Last ) const {
std::for_each(
First, Last,
[this]( glm::vec4 &point ) {
// transform each point using the cached matrix...
point = this->m_inversetransformation * point;
// ...and scale by transformed w
point = glm::vec4{ glm::vec3{ point } / point.w, 1.f }; } ); }
// debug helper, draws shape of frustum in world space
void
draw( glm::vec3 const &Offset ) const;
private:
// members:
cFrustum m_frustum;
std::vector<glm::vec4> m_frustumpoints; // visualization helper; corners of defined frustum, in world space
glm::dvec3 m_position;
glm::mat4 m_projection;
glm::mat4 m_modelview;
glm::mat4 m_inversetransformation; // cached transformation to world space
};
// bare-bones render controller, in lack of anything better yet
@@ -207,9 +222,6 @@ private:
opengl_camera camera;
rendermode draw_mode { rendermode::none };
float draw_range { 0.0f };
void
setup( rendermode const Mode, bool const Framebuffersupport, float const Znear = 0.f, float const Zfar = 1.f, bool const Ignoredebug = false );
};
typedef std::vector<opengl_light> opengllight_array;
@@ -220,6 +232,8 @@ private:
// runs jobs needed to generate graphics for specified render pass
void
Render_pass( rendermode const Mode );
void
setup_pass( renderpass_config &Config, rendermode const Mode, float const Znear = 0.f, float const Zfar = 1.f, bool const Ignoredebug = false );
void
setup_matrices();
void
@@ -269,7 +283,7 @@ private:
void
Render_Alpha( TSubModel *Submodel );
void
Update_Lights( light_array const &Lights );
Update_Lights( light_array &Lights );
glm::vec3
pick_color( std::size_t const Index );
std::size_t
@@ -309,8 +323,8 @@ private:
float m_drawtime { 1000.f / 30.f * 20.f }; // start with presumed 'neutral' average of 30 fps
std::chrono::steady_clock::time_point m_drawstart; // cached start time of previous frame
float m_framerate;
float m_drawtimecolor { 1000.f / 30.f * 20.f };
float m_drawtimeshadows { 0.f };
float m_drawtimecolorpass { 1000.f / 30.f * 20.f };
float m_drawtimeshadowpass { 0.f };
double m_updateaccumulator { 0.0 };
std::string m_debuginfo;

13
sun.cpp
View File

@@ -251,21 +251,18 @@ void cSun::refract() {
void cSun::irradiance() {
static double degrad = 57.295779513; // converts from radians to degrees
static double raddeg = 0.0174532925; // converts from degrees to radians
m_body.dayang = ( simulation::Time.year_day() - 1 ) * 360.0 / 365.0;
double sd = sin( raddeg * m_body.dayang ); // sine of the day angle
double cd = cos( raddeg * m_body.dayang ); // cosine of the day angle or delination
double sd = std::sin( glm::radians( m_body.dayang ) ); // sine of the day angle
double cd = std::cos( glm::radians( m_body.dayang ) ); // cosine of the day angle or delination
m_body.erv = 1.000110 + 0.034221*cd + 0.001280*sd;
double d2 = 2.0 * m_body.dayang;
double c2 = cos( raddeg * d2 );
double s2 = sin( raddeg * d2 );
double c2 = std::cos( glm::radians( d2 ) );
double s2 = std::sin( glm::radians( d2 ) );
m_body.erv += 0.000719*c2 + 0.000077*s2;
double solcon = 1367.0; // Solar constant, 1367 W/sq m
m_body.coszen = cos( raddeg * m_body.zenref );
m_body.coszen = std::cos( glm::radians( m_body.zenref ) );
if( m_body.coszen > 0.0 ) {
m_body.etrn = solcon * m_body.erv;
m_body.etr = m_body.etrn * m_body.coszen;