Basic model shading (#9374)
authorDanila Shutov <dcbrwn2@gmail.com>
Sun, 16 Feb 2020 19:37:28 +0000 (22:37 +0300)
committerGitHub <noreply@github.com>
Sun, 16 Feb 2020 19:37:28 +0000 (20:37 +0100)
client/shaders/object_shader/opengl_fragment.glsl [new file with mode: 0644]
client/shaders/object_shader/opengl_vertex.glsl [new file with mode: 0644]
src/client/client.cpp
src/client/client.h
src/client/clientenvironment.cpp
src/client/content_cao.cpp
src/client/content_cao.h
src/client/shader.cpp
src/client/shader.h

diff --git a/client/shaders/object_shader/opengl_fragment.glsl b/client/shaders/object_shader/opengl_fragment.glsl
new file mode 100644 (file)
index 0000000..bb9e406
--- /dev/null
@@ -0,0 +1,131 @@
+uniform sampler2D baseTexture;
+uniform sampler2D normalTexture;
+uniform sampler2D textureFlags;
+
+uniform vec4 emissiveColor;
+uniform vec4 skyBgColor;
+uniform float fogDistance;
+uniform vec3 eyePosition;
+
+varying vec3 vNormal;
+varying vec3 vPosition;
+varying vec3 worldPosition;
+
+varying vec3 eyeVec;
+varying vec3 lightVec;
+varying float vIDiff;
+
+bool normalTexturePresent = false;
+bool texTileableHorizontal = false;
+bool texTileableVertical = false;
+bool texSeamless = false;
+
+const float e = 2.718281828459;
+const float BS = 10.0;
+const float fogStart = FOG_START;
+const float fogShadingParameter = 1 / ( 1 - fogStart);
+
+void get_texture_flags()
+{
+       vec4 flags = texture2D(textureFlags, vec2(0.0, 0.0));
+       if (flags.r > 0.5) {
+               normalTexturePresent = true;
+       }
+       if (flags.g > 0.5) {
+               texTileableHorizontal = true;
+       }
+       if (flags.b > 0.5) {
+               texTileableVertical = true;
+       }
+       if (texTileableHorizontal && texTileableVertical) {
+               texSeamless = true;
+       }
+}
+
+float intensity(vec3 color)
+{
+       return (color.r + color.g + color.b) / 3.0;
+}
+
+float get_rgb_height(vec2 uv)
+{
+       if (texSeamless) {
+               return intensity(texture2D(baseTexture, uv).rgb);
+       } else {
+               return intensity(texture2D(baseTexture, clamp(uv, 0.0, 0.999)).rgb);
+       }
+}
+
+vec4 get_normal_map(vec2 uv)
+{
+       vec4 bump = texture2D(normalTexture, uv).rgba;
+       bump.xyz = normalize(bump.xyz * 2.0 - 1.0);
+       return bump;
+}
+
+void main(void)
+{
+       vec3 color;
+       vec4 bump;
+       vec2 uv = gl_TexCoord[0].st;
+       bool use_normalmap = false;
+       get_texture_flags();
+
+#if USE_NORMALMAPS == 1
+       if (normalTexturePresent) {
+               bump = get_normal_map(uv);
+               use_normalmap = true;
+       }
+#endif
+
+#if GENERATE_NORMALMAPS == 1
+       if (normalTexturePresent == false) {
+               float tl = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y + SAMPLE_STEP));
+               float t  = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y - SAMPLE_STEP));
+               float tr = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y + SAMPLE_STEP));
+               float r  = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y));
+               float br = get_rgb_height(vec2(uv.x + SAMPLE_STEP, uv.y - SAMPLE_STEP));
+               float b  = get_rgb_height(vec2(uv.x, uv.y - SAMPLE_STEP));
+               float bl = get_rgb_height(vec2(uv.x -SAMPLE_STEP, uv.y - SAMPLE_STEP));
+               float l  = get_rgb_height(vec2(uv.x - SAMPLE_STEP, uv.y));
+               float dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
+               float dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
+               bump = vec4(normalize(vec3 (dX, dY, NORMALMAPS_STRENGTH)), 1.0);
+               use_normalmap = true;
+       }
+#endif
+
+       vec4 base = texture2D(baseTexture, uv).rgba;
+
+#ifdef ENABLE_BUMPMAPPING
+       if (use_normalmap) {
+               vec3 L = normalize(lightVec);
+               vec3 E = normalize(eyeVec);
+               float specular = pow(clamp(dot(reflect(L, bump.xyz), E), 0.0, 1.0), 1.0);
+               float diffuse = dot(-E,bump.xyz);
+               color = (diffuse + 0.1 * specular) * base.rgb;
+       } else {
+               color = base.rgb;
+       }
+#else
+       color = base.rgb;
+#endif
+
+       vec4 col = vec4(color.rgb, base.a);
+
+       col.rgb *= emissiveColor.rgb * vIDiff;
+       // Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
+       // the fog will only be rendered correctly if the last operation before the
+       // clamp() is an addition. Else, the clamp() seems to be ignored.
+       // E.g. the following won't work:
+       //      float clarity = clamp(fogShadingParameter
+       //              * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
+       // As additions usually come for free following a multiplication, the new formula
+       // should be more efficient as well.
+       // Note: clarity = (1 - fogginess)
+       float clarity = clamp(fogShadingParameter
+               - fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
+       col = mix(skyBgColor, col, clarity);
+
+       gl_FragColor = vec4(col.rgb, base.a);
+}
diff --git a/client/shaders/object_shader/opengl_vertex.glsl b/client/shaders/object_shader/opengl_vertex.glsl
new file mode 100644 (file)
index 0000000..99b9b27
--- /dev/null
@@ -0,0 +1,44 @@
+uniform mat4 mWorldViewProj;
+uniform mat4 mWorld;
+
+uniform vec3 eyePosition;
+uniform float animationTimer;
+
+varying vec3 vNormal;
+varying vec3 vPosition;
+varying vec3 worldPosition;
+
+varying vec3 eyeVec;
+varying vec3 lightVec;
+varying float vIDiff;
+
+const float e = 2.718281828459;
+const float BS = 10.0;
+
+float directional_ambient(vec3 normal)
+{
+       vec3 v = normal * normal;
+
+       if (normal.y < 0)
+               return dot(v, vec3(0.670820f, 0.447213f, 0.836660f));
+
+       return dot(v, vec3(0.670820f, 1.000000f, 0.836660f));
+}
+
+void main(void)
+{
+       gl_TexCoord[0] = gl_MultiTexCoord0;
+       gl_Position = mWorldViewProj * gl_Vertex;
+
+       vPosition = gl_Position.xyz;
+       vNormal = gl_Normal;
+       worldPosition = (mWorld * gl_Vertex).xyz;
+
+       vec3 sunPosition = vec3 (0.0, eyePosition.y * BS + 900.0, 0.0);
+
+       lightVec = sunPosition - worldPosition;
+       eyeVec = -(gl_ModelViewMatrix * gl_Vertex).xyz;
+       vIDiff = directional_ambient(normalize(gl_Normal));
+
+       gl_FrontColor = gl_BackColor = gl_Color;
+}
index 6016f940ec8cbd39ba200f235978827e5d43e405..c6d28ce806b28daaf5ecbc23981d43a513c16d7f 100644 (file)
@@ -1860,7 +1860,7 @@ ITextureSource* Client::getTextureSource()
 {
        return m_tsrc;
 }
