Skip to content

Commit

Permalink
UPBGE: Implement PCF jitter shadows;
Browse files Browse the repository at this point in the history
The jitter PCF is a technic to rendomize the position of the samples
averaged in PCF. To randomize a 64x64 texture with random value between
-1 and 1 is passed to shader. Into the new GLSL function test_shadow_pcf_jitter
we found the rand value at the fragment position in the shadow texture
mutliplied by a big dummy value. Then a matrix is constructed with the
rand values and used to transform the samples offset.

The jitter texture is initialized globally in gpu_texture.cpp, it also
now uses filtering and so the SSAO shader disable it to simulate a texture
without filtering.
  • Loading branch information
panzergame committed Jul 31, 2017
1 parent 5d8cd9c commit ca709a6
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 26 deletions.
2 changes: 1 addition & 1 deletion release/scripts/startup/bl_ui/properties_game.py
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ def draw(self, context):
col.prop(lamp, "shadow_buffer_size", text="Size")
if lamp.ge_shadow_buffer_type == "VARIANCE":
col.prop(lamp, "shadow_buffer_sharp", text="Sharpness")
elif lamp.shadow_filter in ("PCF", "PCF_BAIL"):
elif lamp.shadow_filter in ("PCF", "PCF_BAIL", "PCF_JITTER"):
col.prop(lamp, "shadow_buffer_samples", text="Samples")
col.prop(lamp, "shadow_buffer_soft", text="Soft")

Expand Down
4 changes: 3 additions & 1 deletion source/blender/gpu/GPU_texture.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,16 @@ GPUTexture *GPU_texture_create_2D(int w, int h, const float *pixels, GPUHDRType
GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels);
GPUTexture *GPU_texture_create_depth(int w, int h, bool compare, char err_out[256]);
GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]);
GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]);
GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, bool filter, char err_out[256]);
GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]);
GPUTexture *GPU_texture_create_2D_multisample(
int w, int h, const float *pixels, GPUHDRType hdr, int samples, char err_out[256]);
GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, bool compare, char err_out[256]);
GPUTexture *GPU_texture_from_blender(
struct Image *ima, struct ImageUser *iuser, int textarget, bool is_data, double time, int mipmap);
GPUTexture *GPU_texture_from_preview(struct PreviewImage *prv, int mipmap);
GPUTexture *GPU_texture_create_jitter(int w);
GPUTexture *GPU_texture_global_jitter_64(void);
GPUTexture **GPU_texture_global_depth_ptr(void);
void GPU_texture_set_global_depth(GPUTexture *depthtex);
void GPU_invalid_tex_init(void);
Expand Down
19 changes: 2 additions & 17 deletions source/blender/gpu/intern/gpu_compositing.c
Original file line number Diff line number Diff line change
Expand Up @@ -356,21 +356,6 @@ void GPU_fx_compositor_destroy(GPUFX *fx)
MEM_freeN(fx);
}

static GPUTexture * create_jitter_texture(void)
{
float jitter[64 * 64][2];
int i;

for (i = 0; i < 64 * 64; i++) {
jitter[i][0] = 2.0f * BLI_frand() - 1.0f;
jitter[i][1] = 2.0f * BLI_frand() - 1.0f;
normalize_v2(jitter[i]);
}

return GPU_texture_create_2D_procedural(64, 64, &jitter[0][0], true, NULL);
}


