diff --git a/modules/gfx/src/impl/scene_fx.cc b/modules/gfx/src/impl/scene_fx.cc
index 6c4dfb3083b1c022e855fd6cc62aebfc1cbd8311..9e32dc329a8978e3859483e92fe5867317cba4f4 100644
--- a/modules/gfx/src/impl/scene_fx.cc
+++ b/modules/gfx/src/impl/scene_fx.cc
@@ -42,6 +42,7 @@ SceneFX::SceneFX():
   scene_tex2_id_(),
   norm_tex2_id_(),
   scene_fb_(),
+  scene_rb_(),
   depth_rb_(),
   use_fb_(false)
 {}
@@ -63,6 +64,7 @@ void SceneFX::Setup()
   glGenTextures(1,&kernel2_tex_id_);
 
   glGenFramebuffers(1,&scene_fb_);
+  glGenRenderbuffers(1,&scene_rb_);
   glGenRenderbuffers(1,&depth_rb_);
   glGenTextures(1,&scene_tex2_id_);
   glGenTextures(1,&norm_tex2_id_);
@@ -208,7 +210,7 @@ void SceneFX::Postprocess()
 
   if(!shadow_flag && !amb_occl_flag && !depth_dark_flag) {
     // no postprocessing is needed
-    //return;
+    return;
   }
 
   Viewport vp=Scene::Instance().GetViewport();
@@ -255,14 +257,16 @@ void SceneFX::Postprocess()
 
   glUniform1i(glGetUniformLocation(cpr,"scene_map"),0);
   glUniform1i(glGetUniformLocation(cpr,"depth_map"),1);
-  glUniform2f(glGetUniformLocation(cpr,"i_vp"),1.0/static_cast<float>(vp.width),1.0/static_cast<float>(vp.height));
-  double pm[16];
-  glGetDoublev(GL_PROJECTION_MATRIX,pm);
-  glUniform4f(glGetUniformLocation(cpr,"abcd"),pm[0],pm[5],pm[10],pm[14]);
 
   if(shadow_flag) {
     glActiveTexture(GL_TEXTURE2);
     glBindTexture(GL_TEXTURE_2D,shadow_tex_id_);
+    glMatrixMode(GL_TEXTURE);
+    glPushMatrix();
+    // make explicit object instead of temporary to avoid potential crash with Data()
+    geom::Mat4 ttmp=Transpose(shadow_tex_mat_);
+    glLoadMatrix(ttmp.Data());
+    glMatrixMode(GL_MODELVIEW);
     glActiveTexture(GL_TEXTURE0);
     glUniform1i(glGetUniformLocation(cpr,"shadow_flag"),1);
     glUniform1i(glGetUniformLocation(cpr,"shadow_map"),2);
@@ -270,12 +274,6 @@ void SceneFX::Postprocess()
     glUniform1f(glGetUniformLocation(cpr,"shadow_epsilon"),0.002);
     glUniform1f(glGetUniformLocation(cpr,"shadow_multiplier"),0.4);
 
-    glMatrixMode(GL_TEXTURE);
-    glPushMatrix();
-    // make explicit object instead of temporary to avoid potential crash with Data()
-    geom::Mat4 ttmp=Transpose(shadow_tex_mat_);
-    glLoadMatrix(ttmp.Data());
-    glMatrixMode(GL_MODELVIEW);
   } else {
     glUniform1i(glGetUniformLocation(cpr,"shadow_flag"),0);
   }
@@ -304,9 +302,11 @@ void SceneFX::Postprocess()
   draw_screen_quad(vp.width,vp.height);
 
   if(shadow_flag) {
+    glActiveTexture(GL_TEXTURE2);
     glMatrixMode(GL_TEXTURE);
     glPopMatrix();
     glMatrixMode(GL_MODELVIEW);
+    glActiveTexture(GL_TEXTURE0);
   }
 
   glDisable(GL_TEXTURE_1D);
@@ -328,11 +328,30 @@ void SceneFX::DrawTex(unsigned int w, unsigned int h, GLuint texid)
 
 void SceneFX::prep_shadow_map()
 {
-  GLint smap_size=256 << shadow_quality;
+  GLint smap_size=256 * (1+shadow_quality);
+
+#if 1
+  glBindFramebuffer(GL_FRAMEBUFFER, scene_fb_);
+
+  glBindRenderbuffer(GL_RENDERBUFFER, scene_rb_);
+  glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA,smap_size,smap_size);
+  glBindRenderbuffer(GL_RENDERBUFFER, depth_rb_);
+  glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,smap_size,smap_size);
+  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, scene_rb_);
+  glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth_rb_);
+
+  GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+  if(status!=GL_FRAMEBUFFER_COMPLETE) {
+    LOGN_DEBUG("fbo switch for shadow mapping failed, using fallback");
+    glBindRenderbuffer(GL_RENDERBUFFER, 0);
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+  }
+#endif
 
   // modelview transform for the lightsource pov
   mol::Transform ltrans(Scene::Instance().GetTransform());
-  ltrans.SetRot(Scene::Instance().GetLightRot()*Scene::Instance().GetTransform().GetRot());
+  ltrans.SetRot(Scene::Instance().GetLightRot()*ltrans.GetRot());
 
   // calculate encompassing box for ortho projection
   geom::AlignedCuboid bb=Scene::Instance().GetBoundingBox(ltrans);
@@ -384,12 +403,26 @@ void SceneFX::prep_shadow_map()
   glPopAttrib();
   //glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
 