-IShaderSource* Client::getShaderSource()
+IWritableShaderSource* Client::getShaderSource()
 {
        return m_shsrc;
 }
index b9807a11ed723e3125d6d4f3ab0032c7d2d39c40..2933a46e0049b57e2fb0fbb507231c4b6dc1818e 100644 (file)
@@ -367,7 +367,7 @@ public:
        const NodeDefManager* getNodeDefManager() override;
        ICraftDefManager* getCraftDefManager() override;
        ITextureSource* getTextureSource();
-       virtual IShaderSource* getShaderSource();
+       virtual IWritableShaderSource* getShaderSource();
        u16 allocateUnknownNodeId(const std::string &name) override;
        virtual ISoundManager* getSoundManager();
        MtEventManager* getEventManager();
index 5eb0333029fd11743d150a8c6997a22b5d481324..52d13378123f6a120b2a3de5bab85a9329fccb27 100644 (file)
@@ -32,10 +32,65 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "raycast.h"
 #include "voxelalgorithms.h"
 #include "settings.h"
+#include "shader.h"
 #include "content_cao.h"
 #include <algorithm>
 #include "client/renderingengine.h"
 
+/*
+       CAOShaderConstantSetter
+*/
+
+//! Shader constant setter for passing material emissive color to the CAO object_shader
+class CAOShaderConstantSetter : public IShaderConstantSetter
+{
+public:
+       CAOShaderConstantSetter():
+                       m_emissive_color_setting("emissiveColor")
+       {}
+
+       ~CAOShaderConstantSetter() override = default;
+
+       void onSetConstants(video::IMaterialRendererServices *services,
+                       bool is_highlevel) override
+       {
+               if (!is_highlevel)
+                       return;
+
+               // Ambient color
+               video::SColorf emissive_color(m_emissive_color);
+
+               float as_array[4] = {
+                       emissive_color.r,
+                       emissive_color.g,
+                       emissive_color.b,
+                       emissive_color.a,
+               };
+               m_emissive_color_setting.set(as_array, services);
+       }
+
+       void onSetMaterial(const video::SMaterial& material) override
+       {
+               m_emissive_color = material.EmissiveColor;
+       }
+
+private:
+       video::SColor m_emissive_color;
+       CachedPixelShaderSetting<float, 4> m_emissive_color_setting;
+};
+
+class CAOShaderConstantSetterFactory : public IShaderConstantSetterFactory
+{
+public:
+       CAOShaderConstantSetterFactory()
+       {}
+
+       virtual IShaderConstantSetter* create()
+       {
+               return new CAOShaderConstantSetter();
+       }
+};
+
 /*
        ClientEnvironment
 */