bool GPU_fx_compositor_initialize_passes(
GPUFX *fx, const rcti *rect, const rcti *scissor_rect,
const GPUFXSettings *fx_settings)
Expand Down Expand Up @@ -430,7 +415,7 @@ bool GPU_fx_compositor_initialize_passes(

/* try creating the jitter texture */
if (!fx->jitter_buffer)
fx->jitter_buffer = create_jitter_texture();
fx->jitter_buffer = GPU_texture_create_jitter(64);

/* check if color buffers need recreation */
if (!fx->color_buffer || !fx->depth_buffer || w != fx->gbuffer_dim[0] || h != fx->gbuffer_dim[1]) {
Expand Down Expand Up @@ -502,7 +487,7 @@ bool GPU_fx_compositor_initialize_passes(
return false;
}
if (!(fx->dof_nearfar_coc = GPU_texture_create_2D_procedural(
fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, err_out)))
fx->dof_downsampled_w, fx->dof_downsampled_h, NULL, false, false, err_out)))
{
printf("%.256s\n", err_out);
cleanup_fx_gl_data(fx, true);
Expand Down
20 changes: 20 additions & 0 deletions source/blender/gpu/intern/gpu_material.c
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,16 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias),
GPU_uniform(&samp), GPU_uniform(&samplesize), inp, &shadfac);
}
if (lamp->la->shadow_filter == LA_SHADOW_FILTER_PCF_JITTER) {
GPU_link(mat, "shadow_pcf_jitter",
GPU_builtin(GPU_VIEW_POSITION),
GPU_builtin(GPU_VIEW_NORMAL),
GPU_dynamic_texture(lamp->depthtex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias),
GPU_dynamic_texture(GPU_texture_global_jitter_64(), GPU_DYNAMIC_SAMPLER_2DIMAGE, NULL),
GPU_uniform(&samp), GPU_uniform(&samplesize), inp, &shadfac);
}
else if (lamp->la->shadow_filter == LA_SHADOW_FILTER_PCF_BAIL) {
GPU_link(mat, "shadow_pcf_early_bail",
GPU_builtin(GPU_VIEW_POSITION),
Expand Down Expand Up @@ -2912,6 +2922,16 @@ GPUNodeLink *GPU_lamp_get_data(
GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias),
GPU_uniform(&samp), GPU_uniform(&samplesize), inp, &shadowfac);
}
if (lamp->la->shadow_filter == LA_SHADOW_FILTER_PCF_JITTER) {
GPU_link(mat, "shadow_pcf_jitter",
GPU_builtin(GPU_VIEW_POSITION),
GPU_builtin(GPU_VIEW_NORMAL),
GPU_dynamic_texture(lamp->depthtex, GPU_DYNAMIC_SAMPLER_2DSHADOW, lamp->ob),
GPU_dynamic_uniform((float *)lamp->dynpersmat, GPU_DYNAMIC_LAMP_DYNPERSMAT, lamp->ob),
GPU_uniform(&lamp->bias), GPU_uniform(&lamp->slopebias),
GPU_dynamic_texture(GPU_texture_global_jitter_64(), GPU_DYNAMIC_SAMPLER_2DIMAGE, NULL),
GPU_uniform(&samp), GPU_uniform(&samplesize), inp, &shadowfac);
}
else if (lamp->la->shadow_filter == LA_SHADOW_FILTER_PCF_BAIL) {
GPU_link(mat, "shadow_pcf_early_bail",
GPU_builtin(GPU_VIEW_POSITION),
Expand Down
35 changes: 32 additions & 3 deletions source/blender/gpu/intern/gpu_texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_math_base.h"
#include "BLI_math_vector.h"
#include "BLI_rand.h"
#include "BLI_alloca.h"

#include "BKE_global.h"

Expand All @@ -46,6 +49,7 @@ static struct GPUTextureGlobal {
GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */
GPUTexture *invalid_tex_2D;
GPUTexture *invalid_tex_3D;
GPUTexture *jitter_64_tex;
GPUTexture *depth_tex;
} GG = {NULL, NULL, NULL, NULL};

Expand Down Expand Up @@ -546,7 +550,7 @@ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256])
return tex;
}

GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256])
GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, bool filter, char err_out[256])
{
GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, GPU_TEXTURE_MODE_NONE, GPU_HDR_HALF_FLOAT, 2, 0, err_out);

Expand All @@ -556,8 +560,10 @@ GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
if (!filter) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}

GPU_texture_unbind(tex);
}
Expand All @@ -581,6 +587,25 @@ GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char er
return tex;
}

GPUTexture *GPU_texture_create_jitter(int w)
{
float *jitter = BLI_array_alloca(jitter, w * w * 2);
int i;

for (i = 0; i < (w * w); i++) {
jitter[i * 2] = 2.0f * BLI_frand() - 1.0f;
jitter[i * 2 + 1] = 2.0f * BLI_frand() - 1.0f;
normalize_v2(&jitter[i * 2]);
}

return GPU_texture_create_2D_procedural(w, w, jitter, true, true, NULL);
}

GPUTexture *GPU_texture_global_jitter_64(void)
{
return GG.jitter_64_tex;
}

GPUTexture **GPU_texture_global_depth_ptr(void)
{
return &GG.depth_tex;
Expand All @@ -602,6 +627,7 @@ void GPU_invalid_tex_init(void)
GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL);
GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color);
GG.jitter_64_tex = GPU_texture_create_jitter(64);
GG.depth_tex = GG.invalid_tex_2D;
}

Expand All @@ -628,6 +654,9 @@ void GPU_invalid_tex_free(void)
GPU_texture_free(GG.invalid_tex_2D);
if (GG.invalid_tex_3D)
GPU_texture_free(GG.invalid_tex_3D);
if (GG.jitter_64_tex) {
GPU_texture_free(GG.jitter_64_tex);
}
}


