diff --git a/Effects/urban.eff b/Effects/urban.eff
index ef4defa74..a214a112b 100644
--- a/Effects/urban.eff
+++ b/Effects/urban.eff
@@ -39,6 +39,345 @@
 		<tangent type="int">6</tangent>
 		<binormal type="int">7</binormal>
 	</generate>
+	<technique n="6">
+		<predicate>
+			<and>
+				<property>/sim/rendering/rembrandt</property>
+				<property>/sim/rendering/shaders/urban</property>
+				<less-equal>
+					<value type="float">4.0</value>
+					<float-property>/sim/rendering/shaders/urban</float-property>
+				</less-equal>
+				<or>
+					<less-equal>
+						<value type="float">2.0</value>
+						<glversion/>
+					</less-equal>
+					<and>
+						<extension-supported>GL_ARB_shader_objects</extension-supported>
+						<extension-supported>GL_ARB_shading_language_100</extension-supported>
+						<extension-supported>GL_ARB_vertex_shader</extension-supported>
+						<extension-supported>GL_ARB_fragment_shader</extension-supported>
+					</and>
+				</or>
+				<or>
+					<extension-supported>GL_ATI_shader_texture_lod</extension-supported> <!-- not available in NVidia driver -->
+					<extension-supported>GL_ARB_shader_texture_lod</extension-supported> <!-- not available in NVidia driver -->
+					<extension-supported>GL_EXT_gpu_shader4</extension-supported>
+				</or>
+			</and>
+		</predicate>
+		<pass>
+			<lighting>false</lighting>
+			<material>
+				<ambient>
+					<use>material/ambient</use>
+				</ambient>
+				<diffuse>
+					<use>material/diffuse</use>
+				</diffuse>
+				<specular>
+					<use>material/specular</use>
+				</specular>
+				<color-mode>ambient-and-diffuse</color-mode>
+			</material>
+			<blend>false</blend>
+			<alpha-test>false</alpha-test>
+			<shade-model>smooth</shade-model>
+			<cull-face>back</cull-face>
+			<render-bin>
+				<bin-number>0</bin-number>
+				<bin-name>RenderBin</bin-name>
+			</render-bin>
+			<texture-unit>
+				<unit>0</unit>
+				<image>
+					<use>texture[0]/image</use>
+				</image>
+				<filter>
+					<use>texture[0]/filter</use>
+				</filter>
+				<wrap-s>
+					<use>texture[0]/wrap-s</use>
+				</wrap-s>
+				<wrap-t>
+					<use>texture[0]/wrap-t</use>
+				</wrap-t>
+				<internal-format>
+					<use>texture[0]/internal-format</use>
+				</internal-format>
+			</texture-unit>
+			<texture-unit>
+				<unit>1</unit>
+				<image>
+					<use>texture[2]/image</use>
+				</image>
+				<filter>
+					<use>texture[2]/filter</use>
+				</filter>
+				<wrap-s>
+					<use>texture[2]/wrap-s</use>
+				</wrap-s>
+				<wrap-t>
+					<use>texture[2]/wrap-t</use>
+				</wrap-t>
+				<internal-format>
+					<use>texture[2]/internal-format</use>
+				</internal-format>
+			</texture-unit>
+			<texture-unit>
+				<unit>2</unit>
+				<image>
+					<use>texture[2]/image</use>
+				</image>
+				<filter>nearest-mipmap-nearest</filter>
+				<wrap-s>
+					<use>texture[2]/wrap-s</use>
+				</wrap-s>
+				<wrap-t>
+					<use>texture[2]/wrap-t</use>
+				</wrap-t>
+				<internal-format>
+					<use>texture[2]/internal-format</use>
+				</internal-format>
+				<mipmap-control>
+					<function-r>average</function-r>
+					<function-g>average</function-g>
+					<function-b>average</function-b>
+					<function-a>min</function-a>
+				</mipmap-control>
+			</texture-unit>
+			<texture-unit>
+				<unit>3</unit>
+				<type>noise</type>
+			</texture-unit>
+			<program>
+				<vertex-shader n="1">Shaders/urban-gbuffer.vert</vertex-shader>
+				<fragment-shader n="1">Shaders/urban-gbuffer.frag</fragment-shader>
+				<attribute>
+					<name>tangent</name>
+					<index>6</index>
+				</attribute>
+				<attribute>
+					<name>binormal</name>
+					<index>7</index>
+				</attribute>
+				<attribute>
+					<name>normal</name>
+					<index>15</index>
+				</attribute>
+			</program>
+			<uniform>
+				<name>BaseTex</name>
+				<type>sampler-2d</type>
+				<value type="int">0</value>
+			</uniform>
+			<uniform>
+				<name>NormalTex</name>
+				<type>sampler-2d</type>
+				<value type="int">1</value>
+			</uniform>
+			<uniform>
+				<name>QDMTex</name>
+				<type>sampler-2d</type>
+				<value type="int">2</value>
+			</uniform>
+			<uniform>
+				<name>NoiseTex</name>
+				<type>sampler-3d</type>
+				<value type="int">3</value>
+			</uniform>
+			<uniform>
+				<name>depth_factor</name>
+				<type>float</type>
+				<value>
+					<use>depth-factor</use>
+				</value>
+			</uniform>
+			<uniform>
+				<name>tile_size</name>
+				<type>float</type>
+				<value>
+					<use>xsize</use>
+				</value>
+			</uniform>
+			<uniform>
+				<name>quality_level</name>
+				<type>float</type>
+				<value>
+					<use>quality-level</use>
+				</value>
+			</uniform>
+			<uniform>
+				<name>snowlevel</name>
+				<type>float</type>
+				<value>
+					<use>snow-level</use>
+				</value>
+			</uniform>
+			<uniform>
+				<name>max_lod_level</name>
+				<type>float</type>
+				<value>
+					<use>max-lod-level</use>
+				</value>
+			</uniform>
+		</pass>
+	</technique>
+	<technique n="7">
+		<predicate>
+			<and>
+				<property>/sim/rendering/rembrandt</property>
+				<property>/sim/rendering/shaders/urban</property>
+				<less-equal>
+					<value type="float">1.0</value>
+					<float-property>/sim/rendering/shaders/urban</float-property>
+				</less-equal>
+				<or>
+					<less-equal>
+						<value type="float">2.0</value>
+						<glversion/>
+					</less-equal>
+					<and>
+						<extension-supported>GL_ARB_shader_objects</extension-supported>
+						<extension-supported>GL_ARB_shading_language_100</extension-supported>
+						<extension-supported>GL_ARB_vertex_shader</extension-supported>
+						<extension-supported>GL_ARB_fragment_shader</extension-supported>
+					</and>
+				</or>
+				<!-- quality level below 4.0 doesn't require GL_ATI_shader_texture_lod or GL_ARB_shader_texture_lod -->
+			</and>
+		</predicate>
+		<pass>
+			<lighting>false</lighting>
+			<material>
+				<ambient>
+					<use>material/ambient</use>
+				</ambient>
+				<diffuse>
+					<use>material/diffuse</use>
+				</diffuse>
+				<specular>
+					<use>material/specular</use>
+				</specular>
+				<color-mode>ambient-and-diffuse</color-mode>
+			</material>
+			<blend>false</blend>
+			<alpha-test>false</alpha-test>
+			<shade-model>smooth</shade-model>
+			<cull-face>back</cull-face>
+			<render-bin>
+				<bin-number>0</bin-number>
+				<bin-name>RenderBin</bin-name>
+			</render-bin>
+			<texture-unit>
+				<unit>0</unit>
+				<image>
+					<use>texture[0]/image</use>
+				</image>
+				<filter>
+					<use>texture[0]/filter</use>
+				</filter>
+				<wrap-s>
+					<use>texture[0]/wrap-s</use>
+				</wrap-s>
+				<wrap-t>
+					<use>texture[0]/wrap-t</use>
+				</wrap-t>
+				<internal-format>
+					<use>texture[0]/internal-format</use>
+				</internal-format>
+			</texture-unit>
+			<texture-unit>
+				<unit>1</unit>
+				<image>
+					<use>texture[2]/image</use>
+				</image>
+				<filter>
+					<use>texture[2]/filter</use>
+				</filter>
+				<wrap-s>
+					<use>texture[2]/wrap-s</use>
+				</wrap-s>
+				<wrap-t>
+					<use>texture[2]/wrap-t</use>
+				</wrap-t>
+				<internal-format>
+					<use>texture[2]/internal-format</use>
+				</internal-format>
+			</texture-unit>
+			<texture-unit>
+				<unit>2</unit>
+				<type>noise</type>
+			</texture-unit>
+			<program>
+				<vertex-shader>Shaders/urban-gbuffer.vert</vertex-shader>
+				<fragment-shader>Shaders/urban-gbuffer.frag</fragment-shader>
+				<attribute>
+					<name>tangent</name>
+					<index>6</index>
+				</attribute>
+				<attribute>
+					<name>binormal</name>
+					<index>7</index>
+				</attribute>
+				<attribute>
+					<name>normal</name>
+					<index>15</index>
+				</attribute>
+			</program>
+			<uniform>
+				<name>BaseTex</name>
+				<type>sampler-2d</type>
+				<value type="int">0</value>
+			</uniform>
+			<uniform>
+				<name>NormalTex</name>
+				<type>sampler-2d</type>
+				<value type="int">1</value>
+			</uniform>
+			<uniform>
+				<name>NoiseTex</name>
+				<type>sampler-3d</type>
+				<value type="int">2</value>
+			</uniform>
+			<uniform>
+				<name>depth_factor</name>
+				<type>float</type>
+				<value>
+					<use>depth-factor</use>
+				</value>
+			</uniform>
+			<uniform>
+				<name>tile_size</name>
+				<type>float</type>
+				<value>
+					<use>xsize</use>
+				</value>
+			</uniform>
+			<uniform>
+				<name>night_color</name>
+				<type>float-vec3</type>
+				<value>
+					<use>night-color</use>
+				</value>
+			</uniform>
+			<uniform>
+				<name>quality_level</name>
+				<type>float</type>
+				<value>
+					<use>quality-level</use>
+				</value>
+			</uniform>
+			<uniform>
+				<name>snowlevel</name>
+				<type>float</type>
+				<value>
+					<use>snow-level</use>
+				</value>
+			</uniform>
+		</pass>
+	</technique>
 	<technique n="8">
 		<predicate>
 			<and>