+#if 1
+  glBindRenderbuffer(GL_RENDERBUFFER, 0);
+  glBindFramebuffer(GL_FRAMEBUFFER, 0);
+#endif
+
   // set up appropriate texture matrix
   geom::Mat4 bias(0.5,0.0,0.0,0.5,
                   0.0,0.5,0.0,0.5,
                   0.0,0.0,0.5,0.5,
                   0.0,0.0,0.0,1.0);
-  shadow_tex_mat_ = bias*pmat*ltrans.GetMatrix();
+  //shadow_tex_mat_ = bias*pmat*ltrans.GetMatrix();
+  Scene::Instance().ResetProjection();
+  glGetv(GL_PROJECTION_MATRIX, glpmat);
+  geom::Mat4 pmat2(Transpose(geom::Mat4(glpmat)));
+  /*
+    given the normalized coordinates in scenefx, the camera projection and modelview transformation
+    are first reverted, and then the light modelview and projection are applied, resulting (with the
+    bias) in the proper 2D lookup into the shadow map
+  */
+  shadow_tex_mat_ = bias*pmat*ltrans.GetMatrix()*geom::Invert(Scene::Instance().GetTransform().GetMatrix())*geom::Invert(pmat2);
 }
 
 void SceneFX::prep_amb_occlusion()
@@ -482,6 +515,8 @@ void SceneFX::draw_screen_quad(unsigned int w, unsigned int h)
   glPushMatrix();
   glLoadIdentity();
   glEnable(GL_TEXTURE_2D);
+  glActiveTexture(GL_TEXTURE0);
+  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
   // draw
   glColor3f(1.0,0.0,1.0);
   glBegin(GL_QUADS);
diff --git a/modules/gfx/src/impl/scene_fx.hh b/modules/gfx/src/impl/scene_fx.hh
index ebd4ae6e7c97131408af38d3db200974fdc73fe3..3048e1d52dbdcf30980a2a61c5619909acd5f3e0 100644
--- a/modules/gfx/src/impl/scene_fx.hh
+++ b/modules/gfx/src/impl/scene_fx.hh
@@ -82,6 +82,7 @@ private:
   GLuint scene_tex2_id_;
   GLuint norm_tex2_id_;
   GLuint scene_fb_;
+  GLuint scene_rb_;
   GLuint depth_rb_;
 
   bool use_fb_;
diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc
index 38aaaff76d781d76cca6eb6d5f7780415109fb27..c1145759789eefdc2cb5ff8f4152ea749a7dbd29 100644
--- a/modules/gfx/src/scene.cc
+++ b/modules/gfx/src/scene.cc
@@ -181,7 +181,7 @@ bool Scene::GetShadow() const
 void Scene::SetShadowQuality(int q)
 {
 #if OST_SHADER_SUPPORT_ENABLED
-  impl::SceneFX::Instance().shadow_quality=std::min(3,std::max(0,q));
+  impl::SceneFX::Instance().shadow_quality=std::min(8,std::max(0,q));
   RequestRedraw();
 #endif
 }
diff --git a/modules/gfx/src/shader/scenefx_fs.glsl b/modules/gfx/src/shader/scenefx_fs.glsl
index 2c7341de096e8f03c23075cb1046135c59a1a68c..e8acfcefcca8289305183381e403b1999efbce5c 100644
--- a/modules/gfx/src/shader/scenefx_fs.glsl
+++ b/modules/gfx/src/shader/scenefx_fs.glsl
@@ -1,7 +1,5 @@
 uniform sampler2D scene_map;
 uniform sampler2D depth_map;
-uniform vec2 i_vp;
-uniform vec4 abcd;
 uniform bool shadow_flag;
 uniform sampler2D shadow_map;
 uniform float shadow_depth_bias;
@@ -14,13 +12,6 @@ uniform bool dark_flag;
 uniform sampler2D dark_map;
 uniform float dark_mult;
 
-vec3 unproject(in vec3 scr)
-{ 
-  vec3 tmp=vec3(scr.x*i_vp.x*2.0-1.0,scr.y*i_vp.y*2.0-1.0,scr.z);
-  float iw = 1.0/(tmp.z/abcd.w+abcd.z/abcd.w);
-  return iw*vec3(tmp.x/abcd.x,tmp.y/abcd.y,-1.0);
-}
-
 float CalcShadowFactor(in vec4 coord, in vec2 o)
 {
   // get original depth value of line projected towards light
@@ -30,15 +21,21 @@ float CalcShadowFactor(in vec4 coord, in vec2 o)
 
 void main()
 {
+  float depth = texture2D(depth_map,gl_TexCoord[0].xy).r;
+  if(depth>=1.0) {
+    discard;
+  }
   vec4 scene_color=texture2D(scene_map,gl_TexCoord[0].xy);
   gl_FragColor.a = scene_color.a;
 
   float shadow_factor=1.0;
   if(shadow_flag) {
-    float depth = texture2D(depth_map,gl_TexCoord[0].xy).r;
-    vec4 tcoord = gl_ModelViewProjectionMatrixInverse*vec4(gl_FragCoord.xy*i_vp*2.0-1.0,depth,1.0);
-    vec4 coord = gl_TextureMatrix[0]*tcoord;
+    vec4 pcoord = vec4(gl_TexCoord[0].xy*2.0-1.0,depth*2.0-1.0,1.0);
+    vec4 coord = gl_TextureMatrix[2]*pcoord;
     coord/=coord.w;
+    //float d = texture2D(shadow_map, coord.xy).r;
+    //gl_FragColor.rgb=vec3(1.0,d,0.0);
+    //return;
     shadow_factor = 0.0;
     shadow_factor += 0.18*CalcShadowFactor(coord, vec2(-0.7, -0.7));
     shadow_factor += 0.18*CalcShadowFactor(coord, vec2(0.7, -0.7));