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

opengl 3.3 renderer cascaded shadow maps, minor gfx renderer optimizations

This commit is contained in:
tmj-fstate
2019-12-05 15:42:54 +01:00
parent 194400e1af
commit 63619d13a6
21 changed files with 416 additions and 443 deletions

View File

@@ -4334,6 +4334,17 @@ TDynamicObject::tracing_offset() const {
axletoend + iDirection * fAxleDist );
}
// TODO: compute and cache radius during vehicle initialization
double
TDynamicObject::radius() const {
glm::vec3 diagonal(
static_cast<float>( MoverParameters->Dim.L ),
static_cast<float>( MoverParameters->Dim.H ),
static_cast<float>( MoverParameters->Dim.W ) );
return glm::length( diagonal ) * 0.5f;
}
// McZapkie-250202
// wczytywanie pliku z danymi multimedialnymi (dzwieki)
void TDynamicObject::LoadMMediaFile( std::string const &TypeName, std::string const &ReplacableSkin ) {

View File

@@ -603,6 +603,7 @@ private:
return MoverParameters->Dim.L; };
inline double GetWidth() const {
return MoverParameters->Dim.W; };
double radius() const;
// calculates distance between event-starting axle and front of the vehicle
double tracing_offset() const;
inline TTrack * GetTrack() {

View File

@@ -293,11 +293,7 @@ global_settings::ConfigParse(cParser &Parser) {
Parser.getTokens(1, false);
int size;
Parser >> size;
auto p2size { 64 }; // start with 64px
while( (p2size <= 16384 ) && ( p2size <= size ) ) {
iMaxTextureSize = p2size;
p2size = p2size << 1;
}
iMaxTextureSize = clamp_power_of_two( size, 512, 8192 );
}
else if (token == "maxcabtexturesize")
{
@@ -305,11 +301,7 @@ global_settings::ConfigParse(cParser &Parser) {
Parser.getTokens( 1, false );
int size;
Parser >> size;
auto p2size { 64 }; // start with 64px
while( ( p2size <= 16384 ) && ( p2size <= size ) ) {
iMaxCabTextureSize = p2size;
p2size = p2size << 1;
}
iMaxCabTextureSize = clamp_power_of_two( size, 512, 8192 );
}
else if (token == "movelight")
{
@@ -388,11 +380,20 @@ global_settings::ConfigParse(cParser &Parser) {
}
else if( token == "shadowtune" ) {
Parser.getTokens( 4, false );
float discard;
Parser
>> shadowtune.map_size
>> shadowtune.width
>> shadowtune.depth
>> shadowtune.distance;
>> discard
>> shadowtune.range
>> discard;
shadowtune.map_size = clamp_power_of_two<unsigned int>( shadowtune.map_size, 512, 8192 );
// make sure we actually make effective use of all csm stages
shadowtune.range =
std::max(
( shadowtune.map_size <= 2048 ?
75.f :
75.f * shadowtune.map_size / 2048 ),
shadowtune.range );
}
else if( token == "gfx.shadows.cab.range" ) {
// shadow render toggle

View File

@@ -105,7 +105,7 @@ struct global_settings {
// gfx
int iWindowWidth{ 800 };
int iWindowHeight{ 600 };
float fDistanceFactor{ iWindowHeight / 768.f }; // baza do przeliczania odległości dla LoD
float fDistanceFactor{ 1.f }; // baza do przeliczania odległości dla LoD
float targetfps { 0.0f };
bool bFullScreen{ false };
bool VSync{ false };
@@ -121,9 +121,7 @@ struct global_settings {
int RenderCabShadowsRange{ 0 };
struct shadowtune_t {
unsigned int map_size{ 2048 };
float width{ 250.f }; // no longer used
float depth{ 250.f };
float distance{ 500.f }; // no longer used
float range{ 250.f };
} shadowtune;
double ReflectionUpdateInterval{ 300.0 };
bool bUseVBO{ true }; // czy jest VBO w karcie graficznej (czy użyć)

View File

@@ -2010,6 +2010,12 @@ void TModel3d::Init()
std::size_t dataoffset = 0;
Root->create_geometry( dataoffset, m_geometrybank );
}
// determine final bounding radius from the root-level siblings
auto const *root { Root };
while( ( root = root->Next ) != nullptr ) {
Root->m_boundingradius = std::max( Root->m_boundingradius, root->m_boundingradius );
}
if( ( Global.iConvertModels > 0 )
&& ( false == asBinary.empty() ) ) {
SaveToBinFile( asBinary );

View File

@@ -817,34 +817,40 @@ opengl_texture::create() {
datasize = 0,
datawidth = data_width,
dataheight = data_height;
// TBD:
if (is_rendertarget)
{
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap_mode_s);
glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap_mode_t);
if (data_components == GL_DEPTH_COMPONENT)
{
glTexParameteri(target, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
if( false == Global.gfx_usegles ) {
float borderColor[] = { 0.0f, 0.0f, 0.0f, 0.0f };
glTexParameterfv( target, GL_TEXTURE_BORDER_COLOR, borderColor );
}
wrap_mode_s = GL_CLAMP_TO_BORDER;
wrap_mode_t = GL_CLAMP_TO_BORDER;
}
glTexParameteri( target, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( target, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( target, GL_TEXTURE_WRAP_S, wrap_mode_s );
glTexParameteri( target, GL_TEXTURE_WRAP_T, wrap_mode_t );
if (Global.gfx_usegles)
{
if (target == GL_TEXTURE_2D || !glTexStorage2DMultisample)
if( target == GL_TEXTURE_2D )
glTexStorage2D(target, count_trailing_zeros(std::max(data_width, data_height)) + 1, data_format, data_width, data_height);
else if (target == GL_TEXTURE_2D_MULTISAMPLE)
glTexStorage2DMultisample(target, samples, data_format, data_width, data_height, GL_FALSE);
else if( target == GL_TEXTURE_2D_MULTISAMPLE )
glTexStorage2DMultisample( target, samples, data_format, data_width, data_height, GL_FALSE );
else if( target == GL_TEXTURE_2D_ARRAY )
glTexStorage3D( target, count_trailing_zeros( std::max( data_width, data_height ) ) + 1, data_format, data_width, data_height, layers );
else if( target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY )
glTexStorage3DMultisample( target, samples, data_format, data_width, data_height, layers, GL_FALSE );
}
else
{
if (target == GL_TEXTURE_2D)
glTexImage2D(target, 0, data_format, data_width, data_height, 0, data_components, GL_UNSIGNED_SHORT, nullptr);
else if (target == GL_TEXTURE_2D_MULTISAMPLE)
glTexImage2DMultisample(target, samples, data_format, data_width, data_height, GL_FALSE);
else {
if( target == GL_TEXTURE_2D )
glTexImage2D( target, 0, data_format, data_width, data_height, 0, data_components, GL_UNSIGNED_SHORT, nullptr );
else if( target == GL_TEXTURE_2D_MULTISAMPLE )
glTexImage2DMultisample( target, samples, data_format, data_width, data_height, GL_FALSE );
else if( target == GL_TEXTURE_2D_ARRAY )
glTexImage3D( target, 0, data_format, data_width, data_height, layers, 0, data_components, GL_UNSIGNED_SHORT, nullptr );
else if( target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY )
glTexImage3DMultisample( target, samples, data_format, data_width, data_height, layers, GL_FALSE );
}
}
else
@@ -984,7 +990,7 @@ opengl_texture::release() {
}
void
opengl_texture::alloc_rendertarget( GLint format, GLint components, int width, int height, int s, GLint wrap ) {
opengl_texture::alloc_rendertarget( GLint format, GLint components, int width, int height, int l, int s, GLint wrap ) {
data_width = width;
data_height = height;
@@ -995,8 +1001,22 @@ opengl_texture::alloc_rendertarget( GLint format, GLint components, int width, i
wrap_mode_s = wrap;
wrap_mode_t = wrap;
samples = s;
if( samples > 1 )
target = GL_TEXTURE_2D_MULTISAMPLE;
if( Global.gfx_usegles && !glTexStorage2DMultisample ) {
samples = 1;
}
layers = l;
if( layers > 1 ) {
target = (
samples > 1 ?
GL_TEXTURE_2D_MULTISAMPLE_ARRAY :
GL_TEXTURE_2D_ARRAY );
}
else {
target = (
samples > 1 ?
GL_TEXTURE_2D_MULTISAMPLE :
GL_TEXTURE_2D );
}
create();
}

View File

@@ -36,7 +36,7 @@ struct opengl_texture {
void
release();
void
alloc_rendertarget( GLint format, GLint components, int width, int height, int samples = 1, GLint wrap = GL_CLAMP_TO_EDGE );
alloc_rendertarget( GLint format, GLint components, int width, int height, int layers = 1, int samples = 1, GLint wrap = GL_CLAMP_TO_EDGE );
void
set_components_hint( GLint hint );
static void
@@ -78,6 +78,7 @@ private:
// members
bool is_rendertarget = false; // is used as postfx rendertarget, without loaded data
int samples = 1;
int layers = 1;
std::vector<unsigned char> data; // texture data (stored GL-style, bottom-left origin)
resource_state data_state{ resource_state::none }; // current state of texture data
int data_width{ 0 },

View File

@@ -913,8 +913,8 @@ debug_panel::update_section_ai( std::vector<text_line> &Output ) {
+ ", delays: " + to_string( mechanik.fBrake_a0[ 0 ], 2 )
+ "+" + to_string( mechanik.fBrake_a1[ 0 ], 2 )
+ "\n virtual brake position: " + to_string(mechanik.BrakeCtrlPosition, 2)
+ "\n desired diesel percentage: " + to_string(mechanik.DizelPercentage, 0)
+ "/" + to_string(mechanik.DizelPercentage_Speed, 0)
+ "\n desired diesel percentage: " + to_string(mechanik.DizelPercentage)
+ "/" + to_string(mechanik.DizelPercentage_Speed)
+ "/" + to_string(100.4*mechanik.mvControlling->eimic_real, 0);
Output.emplace_back( textline, Global.UITextColor );

View File

@@ -25,6 +25,12 @@ void gl::framebuffer::attach(const opengl_texture &tex, GLenum location)
glFramebufferTexture2D(GL_FRAMEBUFFER, location, tex.target, tex.id, 0);
}
void gl::framebuffer::attach(const opengl_texture &tex, GLenum location, GLint layer)
{
bind();
glFramebufferTextureLayer(GL_FRAMEBUFFER, location, tex.id, 0, layer);
}
void gl::framebuffer::attach(const cubemap &tex, int face, GLenum location)
{
bind();

View File

@@ -15,6 +15,7 @@ namespace gl
~framebuffer();
void attach(const opengl_texture &tex, GLenum location);
void attach( const opengl_texture &tex, GLenum location, GLint layer );
void attach(const cubemap &tex, int face, GLenum location);
void attach(const renderbuffer &rb, GLenum location);
void setup_drawing(int attachments);

View File

@@ -13,6 +13,7 @@ void gl::glsl_common_setup()
"#define EXTRAEFFECTS_ENABLED " + std::to_string((int)Global.gfx_extraeffects) + "\n" +
"#define USE_GLES " + std::to_string((int)Global.gfx_usegles) + "\n" +
"const uint MAX_LIGHTS = " + std::to_string(MAX_LIGHTS) + "U;\n" +
"const uint MAX_CASCADES = " + std::to_string(MAX_CASCADES) + "U;\n" +
"const uint MAX_PARAMS = " + std::to_string(MAX_PARAMS) + "U;\n" +
R"STRING(
const uint LIGHT_SPOT = 0U;
@@ -64,9 +65,9 @@ void gl::glsl_common_setup()
layout (std140) uniform scene_ubo
{
mat4 projection;
mat4 lightview;
mat4 inv_view;
vec3 scene_extra;
mat4 lightview[MAX_CASCADES];
vec4 cascade_end;
float time;
};

View File

@@ -32,17 +32,18 @@ namespace gl
const size_t MAX_TEXTURES = 8;
const size_t ENVMAP_SIZE = 1024;
const size_t MAX_CASCADES = 3;
struct scene_ubs
{
glm::mat4 projection;
glm::mat4 lightview;
glm::mat4 inv_view;
glm::vec3 scene_extra;
glm::mat4 lightview[MAX_CASCADES];
glm::vec4 cascade_end;
float time;
};
static_assert(sizeof(scene_ubs) == 208, "bad size of ubs");
static_assert(sizeof(scene_ubs) == 340, "bad size of ubs");
const size_t MAX_PARAMS = 3;

View File

@@ -99,14 +99,12 @@ opengl33_particles::update( opengl_camera const &Camera ) {
}
}
void
std::size_t
opengl33_particles::render() {
if (!Global.Smoke)
return;
if( m_buffercapacity == 0 ) { return; }
if( m_particlevertices.empty() ) { return; }
if( false == Global.Smoke ) { return 0; }
if( m_buffercapacity == 0 ) { return 0; }
if( m_particlevertices.empty() ) { return 0; }
if (!m_vao) {
m_vao.emplace();
@@ -135,6 +133,8 @@ opengl33_particles::render() {
m_shader->unbind();
m_vao->unbind();
m_buffer->unbind(gl::buffer::ARRAY_BUFFER);
return m_particlevertices.size() / 6;
}
//---------------------------------------------------------------------------

View File

@@ -24,7 +24,7 @@ public:
// methods
void
update( opengl_camera const &Camera );
void
std::size_t
render( );
private:
// types

View File

@@ -166,8 +166,8 @@ bool opengl33_renderer::Init(GLFWwindow *Window)
{
m_shadow_fb = std::make_unique<gl::framebuffer>();
m_shadow_tex = std::make_unique<opengl_texture>();
m_shadow_tex->alloc_rendertarget(Global.gfx_format_depth, GL_DEPTH_COMPONENT, m_shadowbuffersize, m_shadowbuffersize);
m_shadow_fb->attach(*m_shadow_tex, GL_DEPTH_ATTACHMENT);
m_shadow_tex->alloc_rendertarget(Global.gfx_format_depth, GL_DEPTH_COMPONENT, m_shadowbuffersize, m_shadowbuffersize, m_shadowpass.size());
m_shadow_fb->attach(*m_shadow_tex, GL_DEPTH_ATTACHMENT, 0);
if( !m_shadow_fb->is_complete() ) {
ErrorLog( "shadow framebuffer setup failed" );
@@ -175,18 +175,6 @@ bool opengl33_renderer::Init(GLFWwindow *Window)
}
WriteLog("shadows enabled");
m_cabshadows_fb = std::make_unique<gl::framebuffer>();
m_cabshadows_tex = std::make_unique<opengl_texture>();
m_cabshadows_tex->alloc_rendertarget(Global.gfx_format_depth, GL_DEPTH_COMPONENT, m_shadowbuffersize, m_shadowbuffersize);
m_cabshadows_fb->attach(*m_cabshadows_tex, GL_DEPTH_ATTACHMENT);
if( !m_cabshadows_fb->is_complete() ) {
ErrorLog( "cabshadows framebuffer setup failed" );
return false;
}
WriteLog("cabshadows enabled");
}
if (Global.gfx_envmap_enabled)
@@ -378,7 +366,7 @@ bool opengl33_renderer::init_viewport(viewport_config &vp)
vp.msaa_fb->attach(*vp.msaa_rbv, GL_COLOR_ATTACHMENT1);
vp.main_tex = std::make_unique<opengl_texture>();
vp.main_tex->alloc_rendertarget(Global.gfx_format_color, GL_RGB, vp.width, vp.height, 1, GL_CLAMP_TO_EDGE);
vp.main_tex->alloc_rendertarget(Global.gfx_format_color, GL_RGB, vp.width, vp.height, 1, 1, GL_CLAMP_TO_EDGE);
vp.main_fb = std::make_unique<gl::framebuffer>();
vp.main_fb->attach(*vp.main_tex, GL_COLOR_ATTACHMENT0);
@@ -448,7 +436,7 @@ bool opengl33_renderer::Render()
opengl_texture::reset_unit_cache();
m_renderpass.draw_mode = rendermode::none; // force setup anew
m_debugstats = debug_stats();
m_renderpass.draw_stats = debug_stats();
for (auto &viewport : m_viewports) {
Render_pass(*viewport, rendermode::color);
@@ -471,10 +459,27 @@ bool opengl33_renderer::Render()
if (m_gllasttime)
m_debugtimestext += "gpu: " + to_string((double)(m_gllasttime / 1000ULL) / 1000.0, 3) + "ms";
}
m_debugstatstext = "drawcalls: " + to_string(m_debugstats.drawcalls) + "\n" + " vehicles: " + to_string(m_debugstats.dynamics) + "\n" + " models: " + to_string(m_debugstats.models) + "\n" +
" submodels: " + to_string(m_debugstats.submodels) + "\n" + " paths: " + to_string(m_debugstats.paths) + "\n" + " shapes: " + to_string(m_debugstats.shapes) + "\n" +
" traction: " + to_string(m_debugstats.traction) + "\n" + " lines: " + to_string(m_debugstats.lines);
debug_stats shadowstats;
for( auto const &shadowpass : m_shadowpass ) {
shadowstats += shadowpass.draw_stats;
}
m_debugstatstext =
"vehicles: " + to_string( m_colorpass.draw_stats.dynamics, 7 ) + " +" + to_string( shadowstats.dynamics, 7 )
+ " =" + to_string( m_colorpass.draw_stats.dynamics + shadowstats.dynamics, 7 ) + "\n"
+ "models: " + to_string( m_colorpass.draw_stats.models, 7 ) + " +" + to_string( shadowstats.models, 7 )
+ " =" + to_string( m_colorpass.draw_stats.models + shadowstats.models, 7 ) + "\n"
+ "drawcalls: " + to_string( m_colorpass.draw_stats.drawcalls, 7 ) + " +" + to_string( shadowstats.drawcalls, 7 )
+ " =" + to_string( m_colorpass.draw_stats.drawcalls + shadowstats.drawcalls, 7 ) + "\n"
+ " submodels:" + to_string( m_colorpass.draw_stats.submodels, 7 ) + " +" + to_string( shadowstats.submodels, 7 )
+ " =" + to_string( m_colorpass.draw_stats.submodels + shadowstats.submodels, 7 ) + "\n"
+ " paths: " + to_string( m_colorpass.draw_stats.paths, 7 ) + " +" + to_string( shadowstats.paths, 7 )
+ " =" + to_string( m_colorpass.draw_stats.paths + shadowstats.paths, 7 ) + "\n"
+ " shapes: " + to_string( m_colorpass.draw_stats.shapes, 7 ) + " +" + to_string( shadowstats.shapes, 7 )
+ " =" + to_string( m_colorpass.draw_stats.shapes + shadowstats.shapes, 7 ) + "\n"
+ " traction: " + to_string( m_colorpass.draw_stats.traction, 7 ) + "\n"
+ " lines: " + to_string( m_colorpass.draw_stats.lines, 7 ) + "\n"
+ "particles: " + to_string( m_colorpass.draw_stats.particles, 7 );
if (DebugModeFlag)
m_debugtimestext += m_textures.info();
@@ -528,7 +533,7 @@ void opengl33_renderer::draw_debug_ui()
void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
{
setup_pass(vp, m_renderpass, Mode);
switch (m_renderpass.draw_mode)
switch (m_renderpass.draw_mode)
{
case rendermode::color:
@@ -553,14 +558,14 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
break;
}
m_colorpass = m_renderpass; // cache pass data
scene_ubs.time = Timer::GetTime();
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
scene_ubs.inv_view = glm::inverse( glm::mat4{ glm::mat3{ m_renderpass.pass_camera.modelview() } } );
scene_ubo->update(scene_ubs);
scene_ubo->bind_uniform();
m_colorpass = m_renderpass;
if (m_widelines_supported)
glLineWidth(1.0f);
@@ -572,7 +577,7 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
setup_shadow_map(nullptr, m_renderpass);
setup_shadow_unbind_map();
setup_env_map(nullptr);
if (Global.gfx_shadowmap_enabled && vp.main)
@@ -580,10 +585,9 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
glDebug("render shadowmap start");
Timer::subsystem.gfx_shadows.start();
Render_pass(vp, rendermode::shadows);
if (!FreeFlyModeFlag && Global.render_cab)
Render_pass(vp, rendermode::cabshadows);
setup_pass(vp, m_renderpass, Mode); // restore draw mode. TBD, TODO: render mode stack
m_renderpass.draw_stats = {};
Render_pass(vp, rendermode::shadows);
m_renderpass = m_colorpass; // restore draw mode. TBD, TODO: render mode stack
Timer::subsystem.gfx_shadows.stop();
glDebug("render shadowmap end");
@@ -592,8 +596,9 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
if (Global.gfx_envmap_enabled && vp.main)
{
// potentially update environmental cube map
if (Render_reflections(vp))
setup_pass(vp, m_renderpass, Mode); // restore color pass settings
m_renderpass.draw_stats = {};
if (Render_reflections(vp))
m_renderpass = m_colorpass; // restore color pass settings
setup_env_map(m_env_tex.get());
}
@@ -632,6 +637,7 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
Timer::subsystem.gfx_color.start();
setup_matrices();
setup_drawing(true);
m_renderpass.draw_stats = {};
glm::mat4 future;
if (Global.pCamera.m_owner != nullptr)
@@ -649,6 +655,9 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
scene_ubo->update(scene_ubs);
Render(&simulation::Environment);
if( Global.gfx_shadowmap_enabled )
setup_shadow_bind_map();
// opaque parts...
setup_drawing(false);
@@ -657,9 +666,6 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
if (!FreeFlyModeFlag && Global.Overcast <= 1.0f && Global.render_cab)
{
glDebug("render cab opaque");
if( Global.gfx_shadowmap_enabled ) {
setup_shadow_map( m_cabshadows_tex.get(), m_cabshadowpass );
}
// cache shadow colour in case we need to account for cab light
auto const *vehicle{ simulation::Train->Dynamic() };
if( vehicle->InteriorLightLevel > 0.f ) {
@@ -675,9 +681,6 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
model_ubs.future = future;
if (Global.gfx_shadowmap_enabled)
setup_shadow_map(m_shadow_tex.get(), m_shadowpass);
Render(simulation::Region);
// ...translucent parts
@@ -696,9 +699,6 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
{
glDebug("render translucent cab");
model_ubs.future = glm::mat4();
if( Global.gfx_shadowmap_enabled ) {
setup_shadow_map( m_cabshadows_tex.get(), m_cabshadowpass );
}
// cache shadow colour in case we need to account for cab light
auto *vehicle { simulation::Train->Dynamic() };
if( vehicle->InteriorLightLevel > 0.f ) {
@@ -721,7 +721,10 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
Timer::subsystem.gfx_color.stop();
setup_shadow_map(nullptr, m_renderpass);
// store draw stats
m_colorpass.draw_stats = m_renderpass.draw_stats;
setup_shadow_unbind_map();
setup_env_map(nullptr);
if (!Global.gfx_usegles)
@@ -781,58 +784,46 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
glDebug("rendermode::shadows");
glEnable(GL_DEPTH_TEST);
glEnable(GL_DEPTH_TEST);
setup_drawing( false );
glViewport(0, 0, m_shadowbuffersize, m_shadowbuffersize);
m_shadow_fb->bind();
m_shadow_fb->clear(GL_DEPTH_BUFFER_BIT);
setup_matrices();
setup_drawing(false);
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
scene_ubo->update(scene_ubs);
if( m_shadowcolor != colors::white ) {
Render( simulation::Region );
float csmstageboundaries[] = { 0.0f, 5.0f, 25.0f, 1.0f };
if( Global.shadowtune.map_size > 2048 ) {
// increase coverage if our shadow map is large enough to produce decent results
csmstageboundaries[ 1 ] *= Global.shadowtune.map_size / 2048;
csmstageboundaries[ 2 ] *= Global.shadowtune.map_size / 2048;
}
m_shadowpass = m_renderpass;
for( auto idx = 0; idx < m_shadowpass.size(); ++idx ) {
m_shadow_fb->attach( *m_shadow_tex, GL_DEPTH_ATTACHMENT, idx );
m_shadow_fb->clear( GL_DEPTH_BUFFER_BIT );
setup_pass( vp, m_renderpass, rendermode::shadows, csmstageboundaries[ idx ], csmstageboundaries[ idx + 1 ] );
m_shadowpass[ idx ] = m_renderpass; // store pass config for reference in other stages
setup_matrices();
scene_ubs.projection = OpenGLMatrices.data( GL_PROJECTION );
auto const csmstagezfar {
( csmstageboundaries[ idx + 1 ] > 1.f ? csmstageboundaries[ idx + 1 ] : Global.shadowtune.range )
+ ( m_shadowpass.size() - idx ) }; // we can fairly safely add some extra padding in the early stages
scene_ubs.cascade_end[ idx ] = csmstagezfar * csmstagezfar; // store squared to allow semi-optimized length2 comparisons in the shader
scene_ubo->update( scene_ubs );
if( m_shadowcolor != colors::white ) {
Render( simulation::Region );
if( idx > 0 ) { continue; } // render cab only in the closest csm stage
if( !FreeFlyModeFlag && Global.render_cab ) {
Render_cab( simulation::Train->Dynamic(), 0.0f, false );
Render_cab( simulation::Train->Dynamic(), 0.0f, true );
}
}
}
m_shadow_fb->unbind();
glDebug("rendermodeshadows ::end");
break;
}
case rendermode::cabshadows:
{
glDebug("rendermode::cabshadows");
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, m_shadowbuffersize, m_shadowbuffersize);
m_cabshadows_fb->bind();
m_cabshadows_fb->clear(GL_DEPTH_BUFFER_BIT);
setup_matrices();
setup_drawing(false);
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
scene_ubo->update(scene_ubs);
if( m_shadowcolor != colors::white ) {
if( Global.RenderCabShadowsRange > 0 ) {
Render( simulation::Region );
}
Render_cab( simulation::Train->Dynamic(), 0.0f, false );
Render_cab( simulation::Train->Dynamic(), 0.0f, true );
}
m_cabshadowpass = m_renderpass;
m_cabshadows_fb->unbind();
glDebug("rendermode::cabshadows end");
glDebug("rendermode::shadows end");
break;
}
@@ -853,19 +844,17 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
setup_env_map(m_empty_cubemap.get());
setup_matrices();
setup_shadow_map(nullptr, m_renderpass);
// render
// environment...
setup_drawing(true);
setup_shadow_unbind_map();
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
scene_ubo->update(scene_ubs);
Render(&simulation::Environment);
// opaque parts...
setup_drawing(false);
setup_shadow_map(m_shadow_tex.get(), m_shadowpass);
setup_shadow_bind_map();
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
scene_ubo->update(scene_ubs);
Render(simulation::Region);
@@ -922,7 +911,7 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
scene_ubo->update(scene_ubs);
Render(simulation::Region);
Render(simulation::Region);
break;
}
@@ -1124,23 +1113,19 @@ glm::mat4 opengl33_renderer::ortho_frustumtest_projection(float l, float r, floa
void opengl33_renderer::setup_pass(viewport_config &Viewport, renderpass_config &Config, rendermode const Mode,
float const Znear, float const Zfar, bool const Ignoredebug)
{
Config.draw_mode = Mode;
if( false == simulation::is_ready ) { return; }
// 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::cabshadows: { Config.draw_range = ( Global.RenderCabShadowsRange > 0 ? clamp( Global.RenderCabShadowsRange, 5, 100 ) : simulation::Train->Occupied()->Dim.L ); break; }
case rendermode::reflections: { Config.draw_range = Global.BaseDrawRange; break; }
case rendermode::color: { Config.draw_range = Global.BaseDrawRange * Global.fDistanceFactor * Viewport.draw_range; break; }
case rendermode::shadows: { Config.draw_range = Global.shadowtune.range; break; }
case rendermode::reflections: { Config.draw_range = Global.BaseDrawRange * Viewport.draw_range; break; }
case rendermode::pickcontrols: { Config.draw_range = 50.f; break; }
case rendermode::pickscenery: { Config.draw_range = Global.BaseDrawRange * 0.5f; break; }
case rendermode::pickscenery: { Config.draw_range = Global.BaseDrawRange * Viewport.draw_range * 0.5f; break; }
default: { Config.draw_range = 0.f; break; }
}
Config.draw_range *= Viewport.draw_range;
// setup camera
auto &camera = Config.pass_camera;
@@ -1175,9 +1160,14 @@ void opengl33_renderer::setup_pass(viewport_config &Viewport, renderpass_config
Global.pDebugCamera.SetMatrix(viewmatrix);
}
// optimization: don't bother drawing things completely blended with the background
// but ensure at least 2 km range to account for signals and lights
Config.draw_range = std::min( Config.draw_range, m_fogrange * 2 );
Config.draw_range = std::max( 2000.f, Config.draw_range );
// projection
auto const zfar = Config.draw_range * Global.fDistanceFactor * Zfar;
auto const znear = (Znear > 0.f ? Znear * zfar : 0.1f * Global.ZoomFactor);
auto const zfar = ( Zfar > 1.f ? Zfar : Config.draw_range * Zfar );
auto const znear = ( Znear > 1.f ? Znear : Znear > 0.f ? Znear * zfar : 0.1f * Global.ZoomFactor);
camera.projection() = perspective_projection(fovy, aspect, znear, zfar);
frustumtest_proj = perpsective_frustumtest_projection(fovy, aspect, znear, zfar);
@@ -1187,9 +1177,11 @@ void opengl33_renderer::setup_pass(viewport_config &Viewport, renderpass_config
{
// calculate lightview boundaries based on relevant area of the world camera frustum:
// ...setup chunk of frustum we're interested in...
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.range / (Global.BaseDrawRange * Global.fDistanceFactor) * std::max(1.f, Global.ZoomFactor * 0.5f));
// auto const zfar = ( Zfar > 1.f ? Zfar * std::max( 1.f, Global.ZoomFactor * 0.5f ) : Zfar );
auto const zfar = ( Zfar > 1.f ? Zfar : Zfar * Global.shadowtune.range * std::max( Zfar, Global.ZoomFactor * 0.5f ) );
renderpass_config worldview;
setup_pass(Viewport, worldview, rendermode::color, 0.f, zfar, true);
setup_pass(Viewport, worldview, rendermode::color, Znear, zfar, true);
auto &frustumchunkshapepoints = worldview.pass_camera.frustum_points();
// ...modelview matrix: determine the centre of frustum chunk in world space...
glm::vec3 frustumchunkmin, frustumchunkmax;
@@ -1208,29 +1200,14 @@ void opengl33_renderer::setup_pass(viewport_config &Viewport, renderpass_config
}
bounding_box(frustumchunkmin, frustumchunkmax, std::begin(frustumchunkshapepoints), std::end(frustumchunkshapepoints));
// quantize the frustum points and add some padding, to reduce shadow shimmer on scale changes
auto const quantizationstep{std::min(Global.shadowtune.depth, 50.f)};
auto const frustumchunkdepth { zfar - ( Znear > 1.f ? Znear : 0.f ) };
auto const quantizationstep{std::min(frustumchunkdepth, 50.f)};
frustumchunkmin = quantizationstep * glm::floor(frustumchunkmin * (1.f / quantizationstep));
frustumchunkmax = quantizationstep * glm::ceil(frustumchunkmax * (1.f / quantizationstep));
// ...use the dimensions to set up light projection boundaries...
// NOTE: since we only have one cascade map stage, we extend the chunk forward/back to catch areas normally covered by other stages
camera.projection() = ortho_projection(frustumchunkmin.x, frustumchunkmax.x, frustumchunkmin.y, frustumchunkmax.y, frustumchunkmin.z - 500.f, frustumchunkmax.z + 500.f);
frustumtest_proj = ortho_frustumtest_projection(frustumchunkmin.x, frustumchunkmax.x, frustumchunkmin.y, frustumchunkmax.y, frustumchunkmin.z - 500.f, frustumchunkmax.z + 500.f);
/*
// fixed ortho projection from old build, for quick quality comparisons
camera.projection() *=
ortho_projection(
-Global.shadowtune.width, Global.shadowtune.width,
-Global.shadowtune.width, Global.shadowtune.width,
-Global.shadowtune.depth, Global.shadowtune.depth );
camera.position() = Global.pCamera.Pos - glm::dvec3{ m_sunlight.direction };
if( camera.position().y - Global.pCamera.Pos.y < 0.1 ) {
camera.position().y = Global.pCamera.Pos.y + 0.1;
}
viewmatrix *= glm::lookAt(
camera.position(),
glm::dvec3{ Global.pCamera.Pos },
glm::dvec3{ 0.f, 1.f, 0.f } );
*/
// ... and adjust the projection to sample complete shadow map texels:
// get coordinates for a sample texel...
auto shadowmaptexel = glm::vec2{camera.projection() * glm::mat4{viewmatrix} * glm::vec4{0.f, 0.f, 0.f, 1.f}};
@@ -1244,28 +1221,6 @@ void opengl33_renderer::setup_pass(viewport_config &Viewport, renderpass_config
break;
}
case rendermode::cabshadows:
{
// fixed size cube large enough to enclose a vehicle compartment
// modelview
auto const lightvector = glm::normalize(glm::vec3{m_sunlight.direction.x, std::min(m_sunlight.direction.y, -0.2f), m_sunlight.direction.z});
camera.position() = Global.pCamera.Pos - glm::dvec3{lightvector};
viewmatrix *= glm::lookAt(camera.position(), glm::dvec3{Global.pCamera.Pos}, glm::dvec3{0.f, 1.f, 0.f});
// projection
auto const maphalfsize { std::min( 10.f, Config.draw_range * 0.5f ) };
camera.projection() = ortho_projection(-maphalfsize, maphalfsize, -maphalfsize, maphalfsize, -Config.draw_range, Config.draw_range);
frustumtest_proj = ortho_frustumtest_projection(-maphalfsize, maphalfsize, -maphalfsize, maphalfsize, -Config.draw_range, Config.draw_range);
/*
// adjust the projection to sample complete shadow map texels
auto shadowmaptexel = glm::vec2 { camera.projection() * glm::mat4{ viewmatrix } * glm::vec4{ 0.f, 0.f, 0.f, 1.f } };
shadowmaptexel *= ( m_shadowbuffersize / 2 ) * 0.5f;
auto shadowmapadjustment = glm::round( shadowmaptexel ) - shadowmaptexel;
shadowmapadjustment /= ( m_shadowbuffersize / 2 ) * 0.5f;
camera.projection() = glm::translate( glm::mat4{ 1.f }, glm::vec3{ shadowmapadjustment, 0.f } ) * camera.projection();
*/
break;
}
case rendermode::pickcontrols:
case rendermode::pickscenery:
{
@@ -1312,7 +1267,7 @@ void opengl33_renderer::setup_matrices()
OpenGLMatrices.load_matrix(m_renderpass.pass_camera.projection());
// trim modelview matrix just to rotation, since rendering is done in camera-centric world space
OpenGLMatrices.mode(GL_MODELVIEW);
OpenGLMatrices.load_matrix(glm::mat4(glm::mat3(m_renderpass.pass_camera.modelview())));
OpenGLMatrices.load_matrix(glm::mat4{glm::mat3{m_renderpass.pass_camera.modelview()}});
}
void opengl33_renderer::setup_drawing(bool const Alpha)
@@ -1339,7 +1294,6 @@ void opengl33_renderer::setup_drawing(bool const Alpha)
break;
}
case rendermode::shadows:
case rendermode::cabshadows:
{
glCullFace(GL_FRONT);
break;
@@ -1357,50 +1311,52 @@ void opengl33_renderer::setup_drawing(bool const Alpha)
}
}
// configures shadow texture unit for specified shadow map and conersion matrix
void opengl33_renderer::setup_shadow_map(opengl_texture *tex, renderpass_config conf)
void opengl33_renderer::setup_shadow_unbind_map()
{
if (tex)
tex->bind(gl::MAX_TEXTURES + 0);
opengl_texture::unbind( gl::MAX_TEXTURES + 0 );
}
// binds shadow map and updates shadow map uniform data
void opengl33_renderer::setup_shadow_bind_map()
{
m_shadow_tex->bind(gl::MAX_TEXTURES + 0);
glm::mat4 coordmove;
if (GLAD_GL_ARB_clip_control || GLAD_GL_EXT_clip_control)
// transform 1..-1 NDC xy coordinates to 1..0
coordmove = glm::mat4( //
0.5, 0.0, 0.0, 0.0, //
0.0, 0.5, 0.0, 0.0, //
0.0, 0.0, 1.0, 0.0, //
0.5, 0.5, 0.0, 1.0 //
);
else
opengl_texture::unbind(gl::MAX_TEXTURES + 0);
// without clip_control we also need to transform z
coordmove = glm::mat4( //
0.5, 0.0, 0.0, 0.0, //
0.0, 0.5, 0.0, 0.0, //
0.0, 0.0, 0.5, 0.0, //
0.5, 0.5, 0.5, 1.0 //
);
if (tex)
{
glm::mat4 coordmove;
for( auto idx = 0; idx < m_shadowpass.size(); ++idx ) {
if (GLAD_GL_ARB_clip_control || GLAD_GL_EXT_clip_control)
// transform 1..-1 NDC xy coordinates to 1..0
coordmove = glm::mat4( //
0.5, 0.0, 0.0, 0.0, //
0.0, 0.5, 0.0, 0.0, //
0.0, 0.0, 1.0, 0.0, //
0.5, 0.5, 0.0, 1.0 //
);
else
// without clip_control we also need to transform z
coordmove = glm::mat4( //
0.5, 0.0, 0.0, 0.0, //
0.0, 0.5, 0.0, 0.0, //
0.0, 0.0, 0.5, 0.0, //
0.5, 0.5, 0.5, 1.0 //
);
glm::mat4 depthproj = conf.pass_camera.projection();
glm::mat4 depthproj = m_shadowpass[ idx ].pass_camera.projection();
// NOTE: we strip transformations from camera projections to remove jitter that occurs
// with large (and unneded as we only need the offset) transformations back and forth
auto const depthcam{ glm::mat3{ conf.pass_camera.modelview()} };
auto const depthcam{ glm::mat3{ m_shadowpass[ idx ].pass_camera.modelview()} };
auto const worldcam{ glm::mat3{ m_renderpass.pass_camera.modelview()} };
scene_ubs.lightview =
scene_ubs.lightview[ idx ] =
coordmove
* depthproj
* glm::translate(
glm::mat4{ depthcam },
glm::vec3{ m_renderpass.pass_camera.position() - conf.pass_camera.position() } )
glm::vec3{ m_renderpass.pass_camera.position() - m_shadowpass[ idx ].pass_camera.position() } )
* glm::mat4{ glm::inverse( worldcam ) };
scene_ubo->update(scene_ubs);
}
}
scene_ubo->update(scene_ubs);
}
void opengl33_renderer::setup_shadow_color( glm::vec4 const &Shadowcolor ) {
@@ -1918,7 +1874,6 @@ void opengl33_renderer::Render(scene::basic_region *Region)
break;
}
case rendermode::shadows:
case rendermode::cabshadows:
case rendermode::pickscenery:
{
// these render modes don't bother with lights
@@ -1950,7 +1905,6 @@ void opengl33_renderer::Render(section_sequence::iterator First, section_sequenc
{
case rendermode::color:
case rendermode::reflections:
case rendermode::cabshadows:
case rendermode::shadows:
break;
case rendermode::pickscenery:
@@ -1975,7 +1929,6 @@ void opengl33_renderer::Render(section_sequence::iterator First, section_sequenc
case rendermode::color:
case rendermode::reflections:
case rendermode::shadows:
case rendermode::cabshadows:
case rendermode::pickscenery:
{
if (false == section->m_shapes.empty())
@@ -2006,7 +1959,6 @@ void opengl33_renderer::Render(section_sequence::iterator First, section_sequenc
{
case rendermode::color:
case rendermode::shadows:
case rendermode::cabshadows:
case rendermode::pickscenery:
{
for (auto &cell : section->m_cells)
@@ -2033,7 +1985,6 @@ void opengl33_renderer::Render(section_sequence::iterator First, section_sequenc
switch (m_renderpass.draw_mode)
{
case rendermode::shadows:
case rendermode::cabshadows:
{
break;
}
@@ -2099,24 +2050,6 @@ void opengl33_renderer::Render(cell_sequence::iterator First, cell_sequence::ite
break;
}
case rendermode::cabshadows:
{
// since all shapes of the section share center point we can optimize out a few calls here
::glPushMatrix();
auto const originoffset{cell->m_area.center - m_renderpass.pass_camera.position()};
::glTranslated(originoffset.x, originoffset.y, originoffset.z);
// render
// opaque non-instanced shapes
for (auto const &shape : cell->m_shapesopaque)
Render(shape, false);
// NOTE: tracks aren't likely to cast shadows into the cab, so we skip them in this pass
// post-render cleanup
::glPopMatrix();
break;
}
case rendermode::pickscenery:
{
// same procedure like with regular render, but editor-enabled nodes receive custom colour used for picking
@@ -2160,7 +2093,6 @@ void opengl33_renderer::Render(cell_sequence::iterator First, cell_sequence::ite
{
case rendermode::color:
case rendermode::shadows:
case rendermode::cabshadows:
{
// opaque parts of instanced models
for (auto *instance : cell->m_instancesopaque)
@@ -2237,7 +2169,6 @@ void opengl33_renderer::Render(scene::shape_node const &Shape, bool const Ignore
switch (m_renderpass.draw_mode)
{
case rendermode::shadows:
case rendermode::cabshadows:
{
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = Math3D::SquareMagnitude((data.area.center - m_renderpass.viewport_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
@@ -2263,7 +2194,6 @@ void opengl33_renderer::Render(scene::shape_node const &Shape, bool const Ignore
Bind_Material(data.material);
break;
case rendermode::shadows:
case rendermode::cabshadows:
Bind_Material_Shadow(data.material);
break;
case rendermode::pickscenery:
@@ -2277,31 +2207,28 @@ void opengl33_renderer::Render(scene::shape_node const &Shape, bool const Ignore
draw(data.geometry);
// debug data
++m_debugstats.shapes;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.shapes;
++m_renderpass.draw_stats.drawcalls;
}
void opengl33_renderer::Render(TAnimModel *Instance)
{
if (false == Instance->m_visible)
{
return;
}
if (false == Instance->m_visible) { return; }
if( false == m_renderpass.pass_camera.visible( Instance->m_area ) ) { return; }
double distancesquared;
double distancesquared;
switch (m_renderpass.draw_mode)
{
case rendermode::shadows:
case rendermode::cabshadows:
{
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = Math3D::SquareMagnitude((Instance->location() - m_renderpass.viewport_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = glm::length2((Instance->location() - m_renderpass.viewport_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
break;
}
default:
{
distancesquared = Math3D::SquareMagnitude((Instance->location() - m_renderpass.pass_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
distancesquared = glm::length2((Instance->location() - m_renderpass.pass_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
break;
}
}
@@ -2330,6 +2257,8 @@ void opengl33_renderer::Render(TAnimModel *Instance)
{
// renderowanie rekurencyjne submodeli
Render(Instance->pModel, Instance->Material(), distancesquared, Instance->location() - m_renderpass.pass_camera.position(), Instance->vAngle);
// debug data
++m_renderpass.draw_stats.models;
}
}
@@ -2340,13 +2269,11 @@ bool opengl33_renderer::Render(TDynamicObject *Dynamic)
if (!Global.render_cab && Global.pCamera.m_owner == Dynamic)
return false;
Dynamic->renderme = m_renderpass.pass_camera.visible(Dynamic);
if (false == Dynamic->renderme)
{
return false;
}
// debug data
++m_debugstats.dynamics;
Dynamic->renderme = (
( Global.pCamera.m_owner == Dynamic && !FreeFlyModeFlag )
|| ( m_renderpass.pass_camera.visible( Dynamic ) ) );
if (false == Dynamic->renderme) { return false; }
// setup
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>(Dynamic); //żeby nie robić cudzych animacji
@@ -2364,18 +2291,23 @@ bool opengl33_renderer::Render(TDynamicObject *Dynamic)
}
break;
}
case rendermode::cabshadows: {
squaredistance = glm::length2( glm::vec3{ glm::dvec3{ Dynamic->vPosition - m_renderpass.viewport_camera.position() } } / Global.ZoomFactor ) / Global.fDistanceFactor;
// filter out small details
squaredistance = std::max( 100.f * 100.f, squaredistance );
break;
}
default:
{
squaredistance = glm::length2(glm::vec3{originoffset} / Global.ZoomFactor) / Global.fDistanceFactor;
// TODO: filter out small details based on fidelity setting
break;
}
}
// second stage visibility cull, reject vehicles too far away to be noticeable
Dynamic->renderme = ( Dynamic->radius() * Global.ZoomFactor / std::sqrt( squaredistance ) > 0.003 );
if( false == Dynamic->renderme ) {
return false;
}
// debug data
++m_renderpass.draw_stats.dynamics;
Dynamic->ABuLittleUpdate(squaredistance); // ustawianie zmiennych submodeli dla wspólnego modelu
glm::mat4 future_stack = model_ubs.future;
@@ -2428,7 +2360,6 @@ bool opengl33_renderer::Render(TDynamicObject *Dynamic)
break;
}
case rendermode::shadows:
case rendermode::cabshadows:
{
if( Dynamic->mdLowPolyInt ) {
// low poly interior
@@ -2543,7 +2474,8 @@ bool opengl33_renderer::Render_cab(TDynamicObject const *Dynamic, float const Li
break;
}
case rendermode::cabshadows: {
case rendermode::shadows:
{
if( true == Alpha ) {
// translucent parts
Render_Alpha( Dynamic->mdKabina, Dynamic->Material(), 0.0 );
@@ -2592,9 +2524,6 @@ bool opengl33_renderer::Render(TModel3d *Model, material_data const *Material, f
// render
Render(Model->Root);
// debug data
++m_debugstats.models;
// post-render cleanup
return true;
@@ -2627,8 +2556,8 @@ void opengl33_renderer::Render(TSubModel *Submodel)
{
// debug data
++m_debugstats.submodels;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
glm::mat4 future_stack = model_ubs.future;
@@ -2689,7 +2618,6 @@ void opengl33_renderer::Render(TSubModel *Submodel)
break;
}
case rendermode::shadows:
case rendermode::cabshadows:
{
if (Submodel->m_material < 0)
{ // zmienialne skóry
@@ -2781,8 +2709,8 @@ void opengl33_renderer::Render(TTrack *Track)
return;
}
++m_debugstats.paths;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.paths;
++m_renderpass.draw_stats.drawcalls;
switch (m_renderpass.draw_mode)
{
@@ -2813,7 +2741,6 @@ void opengl33_renderer::Render(scene::basic_cell::path_sequence::const_iterator
switch (m_renderpass.draw_mode)
{
case rendermode::shadows:
case rendermode::cabshadows:
{
// NOTE: roads-based platforms tend to miss parts of shadows if rendered with either back or front culling
glDisable(GL_CULL_FACE);
@@ -2841,8 +2768,8 @@ void opengl33_renderer::Render(scene::basic_cell::path_sequence::const_iterator
continue;
}
++m_debugstats.paths;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.paths;
++m_renderpass.draw_stats.drawcalls;
switch (m_renderpass.draw_mode)
{
@@ -2863,7 +2790,6 @@ void opengl33_renderer::Render(scene::basic_cell::path_sequence::const_iterator
break;
}
case rendermode::shadows:
case rendermode::cabshadows:
{
if ((std::abs(track->fTexHeight1) < 0.35f) || (track->iCategoryFlag != 2))
{
@@ -2915,7 +2841,6 @@ void opengl33_renderer::Render(scene::basic_cell::path_sequence::const_iterator
break;
}
case rendermode::shadows:
case rendermode::cabshadows:
{
if ((std::abs(track->fTexHeight1) < 0.35f) || ((track->iCategoryFlag == 1) && (track->eType != tt_Normal)))
{
@@ -2973,7 +2898,6 @@ void opengl33_renderer::Render(scene::basic_cell::path_sequence::const_iterator
break;
}
case rendermode::shadows:
case rendermode::cabshadows:
{
if ((std::abs(track->fTexHeight1) < 0.35f) || ((track->iCategoryFlag == 1) && (track->eType != tt_Normal)))
{
@@ -2997,7 +2921,6 @@ void opengl33_renderer::Render(scene::basic_cell::path_sequence::const_iterator
switch (m_renderpass.draw_mode)
{
case rendermode::shadows:
case rendermode::cabshadows:
{
// restore standard face cull mode
::glEnable(GL_CULL_FACE);
@@ -3024,7 +2947,6 @@ void opengl33_renderer::Render(TMemCell *Memcell)
break;
}
case rendermode::shadows:
case rendermode::cabshadows:
case rendermode::pickscenery:
{
break;
@@ -3050,7 +2972,7 @@ void opengl33_renderer::Render_particles()
Bind_Texture(0, m_smoketexture);
m_particlerenderer.update(m_renderpass.pass_camera);
m_particlerenderer.render();
m_renderpass.draw_stats.particles = m_particlerenderer.render();
}
void opengl33_renderer::Render_precipitation()
@@ -3210,15 +3132,18 @@ void opengl33_renderer::Render_Alpha(cell_sequence::reverse_iterator First, cell
void opengl33_renderer::Render_Alpha(TAnimModel *Instance)
{
if (false == Instance->m_visible)
{
return;
}
if (false == Instance->m_visible) { return; }
if( false == m_renderpass.pass_camera.visible( Instance->m_area ) ) { return; }
double distancesquared;
double distancesquared;
switch (m_renderpass.draw_mode)
{
case rendermode::shadows:
{
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = glm::length2((Instance->location() - m_renderpass.viewport_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
break;
}
default:
{
distancesquared = glm::length2((Instance->location() - m_renderpass.pass_camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
@@ -3277,8 +3202,8 @@ void opengl33_renderer::Render_Alpha(TTraction *Traction)
draw(Traction->m_geometry);
// debug data
++m_debugstats.traction;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.traction;
++m_renderpass.draw_stats.drawcalls;
if (m_widelines_supported)
glLineWidth(1.0f);
@@ -3310,8 +3235,8 @@ void opengl33_renderer::Render_Alpha(scene::lines_node const &Lines)
m_line_shader->bind();
draw(data.geometry);
++m_debugstats.lines;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.lines;
++m_renderpass.draw_stats.drawcalls;
if (m_widelines_supported)
glLineWidth(1.0f);
@@ -3446,8 +3371,8 @@ void opengl33_renderer::Render_Alpha(TSubModel *Submodel)
{
// debug data
++m_debugstats.submodels;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
glm::mat4 future_stack = model_ubs.future;
@@ -3497,7 +3422,7 @@ void opengl33_renderer::Render_Alpha(TSubModel *Submodel)
model_ubs.emission = 0.0f;
break;
}
case rendermode::cabshadows:
case rendermode::shadows:
{
if (Submodel->m_material < 0)
{ // zmienialne skóry
@@ -3610,7 +3535,7 @@ void opengl33_renderer::Render_Alpha(TSubModel *Submodel)
// material configuration:
// limit impact of dense fog on the lights
auto const lightrange { std::max<float>( 500, m_fogrange * 2 ) }; // arbitrary, visibility at least 750m
auto const lightrange { std::max<float>( 500, m_fogrange * 2 ) }; // arbitrary, visibility at least 500m
model_ubs.fog_density = 1.0 / lightrange;
// main draw call
@@ -3901,12 +3826,12 @@ void opengl33_renderer::Update(double const Deltatime)
// TODO: it doesn't make much sense with vsync
if( Global.targetfps == 0.0f ) {
// automatic adjustment
auto const framerate = 1000.f / Timer::subsystem.gfx_color.average();
auto const framerate = 0.5f * ( m_framerate + 1000.f / Timer::subsystem.gfx_color.average() );
float targetfactor;
if( framerate > 90.0 ) { targetfactor = 3.0f; }
else if( framerate > 60.0 ) { targetfactor = 1.5f; }
else if( framerate > 30.0 ) { targetfactor = 1.25; }
else { targetfactor = 1.0f; }
if( framerate > 120.0 ) { targetfactor = 3.00f; }
else if( framerate > 90.0 ) { targetfactor = 1.50f; }
else if( framerate > 60.0 ) { targetfactor = 1.25f; }
else { targetfactor = 1.00f; }
if( targetfactor > Global.fDistanceFactor ) {
Global.fDistanceFactor = std::min( targetfactor, Global.fDistanceFactor + 0.05f );
}

View File

@@ -139,7 +139,6 @@ class opengl33_renderer : public gfx_renderer {
none,
color,
shadows,
cabshadows,
reflections,
pickcontrols,
pickscenery
@@ -154,7 +153,20 @@ class opengl33_renderer : public gfx_renderer {
int traction{0};
int shapes{0};
int lines{0};
int particles{0};
int drawcalls{0};
debug_stats& operator+=( const debug_stats& Right ) {
dynamics += Right.dynamics;
models += Right.models;
submodels += Right.submodels;
paths += Right.paths;
traction += Right.traction;
shapes += Right.shapes;
lines += Right.lines;
particles += Right.particles;
drawcalls += Right.drawcalls;
return *this; }
};
using section_sequence = std::vector<scene::basic_section *>;
@@ -167,6 +179,7 @@ class opengl33_renderer : public gfx_renderer {
opengl_camera viewport_camera;
rendermode draw_mode{rendermode::none};
float draw_range{0.0f};
debug_stats draw_stats;
};
struct viewport_config {
@@ -203,7 +216,8 @@ class opengl33_renderer : public gfx_renderer {
void setup_pass(viewport_config &Viewport, renderpass_config &Config, rendermode const Mode, float const Znear = 0.f, float const Zfar = 1.f, bool const Ignoredebug = false);
void setup_matrices();
void setup_drawing(bool const Alpha = false);
void setup_shadow_map(opengl_texture *tex, renderpass_config conf);
void setup_shadow_unbind_map();
void setup_shadow_bind_map();
void setup_shadow_color( glm::vec4 const &Shadowcolor );
void setup_env_map(gl::cubemap *tex);
void setup_environment_light(TEnvironmentType const Environment = e_flat);
@@ -269,7 +283,6 @@ class opengl33_renderer : public gfx_renderer {
// main shadowmap resources
int m_shadowbuffersize{2048};
glm::mat4 m_shadowtexturematrix; // conversion from camera-centric world space to light-centric clip space
glm::mat4 m_cabshadowtexturematrix; // conversion from cab-centric world space to light-centric clip space
int m_environmentcubetextureface{0}; // helper, currently processed cube map face
double m_environmentupdatetime{0}; // time of the most recent environment map update
@@ -283,7 +296,7 @@ class opengl33_renderer : public gfx_renderer {
double m_updateaccumulator{0.0};
std::string m_debugtimestext;
std::string m_pickdebuginfo;
debug_stats m_debugstats;
//debug_stats m_debugstats;
std::string m_debugstatstext;
glm::vec4 m_baseambient{0.0f, 0.0f, 0.0f, 1.0f};
@@ -298,8 +311,7 @@ class opengl33_renderer : public gfx_renderer {
section_sequence m_sectionqueue; // list of sections in current render pass
cell_sequence m_cellqueue;
renderpass_config m_colorpass; // parametrs of most recent color pass
renderpass_config m_shadowpass; // parametrs of most recent shadowmap pass
renderpass_config m_cabshadowpass; // parameters of most recent cab shadowmap pass
std::array<renderpass_config, 3> m_shadowpass; // parametrs of most recent shadowmap pass for each of csm stages
std::vector<TSubModel const *> m_pickcontrolsitems;
TSubModel const *m_pickcontrolitem{nullptr};
std::vector<scene::basic_node *> m_picksceneryitems;
@@ -356,9 +368,6 @@ class opengl33_renderer : public gfx_renderer {
std::unique_ptr<gl::cubemap> m_empty_cubemap;
std::unique_ptr<gl::framebuffer> m_cabshadows_fb;
std::unique_ptr<opengl_texture> m_cabshadows_tex;
std::unique_ptr<gl::framebuffer> m_env_fb;
std::unique_ptr<gl::renderbuffer> m_env_rb;
std::unique_ptr<gl::cubemap> m_env_tex;

View File

@@ -37,14 +37,8 @@ bool
opengl_camera::visible( TDynamicObject const *Dynamic ) const {
// sphere test is faster than AABB, so we'll use it here
glm::vec3 diagonal(
static_cast<float>( Dynamic->MoverParameters->Dim.L ),
static_cast<float>( Dynamic->MoverParameters->Dim.H ),
static_cast<float>( Dynamic->MoverParameters->Dim.W ) );
// we're giving vehicles some extra padding, to allow for things like shared bogeys extending past the main body
float const radius = glm::length( diagonal ) * 0.65f;
return ( m_frustum.sphere_inside( Dynamic->GetPosition(), radius ) > 0.0f );
return ( m_frustum.sphere_inside( Dynamic->GetPosition(), Dynamic->radius() * 1.25 ) > 0.0f );
}
// debug helper, draws shape of frustum in world space

View File

@@ -330,10 +330,10 @@ opengl_renderer::Render() {
m_sunlight.direction = glm::normalize( quantizationstep * glm::roundEven( m_sunlight.direction * ( 1.f / quantizationstep ) ) );
}
// generate new frame
m_renderpass.draw_mode = rendermode::none; // force setup anew
opengl_texture::reset_unit_cache();
m_renderpass.draw_mode = rendermode::none; // force setup anew
m_renderpass.draw_stats = debug_stats();
m_debugtimestext.clear();
m_debugstats = debug_stats();
Render_pass( rendermode::color );
Timer::subsystem.gfx_color.stop();
// add user interface
@@ -358,15 +358,21 @@ opengl_renderer::Render() {
+ "frame total: " + to_string( Timer::subsystem.gfx_color.average() + Timer::subsystem.gfx_swap.average(), 2 ) + " msec";
m_debugstatstext =
"drawcalls: " + to_string( m_debugstats.drawcalls ) + "\n"
+ " vehicles: " + to_string( m_debugstats.dynamics ) + "\n"
+ " models: " + to_string( m_debugstats.models ) + "\n"
+ " submodels: " + to_string( m_debugstats.submodels ) + "\n"
+ " paths: " + to_string( m_debugstats.paths ) + "\n"
+ " shapes: " + to_string( m_debugstats.shapes ) + "\n"
+ " traction: " + to_string( m_debugstats.traction ) + "\n"
+ " lines: " + to_string( m_debugstats.lines ) + "\n"
+ "particles: " + to_string( m_debugstats.particles );
"vehicles: " + to_string( m_colorpass.draw_stats.dynamics, 7 ) + " +" + to_string( m_shadowpass.draw_stats.dynamics, 7 )
+ " =" + to_string( m_colorpass.draw_stats.dynamics + m_shadowpass.draw_stats.dynamics, 7 ) + "\n"
+ "models: " + to_string( m_colorpass.draw_stats.models, 7 ) + " +" + to_string( m_shadowpass.draw_stats.models, 7 )
+ " =" + to_string( m_colorpass.draw_stats.models + m_shadowpass.draw_stats.models, 7 ) + "\n"
+ "drawcalls: " + to_string( m_colorpass.draw_stats.drawcalls, 7 ) + " +" + to_string( m_shadowpass.draw_stats.drawcalls, 7 )
+ " =" + to_string( m_colorpass.draw_stats.drawcalls + m_shadowpass.draw_stats.drawcalls, 7 ) + "\n"
+ " submodels:" + to_string( m_colorpass.draw_stats.submodels, 7 ) + " +" + to_string( m_shadowpass.draw_stats.submodels, 7 )
+ " =" + to_string( m_colorpass.draw_stats.submodels + m_shadowpass.draw_stats.submodels, 7 ) + "\n"
+ " paths: " + to_string( m_colorpass.draw_stats.paths, 7 ) + " +" + to_string( m_shadowpass.draw_stats.paths, 7 )
+ " =" + to_string( m_colorpass.draw_stats.paths + m_shadowpass.draw_stats.paths, 7 ) + "\n"
+ " shapes: " + to_string( m_colorpass.draw_stats.shapes, 7 ) + " +" + to_string( m_shadowpass.draw_stats.shapes, 7 )
+ " =" + to_string( m_colorpass.draw_stats.shapes + m_shadowpass.draw_stats.shapes, 7 ) + "\n"
+ " traction: " + to_string( m_colorpass.draw_stats.traction, 7 ) + "\n"
+ " lines: " + to_string( m_colorpass.draw_stats.lines, 7 ) + "\n"
+ "particles: " + to_string( m_colorpass.draw_stats.particles, 7 );
++m_framestamp;
@@ -436,6 +442,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
if( ( true == m_environmentcubetexturesupport )
&& ( true == simulation::is_ready ) ) {
// potentially update environmental cube map
m_renderpass.draw_stats = {};
if( true == Render_reflections() ) {
setup_pass( m_renderpass, Mode ); // restore draw mode. TBD, TODO: render mode stack
}
@@ -458,6 +465,7 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
// render
setup_drawing( true );
setup_units( true, false, false );
m_renderpass.draw_stats = {};
Render( &simulation::Environment );
// opaque parts...
setup_drawing( false );
@@ -547,6 +555,9 @@ opengl_renderer::Render_pass( rendermode const Mode ) {
::glMatrixMode( GL_MODELVIEW );
}
}
// store draw stats
m_colorpass.draw_stats = m_renderpass.draw_stats;
break;
}
@@ -863,8 +874,8 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f
if( false == simulation::is_ready ) { return; }
// 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::color: { Config.draw_range = Global.BaseDrawRange * Global.fDistanceFactor; break; }
case rendermode::shadows: { Config.draw_range = Global.shadowtune.range; break; }
case rendermode::cabshadows: { Config.draw_range = ( Global.RenderCabShadowsRange > 0 ? clamp( Global.RenderCabShadowsRange, 5, 100 ) : simulation::Train->Occupied()->Dim.L ); break; }
case rendermode::reflections: { Config.draw_range = Global.BaseDrawRange; break; }
case rendermode::pickcontrols: { Config.draw_range = 50.f; break; }
@@ -888,12 +899,13 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f
camera.position() = Global.pDebugCamera.Pos;
Global.pDebugCamera.SetMatrix( viewmatrix );
}
// optimization: don't bother drawing things completely blended with the background
// but ensure at least 2 km range to account for signals and lights
Config.draw_range = std::min( Config.draw_range, m_fogrange * 2 );
Config.draw_range = std::max( 2000.f, Config.draw_range );
// projection
auto const zfar = Config.draw_range * Global.fDistanceFactor * Zfar;
auto const znear = (
Znear > 0.f ?
Znear * zfar :
0.1f * Global.ZoomFactor );
auto const zfar = ( Zfar > 1.f ? Zfar : Config.draw_range * Zfar );
auto const znear = ( Znear > 1.f ? Znear : Znear > 0.f ? Znear * zfar : 0.1f * Global.ZoomFactor);
camera.projection() *=
glm::perspective(
glm::radians( Global.FieldOfView / Global.ZoomFactor ),
@@ -911,9 +923,11 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f
case rendermode::shadows: {
// calculate lightview boundaries based on relevant area of the world camera frustum:
// ...setup chunk of frustum we're interested in...
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.range / ( Global.BaseDrawRange * Global.fDistanceFactor ) * std::max( 1.f, Global.ZoomFactor * 0.5f ) );
// auto const zfar = Global.shadowtune.range * std::max( Zfar, Global.ZoomFactor * 0.5f );
auto const zfar = ( Zfar > 1.f ? Zfar : Zfar * Global.shadowtune.range * std::max( Zfar, Global.ZoomFactor * 0.5f ) );
renderpass_config worldview;
setup_pass( worldview, rendermode::color, 0.f, zfar, true );
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;
@@ -941,7 +955,8 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f
}
bounding_box( frustumchunkmin, frustumchunkmax, std::begin( frustumchunkshapepoints ), std::end( frustumchunkshapepoints ) );
// quantize the frustum points and add some padding, to reduce shadow shimmer on scale changes
auto const quantizationstep{ std::min( Global.shadowtune.depth, 50.f ) };
auto const frustumchunkdepth { zfar - ( Znear > 1.f ? Znear : 0.f ) };
auto const quantizationstep{std::min(frustumchunkdepth, 50.f)};
frustumchunkmin = quantizationstep * glm::floor( frustumchunkmin * ( 1.f / quantizationstep ) );
frustumchunkmax = quantizationstep * glm::ceil( frustumchunkmax * ( 1.f / quantizationstep ) );
// ...use the dimensions to set up light projection boundaries...
@@ -951,22 +966,6 @@ opengl_renderer::setup_pass( renderpass_config &Config, rendermode const Mode, f
frustumchunkmin.x, frustumchunkmax.x,
frustumchunkmin.y, frustumchunkmax.y,
frustumchunkmin.z - 500.f, frustumchunkmax.z + 500.f );
/*
// fixed ortho projection from old build, for quick quality comparisons
camera.projection() *=
glm::ortho(
-Global.shadowtune.width, Global.shadowtune.width,
-Global.shadowtune.width, Global.shadowtune.width,
-Global.shadowtune.depth, Global.shadowtune.depth );
camera.position() = Global.pCameraPosition - glm::dvec3{ m_sunlight.direction };
if( camera.position().y - Global.pCameraPosition.y < 0.1 ) {
camera.position().y = Global.pCameraPosition.y + 0.1;
}
viewmatrix *= glm::lookAt(
camera.position(),
glm::dvec3{ Global.pCameraPosition },
glm::dvec3{ 0.f, 1.f, 0.f } );
*/
// ... and adjust the projection to sample complete shadow map texels:
// get coordinates for a sample texel...
auto shadowmaptexel = glm::vec2 { camera.projection() * glm::mat4{ viewmatrix } * glm::vec4{ 0.f, 0.f, 0.f, 1.f } };
@@ -2168,27 +2167,26 @@ opengl_renderer::Render( scene::shape_node const &Shape, bool const Ignorerange
// render
m_geometry.draw( data.geometry );
// debug data
++m_debugstats.shapes;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.shapes;
++m_renderpass.draw_stats.drawcalls;
}
void
opengl_renderer::Render( TAnimModel *Instance ) {
if( false == Instance->m_visible ) {
return;
}
if( false == Instance->m_visible ) { return; }
if( false == m_renderpass.camera.visible( Instance->m_area ) ) { return; }
double distancesquared;
switch( m_renderpass.draw_mode ) {
case rendermode::shadows:
case rendermode::cabshadows: {
// 'camera' for the light pass is the light source, but we need to draw what the 'real' camera sees
distancesquared = Math3D::SquareMagnitude( ( Instance->location() - Global.pCamera.Pos ) / Global.ZoomFactor ) / Global.fDistanceFactor;
distancesquared = glm::length2((Instance->location() - m_renderpass.camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
break;
}
default: {
distancesquared = Math3D::SquareMagnitude( ( Instance->location() - m_renderpass.camera.position() ) / (double)Global.ZoomFactor ) / Global.fDistanceFactor;
distancesquared = glm::length2((Instance->location() - m_renderpass.camera.position()) / (double)Global.ZoomFactor) / Global.fDistanceFactor;
break;
}
}
@@ -2223,16 +2221,19 @@ opengl_renderer::Render( TAnimModel *Instance ) {
distancesquared,
Instance->location() - m_renderpass.camera.position(),
Instance->vAngle );
// debug data
++m_renderpass.draw_stats.models;
}
}
bool
opengl_renderer::Render( TDynamicObject *Dynamic ) {
Dynamic->renderme = m_renderpass.camera.visible( Dynamic );
if( false == Dynamic->renderme ) {
return false;
}
Dynamic->renderme = (
( Global.pCamera.m_owner == Dynamic && !FreeFlyModeFlag )
|| ( m_renderpass.camera.visible( Dynamic ) ) );
if( false == Dynamic->renderme ) { return false; }
// lod visibility ranges are defined for base (x 1.0) viewing distance. for render we adjust them for actual range multiplier and zoom
float squaredistance;
@@ -2254,18 +2255,20 @@ opengl_renderer::Render( TDynamicObject *Dynamic ) {
}
default: {
squaredistance = glm::length2( glm::vec3{ originoffset } / Global.ZoomFactor ) / Global.fDistanceFactor;
// TODO: filter out small details based on fidelity setting
break;
}
}
// crude way to reject early items too far to affect the output (mostly relevant for shadow passes)
auto const drawdistancethreshold { m_renderpass.draw_range + 250 };
if( squaredistance > drawdistancethreshold * drawdistancethreshold ) {
// second stage visibility cull, reject vehicles too far away to be noticeable
Dynamic->renderme = ( Dynamic->radius() * Global.ZoomFactor / std::sqrt( squaredistance ) > 0.003 );
if( false == Dynamic->renderme ) {
return false;
}
// debug data
++m_debugstats.dynamics;
++m_renderpass.draw_stats.dynamics;
// setup
TSubModel::iInstance = reinterpret_cast<std::uintptr_t>( Dynamic ); //żeby nie robić cudzych animacji
@@ -2472,9 +2475,6 @@ opengl_renderer::Render( TModel3d *Model, material_data const *Material, float c
// render
Render( Model->Root );
// debug data
++m_debugstats.models;
// post-render cleanup
return true;
@@ -2507,8 +2507,8 @@ opengl_renderer::Render( TSubModel *Submodel ) {
&& ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) {
// debug data
++m_debugstats.submodels;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
if( Submodel->iFlags & 0xC000 ) {
::glPushMatrix();
@@ -2719,7 +2719,7 @@ opengl_renderer::Render( TSubModel *Submodel ) {
// material configuration:
Bind_Material( null_handle );
// limit impact of dense fog on the lights
auto const lightrange { std::max<float>( 500, m_fogrange * 2 ) }; // arbitrary, visibility at least 750m
auto const lightrange { std::max<float>( 500, m_fogrange * 2 ) }; // arbitrary, visibility at least 500m
::glFogf( GL_FOG_DENSITY, static_cast<GLfloat>( 1.0 / lightrange ) );
::glPushAttrib( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_POINT_BIT );
@@ -2837,8 +2837,8 @@ opengl_renderer::Render( TTrack *Track ) {
return;
}
++m_debugstats.paths;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.paths;
++m_renderpass.draw_stats.drawcalls;
switch( m_renderpass.draw_mode ) {
// single path pieces are rendererd in pick scenery mode only
@@ -2898,8 +2898,8 @@ opengl_renderer::Render( scene::basic_cell::path_sequence::const_iterator First,
continue;
}
++m_debugstats.paths;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.paths;
++m_renderpass.draw_stats.drawcalls;
switch( m_renderpass.draw_mode ) {
case rendermode::color:
@@ -3085,7 +3085,7 @@ opengl_renderer::Render_particles() {
::glDepthMask( GL_FALSE );
Bind_Texture( m_smoketexture );
m_debugstats.particles = m_particlerenderer.render( m_diffusetextureunit );
m_renderpass.draw_stats.particles = m_particlerenderer.render( m_diffusetextureunit );
if( Global.bUseVBO ) {
gfx::opengl_vbogeometrybank::reset();
}
@@ -3258,9 +3258,8 @@ opengl_renderer::Render_Alpha( cell_sequence::reverse_iterator First, cell_seque
void
opengl_renderer::Render_Alpha( TAnimModel *Instance ) {
if( false == Instance->m_visible ) {
return;
}
if (false == Instance->m_visible) { return; }
if( false == m_renderpass.camera.visible( Instance->m_area ) ) { return; }
double distancesquared;
switch( m_renderpass.draw_mode ) {
@@ -3350,8 +3349,8 @@ opengl_renderer::Render_Alpha( TTraction *Traction ) {
// render
m_geometry.draw( Traction->m_geometry );
// debug data
++m_debugstats.traction;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.traction;
++m_renderpass.draw_stats.drawcalls;
}
void
@@ -3398,8 +3397,8 @@ opengl_renderer::Render_Alpha( scene::lines_node const &Lines ) {
std::min( 1.f, linealpha ) } ) );
// render
m_geometry.draw( data.geometry );
++m_debugstats.lines;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.lines;
++m_renderpass.draw_stats.drawcalls;
}
bool
@@ -3543,8 +3542,8 @@ opengl_renderer::Render_Alpha( TSubModel *Submodel ) {
&& ( TSubModel::fSquareDist < Submodel->fSquareMaxDist ) ) {
// debug data
++m_debugstats.submodels;
++m_debugstats.drawcalls;
++m_renderpass.draw_stats.submodels;
++m_renderpass.draw_stats.drawcalls;
if( Submodel->iFlags & 0xC000 ) {
::glPushMatrix();
@@ -3985,34 +3984,29 @@ opengl_renderer::Update( double const Deltatime ) {
m_framerate = 1000.f / ( Timer::subsystem.gfx_total.average() );
// adjust draw ranges etc, based on recent performance
auto const framerate = 1000.f / Timer::subsystem.gfx_color.average();
float targetfactor;
if( framerate > 90.0 ) { targetfactor = 3.0f; }
else if( framerate > 60.0 ) { targetfactor = 1.5f; }
else if( framerate > 30.0 ) { targetfactor = 1.25; }
else { targetfactor = std::max( Global.iWindowHeight / 768.f, 1.f ); }
if( targetfactor > Global.fDistanceFactor ) {
Global.fDistanceFactor = std::min( targetfactor, Global.fDistanceFactor + 0.05f );
if( Global.targetfps == 0.0f ) {
// automatic adjustment
auto const framerate = 0.5f * ( m_framerate + 1000.f / Timer::subsystem.gfx_color.average() );
float targetfactor;
if( framerate > 120.0 ) { targetfactor = 3.00f; }
else if( framerate > 90.0 ) { targetfactor = 1.50f; }
else if( framerate > 60.0 ) { targetfactor = 1.25f; }
else { targetfactor = 1.00f; }
if( targetfactor > Global.fDistanceFactor ) {
Global.fDistanceFactor = std::min( targetfactor, Global.fDistanceFactor + 0.05f );
}
else if( targetfactor < Global.fDistanceFactor ) {
Global.fDistanceFactor = std::max( targetfactor, Global.fDistanceFactor - 0.05f );
}
}
else if( targetfactor < Global.fDistanceFactor ) {
Global.fDistanceFactor = std::max( targetfactor, Global.fDistanceFactor - 0.05f );
}
if( ( framerate < 15.0 ) && ( Global.iSlowMotion < 7 ) ) {
Global.iSlowMotion = ( Global.iSlowMotion << 1 ) + 1; // zapalenie kolejnego bitu
if( Global.iSlowMotionMask & 1 )
if( Global.iMultisampling ) // a multisampling jest włączony
::glDisable( GL_MULTISAMPLE ); // wyłączenie multisamplingu powinno poprawić FPS
}
else if( ( framerate > 20.0 ) && Global.iSlowMotion ) { // FPS się zwiększył, można włączyć bajery
Global.iSlowMotion = ( Global.iSlowMotion >> 1 ); // zgaszenie bitu
if( Global.iSlowMotion == 0 ) // jeśli jest pełna prędkość
if( Global.iMultisampling ) // a multisampling jest włączony
::glEnable( GL_MULTISAMPLE );
else {
auto const fps_diff = Global.targetfps - m_framerate;
if( fps_diff > 0.5f ) {
Global.fDistanceFactor = std::max( 1.0f, Global.fDistanceFactor - 0.05f );
}
else if( fps_diff < 1.0f ) {
Global.fDistanceFactor = std::min( 3.0f, Global.fDistanceFactor + 0.05f );
}
}
if( ( true == Global.ResourceSweep )

View File

@@ -153,6 +153,7 @@ private:
opengl_camera camera;
rendermode draw_mode { rendermode::none };
float draw_range { 0.0f };
debug_stats draw_stats;
};
struct units_state {
@@ -318,7 +319,6 @@ private:
// double m_pickupdateaccumulator { 0.0 };
std::string m_debugtimestext;
std::string m_pickdebuginfo;
debug_stats m_debugstats;
std::string m_debugstatstext;
glm::vec4 m_baseambient { 0.0f, 0.0f, 0.0f, 1.0f };

View File

@@ -214,10 +214,10 @@ std::string to_string(double Value)
return o.str();
};
std::string to_string(int Value, int precision)
std::string to_string(int Value, int width)
{
std::ostringstream o;
o << std::fixed << std::setprecision(precision);
o.width(width);
o << Value;
return o.str();
};
@@ -230,15 +230,6 @@ std::string to_string(double Value, int precision)
return o.str();
};
std::string to_string(int Value, int precision, int width)
{
std::ostringstream o;
o.width(width);
o << std::fixed << std::setprecision(precision);
o << Value;
return o.str();
};
std::string to_string(double const Value, int const Precision, int const Width)
{
std::ostringstream converter;

View File

@@ -113,8 +113,7 @@ std::vector<std::string> Split(const std::string &s, char delim);
std::string to_string(int Value);
std::string to_string(unsigned int Value);
std::string to_string(int Value, int precision);
std::string to_string(int Value, int precision, int width);
std::string to_string(int Value, int width);
std::string to_string(double Value);
std::string to_string(double Value, int precision);
std::string to_string(double Value, int precision, int width);
@@ -249,6 +248,20 @@ clamp_circular( Type_ Value, Type_ const Range = static_cast<Type_>(360) ) {
return Value;
}
// rounds down provided value to nearest power of two
template <typename Type_>
Type_
clamp_power_of_two( Type_ Value, Type_ const Min = static_cast<Type_>(1), Type_ const Max = static_cast<Type_>(16384) ) {
Type_ p2size{ Min };
Type_ size;
while( ( p2size <= Max ) && ( p2size <= Value ) ) {
size = p2size;
p2size = p2size << 1;
}
return size;
}
template <typename Type_>
Type_
quantize( Type_ const Value, Type_ const Step ) {