@@ -47,6 +102,8 @@ ClientEnvironment::ClientEnvironment(ClientMap *map,
        m_texturesource(texturesource),
        m_client(client)
 {
+       auto *shdrsrc = m_client->getShaderSource();
+       shdrsrc->addShaderConstantSetterFactory(new CAOShaderConstantSetterFactory());
 }
 
 ClientEnvironment::~ClientEnvironment()
index c76f05bbbab5e17611c8bcf322bcfcfa0fe61a3d..3b203bc0747dd8ead5020637f750e5e952f2fd23 100644 (file)
@@ -46,6 +46,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "wieldmesh.h"
 #include <algorithm>
 #include <cmath>
+#include "client/shader.h"
 
 class Settings;
 struct ToolCapabilities;
@@ -352,6 +353,8 @@ void GenericCAO::initialize(const std::string &data)
                        player->setCAO(this);
                }
        }
+
+       m_enable_shaders = g_settings->getBool("enable_shaders");
 }
 
 void GenericCAO::processInitData(const std::string &data)
@@ -577,8 +580,17 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                return;
        }
 
-       video::E_MATERIAL_TYPE material_type = (m_prop.use_texture_alpha) ?
-               video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+       if (m_enable_shaders) {
+               IShaderSource *shader_source = m_client->getShaderSource();
+               u32 shader_id = shader_source->getShader(
+                               "object_shader",
+                               TILE_MATERIAL_BASIC,
+                               NDT_NORMAL);
+               m_material_type = shader_source->getShaderInfo(shader_id).material;
+       } else {
+               m_material_type = (m_prop.use_texture_alpha) ?
+                       video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+       }
 
        auto grabMatrixNode = [this] {
                infostream << "GenericCAO::addToScene(): " << m_prop.visual << std::endl;
@@ -587,6 +599,18 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                m_matrixnode->grab();
        };
 