diff --git a/Shaders/urban-gbuffer.frag b/Shaders/urban-gbuffer.frag
new file mode 100644
index 000000000..a3349d8a4
--- /dev/null
+++ b/Shaders/urban-gbuffer.frag
@@ -0,0 +1,219 @@
+// -*- mode: C; -*-
+// Licence: GPL v2
+// Author: Frederic Bouvier.
+//  Adapted from the paper by F. Policarpo et al. : Real-time Relief Mapping on Arbitrary Polygonal Surfaces
+//  Adapted from the paper and sources by M. Drobot in GPU Pro : Quadtree Displacement Mapping with Height Blending
+
+#version 120
+
+#extension GL_ATI_shader_texture_lod : enable
+#extension GL_ARB_shader_texture_lod : enable
+
+#define TEXTURE_MIP_LEVELS 10
+#define TEXTURE_PIX_COUNT  1024 //pow(2,TEXTURE_MIP_LEVELS)
+#define BINARY_SEARCH_COUNT 10
+#define BILINEAR_SMOOTH_FACTOR 2.0
+
+varying vec4  rawpos;
+varying vec4  ecPosition;
+varying vec3  VNormal;
+varying vec3  VTangent;
+varying vec3  VBinormal;
+varying vec3  Normal;
+varying vec4  constantColor;
+varying vec4  specular;
+
+uniform sampler3D NoiseTex;
+uniform sampler2D BaseTex;
+uniform sampler2D NormalTex;
+uniform sampler2D QDMTex;
+uniform float depth_factor;
+uniform float tile_size;
+uniform float quality_level;
+uniform float snowlevel;
+
+const float scale = 1.0;
+int linear_search_steps = 10;
+int GlobalIterationCount = 0;
+int gIterationCap = 64;
+
+void QDM(inout vec3 p, inout vec3 v)
+{
+    const int MAX_LEVEL = TEXTURE_MIP_LEVELS;
+    const float NODE_COUNT = TEXTURE_PIX_COUNT;
+    const float TEXEL_SPAN_HALF = 1.0 / NODE_COUNT / 2.0;
+
+    float fDeltaNC = TEXEL_SPAN_HALF * depth_factor;
+
+    vec3 p2 = p;
+    float level = MAX_LEVEL;
+    vec2 dirSign = (sign(v.xy) + 1.0) * 0.5;
+    GlobalIterationCount = 0;
+    float d = 0.0;
+
+    while (level >= 0.0 && GlobalIterationCount < gIterationCap)
+    {
+        vec4 uv = vec4(p2.xyz, level);
+        d = texture2DLod(QDMTex, uv.xy, uv.w).w;
+
+        if (d > p2.z)
+        {
+            //predictive point of ray traversal
+            vec3 tmpP2 = p + v * d;
+
+            //current node count
+            float nodeCount = pow(2.0, (MAX_LEVEL - level));
+            //current and predictive node ID
+            vec4 nodeID = floor(vec4(p2.xy, tmpP2.xy)*nodeCount);
+
+            //check if we are crossing the current cell
+            if (nodeID.x != nodeID.z || nodeID.y != nodeID.w)
+            {
+                //calculate distance to nearest bound
+                vec2 a = p2.xy - p.xy;
+                vec2 p3 = (nodeID.xy + dirSign) / nodeCount;
+                vec2 b = p3.xy - p.xy;
+
+                vec2 dNC = (b.xy * p2.z) / a.xy;
+                //take the nearest cell
+                d = min(d,min(dNC.x, dNC.y))+fDeltaNC;
+
+                level++;
+
+                //use additional convergence speed-up
+                #ifdef USE_QDM_ASCEND_INTERVAL
+                if(frac(level*0.5) > EPSILON)
+                  level++;
+                #elseif USE_QDM_ASCEND_CONST
+                 level++;
+                #endif
+            }
+            p2 = p + v * d;
+        }
+        level--;
+        GlobalIterationCount++;
+    }
+
+    //
+    // Manual Bilinear filtering
+    //
+    float rayLength =  length(p2.xy - p.xy) + fDeltaNC;
+
+    float dA = p2.z * (rayLength - BILINEAR_SMOOTH_FACTOR * TEXEL_SPAN_HALF) / rayLength;
+    float dB = p2.z * (rayLength + BILINEAR_SMOOTH_FACTOR * TEXEL_SPAN_HALF) / rayLength;
+
+    vec4 p2a = vec4(p + v * dA, 0.0);
+    vec4 p2b = vec4(p + v * dB, 0.0);
+    dA = texture2DLod(NormalTex, p2a.xy, p2a.w).w;
+    dB = texture2DLod(NormalTex, p2b.xy, p2b.w).w;
+
+    dA = abs(p2a.z - dA);
+    dB = abs(p2b.z - dB);
+
+    p2 = mix(p2a.xyz, p2b.xyz, dA / (dA + dB));
+
+    p = p2;
+}
+
+float ray_intersect_QDM(vec2 dp, vec2 ds)
+{
+    vec3 p = vec3( dp, 0.0 );
+    vec3 v = vec3( ds, 1.0 );
+    QDM( p, v );
+    return p.z;
+}
+
+float ray_intersect_relief(vec2 dp, vec2 ds)
+{
+    float size = 1.0 / float(linear_search_steps);
+    float depth = 0.0;
+    float best_depth = 1.0;
+
+    for(int i = 0; i < linear_search_steps - 1; ++i)
+    {
+        depth += size;
+        float t = step(0.95, texture2D(NormalTex, dp + ds * depth).a);
+        if(best_depth > 0.996)
+            if(depth >= t)
+                best_depth = depth;
+    }
+    depth = best_depth;
+
+    const int binary_search_steps = 5;
+
+    for(int i = 0; i < binary_search_steps; ++i)
+    {
+        size *= 0.5;
+        float t = step(0.95, texture2D(NormalTex, dp + ds * depth).a);
+        if(depth >= t)
+        {
+            best_depth = depth;
+            depth -= 2.0 * size;
+        }
+        depth += size;
+    }
+
+    return(best_depth);
+}
+
+float ray_intersect(vec2 dp, vec2 ds)
+{
+    if ( quality_level >= 4.0 )
+        return ray_intersect_QDM( dp, ds );
+    else
+        return ray_intersect_relief( dp, ds );
+}
+
+void main (void)
+{
+    if ( quality_level >= 3.0 ) {
+        linear_search_steps = 20;
+    }
+    vec3 ecPos3 = ecPosition.xyz / ecPosition.w;
+    vec3 V = normalize(ecPos3);
+    vec3 s = vec3(dot(V, VTangent), dot(V, VBinormal), dot(VNormal, -V));
+    vec2 ds = s.xy * depth_factor / s.z;
+    vec2 dp = gl_TexCoord[0].st - ds;
+    float d = ray_intersect(dp, ds);
+
+    vec2 uv = dp + ds * d;
+    vec3 N = texture2D(NormalTex, uv).xyz * 2.0 - 1.0;
+
+
+    float emis = N.z;
+    N.z = sqrt(1.0 - min(1.0,dot(N.xy, N.xy)));
+    float Nz = N.z;
+    N = normalize(N.x * VTangent + N.y * VBinormal + N.z * VNormal);
+	gl_FragData[0] = vec4( (N.xy + vec2(1.0,1.0)) * 0.5, 0.0, 1.0 );
+
+    vec4 ambient_light = constantColor + vec4(gl_Color.rgb, 1.0);
+
+    vec4 noisevec   = texture3D(NoiseTex, (rawpos.xyz)*0.01*scale);
+    vec4 nvL   = texture3D(NoiseTex, (rawpos.xyz)*0.00066*scale);
+
+    float n=0.06;
+    n += nvL[0]*0.4;
+    n += nvL[1]*0.6;
+    n += nvL[2]*2.0;
+    n += nvL[3]*4.0;
+    n += noisevec[0]*0.1;
+    n += noisevec[1]*0.4;
+
+    n += noisevec[2]*0.8;
+    n += noisevec[3]*2.1;
+    n = mix(0.6, n, length(ecPosition.xyz) );
+
+    vec4 finalColor = texture2D(BaseTex, uv);
+    finalColor = mix(finalColor, clamp(n+nvL[2]*4.1+vec4(0.1, 0.1, nvL[2]*2.2, 1.0), 0.7, 1.0),
+            step(0.8,Nz)*(1.0-emis)*smoothstep(snowlevel+300.0, snowlevel+360.0, (rawpos.z)+nvL[1]*3000.0));
+    finalColor *= ambient_light;
+
+    vec4 p = vec4( ecPos3 + tile_size * V * (d-1.0) * depth_factor / s.z, 1.0 );
+    vec4 iproj = gl_ProjectionMatrix * p;
+    iproj /= iproj.w;
+
+    gl_FragData[1] = vec4( finalColor.rgb, 1.0 / 255.0 );
+    gl_FragData[2] = vec4( dot(specular.xyz,vec3(0.3, 0.59, 0.11 )), specular.w, 0.0, 1.0 );
+
+    gl_FragDepth = (iproj.z + 1.0) / 2.0;
+}
diff --git a/Shaders/urban-gbuffer.vert b/Shaders/urban-gbuffer.vert
new file mode 100644
index 000000000..285abb533
--- /dev/null
+++ b/Shaders/urban-gbuffer.vert
@@ -0,0 +1,30 @@
+// -*- mode: C; -*-
+// Licence: GPL v2
+// Author: Frederic Bouvier
+
+varying vec4  rawpos;
+varying vec4  ecPosition;
+varying vec3  VNormal;
+varying vec3  Normal;
+varying vec3  VTangent;
+varying vec3  VBinormal;
+varying vec4  constantColor;
+varying vec4  specular;
+
+attribute vec3 tangent, binormal;
+
+void main(void)
+{
+    rawpos     = gl_Vertex;
+    ecPosition = gl_ModelViewMatrix * gl_Vertex;
+    VNormal = normalize(gl_NormalMatrix * gl_Normal);
+    Normal = normalize(gl_Normal);
+    VTangent  = gl_NormalMatrix * tangent;
+    VBinormal = gl_NormalMatrix * binormal;
+    gl_FrontColor = gl_Color;
+    constantColor = gl_FrontMaterial.emission
+        + gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient);  
+    gl_Position = ftransform();
+    gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
+	specular = vec4( gl_FrontMaterial.specular.rgb, gl_FrontMaterial.shininess );
+}