]> git.tdb.fi Git - libs/gl.git/commitdiff
Add a builtin module for standard shaders
authorMikko Rasa <tdb@tdb.fi>
Tue, 15 Nov 2016 17:09:50 +0000 (19:09 +0200)
committerMikko Rasa <tdb@tdb.fi>
Tue, 15 Nov 2016 17:09:50 +0000 (19:09 +0200)
It doesn't support multiple lights as generating the necessary array
interfaces through a geometry shader turned out to be rather non-trivial.
I plan to add deferred rendering modules with multi-light support later.

Build
scripts/resgen.py [new file with mode: 0755]
shaderlib/singlepass.glsl [new file with mode: 0644]
source/resources.cpp
source/resources.h

diff --git a/Build b/Build
index ca380f316aa365871a367e242eb3bd50967b9c68..fcdb63284618d3829180edbb18675b35045da118 100644 (file)
--- a/Build
+++ b/Build
@@ -29,15 +29,24 @@ package "mspgl"
                };
        };
 
+       generate "RES"
+       {
+               in_suffix ".glsl";
+               out_suffix ".cpp";
+               command "scripts/resgen.py";
+       };
+
        library "mspgl"
        {
                source "source";
                source "extensions";
+               source "shaderlib";
                install true;
                install_map
                {
                        map "source" "include/msp/gl";
                        map "extensions" "include/msp/gl/extensions";
+                       map "shaderlib" "include/msp/gl/resources";
                };
        };
 
