16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-18 00:49:19 +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() { TGround::Update_Lights() {
m_lights.update(); 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 // Winger 170204 - szukanie trakcji nad pantografami

View File

@@ -2220,10 +2220,12 @@ world_environment::update() {
m_sun.update(); m_sun.update();
m_moon.update(); m_moon.update();
// ...determine source of key light and adjust global state accordingly... // ...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 auto const moonlightlevel = m_moon.getIntensity() * 0.65f; // scaled down by arbitrary factor, it's pretty bright otherwise
float keylightintensity; float keylightintensity;
float twilightfactor;
glm::vec3 keylightcolor; glm::vec3 keylightcolor;
if( moonlightlevel > sunlightlevel ) { if( moonlightlevel > sunlightlevel ) {
// rare situations when the moon is brighter than the sun, typically at night // 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.set_position( m_sun.getPosition() );
Global::DayLight.direction = -1.0f * m_sun.getDirection(); Global::DayLight.direction = -1.0f * m_sun.getDirection();
keylightintensity = sunlightlevel; keylightintensity = sunlightlevel;
// diffuse (sun) intensity goes down after twilight, and reaches minimum 18 degrees below horizon // include 'golden hour' effect in twilight lighting
twilightfactor = clamp( -Global::SunAngle, 0.0f, 18.0f ) / 18.0f;
float const duskfactor = 1.0f - clamp( Global::SunAngle, 0.0f, 18.0f ) / 18.0f; float const duskfactor = 1.0f - clamp( Global::SunAngle, 0.0f, 18.0f ) / 18.0f;
keylightcolor = interpolate( keylightcolor = interpolate(
glm::vec3( 255.0f / 255.0f, 242.0f / 255.0f, 231.0f / 255.0f ), 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_C ] = clip[ 11 ] + clip[ 10 ];
m_frustum[ side_FRONT ][ plane_D ] = clip[ 15 ] + clip[ 14 ]; m_frustum[ side_FRONT ][ plane_D ] = clip[ 15 ] + clip[ 14 ];
normalize_plane( side_FRONT ); 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 bool
@@ -177,19 +169,6 @@ cFrustum::cube_inside( float const X, float const Y, float const Z, float const
return true; 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 ) { void cFrustum::normalize_plane( cFrustum::side const Side ) {
float magnitude = float magnitude =

View File

@@ -12,10 +12,12 @@ http://mozilla.org/MPL/2.0/.
#include "float3d.h" #include "float3d.h"
#include "dumb3d.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-near
{ -1, -1, 1, 1 },{ 1, -1, 1, 1 },{ 1, 1, 1, 1 },{ -1, 1, 1, 1 } }; // z-far { -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 // generic frustum class. used to determine if objects are inside current view area
class cFrustum { 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 ); } 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 bool
cube_inside( float const X, float const Y, float const Z, float const Size ) const; 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: private:
// types: // types:
@@ -96,5 +81,4 @@ private:
// members: // members:
float m_frustum[6][4]; // holds the A B C and D values (normal & distance) for each side of the frustum. 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 ) ) { if( ( true == light.owner->MoverParameters->Battery ) || ( true == light.owner->MoverParameters->ConverterFlag ) ) {
// with power on, the intensity depends on the state of activated switches // with power on, the intensity depends on the state of activated switches
auto const &lightbits = light.owner->iLights[ light.index ]; auto const &lightbits = light.owner->iLights[ light.index ];
light.count = 0 + light.count = 0
( ( lightbits & 1 ) ? 1 : 0 ) + + ( ( lightbits & TMoverParameters::light::headlight_left ) ? 1 : 0 )
( ( lightbits & 4 ) ? 1 : 0 ) + + ( ( lightbits & TMoverParameters::light::headlight_right ) ? 1 : 0 )
( ( lightbits & 16 ) ? 1 : 0 ); + ( ( lightbits & TMoverParameters::light::headlight_upper ) ? 1 : 0 );
if( light.count > 0 ) { if( light.count > 0 ) {
// TODO: intensity can be affected further by dim switch or other factors // 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 TDynamicObject const *owner; // the object in world which 'carries' the light
int index{ -1 }; // 0: front lights, 1: rear lights 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 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) float intensity{ 0.0f }; // (combined) intensity of the light(s)
int count{ 0 }; // number (or pattern) of active 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 } // 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 // returns true if specified object is within camera frustum, false otherwise
bool bool
opengl_camera::visible( bounding_area const &Area ) const { 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 ); 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 bool
opengl_renderer::Init( GLFWwindow *Window ) { 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_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(); 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_renderpass.draw_mode = rendermode::none; // force setup anew
m_debuginfo.clear();
Render_pass( rendermode::color ); Render_pass( rendermode::color );
m_drawcount = m_drawqueue.size(); m_drawcount = m_drawqueue.size();
// accumulate last 20 frames worth of render time (cap at 1000 fps to prevent calculations going awry) // 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_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_drawtimecolor / 20.f, 2 ) + " msec (" + std::to_string( m_drawqueue.size() ) + " sectors)"; m_debuginfo += "frame total: " + to_string( m_drawtimecolorpass / 20.f, 2 ) + " msec (" + std::to_string( m_drawqueue.size() ) + " sectors) ";
glfwSwapBuffers( m_window ); glfwSwapBuffers( m_window );
@@ -270,25 +296,26 @@ opengl_renderer::Render() {
void void
opengl_renderer::Render_pass( rendermode const Mode ) { opengl_renderer::Render_pass( rendermode const Mode ) {
m_renderpass.setup( Mode, m_framebuffersupport ); setup_pass( m_renderpass, Mode );
switch( m_renderpass.draw_mode ) { switch( m_renderpass.draw_mode ) {
case rendermode::color: { case rendermode::color: {
opengl_camera shadowcamera; // temporary helper, remove once ortho shadowmap code is done 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 // run shadowmap pass before color
Render_pass( rendermode::shadows ); Render_pass( rendermode::shadows );
#ifdef EU07_USE_DEBUG_SHADOWMAP #ifdef EU07_USE_DEBUG_SHADOWMAP
UILayer.set_texture( m_shadowdebugtexture ); UILayer.set_texture( m_shadowdebugtexture );
#endif #endif
shadowcamera = m_renderpass.camera; // cache shadow camera placement for visualization shadowcamera = m_renderpass.camera; // cache shadow camera placement for visualization
setup_pass( m_renderpass, Mode ); // restore draw mode. TBD, TODO: render mode stack
m_renderpass.setup( rendermode::color, m_framebuffersupport ); // restore draw mode. TBD, TODO: render mode stack
#ifdef EU07_USE_DEBUG_CAMERA #ifdef EU07_USE_DEBUG_CAMERA
m_worldcamera.setup( setup_pass(
m_worldcamera,
rendermode::color, rendermode::color,
m_framebuffersupport,
0.f, 0.f,
std::min( std::min(
1.f, 1.f,
@@ -337,10 +364,10 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
::glColor4f( 1.f, 0.9f, 0.8f, 1.f ); ::glColor4f( 1.f, 0.9f, 0.8f, 1.f );
::glDisable( GL_LIGHTING ); ::glDisable( GL_LIGHTING );
::glDisable( GL_TEXTURE_2D ); ::glDisable( GL_TEXTURE_2D );
shadowcamera.frustum().draw( m_renderpass.camera.position() - shadowcamera.position() ); shadowcamera.draw( m_renderpass.camera.position() - shadowcamera.position() );
if( DebugCameraFlag ) { if( DebugCameraFlag ) {
::glColor4f( 0.8f, 1.f, 0.9f, 1.f ); ::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 ); ::glLineWidth( 1.f );
::glEnable( GL_LIGHTING ); ::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 ::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_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_drawtimeshadows / 20.f, 2 ) + " msec (" + std::to_string( m_drawqueue.size() ) + " sectors)"; m_debuginfo += "shadows: " + to_string( m_drawtimeshadowpass / 20.f, 2 ) + " msec (" + std::to_string( m_drawqueue.size() ) + " sectors) ";
} }
break; break;
} }
@@ -453,27 +480,29 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
} }
void 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; } if( false == World.InitPerformed() ) { return; }
// setup draw range
switch( draw_mode ) { switch( Mode ) {
case rendermode::color: { draw_range = Global::BaseDrawRange; break; } case rendermode::color: { Config.draw_range = Global::BaseDrawRange; break; }
case rendermode::shadows: { draw_range = Global::BaseDrawRange * 0.5f; break; } case rendermode::shadows: { Config.draw_range = Global::BaseDrawRange * 0.5f; break; }
case rendermode::pickcontrols: { draw_range = 50.f; break; } case rendermode::pickcontrols: { Config.draw_range = 50.f; break; }
case rendermode::pickscenery: { draw_range = Global::BaseDrawRange * 0.5f; break; } case rendermode::pickscenery: { Config.draw_range = Global::BaseDrawRange * 0.5f; break; }
default: { draw_range = 0.f; break; } default: { Config.draw_range = 0.f; break; }
} }
// setup camera
auto &camera = Config.camera;
camera.projection() = glm::mat4( 1.f ); camera.projection() = glm::mat4( 1.f );
glm::dmat4 viewmatrix( 1.0 ); glm::dmat4 viewmatrix( 1.0 );
switch( draw_mode ) { switch( Mode ) {
case rendermode::color: { case rendermode::color: {
// projection // projection
auto const zfar = draw_range * Global::fDistanceFactor * Zfar; auto const zfar = Config.draw_range * Global::fDistanceFactor * Zfar;
auto const znear = ( auto const znear = (
Znear > 0.f ? Znear > 0.f ?
Znear * zfar : Znear * zfar :
@@ -498,33 +527,29 @@ opengl_renderer::renderpass_config::setup( rendermode const Mode, bool const Fra
case rendermode::shadows: { case rendermode::shadows: {
// calculate lightview boundaries based on relevant area of the world camera frustum: // 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 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 ) ); 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; renderpass_config worldview;
worldview.setup( rendermode::color, Framebuffersupport, znear, zfar, true ); setup_pass( worldview, rendermode::color, znear, zfar, true );
// ...transform frustum shape to camera-centric world space... auto &frustumchunkshapepoints = worldview.camera.frustum_points();
auto frustumchunkshapepoints = ndcfrustumshapepoints; // ...modelview matrix: determine the centre of frustum chunk in world space...
worldview.camera.frustum().transform_to_world( std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) );
// ...determine the centre of frustum chunk in world space...
glm::vec3 frustumchunkmin, frustumchunkmax; glm::vec3 frustumchunkmin, frustumchunkmax;
bounding_box( frustumchunkmin, frustumchunkmax, std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) ); bounding_box( frustumchunkmin, frustumchunkmax, std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) );
auto const frustumchunkcentre = ( frustumchunkmin + frustumchunkmax ) * 0.5f; 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 = auto const lightvector =
glm::normalize( glm::vec3{ glm::normalize( glm::vec3{
-Global::DayLight.direction.x, Global::DayLight.direction.x,
std::max( -Global::DayLight.direction.y, 0.15f ), std::min( Global::DayLight.direction.y, -0.15f ),
-Global::DayLight.direction.z } ); Global::DayLight.direction.z } );
// ...place the light source at the calculated centre... // ...place the light source at the calculated centre and setup world space light view matrix...
camera.position() = lighttarget;// -glm::dvec3{ lightvector }; camera.position() = worldview.camera.position() + glm::dvec3{ frustumchunkcentre };
// ...setup world space light view matrix...
viewmatrix *= glm::lookAt( viewmatrix *= glm::lookAt(
camera.position(), camera.position(),
camera.position() - glm::dvec3{ lightvector }, camera.position() + glm::dvec3{ lightvector },
glm::dvec3{ 0.f, 1.f, 0.f } ); 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 = auto const lightviewmatrix =
glm::translate( glm::translate(
glm::mat4{ glm::mat3{ viewmatrix } }, glm::mat4{ glm::mat3{ viewmatrix } },
@@ -547,7 +572,7 @@ opengl_renderer::renderpass_config::setup( rendermode const Mode, bool const Fra
case rendermode::pickscenery: { case rendermode::pickscenery: {
// TODO: scissor test for pick modes // TODO: scissor test for pick modes
// projection // projection
if( true == Framebuffersupport ) { if( true == m_framebuffersupport ) {
auto const angle = Global::FieldOfView / Global::ZoomFactor; 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 ); auto const height = std::max( 1.0f, (float)Global::iWindowWidth ) / std::max( 1.0f, (float)Global::iWindowHeight ) / ( Global::iWindowWidth / EU07_PICKBUFFERSIZE );
camera.projection() *= camera.projection() *=
@@ -555,7 +580,7 @@ opengl_renderer::renderpass_config::setup( rendermode const Mode, bool const Fra
glm::radians( Global::FieldOfView / Global::ZoomFactor ), glm::radians( Global::FieldOfView / Global::ZoomFactor ),
std::max( 1.f, (float)Global::iWindowWidth ) / std::max( 1.0f, (float)Global::iWindowHeight ) / ( Global::iWindowWidth / EU07_PICKBUFFERSIZE ), std::max( 1.f, (float)Global::iWindowWidth ) / std::max( 1.0f, (float)Global::iWindowHeight ) / ( Global::iWindowWidth / EU07_PICKBUFFERSIZE ),
0.1f * Global::ZoomFactor, 0.1f * Global::ZoomFactor,
draw_range * Global::fDistanceFactor ); Config.draw_range * Global::fDistanceFactor );
} }
else { else {
camera.projection() *= camera.projection() *=
@@ -563,7 +588,7 @@ opengl_renderer::renderpass_config::setup( rendermode const Mode, bool const Fra
glm::radians( Global::FieldOfView / Global::ZoomFactor ), glm::radians( Global::FieldOfView / Global::ZoomFactor ),
std::max( 1.f, (float)Global::iWindowWidth ) / std::max( 1.f, (float)Global::iWindowHeight ), std::max( 1.f, (float)Global::iWindowWidth ) / std::max( 1.f, (float)Global::iWindowHeight ),
0.1f * Global::ZoomFactor, 0.1f * Global::ZoomFactor,
draw_range * Global::fDistanceFactor ); Config.draw_range * Global::fDistanceFactor );
} }
// modelview // modelview
camera.position() = Global::pCameraPosition; camera.position() = Global::pCameraPosition;
@@ -681,7 +706,9 @@ opengl_renderer::setup_units( bool const Diffuse, bool const Shadows, bool const
// shadow texture unit. // shadow texture unit.
// interpolates between primary colour and the previous unit, which should hold darkened variant of the primary colour // interpolates between primary colour and the previous unit, which should hold darkened variant of the primary colour
if( m_shadowtextureunit >= 0 ) { if( m_shadowtextureunit >= 0 ) {
if( ( true == Global::RenderShadows ) && ( true == Shadows ) ) { if( ( true == Global::RenderShadows )
&& ( true == Shadows )
&& ( m_shadowcolor != colors::white ) ) {
::glActiveTexture( m_shadowtextureunit ); ::glActiveTexture( m_shadowtextureunit );
::glBindTexture( GL_TEXTURE_2D, m_shadowtexture ); ::glBindTexture( GL_TEXTURE_2D, m_shadowtexture );
@@ -756,7 +783,9 @@ void
opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool const Reflections ) { opengl_renderer::switch_units( bool const Diffuse, bool const Shadows, bool const Reflections ) {
// helper texture unit. // helper texture unit.
if( m_helpertextureunit >= 0 ) { if( m_helpertextureunit >= 0 ) {
if( ( true == Global::RenderShadows ) && ( true == Shadows ) ) { if( ( true == Global::RenderShadows )
&& ( true == Shadows )
&& ( m_shadowcolor != colors::white ) ) {
::glActiveTexture( m_helpertextureunit ); ::glActiveTexture( m_helpertextureunit );
::glEnable( GL_TEXTURE_2D ); ::glEnable( GL_TEXTURE_2D );
} }
@@ -804,6 +833,17 @@ opengl_renderer::setup_shadow_color( glm::vec4 const &Shadowcolor ) {
bool bool
opengl_renderer::Render( world_environment *Environment ) { 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 ) { if( Global::bWireFrame ) {
// bez nieba w trybie rysowania linii // bez nieba w trybie rysowania linii
return false; return false;
@@ -888,7 +928,10 @@ opengl_renderer::Render( world_environment *Environment ) {
::glLoadIdentity(); // macierz jedynkowa ::glLoadIdentity(); // macierz jedynkowa
::glTranslatef( moonposition.x, moonposition.y, moonposition.z ); ::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 // choose the moon appearance variant, based on current moon phase
// NOTE: implementation specific, 8 variants are laid out in 3x3 arrangement // 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) // 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 ); m_framerate = 1000.f / ( m_drawtime / 20.f );
// adjust draw ranges etc, based on recent performance // 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; float targetfactor;
if( framerate > 90.0 ) { targetfactor = 3.0f; } if( framerate > 90.0 ) { targetfactor = 3.0f; }
@@ -2697,7 +2740,18 @@ opengl_renderer::Info() const {
} }
void 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() ); size_t const count = std::min( m_lights.size(), Lights.data.size() );
if( count == 0 ) { return; } if( count == 0 ) { return; }
@@ -2710,40 +2764,35 @@ opengl_renderer::Update_Lights( light_array const &Lights ) {
// we ran out of lights to assign // we ran out of lights to assign
break; break;
} }
if( scenelight.intensity == 0.0f ) { if( scenelight.intensity == 0.f ) {
// all lights past this one are bound to be off // all lights past this one are bound to be off
break; 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. // 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 // but there could still be weaker lights which are closer, so keep looking
continue; continue;
} }
// if the light passed tests so far, it's good enough // 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; 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; auto const environment = scenelight.owner->fShade;
if( environment > 0.0f ) { if( environment > 0.f ) {
luminance *= environment; luminance *= environment;
} }
renderlight->diffuse[ 0 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.x - luminance ) ); renderlight->diffuse =
renderlight->diffuse[ 1 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.y - luminance ) ); glm::vec4{
renderlight->diffuse[ 2 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.z - luminance ) ); glm::max( glm::vec3{ colors::none }, scenelight.color - glm::vec3{ luminance } ),
renderlight->ambient[ 0 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.x * scenelight.intensity - luminance) ); renderlight->diffuse[ 3 ] };
renderlight->ambient[ 1 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.y * scenelight.intensity - luminance ) ); renderlight->ambient =
renderlight->ambient[ 2 ] = static_cast<GLfloat>( std::max( 0.0, scenelight.color.z * scenelight.intensity - luminance ) ); glm::vec4{
/* glm::max( glm::vec3{ colors::none }, scenelight.color * glm::vec3{ scenelight.intensity } - glm::vec3{ luminance } ),
// NOTE: we have no simple way to determine whether the lights are falling on objects located in darker environment renderlight->ambient[ 3 ] };
// 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 );
*/
::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) ) ); ::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 ); ::glEnable( renderlight->id );

View File

@@ -87,10 +87,9 @@ public:
// methods: // methods:
inline inline
void void
update_frustum() { m_frustum.calculate( m_projection, m_modelview ); } update_frustum() { update_frustum( m_projection, m_modelview ); }
inline
void 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 bool
visible( bounding_area const &Area ) const; visible( bounding_area const &Area ) const;
bool bool
@@ -114,15 +113,31 @@ public:
glm::mat4 & glm::mat4 &
modelview() { return m_modelview; } modelview() { return m_modelview; }
inline inline
cFrustum const & std::vector<glm::vec4> &
frustum() { return m_frustum; } 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: private:
// members: // members:
cFrustum m_frustum; cFrustum m_frustum;
std::vector<glm::vec4> m_frustumpoints; // visualization helper; corners of defined frustum, in world space
glm::dvec3 m_position; glm::dvec3 m_position;
glm::mat4 m_projection; glm::mat4 m_projection;
glm::mat4 m_modelview; glm::mat4 m_modelview;
glm::mat4 m_inversetransformation; // cached transformation to world space
}; };
// bare-bones render controller, in lack of anything better yet // bare-bones render controller, in lack of anything better yet
@@ -207,9 +222,6 @@ private:
opengl_camera camera; opengl_camera camera;
rendermode draw_mode { rendermode::none }; rendermode draw_mode { rendermode::none };
float draw_range { 0.0f }; 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; typedef std::vector<opengl_light> opengllight_array;
@@ -220,6 +232,8 @@ private:
// runs jobs needed to generate graphics for specified render pass // runs jobs needed to generate graphics for specified render pass
void void
Render_pass( rendermode const Mode ); 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 void
setup_matrices(); setup_matrices();
void void
@@ -269,7 +283,7 @@ private:
void void
Render_Alpha( TSubModel *Submodel ); Render_Alpha( TSubModel *Submodel );
void void
Update_Lights( light_array const &Lights ); Update_Lights( light_array &Lights );
glm::vec3 glm::vec3
pick_color( std::size_t const Index ); pick_color( std::size_t const Index );
std::size_t 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 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 std::chrono::steady_clock::time_point m_drawstart; // cached start time of previous frame
float m_framerate; float m_framerate;
float m_drawtimecolor { 1000.f / 30.f * 20.f }; float m_drawtimecolorpass { 1000.f / 30.f * 20.f };
float m_drawtimeshadows { 0.f }; float m_drawtimeshadowpass { 0.f };
double m_updateaccumulator { 0.0 }; double m_updateaccumulator { 0.0 };
std::string m_debuginfo; std::string m_debuginfo;

13
sun.cpp
View File

@@ -251,21 +251,18 @@ void cSun::refract() {
void cSun::irradiance() { 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; 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 sd = std::sin( glm::radians( m_body.dayang ) ); // sine of the day angle
double cd = cos( raddeg * m_body.dayang ); // cosine of the day angle or delination 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; m_body.erv = 1.000110 + 0.034221*cd + 0.001280*sd;
double d2 = 2.0 * m_body.dayang; double d2 = 2.0 * m_body.dayang;
double c2 = cos( raddeg * d2 ); double c2 = std::cos( glm::radians( d2 ) );
double s2 = sin( raddeg * d2 ); double s2 = std::sin( glm::radians( d2 ) );
m_body.erv += 0.000719*c2 + 0.000077*s2; m_body.erv += 0.000719*c2 + 0.000077*s2;
double solcon = 1367.0; // Solar constant, 1367 W/sq m 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 ) { if( m_body.coszen > 0.0 ) {
m_body.etrn = solcon * m_body.erv; m_body.etrn = solcon * m_body.erv;
m_body.etr = m_body.etrn * m_body.coszen; m_body.etr = m_body.etrn * m_body.coszen;