+       auto setSceneNodeMaterial = [this] (scene::ISceneNode *node) {
+               node->setMaterialFlag(video::EMF_LIGHTING, false);
+               node->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
+               node->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+               node->setMaterialType(m_material_type);
+
+               if (m_enable_shaders) {
+                       node->setMaterialFlag(video::EMF_GOURAUD_SHADING, false);
+                       node->setMaterialFlag(video::EMF_NORMALIZE_NORMALS, true);
+               }
+       };
+
        if (m_prop.visual == "sprite") {
                grabMatrixNode();
                m_spritenode = RenderingEngine::get_scene_manager()->addBillboardSceneNode(
@@ -594,10 +618,9 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                m_spritenode->grab();
                m_spritenode->setMaterialTexture(0,
                                tsrc->getTextureForMesh("unknown_node.png"));
-               m_spritenode->setMaterialFlag(video::EMF_LIGHTING, false);
-               m_spritenode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
-               m_spritenode->setMaterialType(material_type);
-               m_spritenode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+
+               setSceneNodeMaterial(m_spritenode);
+
                u8 li = m_last_light;
                m_spritenode->setColor(video::SColor(255,li,li,li));
                m_spritenode->setSize(v2f(m_prop.visual_size.X,
@@ -619,10 +642,10 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                { // Front
                        scene::IMeshBuffer *buf = new scene::SMeshBuffer();
                        video::S3DVertex vertices[4] = {
-                               video::S3DVertex(-dx, -dy, 0, 0,0,0, c, 1,1),
-                               video::S3DVertex( dx, -dy, 0, 0,0,0, c, 0,1),
-                               video::S3DVertex( dx,  dy, 0, 0,0,0, c, 0,0),
-                               video::S3DVertex(-dx,  dy, 0, 0,0,0, c, 1,0),
+                               video::S3DVertex(-dx, -dy, 0, 0,0,1, c, 1,1),
+                               video::S3DVertex( dx, -dy, 0, 0,0,1, c, 0,1),
+                               video::S3DVertex( dx,  dy, 0, 0,0,1, c, 0,0),
+                               video::S3DVertex(-dx,  dy, 0, 0,0,1, c, 1,0),
                        };
                        if (m_is_player) {
                                // Move minimal Y position to 0 (feet position)
@@ -635,7 +658,14 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                        buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
                        buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
                        buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
-                       buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
+                       buf->getMaterial().MaterialType = m_material_type;
+
+                       if (m_enable_shaders) {
+                               buf->getMaterial().EmissiveColor = c;
+                               buf->getMaterial().setFlag(video::EMF_GOURAUD_SHADING, false);
+                               buf->getMaterial().setFlag(video::EMF_NORMALIZE_NORMALS, true);
+                       }
+
                        // Add to mesh
                        mesh->addMeshBuffer(buf);
                        buf->drop();
@@ -643,10 +673,10 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                { // Back
                        scene::IMeshBuffer *buf = new scene::SMeshBuffer();
                        video::S3DVertex vertices[4] = {
-                               video::S3DVertex( dx,-dy, 0, 0,0,0, c, 1,1),
-                               video::S3DVertex(-dx,-dy, 0, 0,0,0, c, 0,1),
-                               video::S3DVertex(-dx, dy, 0, 0,0,0, c, 0,0),
-                               video::S3DVertex( dx, dy, 0, 0,0,0, c, 1,0),
+                               video::S3DVertex( dx,-dy, 0, 0,0,-1, c, 1,1),
+                               video::S3DVertex(-dx,-dy, 0, 0,0,-1, c, 0,1),
+                               video::S3DVertex(-dx, dy, 0, 0,0,-1, c, 0,0),
+                               video::S3DVertex( dx, dy, 0, 0,0,-1, c, 1,0),
                        };
                        if (m_is_player) {
                                // Move minimal Y position to 0 (feet position)
@@ -659,7 +689,14 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                        buf->getMaterial().setFlag(video::EMF_LIGHTING, false);
                        buf->getMaterial().setFlag(video::EMF_BILINEAR_FILTER, false);
                        buf->getMaterial().setFlag(video::EMF_FOG_ENABLE, true);
-                       buf->getMaterial().MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
+                       buf->getMaterial().MaterialType = m_material_type;
+
+                       if (m_enable_shaders) {
+                               buf->getMaterial().EmissiveColor = c;
+                               buf->getMaterial().setFlag(video::EMF_GOURAUD_SHADING, false);
+                               buf->getMaterial().setFlag(video::EMF_NORMALIZE_NORMALS, true);
+                       }
+
                        // Add to mesh
                        mesh->addMeshBuffer(buf);
                        buf->drop();
@@ -683,10 +720,7 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
                u8 li = m_last_light;
                setMeshColor(m_meshnode->getMesh(), video::SColor(255,li,li,li));
 
-               m_meshnode->setMaterialFlag(video::EMF_LIGHTING, false);
-               m_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
-               m_meshnode->setMaterialType(material_type);
-               m_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+               setSceneNodeMaterial(m_meshnode);
        } else if (m_prop.visual == "mesh") {
                grabMatrixNode();
                scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh, true);
@@ -704,10 +738,8 @@ void GenericCAO::addToScene(ITextureSource *tsrc)
 
                        setAnimatedMeshColor(m_animated_meshnode, video::SColor(255,li,li,li));
 
-                       m_animated_meshnode->setMaterialFlag(video::EMF_LIGHTING, true);
-                       m_animated_meshnode->setMaterialFlag(video::EMF_BILINEAR_FILTER, false);
-                       m_animated_meshnode->setMaterialType(material_type);
-                       m_animated_meshnode->setMaterialFlag(video::EMF_FOG_ENABLE, true);
+                       setSceneNodeMaterial(m_animated_meshnode);
+
                        m_animated_meshnode->setMaterialFlag(video::EMF_BACK_FACE_CULLING,
                                m_prop.backface_culling);
                } else
@@ -789,17 +821,41 @@ void GenericCAO::updateLightNoCheck(u8 light_at_pos)
                return;
 
        u8 li = decode_light(light_at_pos + m_glow);
+
        if (li != m_last_light) {
                m_last_light = li;
                video::SColor color(255,li,li,li);
-               if (m_meshnode) {
-                       setMeshColor(m_meshnode->getMesh(), color);
-               } else if (m_animated_meshnode) {
-                       setAnimatedMeshColor(m_animated_meshnode, color);
-               } else if (m_wield_meshnode) {
-                       m_wield_meshnode->setColor(color);
-               } else if (m_spritenode) {
-                       m_spritenode->setColor(color);
+
+               if (m_enable_shaders) {
+                       scene::ISceneNode *node = getSceneNode();
+
+                       if (node == nullptr) {
+                               return;
+                       }
+
+                       if (m_prop.visual == "upright_sprite") {
+                               scene::IMesh *mesh = m_meshnode->getMesh();
+                               for (u32 i = 0; i < mesh->getMeshBufferCount(); ++i) {
+                                       scene::IMeshBuffer* buf = mesh->getMeshBuffer(i);
+                                       video::SMaterial& material = buf->getMaterial();
+                                       material.EmissiveColor = color;
+                               }
+                       } else {
+                               for (u32 i = 0; i < node->getMaterialCount(); ++i) {
+                                       video::SMaterial& material = node->getMaterial(i);
+                                       material.EmissiveColor = color;
+                               }
+                       }
+               } else {
+                       if (m_meshnode) {
+                               setMeshColor(m_meshnode->getMesh(), color);
+                       } else if (m_animated_meshnode) {
+                               setAnimatedMeshColor(m_animated_meshnode, color);
+                       } else if (m_wield_meshnode) {
+                               m_wield_meshnode->setColor(color);
+                       } else if (m_spritenode) {
+                               m_spritenode->setColor(color);
+                       }
                }
        }
 }
@@ -1101,16 +1157,13 @@ void GenericCAO::updateTextures(std::string mod)
        m_current_texture_modifier = mod;
        m_glow = m_prop.glow;
 
-       video::E_MATERIAL_TYPE material_type = (m_prop.use_texture_alpha) ?
-               video::EMT_TRANSPARENT_ALPHA_CHANNEL : video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF;
-
        if (m_spritenode) {
                if (m_prop.visual == "sprite") {
                        std::string texturestring = "unknown_node.png";
                        if (!m_prop.textures.empty())
                                texturestring = m_prop.textures[0];
                        texturestring += mod;
-                       m_spritenode->getMaterial(0).MaterialType = material_type;
+                       m_spritenode->getMaterial(0).MaterialType = m_material_type;
                        m_spritenode->getMaterial(0).MaterialTypeParam = 0.5f;
                        m_spritenode->setMaterialTexture(0,
                                        tsrc->getTextureForMesh(texturestring));
@@ -1146,7 +1199,7 @@ void GenericCAO::updateTextures(std::string mod)
 
                                // Set material flags and texture
                                video::SMaterial& material = m_animated_meshnode->getMaterial(i);
-                               material.MaterialType = material_type;
+                               material.MaterialType = m_material_type;
                                material.MaterialTypeParam = 0.5f;
                                material.TextureLayer[0].Texture = texture;
                                material.setFlag(video::EMF_LIGHTING, true);
@@ -1193,7 +1246,7 @@ void GenericCAO::updateTextures(std::string mod)
 
                                // Set material flags and texture
                                video::SMaterial& material = m_meshnode->getMaterial(i);
-                               material.MaterialType = material_type;
+                               material.MaterialType = m_material_type;
                                material.MaterialTypeParam = 0.5f;
                                material.setFlag(video::EMF_LIGHTING, false);
                                material.setFlag(video::EMF_BILINEAR_FILTER, false);
index 6f3b2f06b877c20afd84c41caff170bb94560a29..a1098305a567cc8f9a998631bae967c011c8cf85 100644 (file)
@@ -125,6 +125,10 @@ private:
        u8 m_last_light = 255;
        bool m_is_visible = false;
        s8 m_glow = 0;
+       // Material
+       video::E_MATERIAL_TYPE m_material_type;
+       // Settings
+       bool m_enable_shaders = false;
 
 public:
        GenericCAO(Client *client, ClientEnvironment *env);
index f36ff3d85417b20356a9358877ccab3d30c0654a..eda415ce6ee59d54622c117a1b15ed73e299aff3 100644 (file)
@@ -188,7 +188,7 @@ public:
                        delete setter;
        }
 
-       virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData)
+       virtual void OnSetConstants(video::IMaterialRendererServices *services, s32 userData) override
        {
                video::IVideoDriver *driver = services->getVideoDriver();
                sanity_check(driver != NULL);
@@ -198,6 +198,12 @@ public:
                for (IShaderConstantSetter *setter : m_setters)
                        setter->onSetConstants(services, is_highlevel);
        }
+
+       virtual void OnSetMaterial(const video::SMaterial& material) override
+       {
+               for (IShaderConstantSetter *setter : m_setters)
+                       setter->onSetMaterial(material);
+       }
 };
 
 
index 583c776f4fdfbca62746d98210bc4f93c6955f10..109d393361700b2bbcf1f359c54ac72f1a600022 100644 (file)
@@ -67,6 +67,8 @@ public:
        virtual ~IShaderConstantSetter() = default;
        virtual void onSetConstants(video::IMaterialRendererServices *services,
                        bool is_highlevel) = 0;
+       virtual void onSetMaterial(const video::SMaterial& material)
+       { }
 };