diff --git a/scripts/resgen.py b/scripts/resgen.py
new file mode 100755 (executable)
index 0000000..16cfbfb
--- /dev/null
@@ -0,0 +1,41 @@
+#!/usr/bin/python
+
+import sys
+import os
+
+def makename(text):
+       result = ""
+       for c in text:
+               if c.isalnum():
+                       result += c
+               else:
+                       result += '_'
+       return result
+
+def escape(text):
+       result = ""
+       for c in text:
+               if c=='\t':
+                       result += "\\t"
+               elif c=='\n':
+                       result += "\\n"
+               elif c=='"':
+                       result += "\\\""
+               else:
+                       result += c
+       return result
+
+name = makename(os.path.split(sys.argv[1])[1])
+lines = open(sys.argv[1]).readlines()
+out = open(sys.argv[2], "w")
+out.write("""namespace Msp {
+namespace GL {
+""")
+out.write("extern const char {}_data[] =\n".format(name))
+for l in lines:
+       out.write("\t\"{}\"\n".format(escape(l)))
+out.write(""";
+
+} // namespace GL
+} // namespace Msp
+""")
diff --git a/shaderlib/singlepass.glsl b/shaderlib/singlepass.glsl
new file mode 100644 (file)
index 0000000..f8940f7
--- /dev/null
@@ -0,0 +1,247 @@
+struct LightSourceParameters
+{
+       vec4 position;
+       vec4 diffuse;
+       vec4 specular;
+};
+
+struct MaterialParameters
+{
+       vec4 ambient;
+       vec4 diffuse;
+       vec4 specular;
+       float shininess;
+};
+
+struct ClipPlane
+{
+       vec4 equation;
+};
+
+uniform mat4 eye_obj_matrix;
+uniform mat3 eye_obj_normal_matrix;
+uniform Transform
+{
+       mat4 projection_matrix;
+};
+
+uniform Material
+{
+       MaterialParameters material;
+       float reflectivity;
+};
+
+const bool use_vertex_color = false;
+
+const bool use_lighting = false;
+const bool use_specular = false;
+const bool use_sky = false;
+const bool use_fog = false;
+uniform Lighting
+{
+       // Declared as an array for compatibility reasons
+       LightSourceParameters light_sources[1];
+       vec4 ambient_color;
+       vec4 sky_color;
+       vec3 eye_sky_dir;
+       float horizon_limit;
+       vec4 fog_color;
+       float fog_density;
+};
+
+const bool use_diffuse_map = false;
+uniform sampler2D diffuse_map;
+
+const bool use_normal_map = false;
+uniform sampler2D normal_map;
+
+const bool use_shadow_map = false;
+uniform sampler2DShadow shadow;
+uniform ShadowMap
+{
+       float shadow_darkness;
+       mat4 shd_eye_matrix;
+};
+
+const bool use_reflection = false;
+const bool use_environment_map = false;
+uniform samplerCube environment;
+uniform EnvMap
+{
+       mat3 env_eye_matrix;
+};
+
+const int max_clip_planes = 0;
+uniform Clipping
+{
+       ClipPlane clip_planes[max_clip_planes];
+};
+
+////// vertex
+in vec4 vertex;
+in vec4 texcoord;
+in vec4 color;
+in vec3 normal;
+in vec3 tangent;
+in vec3 binormal;
+
+vec4 get_vertex_position()
+{
+       return vertex;
+}
+
+vec3 get_vertex_normal()
+{
+       return normal;
+}
+
+void singlepass_transform_and_lighting()
+{
+       out vec4 eye_vertex = eye_obj_matrix*get_vertex_position();
+       gl_Position = projection_matrix*eye_vertex;
+
+       out vec3 eye_normal = eye_obj_normal_matrix*get_vertex_normal();
+       vec3 eye_tangent = eye_obj_normal_matrix*tangent;
+       vec3 eye_binormal = eye_obj_normal_matrix*binormal;
+       out mat3 eye_tbn_matrix = mat3(eye_tangent, eye_binormal, eye_normal);
+
+       out vec3 incident_dir = normalize(eye_vertex.xyz);
+       if(use_normal_map)
+               incident_dir = incident_dir*eye_tbn_matrix;
+
+       vec3 ldir = normalize(light_sources[0].position.xyz-eye_vertex.xyz*light_sources[0].position.w);
+       if(use_normal_map)
+               ldir = ldir*eye_tbn_matrix;
+       out vec3 light_dir = ldir;
+
+       out vec3 tbn_sky_dir = eye_sky_dir*eye_tbn_matrix;
+       out vec3 shadow_coord = (shd_eye_matrix*eye_vertex).xyz;
+       out float fog_coord = eye_vertex.z;
+
+       for(int i=0; i<max_clip_planes; ++i)
+               gl_ClipDistance[i] = dot(eye_vertex, clip_planes[i].equation);
+}
+
+void main()
+{
+       singlepass_transform_and_lighting();
+       passthrough;
+}
+
+////// fragment
+out vec4 frag_color;
+
+vec4 get_diffuse_sample()
+{
+       return texture(diffuse_map, texcoord.xy);
+}
+
+vec3 get_normal_sample()
+{
+       return texture(normal_map, texcoord.xy).xyz*2.0-1.0;
+}
+
+vec3 normal;
+vec4 diffuse_sample;
+
+vec3 singlepass_lighting()
+{
+       float shadow_sample = texture(shadow, shadow_coord);
+       float shadow_intensity = mix(1.0, shadow_sample, shadow_darkness);
+
+       vec3 ambient_light = ambient_color.rgb;
+       if(use_sky)
+       {
+               vec3 sky_dir;
+               if(use_normal_map)
+                       sky_dir = tbn_sky_dir;
+               else
+                       sky_dir = eye_sky_dir;
+               float skylight_intensity = dot(normal, sky_dir)*0.5+0.5;
+               ambient_light += skylight_intensity*sky_color.rgb;
+       }
+
+       vec3 n_light_dir = normalize(light_dir);
+       float diffuse_intensity = max(dot(normal, n_light_dir), 0.0);
+       if(use_shadow_map)
+               diffuse_intensity *= shadow_intensity;
+       vec3 diffuse_light = diffuse_intensity*light_sources[0].diffuse.rgb;
+
+       vec3 half_vec = normalize(light_dir-incident_dir);
+       float specular_intensity = pow(max(dot(half_vec, normal), 0.0), material.shininess);
+       if(use_shadow_map)
+               specular_intensity *= shadow_intensity;
+       vec3 specular_light = specular_intensity*light_sources[0].specular.rgb;
+
+       vec3 result = material.ambient.rgb*ambient_light+material.diffuse.rgb*diffuse_light;
+       if(use_diffuse_map)
+               result *= diffuse_sample.rgb;
+       if(use_specular)
+               result += material.specular.rgb*specular_light;
+
+       return result;
+}
+
+float singlepass_transparency()
+{
+       float alpha = material.diffuse.a;
+       if(use_diffuse_map)
+               alpha *= diffuse_sample.a;
+       return alpha;
+}
+
+vec3 singlepass_reflection()
+{
+       vec3 reflect_dir = reflect(incident_dir, normal);
+       if(use_normal_map)
+               reflect_dir = eye_tbn_matrix*reflect_dir;
+       vec3 result = vec3(0.0);
+
+       if(use_environment_map)
+               result += texture(environment, env_eye_matrix*reflect_dir).rgb*reflectivity;
+
+       if(use_sky && use_specular)
+       {
+               float reflect_altitude = clamp(dot(reflect_dir, eye_sky_dir)-horizon_limit, -1.0, 0.0);
+               float sky_specular_intensity = pow((1.0-reflect_altitude*reflect_altitude), material.shininess/2.0);
+               result += sky_specular_intensity*sky_color.rgb;
+       }
+
+       return result;
+}
+
+vec4 singlepass_color()
+{
+       vec4 result = vec4(1.0);
+       if(use_vertex_color)
+               result *= color;
+       if(use_diffuse_map)
+               result *= get_diffuse_sample();
+       return result;
+}
+
+void main()
+{
+       if(use_normal_map)
+               normal = get_normal_sample();
+       else
+               normal = normalize(eye_normal);
+
+       diffuse_sample = get_diffuse_sample();
+
+       vec4 final_color;
+       if(use_lighting)
+               final_color = vec4(singlepass_lighting(), singlepass_transparency());
+       else
+               final_color = singlepass_color();
+
+       if(use_reflection)
+               final_color += vec4(singlepass_reflection(), 0.0);
+       if(use_fog)
+       {
+               float fog_value = exp(fog_coord*fog_density);
+               final_color = vec4(mix(fog_color.rgb, final_color.rgb, fog_value), final_color.a);
+       }
+
+       frag_color = final_color;
+}
index bba69315de900890e5c365a1c7a325e356394e63..48e986cea064b2742eadf3d2625f418ccf1cef24 100644 (file)
@@ -23,6 +23,8 @@ using namespace std;
 namespace Msp {
 namespace GL {
 
+extern const char singlepass_glsl_data[];
+
 Resources::Resources():
        default_tex_filter(SGIS_generate_mipmap ? LINEAR_MIPMAP_LINEAR : LINEAR),
        srgb_conversion(false),
@@ -43,6 +45,22 @@ Resources::Resources():
        add_type<Texture3D>().base<Texture>().suffix(".tex3d").keyword("texture3d");
        add_type<TextureCube>().base<Texture>().suffix(".texcb").keyword("texture_cube");
        add_type<Texture2DArray>().base<Texture>().suffix(".tex2da").keyword("texture2d_array");
+
+       add_source(get_builtins());
+}
+
+DataFile::BuiltinSource &Resources::get_builtins()
+{
+       static DataFile::BuiltinSource builtins;
+       bool init_done = false;
+
+       if(!init_done)
+       {
+               builtins.add_object("singlepass.glsl", singlepass_glsl_data);
+               init_done = true;
+       }
+
+       return builtins;
 }
 
 void Resources::set_default_texture_filter(TextureFilter tf)
@@ -117,7 +135,7 @@ Program *Resources::create_program(const string &name)
        if(RefPtr<IO::Seekable> io = open_from_sources(name))
        {
                ProgramCompiler compiler;
-               compiler.compile(*io);
+               compiler.compile(*io, this);
                RefPtr<Program> program = new Program;
                compiler.add_shaders(*program);
                program->link();
index 1f3880aa431c86f69e278a07e951b9423a3273f4..838b022989b69eb9ea73c31c5cb57a6da4ab62bd 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef MSP_GL_RESOURCES_H_
 #define MSP_GL_RESOURCES_H_
 
+#include <msp/datafile/builtinsource.h>
 #include <msp/datafile/collection.h>
 #include "texture.h"
 
@@ -26,6 +27,10 @@ private:
 public:
        Resources();
 
+private:
+       static DataFile::BuiltinSource &get_builtins();
+
+public:
        void set_default_texture_filter(TextureFilter);
 
        /** Enables or disables sRGB conversion.  If enabled, textures and material