Index: binaries/data/config/default.cfg
===================================================================
--- binaries/data/config/default.cfg
+++ binaries/data/config/default.cfg
@@ -69,9 +69,10 @@
shadowsonwater = false
shadows = true
-shadowquality = 0 ; Shadow map resolution. (-2 - Very Low, -1 - Low, 0 - Medium, 1 - High, 2 - Very High)
- ; High values can crash the game when using a graphics card with low memory!
-shadowpcf = true
+shadowquality = 1 ; Shadow map resolution. (0 - Low, 1 - Medium, 2 - High, 3 - Ultra)
+ ; High values can break shadows when using a graphics card with low memory!
+shadowpcf = true ; Basic shadow filtering.
+shadowpcss = false ; High quality (and expensive) variable penumbra shadows.
vsync = false
particles = true
fog = true
@@ -100,7 +101,7 @@
;;;;; EXPERIMENTAL ;;;;;
; Prefer GLSL shaders over ARB shaders. Allows fancier graphical effects.
-preferglsl = false
+preferglsl = true
; Experimental probably-non-working GPU skinning support; requires preferglsl; use at own risk
gpuskinning = false
@@ -111,6 +112,8 @@
; Use screen-space postprocessing filters (HDR, bloom, DOF, etc). Incompatible with fixed renderpath.
postproc = false
+dof = false ; Use depth of field effect.
+
; Quality level of shader effects (set to 10 to display all effects)
materialmgr.quality = 2.0
Index: binaries/data/mods/public/gui/options/options.json
===================================================================
--- binaries/data/mods/public/gui/options/options.json
+++ binaries/data/mods/public/gui/options/options.json
@@ -58,6 +58,13 @@
"config": "gui.session.ceasefirecounter"
},
{
+ "type": "boolean",
+ "label": "Unit Silhouettes",
+ "tooltip": "Show outlines of units behind buildings.",
+ "config": "silhouettes",
+ "function": "Renderer_SetSilhouettesEnabled"
+ },
+ {
"type": "dropdown",
"label": "Late Observer Joins",
"tooltip": "Allow everybody or buddies only to join the game as observer after it started.",
@@ -97,16 +104,8 @@
},
{
"type": "boolean",
- "label": "Prefer GLSL",
- "tooltip": "Use OpenGL 2.0 shaders (recommended).",
- "config": "preferglsl",
- "function": "Renderer_SetPreferGLSLEnabled"
- },
- {
- "type": "boolean",
"label": "Fog",
"tooltip": "Enable Fog.",
- "dependencies": ["preferglsl"],
"config": "fog",
"function": "Renderer_SetFogEnabled"
},
@@ -118,6 +117,14 @@
"function": "Renderer_SetPostprocEnabled"
},
{
+ "type": "boolean",
+ "label": "Depth of Field",
+ "tooltip": "Apply the depth of field postprocessing effect.",
+ "dependencies": ["postproc"],
+ "config": "dof",
+ "function": "Renderer_SetDOFEnabled"
+ },
+ {
"type": "slider",
"label": "Shader Effects",
"tooltip": "Number of shader effects. REQUIRES GAME RESTART",
@@ -135,16 +142,15 @@
{
"type": "dropdown",
"label": "Shadow Quality",
- "tooltip": "Shadow map resolution. High values can crash the game when using a graphics card with low memory!",
+ "tooltip": "Shadow map resolution.",
"dependencies": ["shadows"],
"config": "shadowquality",
"function": "Renderer_RecreateShadowMap",
"list": [
- { "value": -2, "label": "Very Low" },
- { "value": -1, "label": "Low" },
- { "value": 0, "label": "Medium" },
- { "value": 1, "label": "High" },
- { "value": 2, "label": "Very High" }
+ { "value": 0, "label": "Low" },
+ { "value": 1, "label": "Medium" },
+ { "value": 2, "label": "High" },
+ { "value": 3, "label": "Ultra (MAY NOT WORK)" }
]
},
{
@@ -157,10 +163,11 @@
},
{
"type": "boolean",
- "label": "Unit Silhouettes",
- "tooltip": "Show outlines of units behind buildings.",
- "config": "silhouettes",
- "function": "Renderer_SetSilhouettesEnabled"
+ "label": "Soft Shadows",
+ "tooltip": "Variable penumbra shadows. (Expensive)",
+ "dependencies": ["shadows", "shadowpcf"],
+ "config": "shadowpcss",
+ "function": "Renderer_SetShadowPCSSEnabled"
},
{
"type": "boolean",
Index: binaries/data/mods/public/shaders/effects/postproc/DOF.xml
===================================================================
--- binaries/data/mods/public/shaders/effects/postproc/DOF.xml
+++ binaries/data/mods/public/shaders/effects/postproc/DOF.xml
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
Index: binaries/data/mods/public/shaders/effects/postproc/HDR.xml
===================================================================
--- binaries/data/mods/public/shaders/effects/postproc/HDR.xml
+++ binaries/data/mods/public/shaders/effects/postproc/HDR.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
Index: binaries/data/mods/public/shaders/effects/postproc/hdr.xml
===================================================================
--- binaries/data/mods/public/shaders/effects/postproc/hdr.xml
+++ binaries/data/mods/public/shaders/effects/postproc/hdr.xml
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
Index: binaries/data/mods/public/shaders/glsl/bloom.fs
===================================================================
--- binaries/data/mods/public/shaders/glsl/bloom.fs
+++ binaries/data/mods/public/shaders/glsl/bloom.fs
@@ -1,41 +1,37 @@
-#version 110
+#version 120
varying vec2 v_tex;
uniform sampler2D renderedTex;
uniform vec2 texSize;
+#if BIG_BLUR
+ // 5 tap linear sampled gaussian blur, created using BlurNinja: https://github.com/manuelbua/blur-ninja
+ uniform float weight[2] = float[](0.375, 0.3125);
+ uniform float offset = 1.2;
+#else
+ // 3 tap gaussian blur
+ uniform float weight[2] = float[](0.5, 0.25);
+ uniform float offset = 1.0;
+#endif
+
void main()
{
- #if BLOOM_NOP
- gl_FragColor = texture2D(renderedTex, v_tex);
- gl_FragColor.a = 1.0;
- #endif
+ #if BLOOM_NOP
+ gl_FragColor = texture2D(renderedTex, v_tex);
+ gl_FragColor.a = 1.0;
+ #endif
+
+ #if BLOOM_PASS_H
+ gl_FragColor = texture2D(renderedTex, gl_FragCoord.xy / texSize) * weight[0];
+ gl_FragColor += texture2D(renderedTex, (gl_FragCoord.xy + vec2(offset, 0.0))/texSize) * weight[1];
+ gl_FragColor += texture2D(renderedTex, (gl_FragCoord.xy - vec2(offset, 0.0))/texSize) * weight[1];
+ gl_FragColor.a = 1.0;
+ #endif
- #if BLOOM_PASS_H
- vec4 color = vec4(0.0);
- vec2 v_tex_offs = vec2(v_tex.x - 0.01, v_tex.y);
-
- for (int i = 0; i < 6; ++i)
- {
- color += texture2D(renderedTex, v_tex_offs);
- v_tex_offs += vec2(0.004, 0.0);
- }
-
- gl_FragColor.rgb = color.rgb / 6.0;
- gl_FragColor.a = 1.0;
- #endif
-
- #if BLOOM_PASS_V
- vec4 color = vec4(0.0);
- vec2 v_tex_offs = vec2(v_tex.x, v_tex.y - 0.01);
-
- for (int i = 0; i < 6; ++i)
- {
- color += texture2D(renderedTex, v_tex_offs);
- v_tex_offs += vec2(0.0, 0.004);
- }
-
- gl_FragColor.rgb = color.rgb / 6.0;
- gl_FragColor.a = 1.0;
- #endif
+ #if BLOOM_PASS_V
+ gl_FragColor = texture2D(renderedTex, gl_FragCoord.xy / texSize) * weight[0];
+ gl_FragColor += texture2D(renderedTex, ((gl_FragCoord.xy + vec2(0.0, offset))/texSize)) * weight[1];
+ gl_FragColor += texture2D(renderedTex, ((gl_FragCoord.xy - vec2(0.0, offset))/texSize)) * weight[1];
+ gl_FragColor.a = 1.0;
+ #endif
}
\ No newline at end of file
Index: binaries/data/mods/public/shaders/glsl/bloom.xml
===================================================================
--- binaries/data/mods/public/shaders/glsl/bloom.xml
+++ binaries/data/mods/public/shaders/glsl/bloom.xml
@@ -1,7 +1,7 @@
-
+
Index: binaries/data/mods/public/shaders/glsl/dof_hdr.fs
===================================================================
--- binaries/data/mods/public/shaders/glsl/dof_hdr.fs
+++ binaries/data/mods/public/shaders/glsl/dof_hdr.fs
@@ -0,0 +1,71 @@
+#version 120
+
+uniform sampler2D renderedTex;
+uniform sampler2D depthTex;
+uniform sampler2D downscaleTex2;
+uniform sampler2D blurTex2;
+uniform sampler2D blurTex4;
+uniform sampler2D blurTex8;
+
+uniform float width;
+uniform float height;
+
+uniform float zNear;
+uniform float zFar;
+
+uniform float brightness;
+uniform float contrast;
+uniform float saturation;
+uniform float bloom;
+
+varying vec2 v_tex;
+
+float linearizeDepth(float depth)
+{
+ return 2.0 * zNear / (zNear + zFar - depth * (zFar - zNear));
+}
+
+void main(void)
+{
+ vec3 color = texture2D(renderedTex, v_tex).rgb;
+ vec3 blur2 = texture2D(blurTex2, v_tex).rgb;
+
+ #if USE_DOF
+ // Apply Depth of Field
+ vec3 down2 = texture2D(downscaleTex2, v_tex).rgb;
+
+ float depth = linearizeDepth(texture2D(depthTex, v_tex).r);
+ float amount = pow(depth, 1.25) * 6.5; // Using a semi-exponential ramp to keep nearby objects from being semi-blurred.
+
+ if (amount < 1.0){
+ color = mix(color, down2, amount);
+ }else{
+ amount = clamp(amount - 1.0, 0.0, 1.0);
+ color = mix(down2, blur2, amount);
+ }
+ #endif
+
+ #if USE_HDR
+ // Apply bloom and color adjustments
+ if (bloom < 0.2){
+ // Note: 0.2 is the "zero" setting for bloom for some unfathomable reason.
+ // If bloom is set to "zero" we skip all the texture reads and operations so as not to waste GPU cycles.
+ vec3 blur4 = texture2D(blurTex4, v_tex).rgb;
+ vec3 blur8 = texture2D(blurTex8, v_tex).rgb;
+ vec3 blur = (blur2 + blur4 + blur8)/3.0;
+
+ blur = mix(color, blur, (1.0 - (bloom * 5.0)));
+
+ color = max(blur, color);
+ }
+
+ color = (color + brightness - 0.5) * contrast + 0.5;
+
+ color = mix(vec3(dot(color, vec3(0.299, 0.587, 0.114))), color, saturation);
+ #endif
+
+ gl_FragColor.rgb = color;
+ gl_FragColor.a = 1.0;
+}
+
+
Index: binaries/data/mods/public/shaders/glsl/dof_hdr.vs
===================================================================
--- binaries/data/mods/public/shaders/glsl/dof_hdr.vs
+++ binaries/data/mods/public/shaders/glsl/dof_hdr.vs
@@ -0,0 +1,13 @@
+#version 110
+
+varying vec2 v_tex;
+
+attribute vec3 a_vertex;
+attribute vec2 a_uv0;
+
+void main()
+{
+ gl_Position = vec4(a_vertex, 1.0);
+
+ v_tex = a_uv0;
+}
Index: binaries/data/mods/public/shaders/glsl/dof_hdr.xml
===================================================================
--- binaries/data/mods/public/shaders/glsl/dof_hdr.xml
+++ binaries/data/mods/public/shaders/glsl/dof_hdr.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: binaries/data/mods/public/shaders/glsl/model_common.fs
===================================================================
--- binaries/data/mods/public/shaders/glsl/model_common.fs
+++ binaries/data/mods/public/shaders/glsl/model_common.fs
@@ -10,9 +10,15 @@
varying vec4 v_shadow;
#if USE_SHADOW_SAMPLER
uniform sampler2DShadow shadowTex;
- #if USE_SHADOW_PCF
- uniform vec4 shadowScale;
+ #if USE_SHADOW_PCF || USE_SHADOW_PCSS
+ uniform vec4 shadowScale;
+ // shadowScale.xy gives the dimensionless scale factor based on the shadow map resolution and the shadow frustum x and y bounds.
+ // shadowScale.z gives the dimensionless relative z bounds of the shadow frustum.
+ // shadowScale.w gives 1.0 divided by the shadow map length in texels, for tex coord scaling.
#endif
+ #if USE_SHADOW_PCSS
+ uniform sampler2D blockerTex;
+ #endif
#else
uniform sampler2D shadowTex;
#endif
@@ -26,6 +32,20 @@
#endif
#endif
+#if USE_SHADOW_PCF || (USE_SHADOW_PCSS && USE_TRANSPARENT)
+ // This is a 'random' poisson disk with a uniform distribution created with a poisson disk generator.
+ uniform vec2 offsets[8] = vec2[](
+ vec2(-0.353553, 0.612372),
+ vec2(-0.25, -0.433013),
+ vec2(0.663414, 0.55667),
+ vec2(-0.332232, 0.120922),
+ vec2(0.137281, -0.778559),
+ vec2(0.106337, 0.603069),
+ vec2(-0.879002, -0.319931),
+ vec2(0.191511, -0.160697)
+ );
+#endif
+
uniform vec3 shadingColor;
uniform vec3 ambient;
uniform vec3 sunColor;
@@ -71,18 +91,72 @@
#if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS
float biasedShdwZ = v_shadow.z - shadowBias;
#if USE_SHADOW_SAMPLER
- #if USE_SHADOW_PCF
- vec2 offset = fract(v_shadow.xy - 0.5);
- vec4 size = vec4(offset + 1.0, 2.0 - offset);
- vec4 weight = (vec4(1.0, 1.0, -0.5, -0.5) + (v_shadow.xy - 0.5*offset).xyxy) * shadowScale.zwzw;
- return (1.0/9.0)*dot(size.zxzx*size.wwyy,
- vec4(shadow2D(shadowTex, vec3(weight.zw, biasedShdwZ)).r,
- shadow2D(shadowTex, vec3(weight.xw, biasedShdwZ)).r,
- shadow2D(shadowTex, vec3(weight.zy, biasedShdwZ)).r,
- shadow2D(shadowTex, vec3(weight.xy, biasedShdwZ)).r));
- #else
- return shadow2D(shadowTex, vec3(v_shadow.xy, biasedShdwZ)).r;
- #endif
+ #if USE_SHADOW_PCF || (USE_SHADOW_PCSS && USE_TRANSPARENT)
+ float blurRadius = 3.0;
+ const int numSamples = 8;
+ float lit = 0.0;
+ vec2 uv = v_shadow.xy - (0.5 * fract(v_shadow.xy - 0.5));
+
+ for (int i = 0; i < numSamples; ++i){
+ vec2 offset = (uv + offsets[i] * blurRadius * shadowScale.xy) * shadowScale.w;
+ lit += shadow2D(shadowTex, vec3(offset, biasedShdwZ)).r;
+ }
+
+ return lit/float(numSamples);
+ #else
+ #if USE_SHADOW_PCSS
+ int numSamples = 5;
+ vec2 uv = v_shadow.xy - (0.5 * fract(v_shadow.xy - 0.5));
+
+ // Perform blocker search
+ float hits = 0.0;
+ float avgdist = 0.0;
+ vec2 off = vec2(-24.5);
+ for (int i = 0; i < numSamples; ++i){
+ for (int j = 0; j < numSamples; ++j){
+ vec2 offset = (uv + vec2(off.x + 9.6 * float(j), off.y) * shadowScale.xy) * shadowScale.w;
+ float dist = texture2D(blockerTex, offset).z;
+
+ // Note: I'm converting a bool to a float here to avoid a nasty branch in the shader.
+ float hit = float(dist < biasedShdwZ);
+ hits += hit;
+ avgdist += dist * hit;
+ }
+ off.y = off.y + 9.6;
+ }
+
+ if (hits == 0.0) return 1.0; // Early exit if no blockers are found.
+
+ // Perform penumbra estimation and scale the number of samples with blur size for efficiency.
+ avgdist /= hits;
+
+ float lightsize = 1.25 * shadowScale.z;
+ float penumbrascale = (biasedShdwZ - avgdist)/avgdist;
+
+ float amount = min(lightsize * penumbrascale, 1.0);
+ float sampleamount = min((lightsize/1.5) * penumbrascale, 1.0);
+
+ numSamples = int(floor(mix(2.0, 16.0, amount)));
+ float sampleScale = mix(1.0, 24.0, sampleamount); // This allows smooth transitions by varying the spacing of the samples.
+ float blurscale = sampleScale/float(numSamples);
+
+ // Perform shadow sampling
+ float lit = 0.0;
+ off = vec2(-0.5 - float(numSamples));
+ lit += shadow2D(shadowTex, vec3(uv * shadowScale.w, biasedShdwZ)).r;
+ for (int i = 0; i < numSamples; ++i){
+ for (int j = 0; j < numSamples; ++j){
+ vec2 offset = (uv + vec2(off.x + 2.0 * float(j), off.y) * blurscale * shadowScale.xy) * shadowScale.w;
+ lit += shadow2D(shadowTex, vec3(offset, biasedShdwZ)).r;
+ }
+ off.y = off.y + 2.0;
+ }
+ float shad = 1.0 - lit/(float(numSamples * numSamples) + 1.0);
+ return 1.0 - pow(shad, 1.25);
+ #else
+ return shadow2D(shadowTex, vec3(v_shadow.xy, biasedShdwZ)).r;
+ #endif
+ #endif
#else
if (biasedShdwZ >= 1.0)
return 1.0;
Index: binaries/data/mods/public/shaders/glsl/model_common.vs
===================================================================
--- binaries/data/mods/public/shaders/glsl/model_common.vs
+++ binaries/data/mods/public/shaders/glsl/model_common.vs
@@ -13,7 +13,7 @@
uniform mat4 shadowTransform;
uniform mat4 instancingTransform;
-#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF
+#if USE_SHADOW_SAMPLER && (USE_SHADOW_PCF || USE_SHADOW_PCSS)
uniform vec4 shadowScale;
#endif
@@ -165,8 +165,9 @@
#endif
#endif
- v_lighting.xyz = max(0.0, dot(normal, -sunDir)) * sunColor;
+ v_lighting.xyz = max(0.0, dot(normal, -sunDir)) * sunColor;
+
v_tex = a_uv0;
#if (USE_INSTANCING || USE_GPU_SKINNING) && USE_AO
@@ -175,8 +176,8 @@
#if USE_SHADOW
v_shadow = shadowTransform * position;
- #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF
- v_shadow.xy *= shadowScale.xy;
+ #if USE_SHADOW_SAMPLER && (USE_SHADOW_PCF || USE_SHADOW_PCSS)
+ v_shadow.xy /= shadowScale.w;
#endif
#endif
Index: binaries/data/mods/public/shaders/glsl/terrain_common.fs
===================================================================
--- binaries/data/mods/public/shaders/glsl/terrain_common.fs
+++ binaries/data/mods/public/shaders/glsl/terrain_common.fs
@@ -7,12 +7,17 @@
uniform sampler2D specTex;
#if USE_SHADOW
- uniform float shadowAngle;
#if USE_SHADOW_SAMPLER
uniform sampler2DShadow shadowTex;
- #if USE_SHADOW_PCF
- uniform vec4 shadowScale;
+ #if USE_SHADOW_PCF || USE_SHADOW_PCSS
+ uniform vec4 shadowScale;
+ // shadowScale.xy gives the dimensionless scale factor based on the shadow map resolution and the shadow frustum x and y bounds.
+ // shadowScale.z gives the dimensionless relative z bounds of the shadow frustum.
+ // shadowScale.w gives 1.0 divided by the shadow map length in texels, for tex coord scaling.
#endif
+ #if USE_SHADOW_PCSS
+ uniform sampler2D blockerTex;
+ #endif
#else
uniform sampler2D shadowTex;
#endif
@@ -64,6 +69,28 @@
#endif
#endif
+#if USE_SHADOW_PCF || USE_SHADOW_PCSS
+ // This is a 'random' poisson disk with a uniform distribution created with a poisson disk generator.
+ uniform vec2 offsets[16] = vec2[](
+ vec2(-0.353553, 0.612372),
+ vec2(-0.25, -0.433013),
+ vec2(0.663414, 0.55667),
+ vec2(-0.332232, 0.120922),
+ vec2(0.137281, -0.778559),
+ vec2(0.106337, 0.603069),
+ vec2(-0.879002, -0.319931),
+ vec2(0.191511, -0.160697),
+ vec2(0.729784, 0.172962),
+ vec2(-0.383621, 0.406614),
+ vec2(-0.258521, -0.86352),
+ vec2(0.258577, 0.34733),
+ vec2(-0.82355, 0.0962588),
+ vec2(0.261982, -0.607343),
+ vec2(-0.0562987, 0.966608),
+ vec2(-0.147695, -0.0971404)
+ );
+#endif
+
float get_shadow()
{
float shadowBias = 0.0005;
@@ -70,18 +97,72 @@
#if USE_SHADOW && !DISABLE_RECEIVE_SHADOWS
float biasedShdwZ = v_shadow.z - shadowBias;
#if USE_SHADOW_SAMPLER
- #if USE_SHADOW_PCF
- vec2 offset = fract(v_shadow.xy - 0.5);
- vec4 size = vec4(offset + 1.0, 2.0 - offset);
- vec4 weight = (vec4(1.0, 1.0, -0.5, -0.5) + (v_shadow.xy - 0.5*offset).xyxy) * shadowScale.zwzw;
- return (1.0/9.0)*dot(size.zxzx*size.wwyy,
- vec4(shadow2D(shadowTex, vec3(weight.zw, biasedShdwZ)).r,
- shadow2D(shadowTex, vec3(weight.xw, biasedShdwZ)).r,
- shadow2D(shadowTex, vec3(weight.zy, biasedShdwZ)).r,
- shadow2D(shadowTex, vec3(weight.xy, biasedShdwZ)).r));
- #else
- return shadow2D(shadowTex, vec3(v_shadow.xy, biasedShdwZ)).r;
- #endif
+ #if USE_SHADOW_PCF
+ float blurRadius = 3.0;
+ const int numSamples = 16;
+ float lit = 0.0;
+ vec2 uv = v_shadow.xy - (0.5 * fract(v_shadow.xy - 0.5));
+
+ for (int i = 0; i < numSamples; ++i){
+ vec2 offset = (uv + offsets[i] * blurRadius * shadowScale.xy) * shadowScale.w;
+ lit += shadow2D(shadowTex, vec3(offset, biasedShdwZ)).r;
+ }
+
+ return lit/float(numSamples);
+ #else
+ #if USE_SHADOW_PCSS
+ int numSamples = 5;
+ vec2 uv = v_shadow.xy - (0.5 * fract(v_shadow.xy - 0.5));
+
+ // Perform blocker search
+ float hits = 0.0;
+ float avgdist = 0.0;
+ vec2 off = vec2(-24.5);
+ for (int i = 0; i < numSamples; ++i){
+ for (int j = 0; j < numSamples; ++j){
+ vec2 offset = (uv + vec2(off.x + 9.6 * float(j), off.y) * shadowScale.xy) * shadowScale.w;
+ float dist = texture2D(blockerTex, offset).z;
+
+ // Note: I'm converting a bool to a float here to avoid a nasty branch in the shader.
+ float hit = float(dist < biasedShdwZ);
+ hits += hit;
+ avgdist += dist * hit;
+ }
+ off.y = off.y + 9.6;
+ }
+
+ if (hits == 0.0) return 1.0; // Early exit if no blockers are found.
+
+ // Perform penumbra estimation and scale the number of samples with blur size for efficiency.
+ avgdist /= hits;
+
+ float lightsize = 1.25 * shadowScale.z;
+ float penumbrascale = (biasedShdwZ - avgdist)/avgdist;
+
+ float amount = min(lightsize * penumbrascale, 1.0);
+ float sampleamount = min((lightsize/1.5) * penumbrascale, 1.0);
+
+ numSamples = int(floor(mix(2.0, 16.0, amount)));
+ float sampleScale = mix(1.0, 24.0, sampleamount); // This allows smooth transitions by varying the spacing of the samples.
+ float blurscale = sampleScale/float(numSamples);
+
+ // Perform shadow sampling
+ float lit = 0.0;
+ off = vec2(-0.5 - float(numSamples));
+ lit += shadow2D(shadowTex, vec3(uv * shadowScale.w, biasedShdwZ)).r;
+ for (int i = 0; i < numSamples; ++i){
+ for (int j = 0; j < numSamples; ++j){
+ vec2 offset = (uv + vec2(off.x + 2.0 * float(j), off.y) * blurscale * shadowScale.xy) * shadowScale.w;
+ lit += shadow2D(shadowTex, vec3(offset, biasedShdwZ)).r;
+ }
+ off.y = off.y + 2.0;
+ }
+ float shad = 1.0 - lit/(float(numSamples * numSamples) + 1.0);
+ return 1.0 - pow(shad, 1.25);
+ #else
+ return shadow2D(shadowTex, vec3(v_shadow.xy, biasedShdwZ)).r;
+ #endif
+ #endif
#else
if (biasedShdwZ >= 1.0)
return 1.0;
Index: binaries/data/mods/public/shaders/glsl/terrain_common.vs
===================================================================
--- binaries/data/mods/public/shaders/glsl/terrain_common.vs
+++ binaries/data/mods/public/shaders/glsl/terrain_common.vs
@@ -13,7 +13,7 @@
uniform vec2 losTransform;
uniform mat4 shadowTransform;
-#if USE_SHADOW_SAMPLER && USE_SHADOW_PCF
+#if USE_SHADOW_SAMPLER && (USE_SHADOW_PCF || USE_SHADOW_PCSS)
uniform vec4 shadowScale;
#endif
@@ -92,8 +92,8 @@
#if USE_SHADOW
v_shadow = shadowTransform * vec4(a_vertex, 1.0);
- #if USE_SHADOW_SAMPLER && USE_SHADOW_PCF
- v_shadow.xy *= shadowScale.xy;
+ #if USE_SHADOW_SAMPLER && (USE_SHADOW_PCF || USE_SHADOW_PCSS)
+ v_shadow.xy /= shadowScale.w;
#endif
#endif
Index: source/graphics/MapReader.cpp
===================================================================
--- source/graphics/MapReader.cpp
+++ source/graphics/MapReader.cpp
@@ -1432,7 +1432,7 @@
}
if (pPostproc)
- pPostproc->SetPostEffect(L"default");
+ pPostproc->SetPostEffect(L"None");
std::wstring skySet;
GET_ENVIRONMENT_PROPERTY(envObj, SkySet, skySet)
Index: source/ps/CStrInternStatic.h
===================================================================
--- source/ps/CStrInternStatic.h
+++ source/ps/CStrInternStatic.h
@@ -31,6 +31,7 @@
X(2)
X(ALPHABLEND_PASS_BLEND)
X(ALPHABLEND_PASS_OPAQUE)
+X(BIG_BLUR)
X(BLEND)
X(BLOOM_NOP)
X(BLOOM_PASS_H)
@@ -50,8 +51,10 @@
X(SYS_HAS_GLSL)
X(SYS_PREFER_GLSL)
X(USE_FANCY_EFFECTS)
+X(USE_DOF)
X(USE_FP_SHADOW)
X(USE_GPU_SKINNING)
+X(USE_HDR)
X(USE_INSTANCING)
X(USE_NORMALS)
X(USE_OBJECTCOLOR)
@@ -60,6 +63,7 @@
X(USE_REFRACTION)
X(USE_SHADOW)
X(USE_SHADOW_PCF)
+X(USE_SHADOW_PCSS)
X(USE_SHADOW_SAMPLER)
X(USE_SHADOWS_ON_WATER)
X(USE_FOG)
@@ -77,7 +81,9 @@
X(ambient)
X(baseTex)
X(blendTex)
+X(blockerTex)
X(bloom)
+X(downscaleTex2)
X(blurTex2)
X(blurTex4)
X(blurTex8)
@@ -86,6 +92,7 @@
X(color)
X(colorAdd)
X(colorMul)
+X(contrast)
X(delta)
X(depthTex)
X(foamTex)
@@ -98,7 +105,6 @@
X(gui_solid)
X(gui_solid_mask)
X(gui_text)
-X(hdr)
X(height)
X(instancingTransform)
X(losMap)
Index: source/ps/GameSetup/Config.h
===================================================================
--- source/ps/GameSetup/Config.h
+++ source/ps/GameSetup/Config.h
@@ -65,6 +65,8 @@
// flag to switch on shadow PCF
extern bool g_ShadowPCF;
+// flag to switch on shadow PCSS
+extern bool g_ShadowPCSS;
// flag to switch on particles rendering
extern bool g_Particles;
// flag to switch on fog
@@ -78,6 +80,8 @@
extern bool g_PreferGLSL;
// Use screen-space postprocessing filters (HDR, bloom, DOF, etc)
extern bool g_PostProc;
+// Use depth of field
+extern bool g_DOF;
// Use smooth LOS interpolation
extern bool g_SmoothLOS;
Index: source/ps/GameSetup/Config.cpp
===================================================================
--- source/ps/GameSetup/Config.cpp
+++ source/ps/GameSetup/Config.cpp
@@ -41,6 +41,7 @@
bool g_Shadows = false;
bool g_ShadowPCF = false;
+bool g_ShadowPCSS = false;
bool g_WaterEffects = true;
bool g_WaterFancyEffects = false;
@@ -56,6 +57,7 @@
bool g_PreferGLSL = false;
bool g_PostProc = false;
+bool g_DOF = false;
bool g_SmoothLOS = false;
float g_Gamma = 1.0f;
@@ -96,6 +98,7 @@
CFG_GET_VAL("renderactors", g_RenderActors);
CFG_GET_VAL("shadows", g_Shadows);
CFG_GET_VAL("shadowpcf", g_ShadowPCF);
+ CFG_GET_VAL("shadowpcss", g_ShadowPCSS);
CFG_GET_VAL("watereffects", g_WaterEffects);
CFG_GET_VAL("waterfancyeffects", g_WaterFancyEffects);
@@ -111,6 +114,7 @@
CFG_GET_VAL("showsky", g_ShowSky);
CFG_GET_VAL("preferglsl", g_PreferGLSL);
CFG_GET_VAL("postproc", g_PostProc);
+ CFG_GET_VAL("dof", g_DOF);
CFG_GET_VAL("smoothlos", g_SmoothLOS);
CFG_GET_VAL("gui.scale", g_GuiScale);
}
Index: source/ps/GameSetup/GameSetup.cpp
===================================================================
--- source/ps/GameSetup/GameSetup.cpp
+++ source/ps/GameSetup/GameSetup.cpp
@@ -598,6 +598,8 @@
g_Renderer.SetRenderPath(CRenderer::GetRenderPathByName(g_RenderPath));
g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWPCF, g_ShadowPCF);
g_ConfigDB.SetValueBool(CFG_SYSTEM, "shadowpcf", g_ShadowPCF);
+ g_Renderer.SetOptionBool(CRenderer::OPT_SHADOWPCSS, g_ShadowPCSS);
+ g_ConfigDB.SetValueBool(CFG_SYSTEM, "shadowpcss", g_ShadowPCSS);
g_Renderer.SetOptionBool(CRenderer::OPT_PARTICLES, g_Particles);
g_ConfigDB.SetValueBool(CFG_SYSTEM, "particles", g_Particles);
g_Renderer.SetOptionBool(CRenderer::OPT_FOG, g_Fog);
@@ -610,6 +612,8 @@
g_ConfigDB.SetValueBool(CFG_SYSTEM, "preferglsl", g_PreferGLSL);
g_Renderer.SetOptionBool(CRenderer::OPT_POSTPROC, g_PostProc);
g_ConfigDB.SetValueBool(CFG_SYSTEM, "postproc", g_PostProc);
+ g_Renderer.SetOptionBool(CRenderer::OPT_DOF, g_DOF);
+ g_ConfigDB.SetValueBool(CFG_SYSTEM, "dof", g_DOF);
g_Renderer.SetOptionBool(CRenderer::OPT_SMOOTHLOS, g_SmoothLOS);
g_ConfigDB.SetValueBool(CFG_SYSTEM, "smoothlos", g_SmoothLOS);
Index: source/renderer/PostprocManager.h
===================================================================
--- source/renderer/PostprocManager.h
+++ source/renderer/PostprocManager.h
@@ -40,6 +40,9 @@
// Indicates which of the ping-pong buffers is used for reading and which for drawing.
bool m_WhichBuffer;
+ // Indicates whether the current map has HDR enabled.
+ bool m_MapHDR;
+
// The name and shader technique we are using. "default" name means no technique is used
// (i.e. while we do allocate the buffers, no effects are rendered).
CStrW m_PostProcEffect;
@@ -61,7 +64,7 @@
// GPU-based Gaussian blur in two passes. inOutTex contains the input image and will be filled
// with the blurred image. tempTex must have the same size as inOutTex.
// inWidth and inHeight are the dimensions of the images in texels.
- void ApplyBlurGauss(GLuint inOutTex, GLuint tempTex, int inWidth, int inHeight);
+ void ApplyBlurGauss(GLuint inOutTex, GLuint tempTex, int inWidth, int inHeight, bool bigBlur);
// Applies a pass of a given effect to the entire current framebuffer. The shader is
// provided with a number of general-purpose variables, including the rendered screen so far,
@@ -99,6 +102,9 @@
// Sets the current effect.
void SetPostEffect(const CStrW& name);
+ // Refreshes the shaders.
+ void MakeShadersDirty();
+
// Clears the two color buffers and depth buffer, and redirects all rendering
// to our textures instead of directly to the system framebuffer.
// @note CPostprocManager must be initialized first
Index: source/renderer/PostprocManager.cpp
===================================================================
--- source/renderer/PostprocManager.cpp
+++ source/renderer/PostprocManager.cpp
@@ -37,7 +37,7 @@
#if !CONFIG2_GLES
CPostprocManager::CPostprocManager()
- : m_IsInitialized(false), m_PingFbo(0), m_PongFbo(0), m_PostProcEffect(L"default"), m_ColorTex1(0), m_ColorTex2(0),
+ : m_IsInitialized(false), m_PingFbo(0), m_PongFbo(0), m_PostProcEffect(L"None"), m_ColorTex1(0), m_ColorTex2(0),
m_DepthTex(0), m_BloomFbo(0), m_BlurTex2a(0), m_BlurTex2b(0), m_BlurTex4a(0), m_BlurTex4b(0),
m_BlurTex8a(0), m_BlurTex8b(0), m_WhichBuffer(true)
{
@@ -102,15 +102,17 @@
{
Cleanup();
- #define GEN_BUFFER_RGBA(name, w, h) \
- glGenTextures(1, (GLuint*)&name); \
- glBindTexture(GL_TEXTURE_2D, name); \
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); \
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); \
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); \
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); \
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (!g_Renderer.m_Options.m_Postproc) return; // Don't create textures if we're not going to use them.
+#define GEN_BUFFER_RGBA(name, w, h) \
+ glGenTextures(1, (GLuint*)&name); \
+ glBindTexture(GL_TEXTURE_2D, name); \
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); \
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); \
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); \
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); \
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
// Two fullscreen ping-pong textures.
GEN_BUFFER_RGBA(m_ColorTex1, m_Width, m_Height);
GEN_BUFFER_RGBA(m_ColorTex2, m_Width, m_Height);
@@ -128,7 +130,7 @@
GEN_BUFFER_RGBA(m_BlurTex8a, m_Width / 8, m_Height / 8);
GEN_BUFFER_RGBA(m_BlurTex8b, m_Width / 8, m_Height / 8);
- #undef GEN_BUFFER_RGBA
+#undef GEN_BUFFER_RGBA
// Allocate the Depth/Stencil texture.
glGenTextures(1, (GLuint*)&m_DepthTex);
@@ -135,7 +137,7 @@
glBindTexture(GL_TEXTURE_2D, m_DepthTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, m_Width, m_Height,
- 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 0);
+ 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -151,10 +153,10 @@
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PingFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- GL_TEXTURE_2D, m_ColorTex1, 0);
+ GL_TEXTURE_2D, m_ColorTex1, 0);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT,
- GL_TEXTURE_2D, m_DepthTex, 0);
+ GL_TEXTURE_2D, m_DepthTex, 0);
GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
@@ -166,10 +168,10 @@
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- GL_TEXTURE_2D, m_ColorTex2, 0);
+ GL_TEXTURE_2D, m_ColorTex2, 0);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT,
- GL_TEXTURE_2D, m_DepthTex, 0);
+ GL_TEXTURE_2D, m_DepthTex, 0);
status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
@@ -182,7 +184,7 @@
/*
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
- GL_TEXTURE_2D, m_BloomTex1, 0);
+ GL_TEXTURE_2D, m_BloomTex1, 0);
status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
@@ -254,7 +256,7 @@
tech->EndPass();
}
-void CPostprocManager::ApplyBlurGauss(GLuint inOutTex, GLuint tempTex, int inWidth, int inHeight)
+void CPostprocManager::ApplyBlurGauss(GLuint inOutTex, GLuint tempTex, int inWidth, int inHeight, bool bigBlur)
{
// Set tempTex as our rendering target.
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_BloomFbo);
@@ -263,6 +265,7 @@
// Get bloom shader, for a horizontal Gaussian blur pass.
CShaderDefines defines2;
defines2.Add(str_BLOOM_PASS_H, str_1);
+ if (bigBlur) defines2.Add(str_BIG_BLUR, str_1);
CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom,
g_Renderer.GetSystemShaderDefines(), defines2);
@@ -309,6 +312,7 @@
// Get bloom shader, for a vertical Gaussian blur pass.
CShaderDefines defines3;
defines3.Add(str_BLOOM_PASS_V, str_1);
+ if (bigBlur) defines3.Add(str_BIG_BLUR, str_1);
tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom,
g_Renderer.GetSystemShaderDefines(), defines3);
@@ -340,19 +344,32 @@
int width = m_Width, height = m_Height;
- #define SCALE_AND_BLUR(tex1, tex2, temptex) \
+ #define SCALE_AND_BLUR_3_TAP(tex1, tex2, temptex) \
ApplyBlurDownscale2x(tex1, tex2, width, height); \
width /= 2; \
height /= 2; \
- ApplyBlurGauss(tex2, temptex, width, height);
+ ApplyBlurGauss(tex2, temptex, width, height, false); \
+ if (g_Renderer.m_Options.m_DOF) ApplyBlurDownscale2x(tex1, temptex, width * 2, height * 2);
- // We do the same thing for each scale, incrementally adding more and more blur.
- SCALE_AND_BLUR(m_WhichBuffer ? m_ColorTex1 : m_ColorTex2, m_BlurTex2a, m_BlurTex2b);
- SCALE_AND_BLUR(m_BlurTex2a, m_BlurTex4a, m_BlurTex4b);
- SCALE_AND_BLUR(m_BlurTex4a, m_BlurTex8a, m_BlurTex8b);
+ #define SCALE_AND_BLUR_5_TAP(tex1, tex2, temptex) \
+ ApplyBlurDownscale2x(tex1, tex2, width, height); \
+ width /= 2; \
+ height /= 2; \
+ ApplyBlurGauss(tex2, temptex, width, height, true);
- #undef SCALE_AND_BLUR
+ // Apply a small blur for dof and cache an extra non-blurred downscaled image for smooth interpolation.
+ SCALE_AND_BLUR_3_TAP(m_WhichBuffer ? m_ColorTex1 : m_ColorTex2, m_BlurTex2a, m_BlurTex2b);
+
+ // Apply a large blur for bloom.
+ if (m_MapHDR && g_LightEnv.m_Bloom < 0.2f)
+ {
+ SCALE_AND_BLUR_5_TAP(m_BlurTex2a, m_BlurTex4a, m_BlurTex4b);
+ SCALE_AND_BLUR_5_TAP(m_BlurTex4a, m_BlurTex8a, m_BlurTex8b);
+ }
+ #undef SCALE_AND_BLUR_3_TAP
+ #undef SCALE_AND_BLUR_5_TAP
+
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, originalFBO);
}
@@ -424,10 +441,10 @@
shader->BindTexture(str_depthTex, m_DepthTex);
+ shader->BindTexture(str_downscaleTex2, m_BlurTex2b);
shader->BindTexture(str_blurTex2, m_BlurTex2a);
shader->BindTexture(str_blurTex4, m_BlurTex4a);
shader->BindTexture(str_blurTex8, m_BlurTex8a);
-
shader->Uniform(str_width, m_Width);
shader->Uniform(str_height, m_Height);
shader->Uniform(str_zNear, g_Game->GetView()->GetNear());
@@ -434,7 +451,7 @@
shader->Uniform(str_zFar, g_Game->GetView()->GetFar());
shader->Uniform(str_brightness, g_LightEnv.m_Brightness);
- shader->Uniform(str_hdr, g_LightEnv.m_Contrast);
+ shader->Uniform(str_contrast, g_LightEnv.m_Contrast);
shader->Uniform(str_saturation, g_LightEnv.m_Saturation);
shader->Uniform(str_bloom, g_LightEnv.m_Bloom);
@@ -475,10 +492,6 @@
{
ENSURE(m_IsInitialized);
- // Don't do anything if we are using the default effect.
- if (m_PostProcEffect == L"default")
- return;
-
pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_PongFbo);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, 0, 0);
@@ -526,7 +539,7 @@
effects.push_back(path.Basename().string());
// Add the default "null" effect to the list.
- effects.push_back(L"default");
+ effects.push_back(L"None");
sort(effects.begin(), effects.end());
@@ -535,16 +548,32 @@
void CPostprocManager::SetPostEffect(const CStrW& name)
{
+ if (name == L"default" || name == L"None" || name == L"DOF")
+ {
+ m_MapHDR = false;
+ m_PostProcEffect = L"None";
+ }else if (name == L"hdr" || name == L"HDR")
+ {
+ m_MapHDR = true;
+ m_PostProcEffect = L"HDR";
+ }else
+ {
+ // Custom effects are not actually supported without modifying PostprocManager. This is a stub!
+ //CStrW n = L"postproc/" + name;
+ }
+ MakeShadersDirty();
+}
+
+void CPostprocManager::MakeShadersDirty()
+{
if (m_IsInitialized)
{
- if (name != L"default")
- {
- CStrW n = L"postproc/" + name;
- m_PostProcTech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern(n.ToUTF8()));
- }
+ CStrW n = L"postproc/HDR";
+ CShaderDefines techdefines;
+ if (g_Renderer.m_Options.m_DOF) techdefines.Add(str_USE_DOF, str_1);
+ if (m_MapHDR) techdefines.Add(str_USE_HDR, str_1);
+ m_PostProcTech = g_Renderer.GetShaderManager().LoadEffect(CStrIntern(n.ToUTF8()), g_Renderer.GetSystemShaderDefines(), techdefines);
}
-
- m_PostProcEffect = name;
}
#else
Index: source/renderer/RenderModifiers.cpp
===================================================================
--- source/renderer/RenderModifiers.cpp
+++ source/renderer/RenderModifiers.cpp
@@ -79,10 +79,10 @@
if (GetShadowMap() && shader->GetTextureBinding(str_shadowTex).Active())
{
shader->BindTexture(str_shadowTex, GetShadowMap()->GetTexture());
+ shader->BindTexture(str_blockerTex, GetShadowMap()->GetBlockerTexture());
shader->Uniform(str_shadowTransform, GetShadowMap()->GetTextureMatrix());
- int width = GetShadowMap()->GetWidth();
- int height = GetShadowMap()->GetHeight();
- shader->Uniform(str_shadowScale, width, height, 1.0f / width, 1.0f / height);
+ const CVector4D& shadowscale = GetShadowMap()->GetShadowScale();
+ shader->Uniform(str_shadowScale, shadowscale.X, shadowscale.Y, shadowscale.Z, shadowscale.W);
}
if (GetLightEnv())
Index: source/renderer/Renderer.h
===================================================================
--- source/renderer/Renderer.h
+++ source/renderer/Renderer.h
@@ -83,6 +83,7 @@
OPT_WATERREFRACTION,
OPT_SHADOWSONWATER,
OPT_SHADOWPCF,
+ OPT_SHADOWPCSS,
OPT_PARTICLES,
OPT_PREFERGLSL,
OPT_FOG,
@@ -90,6 +91,7 @@
OPT_SHOWSKY,
OPT_SMOOTHLOS,
OPT_POSTPROC,
+ OPT_DOF,
OPT_DISPLAYFRUSTUM,
};
@@ -151,6 +153,7 @@
bool m_ShadowAlphaFix;
bool m_ARBProgramShadow;
bool m_ShadowPCF;
+ bool m_ShadowPCSS;
bool m_Particles;
bool m_PreferGLSL;
bool m_ForceAlphaTest;
@@ -160,6 +163,7 @@
bool m_SmoothLOS;
bool m_ShowSky;
bool m_Postproc;
+ bool m_DOF;
bool m_DisplayFrustum;
} m_Options;
Index: source/renderer/Renderer.cpp
===================================================================
--- source/renderer/Renderer.cpp
+++ source/renderer/Renderer.cpp
@@ -440,6 +440,7 @@
m_Options.m_ShadowAlphaFix = true;
m_Options.m_ARBProgramShadow = true;
m_Options.m_ShadowPCF = false;
+ m_Options.m_ShadowPCSS = false;
m_Options.m_Particles = false;
m_Options.m_Silhouettes = false;
m_Options.m_PreferGLSL = false;
@@ -573,8 +574,10 @@
m->globalContext.Add(str_USE_SHADOW, str_1);
if (m_Caps.m_ARBProgramShadow && m_Options.m_ARBProgramShadow)
m->globalContext.Add(str_USE_FP_SHADOW, str_1);
- if (m_Options.m_ShadowPCF)
+ if (m_Options.m_ShadowPCF && !m_Options.m_ShadowPCSS)
m->globalContext.Add(str_USE_SHADOW_PCF, str_1);
+ if (m_Options.m_ShadowPCF && m_Options.m_ShadowPCSS)
+ m->globalContext.Add(str_USE_SHADOW_PCSS, str_1);
#if !CONFIG2_GLES
m->globalContext.Add(str_USE_SHADOW_SAMPLER, str_1);
#endif
@@ -663,6 +666,8 @@
if (m_Options.m_Postproc)
m->postprocManager.Initialize();
+ m->shadow.RecreateTexture();
+
return true;
}
@@ -669,12 +674,12 @@
// resize renderer view
void CRenderer::Resize(int width, int height)
{
+ m_Width = width;
+ m_Height = height;
+
// need to recreate the shadow map object to resize the shadow texture
m->shadow.RecreateTexture();
- m_Width = width;
- m_Height = height;
-
m->postprocManager.Resize();
m_WaterManager->Resize();
@@ -717,7 +722,13 @@
case OPT_SHADOWPCF:
m_Options.m_ShadowPCF = value;
MakeShadersDirty();
+ if (m_Options.m_ShadowPCSS) m->shadow.RecreateTexture();
break;
+ case OPT_SHADOWPCSS:
+ m_Options.m_ShadowPCSS = value;
+ MakeShadersDirty();
+ m->shadow.RecreateTexture();
+ break;
case OPT_PARTICLES:
m_Options.m_Particles = value;
break;
@@ -741,7 +752,12 @@
break;
case OPT_POSTPROC:
m_Options.m_Postproc = value;
+ m->postprocManager.Resize();
break;
+ case OPT_DOF:
+ m_Options.m_DOF = value;
+ m->postprocManager.MakeShadersDirty();
+ break;
case OPT_DISPLAYFRUSTUM:
m_Options.m_DisplayFrustum = value;
break;
@@ -774,6 +790,8 @@
return m_Options.m_WaterShadows;
case OPT_SHADOWPCF:
return m_Options.m_ShadowPCF;
+ case OPT_SHADOWPCSS:
+ return m_Options.m_ShadowPCSS;
case OPT_PARTICLES:
return m_Options.m_Particles;
case OPT_PREFERGLSL:
@@ -788,6 +806,8 @@
return m_Options.m_SmoothLOS;
case OPT_POSTPROC:
return m_Options.m_Postproc;
+ case OPT_DOF:
+ return m_Options.m_DOF;
case OPT_DISPLAYFRUSTUM:
return m_Options.m_DisplayFrustum;
default:
@@ -1237,10 +1257,10 @@
else
{
// Render terrain and models
+ RenderModels(context, CULL_REFLECTIONS);
+ ogl_WarnIfError();
RenderPatches(context, CULL_REFLECTIONS);
ogl_WarnIfError();
- RenderModels(context, CULL_REFLECTIONS);
- ogl_WarnIfError();
RenderTransparentModels(context, CULL_REFLECTIONS, TRANSPARENT, true);
ogl_WarnIfError();
}
@@ -1311,10 +1331,10 @@
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render terrain and models
+ RenderModels(context, CULL_REFRACTIONS);
+ ogl_WarnIfError();
RenderPatches(context, CULL_REFRACTIONS);
ogl_WarnIfError();
- RenderModels(context, CULL_REFRACTIONS);
- ogl_WarnIfError();
RenderTransparentModels(context, CULL_REFRACTIONS, TRANSPARENT_OPAQUE, false);
ogl_WarnIfError();
@@ -1531,56 +1551,50 @@
}
}
+ // Render submitted terrain patches and models
+ RenderModels(context, cullGroup);
+ ogl_WarnIfError();
+
+ RenderPatches(context, cullGroup);
+ ogl_WarnIfError();
+
if (m_Options.m_ShowSky)
{
m->skyManager.RenderSky();
}
- // render submitted patches and models
- RenderPatches(context, cullGroup);
+ // Render the occluding parts of alpha-blended objects.
+ RenderTransparentModels(context, cullGroup, TRANSPARENT_OPAQUE, false);
ogl_WarnIfError();
- // render debug-related terrain overlays
+ // Render debug-related terrain overlays
ITerrainOverlay::RenderOverlaysBeforeWater();
ogl_WarnIfError();
- // render other debug-related overlays before water (so they can be seen when underwater)
+ // Render other debug-related overlays before water (so they can be seen when underwater)
m->overlayRenderer.RenderOverlaysBeforeWater();
ogl_WarnIfError();
- RenderModels(context, cullGroup);
- ogl_WarnIfError();
-
// render water
if (m_WaterManager->m_RenderWater && g_Game && waterScissor.GetVolume() > 0)
{
- // render transparent stuff, but only the solid parts that can occlude block water
- RenderTransparentModels(context, cullGroup, TRANSPARENT_OPAQUE, false);
- ogl_WarnIfError();
-
m->terrainRenderer.RenderWater(context, cullGroup, &m->shadow);
ogl_WarnIfError();
-
- // render transparent stuff again, but only the blended parts that overlap water
- RenderTransparentModels(context, cullGroup, TRANSPARENT_BLEND, false);
- ogl_WarnIfError();
}
- else
- {
- // render transparent stuff, so it can overlap models/terrain
- RenderTransparentModels(context, cullGroup, TRANSPARENT, false);
- ogl_WarnIfError();
- }
- // render debug-related terrain overlays
+ // Render the transparent parts of alpha-blended objects.
+ RenderTransparentModels(context, cullGroup, TRANSPARENT_BLEND, false);
+ ogl_WarnIfError();
+
+ // Render debug-related terrain overlays
ITerrainOverlay::RenderOverlaysAfterWater(cullGroup);
ogl_WarnIfError();
- // render some other overlays after water (so they can be displayed on top of water)
+ // Render some other overlays after water (so they can be displayed on top of water)
m->overlayRenderer.RenderOverlaysAfterWater();
ogl_WarnIfError();
- // particles are transparent so render after water
+ // Particles are transparent so render after water
if (m_Options.m_Particles)
{
RenderParticles(cullGroup);
Index: source/renderer/ShadowMap.h
===================================================================
--- source/renderer/ShadowMap.h
+++ source/renderer/ShadowMap.h
@@ -136,6 +136,14 @@
GLuint GetTexture() const;
/**
+ * GetBlockerTexture: Retrieve the OpenGL texture object name that contains the shadow map copy used
+ * for blocker search by PCSS.
+ *
+ * @return the texture name of the shadow map blocker search texture
+ */
+ GLuint GetBlockerTexture() const;
+
+ /**
* GetTextureMatrix: Retrieve the world-space to shadow map texture coordinates
* transformation matrix.
*
@@ -145,6 +153,14 @@
const CMatrix3D& GetTextureMatrix() const;
/**
+ * GetLightspaceScale: Retrieve the 3D scale factor for scaling shadow filter kernels.
+ *
+ * @return the vector representing the relative scale of the shadow map resolution
+ * and the bounds of the light space frustum.
+ */
+ const CVector4D& GetShadowScale() const;
+
+ /**
* Visualize shadow mapping calculations to help in
* debugging and optimal shadow map usage.
*/
Index: source/renderer/ShadowMap.cpp
===================================================================
--- source/renderer/ShadowMap.cpp
+++ source/renderer/ShadowMap.cpp
@@ -52,8 +52,10 @@
int DepthTextureBits;
// the EXT_framebuffer_object framebuffer
GLuint Framebuffer;
+ GLuint BlockerFramebuffer;
// handle of shadow map
GLuint Texture;
+ GLuint blockerTexture;
// width, height of shadow map
int Width, Height;
// Shadow map quality (-2 - Very Low, -1 - Low, 0 - Medium, 1 - High, 2 - Very High)
@@ -78,6 +80,8 @@
CBoundingBoxAligned ShadowRenderBound;
+ CVector4D ShadowScale;
+
// Camera transformed into light space
CCamera LightspaceCamera;
@@ -106,7 +110,9 @@
{
m = new ShadowMapInternals;
m->Framebuffer = 0;
+ m->BlockerFramebuffer = 0;
m->Texture = 0;
+ m->blockerTexture = 0;
m->DummyTexture = 0;
m->Width = 0;
m->Height = 0;
@@ -129,10 +135,14 @@
{
if (m->Texture)
glDeleteTextures(1, &m->Texture);
+ if (m->blockerTexture)
+ glDeleteTextures(1, &m->blockerTexture);
if (m->DummyTexture)
glDeleteTextures(1, &m->DummyTexture);
if (m->Framebuffer)
pglDeleteFramebuffersEXT(1, &m->Framebuffer);
+ if (m->BlockerFramebuffer)
+ pglDeleteFramebuffersEXT(1, &m->BlockerFramebuffer);
delete m;
}
@@ -144,16 +154,22 @@
{
if (m->Texture)
glDeleteTextures(1, &m->Texture);
+ if (m->blockerTexture)
+ glDeleteTextures(1, &m->blockerTexture);
if (m->DummyTexture)
glDeleteTextures(1, &m->DummyTexture);
if (m->Framebuffer)
pglDeleteFramebuffersEXT(1, &m->Framebuffer);
+ if (m->BlockerFramebuffer)
+ pglDeleteFramebuffersEXT(1, &m->BlockerFramebuffer);
m->Texture = 0;
+ m->blockerTexture = 0;
m->DummyTexture = 0;
m->Framebuffer = 0;
+ m->BlockerFramebuffer = 0;
- // (Texture will be constructed in next SetupFrame)
+ m->CreateTexture();
}
//////////////////////////////////////////////////////////////////////////////
@@ -160,9 +176,6 @@
// SetupFrame: camera and light direction for this frame
void ShadowMap::SetupFrame(const CCamera& camera, const CVector3D& lightdir)
{
- if (!m->Texture)
- m->CreateTexture();
-
CVector3D z = lightdir;
CVector3D y;
CVector3D x = camera.m_Orientation.GetIn();
@@ -306,6 +319,7 @@
ShadowRenderBound[1].X = ceil(ShadowRenderBound[1].X / boundInc) * boundInc;
ShadowRenderBound[1].Y = ceil(ShadowRenderBound[1].Y / boundInc) * boundInc;
+
// Setup orthogonal projection (lightspace -> clip space) for shadowmap rendering
CVector3D scale = ShadowRenderBound[1] - ShadowRenderBound[0];
CVector3D shift = (ShadowRenderBound[1] + ShadowRenderBound[0]) * -0.5;
@@ -324,6 +338,7 @@
// make sure a given world position falls on a consistent shadowmap texel fractional offset
float offsetX = fmod(ShadowRenderBound[0].X - LightTransform._14, 2.0f/(scale.X*EffectiveWidth));
float offsetY = fmod(ShadowRenderBound[0].Y - LightTransform._24, 2.0f/(scale.Y*EffectiveHeight));
+
LightProjection.SetZero();
LightProjection._11 = scale.X;
@@ -351,6 +366,12 @@
lightToTex._34 = -ShadowRenderBound[0].Z * texscalez;
lightToTex._44 = 1.0;
+ // Set up the shadow scaling factors for constant-width PCF/PCSS filtering.
+ ShadowScale.X = (float)Width / (2048.f * (ShadowRenderBound[1].X - ShadowRenderBound[0].X)/100.f);
+ ShadowScale.Y = (float)Width / (2048.f * (ShadowRenderBound[1].Y - ShadowRenderBound[0].Y)/100.f);
+ ShadowScale.Z = (ShadowRenderBound[1].Z - ShadowRenderBound[0].Z) / 100.f;
+ ShadowScale.W = 1.f / (float)Width;
+
TextureMatrix = lightToTex * LightTransform;
}
@@ -360,23 +381,6 @@
// Create the shadow map
void ShadowMapInternals::CreateTexture()
{
- // Cleanup
- if (Texture)
- {
- glDeleteTextures(1, &Texture);
- Texture = 0;
- }
- if (DummyTexture)
- {
- glDeleteTextures(1, &DummyTexture);
- DummyTexture = 0;
- }
- if (Framebuffer)
- {
- pglDeleteFramebuffersEXT(1, &Framebuffer);
- Framebuffer = 0;
- }
-
// save the caller's FBO
glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &SavedViewFBO);
@@ -395,20 +399,16 @@
int shadow_map_size = (int)round_up_to_pow2((unsigned)std::max(g_Renderer.GetWidth(), g_Renderer.GetHeight()));
switch (QualityLevel)
{
- // Very Low
- case -2:
- shadow_map_size /= 4;
- break;
// Low
- case -1:
+ case 0:
shadow_map_size /= 2;
break;
// High
- case 1:
+ case 2:
shadow_map_size *= 2;
break;
// Ultra
- case 2:
+ case 3:
shadow_map_size *= 4;
break;
// Medium as is
@@ -426,19 +426,24 @@
EffectiveHeight = Height;
const char* formatname;
+ GLenum format;
- switch(DepthTextureBits)
- {
- case 16: formatname = "DEPTH_COMPONENT16"; break;
- case 24: formatname = "DEPTH_COMPONENT24"; break;
- case 32: formatname = "DEPTH_COMPONENT32"; break;
- default: formatname = "DEPTH_COMPONENT"; break;
- }
+ #if CONFIG2_GLES
+ formatname = "DEPTH_COMPONENT";
+ format = GL_DEPTH_COMPONENT;
+ #else
+ switch (DepthTextureBits)
+ {
+ case 16: formatname = "DEPTH_COMPONENT16"; format = GL_DEPTH_COMPONENT16; break;
+ case 24: formatname = "DEPTH_COMPONENT24"; format = GL_DEPTH_COMPONENT24; break;
+ case 32: formatname = "DEPTH_COMPONENT32"; format = GL_DEPTH_COMPONENT32; break;
+ default: formatname = "DEPTH_COMPONENT16"; format = GL_DEPTH_COMPONENT16; break;
+ }
+ #endif
- LOGMESSAGE("Creating shadow texture (size %dx%d) (format = %s)",
+ LOGMESSAGE("Creating shadow textures (size %d x %d) (format = %s)",
Width, Height, formatname);
-
if (g_Renderer.m_Options.m_ShadowAlphaFix)
{
glGenTextures(1, &DummyTexture);
@@ -453,20 +458,8 @@
glGenTextures(1, &Texture);
g_Renderer.BindTexture(0, Texture);
- GLenum format;
+
-#if CONFIG2_GLES
- format = GL_DEPTH_COMPONENT;
-#else
- switch (DepthTextureBits)
- {
- case 16: format = GL_DEPTH_COMPONENT16; break;
- case 24: format = GL_DEPTH_COMPONENT24; break;
- case 32: format = GL_DEPTH_COMPONENT32; break;
- default: format = GL_DEPTH_COMPONENT; break;
- }
-#endif
-
glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
// GLES requires type == UNSIGNED_SHORT or UNSIGNED_INT
@@ -474,21 +467,21 @@
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-#if CONFIG2_GLES
- // GLES doesn't do depth comparisons, so treat it as a
- // basic unfiltered depth texture
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-#else
- // Enable automatic depth comparisons
- glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
+ #if CONFIG2_GLES
+ // GLES doesn't do depth comparisons, so treat it as a
+ // basic unfiltered depth texture
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ #else
+ // Enable automatic depth comparisons
+ glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
- // Use GL_LINEAR to trigger automatic PCF on some devices
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-#endif
+ // Use GL_LINEAR for higher quality sampling.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ #endif
ogl_WarnIfError();
@@ -502,32 +495,74 @@
{
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, DummyTexture, 0);
}
- else
- {
-#if CONFIG2_GLES
-#warning TODO: figure out whether the glDrawBuffer/glReadBuffer stuff is needed, since it is not supported by GLES
-#else
- glDrawBuffer(GL_NONE);
-#endif
- }
-#if !CONFIG2_GLES
- glReadBuffer(GL_NONE);
-#endif
-
ogl_WarnIfError();
GLenum status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
- pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, SavedViewFBO);
-
if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
{
- LOGWARNING("Framebuffer object incomplete: 0x%04X", status);
+ LOGWARNING("Shadow Map Framebuffer object incomplete: 0x%04X", status);
// Disable shadow rendering (but let the user try again if they want)
g_Renderer.m_Options.m_Shadows = false;
+ g_Renderer.MakeShadersDirty();
}
+
+ if (g_Renderer.m_Options.m_ShadowPCF && g_Renderer.m_Options.m_ShadowPCSS)
+ {
+ // generate texture for PCSS blocker search
+ pglGenFramebuffersEXT(1, &BlockerFramebuffer);
+ glGenTextures(1, &blockerTexture);
+ g_Renderer.BindTexture(0, blockerTexture);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, format, Width, Height, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);
+ // GLES requires type == UNSIGNED_SHORT or UNSIGNED_INT
+
+ // set texture parameters
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ #if CONFIG2_GLES
+ // GLES doesn't do depth comparisons, so treat it as a
+ // basic unfiltered depth texture
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ #else
+ // Disable automatic depth comparisons
+ glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+
+ // Use GL_NEAREST for accurate blocker search.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ #endif
+
+ ogl_WarnIfError();
+
+ // bind to framebuffer object
+ glBindTexture(GL_TEXTURE_2D, 0);
+ pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, BlockerFramebuffer);
+
+ pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, blockerTexture, 0);
+
+ ogl_WarnIfError();
+
+ status = pglCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+ {
+ LOGWARNING("PCSS Blocker Search Framebuffer object incomplete: 0x%04X", status);
+
+ // Disable shadow rendering (but let the user try again if they want)
+ g_Renderer.m_Options.m_ShadowPCSS = false;
+ g_Renderer.MakeShadersDirty();
+ g_ConfigDB.SetValueBool(CFG_USER, "shadowpcss", false);
+
+ }
+ }
+
+ pglBindFramebufferEXT(GL_FRAMEBUFFER_EXT, SavedViewFBO);
}
@@ -586,6 +621,14 @@
// Finish rendering into shadow map texture
void ShadowMap::EndRender()
{
+ if (g_Renderer.m_Options.m_ShadowPCF && g_Renderer.m_Options.m_ShadowPCSS && m->BlockerFramebuffer)
+ {
+ // Copy the shadow map for PCSS blocker search
+ pglBindFramebufferEXT(GL_READ_FRAMEBUFFER, m->Framebuffer);
+ pglBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, m->BlockerFramebuffer);
+ pglBlitFramebufferEXT(0, 0, m->EffectiveWidth, m->EffectiveHeight, 0, 0, m->EffectiveWidth, m->EffectiveHeight, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+
glDisable(GL_SCISSOR_TEST);
g_Renderer.SetViewCamera(m->SavedViewCamera);
@@ -609,12 +652,22 @@
return m->Texture;
}
+GLuint ShadowMap::GetBlockerTexture() const
+{
+ return m->blockerTexture;
+}
+
const CMatrix3D& ShadowMap::GetTextureMatrix() const
{
return m->TextureMatrix;
}
+const CVector4D& ShadowMap::GetShadowScale() const
+{
+ return m->ShadowScale;
+}
+
///////////////////////////////////////////////////////////////////////////////////////////////////
// Depth texture bits
int ShadowMap::GetDepthTextureBits() const
@@ -626,14 +679,8 @@
{
if (bits != m->DepthTextureBits)
{
- if (m->Texture)
- {
- glDeleteTextures(1, &m->Texture);
- m->Texture = 0;
- }
- m->Width = m->Height = 0;
-
m->DepthTextureBits = bits;
+ RecreateTexture();
}
}
Index: source/renderer/TerrainRenderer.cpp
===================================================================
--- source/renderer/TerrainRenderer.cpp
+++ source/renderer/TerrainRenderer.cpp
@@ -458,10 +458,10 @@
if (shadow)
{
shader->BindTexture(str_shadowTex, shadow->GetTexture());
+ shader->BindTexture(str_blockerTex, shadow->GetBlockerTexture());
shader->Uniform(str_shadowTransform, shadow->GetTextureMatrix());
- int width = shadow->GetWidth();
- int height = shadow->GetHeight();
- shader->Uniform(str_shadowScale, width, height, 1.0f / width, 1.0f / height);
+ const CVector4D& shadowscale = shadow->GetShadowScale();
+ shader->Uniform(str_shadowScale, shadowscale.X, shadowscale.Y, shadowscale.Z, shadowscale.W);
}
CLOSTexture& los = g_Renderer.GetScene().GetLOSTexture();
Index: source/renderer/scripting/JSInterface_Renderer.h
===================================================================
--- source/renderer/scripting/JSInterface_Renderer.h
+++ source/renderer/scripting/JSInterface_Renderer.h
@@ -33,6 +33,7 @@
DECLARE_BOOLEAN_SCRIPT_SETTING(Shadows);
DECLARE_BOOLEAN_SCRIPT_SETTING(ShadowPCF);
+ DECLARE_BOOLEAN_SCRIPT_SETTING(ShadowPCSS);
DECLARE_BOOLEAN_SCRIPT_SETTING(Particles);
DECLARE_BOOLEAN_SCRIPT_SETTING(PreferGLSL);
DECLARE_BOOLEAN_SCRIPT_SETTING(WaterEffects);
@@ -46,6 +47,7 @@
DECLARE_BOOLEAN_SCRIPT_SETTING(ShowSky);
DECLARE_BOOLEAN_SCRIPT_SETTING(SmoothLOS);
DECLARE_BOOLEAN_SCRIPT_SETTING(Postproc);
+ DECLARE_BOOLEAN_SCRIPT_SETTING(DOF);
DECLARE_BOOLEAN_SCRIPT_SETTING(DisplayFrustum);
void RegisterScriptFunctions(const ScriptInterface& scriptInterface);
Index: source/renderer/scripting/JSInterface_Renderer.cpp
===================================================================
--- source/renderer/scripting/JSInterface_Renderer.cpp
+++ source/renderer/scripting/JSInterface_Renderer.cpp
@@ -38,6 +38,7 @@
IMPLEMENT_BOOLEAN_SCRIPT_SETTING(WATEREFFECTS, WaterEffects);
IMPLEMENT_BOOLEAN_SCRIPT_SETTING(WATERFANCYEFFECTS, WaterFancyEffects);
IMPLEMENT_BOOLEAN_SCRIPT_SETTING(SHADOWPCF, ShadowPCF);
+IMPLEMENT_BOOLEAN_SCRIPT_SETTING(SHADOWPCSS, ShadowPCSS);
IMPLEMENT_BOOLEAN_SCRIPT_SETTING(SHADOWS, Shadows);
IMPLEMENT_BOOLEAN_SCRIPT_SETTING(WATERREALDEPTH, WaterRealDepth);
IMPLEMENT_BOOLEAN_SCRIPT_SETTING(WATERREFLECTION, WaterReflection);
@@ -48,6 +49,7 @@
IMPLEMENT_BOOLEAN_SCRIPT_SETTING(SHOWSKY, ShowSky);
IMPLEMENT_BOOLEAN_SCRIPT_SETTING(SMOOTHLOS, SmoothLOS);
IMPLEMENT_BOOLEAN_SCRIPT_SETTING(POSTPROC, Postproc);
+IMPLEMENT_BOOLEAN_SCRIPT_SETTING(DOF, DOF);
IMPLEMENT_BOOLEAN_SCRIPT_SETTING(DISPLAYFRUSTUM, DisplayFrustum);
#undef IMPLEMENT_BOOLEAN_SCRIPT_SETTING
@@ -79,6 +81,7 @@
scriptInterface.RegisterFunction("Renderer_RecreateShadowMap");
REGISTER_BOOLEAN_SCRIPT_SETTING(Shadows);
REGISTER_BOOLEAN_SCRIPT_SETTING(ShadowPCF);
+ REGISTER_BOOLEAN_SCRIPT_SETTING(ShadowPCSS);
REGISTER_BOOLEAN_SCRIPT_SETTING(Particles);
REGISTER_BOOLEAN_SCRIPT_SETTING(PreferGLSL);
REGISTER_BOOLEAN_SCRIPT_SETTING(WaterEffects);
@@ -92,6 +95,7 @@
REGISTER_BOOLEAN_SCRIPT_SETTING(ShowSky);
REGISTER_BOOLEAN_SCRIPT_SETTING(SmoothLOS);
REGISTER_BOOLEAN_SCRIPT_SETTING(Postproc);
+ REGISTER_BOOLEAN_SCRIPT_SETTING(DOF);
REGISTER_BOOLEAN_SCRIPT_SETTING(DisplayFrustum);
}