]> git.tdb.fi Git - libs/gl.git/commitdiff
Implement alpha cutoff for materials
authorMikko Rasa <tdb@tdb.fi>
Fri, 11 Mar 2022 09:55:49 +0000 (11:55 +0200)
committerMikko Rasa <tdb@tdb.fi>
Fri, 11 Mar 2022 10:06:02 +0000 (12:06 +0200)
Having to implement it separately in each material's shader is not
optimal, but since they each define their own uniform block, no better
solution is readily apparent.

The occluder shader also supports alpha cutoff so that objects with
such materials can cast proper shadows.

shaderlib/cooktorrance.glsl
shaderlib/occluder.glsl
shaderlib/phong.glsl
shaderlib/unlit.glsl
source/materials/material.cpp
source/materials/material.h

index ff1a56c7c237e240ebd7cb4c69df8a7ce24a36ba..ad1a459d2e32932d9cb79a0501fb339b5ad6b7ba 100644 (file)
@@ -13,6 +13,7 @@ struct PbrMaterialParameters
 uniform PbrMaterial
 {
        PbrMaterialParameters pbr_material;
+       float alpha_cutoff;
 };
 
 uniform sampler2D base_color_map;
@@ -29,6 +30,7 @@ layout(constant_id=auto) const bool use_occlusion_map = false;
 layout(constant_id=auto) const bool use_emission = false;
 layout(constant_id=auto) const bool use_emission_map = false;
 layout(constant_id=auto) const bool use_image_based_lighting = false;
+layout(constant_id=auto) const bool use_alpha_cutoff = false;
 
 #pragma MSP stage(fragment)
 virtual vec4 get_base_color()
