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:
11
DynObj.cpp
11
DynObj.cpp
@@ -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 ) {
|
||||
|
||||
1
DynObj.h
1
DynObj.h
@@ -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() {
|
||||
|
||||
27
Globals.cpp
27
Globals.cpp
@@ -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
|
||||
|
||||
@@ -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ć)
|
||||
|
||||
@@ -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 );
|
||||
|
||||
60
Texture.cpp
60
Texture.cpp
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
7
gl/ubo.h
7
gl/ubo.h
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
// methods
|
||||
void
|
||||
update( opengl_camera const &Camera );
|
||||
void
|
||||
std::size_t
|
||||
render( );
|
||||
private:
|
||||
// types
|
||||
|
||||
@@ -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);
|
||||
@@ -472,9 +460,26 @@ bool opengl33_renderer::Render()
|
||||
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();
|
||||
@@ -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();
|
||||
|
||||
m_renderpass.draw_stats = {};
|
||||
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 = 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
|
||||
m_renderpass.draw_stats = {};
|
||||
if (Render_reflections(vp))
|
||||
setup_pass(vp, m_renderpass, Mode); // restore color pass settings
|
||||
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)
|
||||
@@ -782,57 +785,45 @@ void opengl33_renderer::Render_pass(viewport_config &vp, rendermode const Mode)
|
||||
glDebug("rendermode::shadows");
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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();
|
||||
setup_drawing(false);
|
||||
|
||||
scene_ubs.projection = OpenGLMatrices.data(GL_PROJECTION);
|
||||
scene_ubo->update(scene_ubs);
|
||||
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 );
|
||||
}
|
||||
m_shadowpass = m_renderpass;
|
||||
|
||||
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 );
|
||||
}
|
||||
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_cabshadowpass = m_renderpass;
|
||||
}
|
||||
}
|
||||
m_shadow_fb->unbind();
|
||||
|
||||
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);
|
||||
@@ -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,16 +1311,16 @@ 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);
|
||||
else
|
||||
opengl_texture::unbind(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);
|
||||
|
||||
if (tex)
|
||||
{
|
||||
glm::mat4 coordmove;
|
||||
|
||||
if (GLAD_GL_ARB_clip_control || GLAD_GL_EXT_clip_control)
|
||||
@@ -1385,22 +1339,24 @@ void opengl33_renderer::setup_shadow_map(opengl_texture *tex, renderpass_config
|
||||
0.0, 0.0, 0.5, 0.0, //
|
||||
0.5, 0.5, 0.5, 1.0 //
|
||||
);
|
||||
glm::mat4 depthproj = conf.pass_camera.projection();
|
||||
|
||||
for( auto idx = 0; idx < m_shadowpass.size(); ++idx ) {
|
||||
|
||||
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;
|
||||
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;
|
||||
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;
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
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 > 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( 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 );
|
||||
}
|
||||
|
||||
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 )
|
||||
|
||||
@@ -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 };
|
||||
|
||||
@@ -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;
|
||||
|
||||
17
utilities.h
17
utilities.h
@@ -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 ) {
|
||||
|
||||
Reference in New Issue
Block a user