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 @@
6
7
+
+
+
+ /sim/rendering/rembrandt
+ /sim/rendering/shaders/urban
+
+ 4.0
+ /sim/rendering/shaders/urban
+
+
+
+ 2.0
+
+
+
+ GL_ARB_shader_objects
+ GL_ARB_shading_language_100
+ GL_ARB_vertex_shader
+ GL_ARB_fragment_shader
+
+
+
+ GL_ATI_shader_texture_lod
+ GL_ARB_shader_texture_lod
+ GL_EXT_gpu_shader4
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+ ambient-and-diffuse
+
+ false
+ false
+ smooth
+ back
+
+ 0
+ RenderBin
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2
+
+
+
+ nearest-mipmap-nearest
+
+
+
+
+
+
+
+
+
+
+ average
+ average
+ average
+ min
+
+
+
+ 3
+ noise
+
+
+ Shaders/urban-gbuffer.vert
+ Shaders/urban-gbuffer.frag
+
+ tangent
+ 6
+
+
+ binormal
+ 7
+
+
+ normal
+ 15
+
+
+
+ BaseTex
+ sampler-2d
+ 0
+
+
+ NormalTex
+ sampler-2d
+ 1
+
+
+ QDMTex
+ sampler-2d
+ 2
+
+
+ NoiseTex
+ sampler-3d
+ 3
+
+
+ depth_factor
+ float
+
+
+
+
+
+ tile_size
+ float
+
+
+
+
+
+ quality_level
+ float
+
+
+
+
+
+ snowlevel
+ float
+
+
+
+
+
+ max_lod_level
+ float
+
+
+
+
+
+
+
+
+
+ /sim/rendering/rembrandt
+ /sim/rendering/shaders/urban
+
+ 1.0
+ /sim/rendering/shaders/urban
+
+
+
+ 2.0
+
+
+
+ GL_ARB_shader_objects
+ GL_ARB_shading_language_100
+ GL_ARB_vertex_shader
+ GL_ARB_fragment_shader
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+ ambient-and-diffuse
+
+ false
+ false
+ smooth
+ back
+
+ 0
+ RenderBin
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2
+ noise
+
+
+ Shaders/urban-gbuffer.vert
+ Shaders/urban-gbuffer.frag
+
+ tangent
+ 6
+
+
+ binormal
+ 7
+
+
+ normal
+ 15
+
+
+
+ BaseTex
+ sampler-2d
+ 0
+
+
+ NormalTex
+ sampler-2d
+ 1
+
+
+ NoiseTex
+ sampler-3d
+ 2
+
+
+ depth_factor
+ float
+
+
+
+
+
+ tile_size
+ float
+
+
+
+
+
+ night_color
+ float-vec3
+
+
+
+
+
+ quality_level
+ float
+
+
+
+
+
+ snowlevel
+ float
+
+
+
+
+
+
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 );
+}