@@ -173,10 +175,13 @@ vec3 cooktorrance_lighting(vec3 normal, vec3 look, vec3 base_color, float metaln
 
 void main()
 {
+       vec4 base_color = get_base_color();
+       if(use_alpha_cutoff && base_color.a<alpha_cutoff)
+               discard;
+
        vec3 normal = get_fragment_normal();
        vec3 look = normalize(world_look_dir);
 
-       vec4 base_color = get_base_color();
        float metalness = get_metalness_value();
        float roughness = get_roughness_value();
 
index b5d05f09ad25dee7b98563dac8564dd0ff98bb82..abd29a0aaa07dde0db265fd95eec33d4464aed9d 100644 (file)
@@ -1,5 +1,14 @@
 import msp_interface;
 
+uniform AlphaCutoff
+{
+       float alpha_cutoff;
+};
+
+uniform sampler2D alpha_map;
+
+layout(constant_id=auto) const bool use_alpha_cutoff = false;
+
 #pragma MSP stage(vertex)
 virtual vec4 get_vertex_position()
 {
@@ -20,4 +29,19 @@ void main()
        vec4 eye_vertex = eye_world_matrix*get_vertex_transform()*get_vertex_position();
        clipping(eye_vertex.xyz);
        gl_Position = clip_eye_matrix*eye_vertex;
+       passthrough;
+}
+
+#pragma MSP stage(fragment)
+layout(location=0) out vec4 frag_color;
+
+void main()
+{
+       if(use_alpha_cutoff)
+       {
+               float alpha = texture(alpha_map, texcoord.xy).a;
+               if(alpha<alpha_cutoff)
+                       discard;
+               frag_color = vec4(1.0);
+       }
 }
index 080c904895668f1e985a893ef959fb467ee0a91d..234897116183a4997c625687447b65172ef8036d 100644 (file)
@@ -14,6 +14,7 @@ struct BasicMaterialParameters
 uniform BasicMaterial
 {
        BasicMaterialParameters basic_material;
+       float alpha_cutoff;
 };
 
 uniform sampler2D diffuse_map;
@@ -30,6 +31,7 @@ layout(constant_id=auto) const bool use_emission = false;
 layout(constant_id=auto) const bool use_emission_map = false;
 layout(constant_id=auto) const bool use_reflectivity = false;
 layout(constant_id=auto) const bool use_reflectivity_map = false;
+layout(constant_id=auto) const bool use_alpha_cutoff = false;
 
 #pragma MSP stage(fragment)
 virtual vec4 get_diffuse_color()
@@ -112,10 +114,13 @@ vec3 phong_lighting(vec3 normal, vec3 look, vec3 surface_diffuse, vec3 surface_s
 
 void main()
 {
+       vec4 surface_diffuse = get_diffuse_color();
+       if(use_alpha_cutoff && surface_diffuse.a<alpha_cutoff)
+               discard;
+
        vec3 normal = get_fragment_normal();
        vec3 look = normalize(world_look_dir);
 
-       vec4 surface_diffuse = get_diffuse_color();
        vec3 surface_specular = get_specular_color();
        float shininess = get_shininess_value();
 
index 85275558b399346b8b1a89758b80ac52ea9d3458..f4920a7982db397babd59fcc61e66dc725a55dbf 100644 (file)
@@ -9,6 +9,7 @@ struct UnlitMaterialParameters
 uniform UnlitMaterial
 {
        UnlitMaterialParameters unlit_material;
+       float alpha_cutoff;
 };
 
 uniform sampler2D color_tex;
@@ -16,6 +17,7 @@ uniform sampler2D color_tex;
 layout(constant_id=auto) const bool use_texture = false;
 layout(constant_id=auto) const bool use_vertex_color = false;
 layout(constant_id=auto) const bool use_fog = false;
+layout(constant_id=auto) const bool use_alpha_cutoff = false;
 
 #pragma MSP stage(fragment)
 virtual vec4 get_color()
@@ -31,6 +33,9 @@ virtual vec4 get_color()
 void main()
 {
        vec4 color = get_color();
+       if(use_alpha_cutoff && color.a<alpha_cutoff)
+               discard;
+
        if(use_fog)
                color.rgb = apply_fog(color.rgb);
        frag_color = color;
index a34c0457384025f2af87f91ed45fac78dd042835..6af833e6b5c30e48badcfd6bec78d45bce64eeee 100644 (file)
@@ -11,10 +11,18 @@ using namespace std;
 namespace Msp {
 namespace GL {
 
+Material::Material()
+{
+       set_alpha_cutoff(0.0f);
+}
+
 const Program *Material::create_compatible_shader(const map<string, int> &extra_spec) const
 {
        string module_name;
        map<string, int> spec_values;
+       if(alpha_cutoff>0.0f)
+               spec_values["use_alpha_cutoff"] = true;
+
        fill_program_info(module_name, spec_values);
 
        for(const auto &kvp: extra_spec)
@@ -48,6 +56,12 @@ const Program *Material::create_compatible_shader(const map<string, int> &extra_
        return shprog;
 }
 
+void Material::set_alpha_cutoff(float a)
+{
+       alpha_cutoff = a;
+       shdata.uniform("alpha_cutoff", a);
+}
+
 void Material::set_debug_name(const string &name)
 {
 #ifdef DEBUG
@@ -78,9 +92,15 @@ Material::Loader::Loader(Material &m, Collection &c):
 
 void Material::Loader::init_actions()
 {
+       add("alpha_cutoff", &Loader::alpha_cutoff);
        add("sampler", &Loader::sampler);
 }
 
+void Material::Loader::alpha_cutoff(float a)
+{
+       obj.set_alpha_cutoff(a);
+}
+
 void Material::Loader::sampler(const string &name)
 {
        obj.sampler = &get_collection().get<Sampler>(name);
index ff7f53c0d3ffdb23acf15f55c649f6aacaa1708d..75ff972cd4e1312de7e6d63a74480bf3c3b0409a 100644 (file)
@@ -27,6 +27,7 @@ private:
                virtual void init_actions();
 
        private:
+               void alpha_cutoff(float);
                void sampler(const std::string &);
        };
 
@@ -72,9 +73,10 @@ public:
 
 protected:
        const Sampler *sampler = 0;
+       float alpha_cutoff = 0.0f;
        ProgramData shdata;
 
-       Material() = default;
+       Material();
 public:
        virtual ~Material() = default;
 
@@ -96,6 +98,9 @@ public:
        virtual const Texture *get_texture(Tag) const = 0;
        virtual const Sampler *get_sampler(Tag) const { return sampler; }
 
+       void set_alpha_cutoff(float a);
+       float get_alpha_cutoff() const { return alpha_cutoff; }
+
        void set_debug_name(const std::string &);
 
        template<typename T>