mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-08 10:31:01 +01:00
feat(render): matte and tinted copies of a material, the steel weathered or tinted as far as the userdata of its vertices says
Matte_Material() gives a copy of a material with its glossiness damped and its weathering on: the faces cut out of a polished surface, as the sides of a worn rail head, darken and lose the shine by the userdata of their vertices. Tinted_Material() gives a copy whose texture is tinted to a colour as far instead. Both are made once per material. The weathering and the tint colour have a param slot of their own, param[3]: the shaders of the materials use all four components of param[2] among them (detail, parallax, water, the terrain placement), and light_common.glsl is included in all of them. MAX_PARAMS grows from 3 to 4, the model UBO by 16 bytes. Neither copy is made when another param of the shader lies on the components it would set.
This commit is contained in:
2
gl/ubo.h
2
gl/ubo.h
@@ -62,7 +62,7 @@ namespace gl
|
|||||||
|
|
||||||
static_assert(sizeof(scene_ubs) == 400, "bad size of ubs");
|
static_assert(sizeof(scene_ubs) == 400, "bad size of ubs");
|
||||||
|
|
||||||
const size_t MAX_PARAMS = 3;
|
const size_t MAX_PARAMS = 4;
|
||||||
|
|
||||||
struct model_ubs
|
struct model_ubs
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -662,6 +662,123 @@ material_manager::create_from_text( std::string const &Name, std::string const &
|
|||||||
return materialhandle;
|
return materialhandle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
opengl_material
|
||||||
|
variant_of( opengl_material const &Source, std::string const &Suffix ) {
|
||||||
|
|
||||||
|
opengl_material variant;
|
||||||
|
variant.textures = Source.textures;
|
||||||
|
variant.texture_variants = Source.texture_variants;
|
||||||
|
variant.params = Source.params;
|
||||||
|
variant.params_state = Source.params_state;
|
||||||
|
variant.shader = Source.shader;
|
||||||
|
variant.opacity = Source.opacity;
|
||||||
|
variant.selfillum = Source.selfillum;
|
||||||
|
variant.shadow_rank = Source.shadow_rank;
|
||||||
|
variant.name = Source.name + Suffix;
|
||||||
|
variant.size = Source.size;
|
||||||
|
variant.is_good = Source.is_good;
|
||||||
|
variant.path = Source.path;
|
||||||
|
return variant;
|
||||||
|
}
|
||||||
|
|
||||||
|
// whether another param of the shader lies on a component of the named one, which a value set for that one would change too
|
||||||
|
bool
|
||||||
|
shares_slot( std::unordered_map<std::string, gl::shader::param_entry> const &Conf, std::string const &Name ) {
|
||||||
|
|
||||||
|
auto const own { Conf.find( Name ) };
|
||||||
|
if( own == Conf.end() ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return std::any_of(
|
||||||
|
std::begin( Conf ), std::end( Conf ),
|
||||||
|
[&]( auto const &Entry ) {
|
||||||
|
return Entry.first != Name
|
||||||
|
&& Entry.second.location == own->second.location
|
||||||
|
&& Entry.second.offset < own->second.offset + own->second.size
|
||||||
|
&& own->second.offset < Entry.second.offset + Entry.second.size; } );
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
material_handle
|
||||||
|
material_manager::create_matte( material_handle const Material ) {
|
||||||
|
|
||||||
|
if( Material == null_handle || Material >= m_materials.size() ) {
|
||||||
|
return Material;
|
||||||
|
}
|
||||||
|
auto const lookup { m_mattes.find( Material ) };
|
||||||
|
if( lookup != m_mattes.end() ) {
|
||||||
|
return lookup->second;
|
||||||
|
}
|
||||||
|
auto matte { variant_of( m_materials[ Material ], ":matte" ) };
|
||||||
|
matte.glossiness = 0.1f;
|
||||||
|
if( matte.shader ) {
|
||||||
|
for( auto const &[ key, value ] : std::vector<std::pair<std::string, glm::vec4>>{ { "weathering", glm::vec4{ 1.f } } } ) {
|
||||||
|
auto const entry { matte.shader->param_conf.find( key ) };
|
||||||
|
if( entry == matte.shader->param_conf.end()
|
||||||
|
|| shares_slot( matte.shader->param_conf, key ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for( std::size_t i = 0; i < entry->second.size; ++i ) {
|
||||||
|
matte.params[ entry->second.location ][ entry->second.offset + i ] = value[ static_cast<glm::length_t>( i ) ];
|
||||||
|
}
|
||||||
|
matte.params_state.erase(
|
||||||
|
std::remove_if(
|
||||||
|
std::begin( matte.params_state ), std::end( matte.params_state ),
|
||||||
|
[&]( gl::shader::param_entry const &State ) {
|
||||||
|
return State.location == entry->second.location && State.offset == entry->second.offset; } ),
|
||||||
|
std::end( matte.params_state ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto const mattehandle { static_cast<material_handle>( m_materials.size() ) };
|
||||||
|
m_materials.emplace_back( std::move( matte ) );
|
||||||
|
m_mattes.emplace( Material, mattehandle );
|
||||||
|
return mattehandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
material_handle
|
||||||
|
material_manager::create_tinted( material_handle const Material, glm::vec3 const &Colour ) {
|
||||||
|
|
||||||
|
if( Material == null_handle || Material >= m_materials.size() || !m_materials[ Material ].shader ) {
|
||||||
|
return Material;
|
||||||
|
}
|
||||||
|
auto const key { std::make_tuple( Material, Colour.r, Colour.g, Colour.b ) };
|
||||||
|
if( auto const lookup { m_tints.find( key ) }; lookup != m_tints.end() ) {
|
||||||
|
return lookup->second;
|
||||||
|
}
|
||||||
|
// the colour in the rgb of the slot of the weathering, which tells the shader to tint by its sign; nothing else in that slot
|
||||||
|
auto const &conf { m_materials[ Material ].shader->param_conf };
|
||||||
|
auto const weathering { conf.find( "weathering" ) };
|
||||||
|
auto const tint { conf.find( "tint" ) };
|
||||||
|
if( weathering == conf.end()
|
||||||
|
|| tint == conf.end()
|
||||||
|
|| weathering->second.offset != 3
|
||||||
|
|| tint->second.location != weathering->second.location
|
||||||
|
|| tint->second.offset != 0
|
||||||
|
|| std::any_of(
|
||||||
|
std::begin( conf ), std::end( conf ),
|
||||||
|
[&]( auto const &Entry ) {
|
||||||
|
return Entry.first != weathering->first && Entry.first != tint->first && Entry.second.location == weathering->second.location; } ) ) {
|
||||||
|
return Material;
|
||||||
|
}
|
||||||
|
auto tinted { variant_of( m_materials[ Material ], ":tinted" ) };
|
||||||
|
tinted.glossiness = m_materials[ Material ].glossiness;
|
||||||
|
auto const location { weathering->second.location };
|
||||||
|
tinted.params[ location ] = glm::vec4{ Colour, -1.f };
|
||||||
|
tinted.params_state.erase(
|
||||||
|
std::remove_if(
|
||||||
|
std::begin( tinted.params_state ), std::end( tinted.params_state ),
|
||||||
|
[&]( gl::shader::param_entry const &State ) {
|
||||||
|
return State.location == location; } ),
|
||||||
|
std::end( tinted.params_state ) );
|
||||||
|
auto const tintedhandle { static_cast<material_handle>( m_materials.size() ) };
|
||||||
|
m_materials.emplace_back( std::move( tinted ) );
|
||||||
|
m_tints.emplace( key, tintedhandle );
|
||||||
|
return tintedhandle;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
material_manager::on_weather_change() {
|
material_manager::on_weather_change() {
|
||||||
|
|
||||||
|
|||||||
@@ -142,6 +142,11 @@ public:
|
|||||||
// material described by provided text (the content of a .mat file), not kept in a file. returns: handle to the material or null_handle
|
// material described by provided text (the content of a .mat file), not kept in a file. returns: handle to the material or null_handle
|
||||||
material_handle
|
material_handle
|
||||||
create_from_text( std::string const &Name, std::string const &Definition );
|
create_from_text( std::string const &Name, std::string const &Definition );
|
||||||
|
// copy of provided material with its specular highlights and reflections damped. returns: handle to the copy, made once per material
|
||||||
|
material_handle
|
||||||
|
create_matte( material_handle const Material );
|
||||||
|
material_handle
|
||||||
|
create_tinted( material_handle const Material, glm::vec3 const &Colour );
|
||||||
opengl_material const &
|
opengl_material const &
|
||||||
material( material_handle const Material ) const { return m_materials[ Material ]; }
|
material( material_handle const Material ) const { return m_materials[ Material ]; }
|
||||||
opengl_material &
|
opengl_material &
|
||||||
@@ -170,6 +175,8 @@ private:
|
|||||||
// members:
|
// members:
|
||||||
material_sequence m_materials;
|
material_sequence m_materials;
|
||||||
index_map m_materialmappings;
|
index_map m_materialmappings;
|
||||||
|
std::unordered_map<material_handle, material_handle> m_mattes;
|
||||||
|
std::map<std::tuple<material_handle, float, float, float>, material_handle> m_tints;
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -9,6 +9,11 @@ uniform sampler2D headlightmap;
|
|||||||
|
|
||||||
float glossiness = 1.0;
|
float glossiness = 1.0;
|
||||||
float metalic = 0.0;
|
float metalic = 0.0;
|
||||||
|
in vec4 UserData;
|
||||||
|
// a slot of its own, the shaders of the materials using all of param[2]: how weathered the steel is as far as the userdata of
|
||||||
|
// its vertices says; below 0: the texture tinted to the colour of tint as far instead
|
||||||
|
#param (weathering, 3, 3, 1, zero)
|
||||||
|
#param (tint, 3, 0, 3, one)
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Lighting balance tunables - tweak these to control overall scene
|
// Lighting balance tunables - tweak these to control overall scene
|
||||||
@@ -285,6 +290,19 @@ vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float refl
|
|||||||
{
|
{
|
||||||
// Diffuse colour is applied once, to the albedo; the light terms below are not scaled by it again
|
// Diffuse colour is applied once, to the albedo; the light terms below are not scaled by it again
|
||||||
texturecolor *= material_diffuse();
|
texturecolor *= material_diffuse();
|
||||||
|
float weathered = (param[3].w > 0.0 ? clamp(param[3].w * UserData.x, 0.0, 1.0) : 0.0);
|
||||||
|
float tinted = (param[3].w < 0.0 ? clamp(-param[3].w * UserData.x, 0.0, 1.0) : 0.0);
|
||||||
|
// a tint only scales the colour of the texture, the steel keeps its own polish
|
||||||
|
float polished = weathered * smoothstep(0.03, 0.12, dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)));
|
||||||
|
float weatheredluma = min(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 0.05);
|
||||||
|
vec3 unused = texturecolor * (weatheredluma / max(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 1e-4));
|
||||||
|
unused = mix(unused, vec3(1.0, 0.82, 0.74) * (weatheredluma / 0.8525), 0.5);
|
||||||
|
texturecolor = mix(texturecolor, unused, smoothstep(0.0, 0.4, weathered));
|
||||||
|
texturecolor = (tinted > 0.0 ? texturecolor * mix(vec3(1.0), param[3].rgb, tinted) : texturecolor);
|
||||||
|
specularity = mix(specularity, min(specularity, 0.03), smoothstep(0.0, 0.4, polished));
|
||||||
|
metalic = mix(metalic, 0.0, polished);
|
||||||
|
glossiness = mix(glossiness, min(glossiness, 0.06 * abs(param[1].w)), polished);
|
||||||
|
reflectivity = mix(reflectivity, min(reflectivity, 0.08 * param[1].z), smoothstep(0.0, 0.4, polished));
|
||||||
// Scale ambient before it gets tinted by the texture.
|
// Scale ambient before it gets tinted by the texture.
|
||||||
// Sun, headlights and emission are added afterwards so they are NOT
|
// Sun, headlights and emission are added afterwards so they are NOT
|
||||||
// attenuated by AMBIENT_SCALE - this only dims the indirect term.
|
// attenuated by AMBIENT_SCALE - this only dims the indirect term.
|
||||||
|
|||||||
Reference in New Issue
Block a user