Expand Down
2 changes: 1 addition & 1 deletion source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ vec3 calculate_view_space_normal(in vec3 viewposition)
float calculate_ssao_factor(float depth)
{
/* take the normalized ray direction here */
vec2 rotX = texture2D(jitter_tex, uvcoordsvar.xy * ssao_sample_params.yz).rg;
vec2 rotX = texture2DLod(jitter_tex, uvcoordsvar.xy * ssao_sample_params.yz, 0).rg;
vec2 rotY = vec2(-rotX.y, rotX.x);

/* occlusion is zero in full depth */
Expand Down
49 changes: 46 additions & 3 deletions source/blender/gpu/shaders/gpu_shader_material.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -2415,8 +2415,8 @@ float texture_shadow_offset(sampler2DShadow shadowmap, vec4 co, vec2 offset)
float test_shadow_pcf_early_bail(sampler2DShadow shadowmap, vec4 co, float samples, float samplesize)
{
float step = samplesize / samples;
float fullstep = samplesize - step * 0.95;
float halfsample = samplesize / 2.0 - step * 0.5 * 0.95;
float fullstep = samplesize - step * 0.98;
float halfsample = samplesize * 0.5 - step * 0.49;

float result = 0.0;
for (float y = -halfsample; y <= halfsample; y += fullstep) {
Expand Down Expand Up @@ -2449,7 +2449,7 @@ float test_shadow_pcf_early_bail(sampler2DShadow shadowmap, vec4 co, float sampl
float test_shadow_pcf(sampler2DShadow shadowmap, vec4 co, float samples, float samplesize)
{
float step = samplesize / samples;
float halfsample = samplesize / 2.0 - step * 0.5 * 0.95;
float halfsample = samplesize * 0.5 - step * 0.49;

float result = 0.0;
for (float y = -halfsample; y <= halfsample; y += step) {
Expand All @@ -2462,6 +2462,29 @@ float test_shadow_pcf(sampler2DShadow shadowmap, vec4 co, float samples, float s
return result;
}

float test_shadow_pcf_jitter(sampler2DShadow shadowmap, vec4 co, sampler2D jitter, float samples, float samplesize)
{
float step = samplesize / samples;
float halfsample = samplesize * 0.5 - step * 0.49;

vec2 jitterco = co.xy * 43543.0;
vec2 vec = texture2D(jitter, jitterco).xy;

mat2 rot = mat2(vec.x, vec.y,
-vec.y, vec.x);

float result = 0.0;
for (float y = -halfsample; y <= halfsample; y += step) {
for (float x = -halfsample; x <= halfsample; x += step) {
vec2 ofs = vec2(x, y) * 0.1;
result += texture_shadow_offset(shadowmap, co, (vec2(x, y) * rot) * 0.1);
}
}
result /= (samples * samples);

return result;
}

float test_shadow_vsm(sampler2D shadowmap, vec4 co, float bias, float bleedbias)
{
vec2 moments = texture2DProj(shadowmap, co).rg;
Expand Down Expand Up @@ -2522,6 +2545,26 @@ void shadow_pcf(
}
}

void shadow_pcf_jitter(
vec3 rco, vec3 vn, sampler2DShadow shadowmap, mat4 shadowpersmat, float bias, float slopebias,
sampler2D jitter, float samples, float samplesize, float inp,
out float result)
{
if (inp <= 0.0) {
result = 0.0;
}
else {
vec4 co = shadow_proj_coord(rco, vn, shadowpersmat, bias, slopebias);

if (shadow_visibility(co)) {
result = test_shadow_pcf_jitter(shadowmap, co, jitter, samples, samplesize);
}
else {
result = 1.0;
}
}
}

void shadow_pcf_early_bail(
vec3 rco, vec3 vn, sampler2DShadow shadowmap, mat4 shadowpersmat, float bias, float slopebias,
float samples, float samplesize, float inp,
Expand Down
1 change: 1 addition & 0 deletions source/blender/makesdna/DNA_lamp_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ typedef struct Lamp {
#define LA_SHADOW_FILTER_NONE 0
#define LA_SHADOW_FILTER_PCF 1
#define LA_SHADOW_FILTER_PCF_BAIL 2
#define LA_SHADOW_FILTER_PCF_JITTER 3

/* layer_shadow */
#define LA_LAYER_SHADOW_BOTH 0
Expand Down
1 change: 1 addition & 0 deletions source/blender/makesrna/intern/rna_lamp.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,7 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area)
{LA_SHADOW_FILTER_NONE, "NONE", 0, "None", "None filtering"},
{LA_SHADOW_FILTER_PCF, "PCF", 0, "PCF", "Percentage Closer Filtering"},
{LA_SHADOW_FILTER_PCF_BAIL, "PCF_BAIL", 0, "PCF Early Bail", "Percentage Closer Filtering Early Bail"},
{LA_SHADOW_FILTER_PCF_JITTER, "PCF_JITTER", 0, "PCF Jitter", "Percentage Closer Filtering Jitter"},
{0, NULL, 0, NULL, NULL}
};

Expand Down

0 comments on commit ca709a6

Please sign in to comment.