306 lines
12 KiB
GLSL
306 lines
12 KiB
GLSL
|
|
#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
|
|
#pragma BLENDER_REQUIRE(lights_lib.glsl)
|
|
#pragma BLENDER_REQUIRE(lightprobe_lib.glsl)
|
|
|
|
/**
|
|
* Extensive use of Macros to be able to change the maximum amount of evaluated closure easily.
|
|
* NOTE: GLSL does not support variadic macros.
|
|
*
|
|
* Example
|
|
* // Declare the cl_eval function
|
|
* CLOSURE_EVAL_FUNCTION_DECLARE_3(name, Diffuse, Glossy, Refraction);
|
|
* // Declare the inputs & outputs
|
|
* CLOSURE_VARS_DECLARE(Diffuse, Glossy, Refraction);
|
|
* // Specify inputs
|
|
* in_Diffuse_0.N = N;
|
|
* ...
|
|
* // Call the cl_eval function
|
|
* CLOSURE_EVAL_FUNCTION_3(name, Diffuse, Glossy, Refraction);
|
|
* // Get the cl_out
|
|
* closure.radiance = out_Diffuse_0.radiance + out_Glossy_1.radiance + out_Refraction_2.radiance;
|
|
**/
|
|
|
|
#define CLOSURE_VARS_DECLARE(t0, t1, t2, t3) \
|
|
ClosureInputCommon in_common = CLOSURE_INPUT_COMMON_DEFAULT; \
|
|
ClosureInput##t0 in_##t0##_0 = CLOSURE_INPUT_##t0##_DEFAULT; \
|
|
ClosureInput##t1 in_##t1##_1 = CLOSURE_INPUT_##t1##_DEFAULT; \
|
|
ClosureInput##t2 in_##t2##_2 = CLOSURE_INPUT_##t2##_DEFAULT; \
|
|
ClosureInput##t3 in_##t3##_3 = CLOSURE_INPUT_##t3##_DEFAULT; \
|
|
ClosureOutput##t0 out_##t0##_0; \
|
|
ClosureOutput##t1 out_##t1##_1; \
|
|
ClosureOutput##t2 out_##t2##_2; \
|
|
ClosureOutput##t3 out_##t3##_3;
|
|
|
|
#define CLOSURE_EVAL_DECLARE(t0, t1, t2, t3) \
|
|
ClosureEvalCommon cl_common = closure_Common_eval_init(in_common); \
|
|
ClosureEval##t0 eval_##t0##_0 = closure_##t0##_eval_init(in_##t0##_0, cl_common, out_##t0##_0); \
|
|
ClosureEval##t1 eval_##t1##_1 = closure_##t1##_eval_init(in_##t1##_1, cl_common, out_##t1##_1); \
|
|
ClosureEval##t2 eval_##t2##_2 = closure_##t2##_eval_init(in_##t2##_2, cl_common, out_##t2##_2); \
|
|
ClosureEval##t3 eval_##t3##_3 = closure_##t3##_eval_init(in_##t3##_3, cl_common, out_##t3##_3);
|
|
|
|
#define CLOSURE_META_SUBROUTINE(subroutine, t0, t1, t2, t3) \
|
|
closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, out_##t0##_0); \
|
|
closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, out_##t1##_1); \
|
|
closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, out_##t2##_2); \
|
|
closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, out_##t3##_3);
|
|
|
|
#define CLOSURE_META_SUBROUTINE_DATA(subroutine, sub_data, t0, t1, t2, t3) \
|
|
closure_##t0##_##subroutine(in_##t0##_0, eval_##t0##_0, cl_common, sub_data, out_##t0##_0); \
|
|
closure_##t1##_##subroutine(in_##t1##_1, eval_##t1##_1, cl_common, sub_data, out_##t1##_1); \
|
|
closure_##t2##_##subroutine(in_##t2##_2, eval_##t2##_2, cl_common, sub_data, out_##t2##_2); \
|
|
closure_##t3##_##subroutine(in_##t3##_3, eval_##t3##_3, cl_common, sub_data, out_##t3##_3);
|
|
|
|
/* Inputs are inout so that callers can get the final inputs used for evaluation. */
|
|
#define CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3) \
|
|
void closure_##name##_eval(ClosureInputCommon in_common, \
|
|
inout ClosureInput##t0 in_##t0##_0, \
|
|
inout ClosureInput##t1 in_##t1##_1, \
|
|
inout ClosureInput##t2 in_##t2##_2, \
|
|
inout ClosureInput##t3 in_##t3##_3, \
|
|
out ClosureOutput##t0 out_##t0##_0, \
|
|
out ClosureOutput##t1 out_##t1##_1, \
|
|
out ClosureOutput##t2 out_##t2##_2, \
|
|
out ClosureOutput##t3 out_##t3##_3) \
|
|
{ \
|
|
CLOSURE_EVAL_DECLARE(t0, t1, t2, t3); \
|
|
\
|
|
/* Starts at 1 because 0 is world cubemap. */ \
|
|
for (int i = 1; cl_common.specular_accum > 0.0 && i < prbNumRenderCube && i < MAX_PROBE; \
|
|
i++) { \
|
|
ClosureCubemapData cube = closure_cubemap_eval_init(i, cl_common); \
|
|
if (cube.attenuation > 1e-8) { \
|
|
CLOSURE_META_SUBROUTINE_DATA(cubemap_eval, cube, t0, t1, t2, t3); \
|
|
} \
|
|
} \
|
|
\
|
|
/* Starts at 1 because 0 is world irradiance. */ \
|
|
for (int i = 1; cl_common.diffuse_accum > 0.0 && i < prbNumRenderGrid && i < MAX_GRID; i++) { \
|
|
ClosureGridData grid = closure_grid_eval_init(i, cl_common); \
|
|
if (grid.attenuation > 1e-8) { \
|
|
CLOSURE_META_SUBROUTINE_DATA(grid_eval, grid, t0, t1, t2, t3); \
|
|
} \
|
|
} \
|
|
\
|
|
CLOSURE_META_SUBROUTINE(indirect_end, t0, t1, t2, t3); \
|
|
\
|
|
ClosurePlanarData planar = closure_planar_eval_init(cl_common); \
|
|
if (planar.attenuation > 1e-8) { \
|
|
CLOSURE_META_SUBROUTINE_DATA(planar_eval, planar, t0, t1, t2, t3); \
|
|
} \
|
|
\
|
|
for (int i = 0; i < laNumLight && i < MAX_LIGHT; i++) { \
|
|
ClosureLightData light = closure_light_eval_init(cl_common, i); \
|
|
if (light.vis > 1e-8) { \
|
|
CLOSURE_META_SUBROUTINE_DATA(light_eval, light, t0, t1, t2, t3); \
|
|
} \
|
|
} \
|
|
\
|
|
CLOSURE_META_SUBROUTINE(eval_end, t0, t1, t2, t3); \
|
|
}
|
|
|
|
#define CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3) \
|
|
closure_##name##_eval(in_common, \
|
|
in_##t0##_0, \
|
|
in_##t1##_1, \
|
|
in_##t2##_2, \
|
|
in_##t3##_3, \
|
|
out_##t0##_0, \
|
|
out_##t1##_1, \
|
|
out_##t2##_2, \
|
|
out_##t3##_3)
|
|
|
|
#define CLOSURE_EVAL_FUNCTION_DECLARE_1(name, t0) \
|
|
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, Dummy, Dummy, Dummy)
|
|
#define CLOSURE_EVAL_FUNCTION_DECLARE_2(name, t0, t1) \
|
|
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, Dummy, Dummy)
|
|
#define CLOSURE_EVAL_FUNCTION_DECLARE_3(name, t0, t1, t2) \
|
|
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, Dummy)
|
|
#define CLOSURE_EVAL_FUNCTION_DECLARE_4(name, t0, t1, t2, t3) \
|
|
CLOSURE_EVAL_FUNCTION_DECLARE(name, t0, t1, t2, t3)
|
|
|
|
#define CLOSURE_VARS_DECLARE_1(t0) CLOSURE_VARS_DECLARE(t0, Dummy, Dummy, Dummy)
|
|
#define CLOSURE_VARS_DECLARE_2(t0, t1) CLOSURE_VARS_DECLARE(t0, t1, Dummy, Dummy)
|
|
#define CLOSURE_VARS_DECLARE_3(t0, t1, t2) CLOSURE_VARS_DECLARE(t0, t1, t2, Dummy)
|
|
#define CLOSURE_VARS_DECLARE_4(t0, t1, t2, t3) CLOSURE_VARS_DECLARE(t0, t1, t2, t3)
|
|
|
|
#define CLOSURE_EVAL_FUNCTION_1(name, t0) CLOSURE_EVAL_FUNCTION(name, t0, Dummy, Dummy, Dummy)
|
|
#define CLOSURE_EVAL_FUNCTION_2(name, t0, t1) CLOSURE_EVAL_FUNCTION(name, t0, t1, Dummy, Dummy)
|
|
#define CLOSURE_EVAL_FUNCTION_3(name, t0, t1, t2) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, Dummy)
|
|
#define CLOSURE_EVAL_FUNCTION_4(name, t0, t1, t2, t3) CLOSURE_EVAL_FUNCTION(name, t0, t1, t2, t3)
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Dummy Closure
|
|
*
|
|
* Dummy closure type that will be optimized out by the compiler.
|
|
* \{ */
|
|
|
|
#define ClosureInputDummy ClosureOutput
|
|
#define ClosureOutputDummy ClosureOutput
|
|
#define ClosureEvalDummy ClosureOutput
|
|
#define CLOSURE_EVAL_DUMMY ClosureOutput(vec3(0))
|
|
#define CLOSURE_INPUT_Dummy_DEFAULT CLOSURE_EVAL_DUMMY
|
|
#define closure_Dummy_eval_init(cl_in, cl_common, cl_out) CLOSURE_EVAL_DUMMY
|
|
#define closure_Dummy_planar_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
|
#define closure_Dummy_cubemap_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
|
#define closure_Dummy_grid_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
|
#define closure_Dummy_indirect_end(cl_in, cl_eval, cl_common, cl_out)
|
|
#define closure_Dummy_light_eval(cl_in, cl_eval, cl_common, data, cl_out)
|
|
#define closure_Dummy_eval_end(cl_in, cl_eval, cl_common, cl_out)
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Common cl_eval data
|
|
*
|
|
* Eval data not dependant on input parameters. All might not be used but unused ones
|
|
* will be optimized out.
|
|
* \{ */
|
|
|
|
struct ClosureInputCommon {
|
|
/** Custom occlusion value set by the user. */
|
|
float occlusion;
|
|
};
|
|
|
|
#define CLOSURE_INPUT_COMMON_DEFAULT ClosureInputCommon(1.0)
|
|
|
|
struct ClosureEvalCommon {
|
|
/** Result of SSAO. */
|
|
OcclusionData occlusion_data;
|
|
/** View vector. */
|
|
vec3 V;
|
|
/** Surface position. */
|
|
vec3 P;
|
|
/** Normal vector, always facing camera. */
|
|
vec3 N;
|
|
/** Normal vector, always facing camera. (viewspace) */
|
|
vec3 vN;
|
|
/** Surface position. (viewspace) */
|
|
vec3 vP;
|
|
/** Geometric normal, always facing camera. */
|
|
vec3 Ng;
|
|
/** Geometric normal, always facing camera. (viewspace) */
|
|
vec3 vNg;
|
|
/** Random numbers. 3 random sequences. zw is a random point on a circle. */
|
|
vec4 rand;
|
|
/** Specular probe accumulator. Shared between planar and cubemap probe. */
|
|
float specular_accum;
|
|
/** Diffuse probe accumulator. */
|
|
float diffuse_accum;
|
|
};
|
|
|
|
/* Common cl_out struct used by most closures. */
|
|
struct ClosureOutput {
|
|
vec3 radiance;
|
|
};
|
|
|
|
/* Workaround for screenspace shadows in SSR pass. */
|
|
float FragDepth;
|
|
|
|
ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in)
|
|
{
|
|
ClosureEvalCommon cl_eval;
|
|
cl_eval.rand = texelfetch_noise_tex(gl_FragCoord.xy);
|
|
cl_eval.V = cameraVec(worldPosition);
|
|
cl_eval.P = worldPosition;
|
|
cl_eval.N = safe_normalize(gl_FrontFacing ? worldNormal : -worldNormal);
|
|
cl_eval.vN = safe_normalize(gl_FrontFacing ? viewNormal : -viewNormal);
|
|
cl_eval.vP = viewPosition;
|
|
cl_eval.Ng = safe_normalize(cross(dFdx(cl_eval.P), dFdy(cl_eval.P)));
|
|
cl_eval.vNg = transform_direction(ViewMatrix, cl_eval.Ng);
|
|
|
|
cl_eval.occlusion_data = occlusion_load(cl_eval.vP, cl_in.occlusion);
|
|
|
|
cl_eval.specular_accum = 1.0;
|
|
cl_eval.diffuse_accum = 1.0;
|
|
return cl_eval;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Loop data
|
|
*
|
|
* Loop datas are conveniently packed into struct to make it future proof.
|
|
* \{ */
|
|
|
|
struct ClosureLightData {
|
|
LightData data; /** Light Data. */
|
|
vec4 L; /** Non-Normalized Light Vector (surface to light) with length in W component. */
|
|
float vis; /** Light visibility. */
|
|
float contact_shadow; /** Result of contact shadow tracing. */
|
|
};
|
|
|
|
ClosureLightData closure_light_eval_init(ClosureEvalCommon cl_common, int light_id)
|
|
{
|
|
ClosureLightData light;
|
|
light.data = lights_data[light_id];
|
|
|
|
light.L.xyz = light.data.l_position - cl_common.P;
|
|
light.L.w = length(light.L.xyz);
|
|
|
|
light.vis = light_visibility(light.data, cl_common.P, light.L);
|
|
light.contact_shadow = light_contact_shadows(
|
|
light.data, cl_common.P, cl_common.vP, cl_common.vNg, cl_common.rand.x, light.vis);
|
|
|
|
return light;
|
|
}
|
|
|
|
struct ClosureCubemapData {
|
|
int id; /** Probe id. */
|
|
float attenuation; /** Attenuation. */
|
|
};
|
|
|
|
ClosureCubemapData closure_cubemap_eval_init(int cube_id, inout ClosureEvalCommon cl_common)
|
|
{
|
|
ClosureCubemapData cube;
|
|
cube.id = cube_id;
|
|
cube.attenuation = probe_attenuation_cube(cube_id, cl_common.P);
|
|
cube.attenuation = min(cube.attenuation, cl_common.specular_accum);
|
|
cl_common.specular_accum -= cube.attenuation;
|
|
return cube;
|
|
}
|
|
|
|
struct ClosurePlanarData {
|
|
int id; /** Probe id. */
|
|
PlanarData data; /** planars_data[id]. */
|
|
float attenuation; /** Attenuation. */
|
|
};
|
|
|
|
ClosurePlanarData closure_planar_eval_init(inout ClosureEvalCommon cl_common)
|
|
{
|
|
ClosurePlanarData planar;
|
|
planar.attenuation = 0.0;
|
|
|
|
/* Find planar with the maximum weight. TODO(fclem) */
|
|
for (int i = 0; i < prbNumPlanar && i < MAX_PLANAR; i++) {
|
|
float attenuation = probe_attenuation_planar(planars_data[i], cl_common.P);
|
|
if (attenuation > planar.attenuation) {
|
|
planar.id = i;
|
|
planar.attenuation = attenuation;
|
|
planar.data = planars_data[i];
|
|
}
|
|
}
|
|
return planar;
|
|
}
|
|
|
|
struct ClosureGridData {
|
|
int id; /** Grid id. */
|
|
GridData data; /** grids_data[id] */
|
|
float attenuation; /** Attenuation. */
|
|
vec3 local_pos; /** Local position inside the grid. */
|
|
};
|
|
|
|
ClosureGridData closure_grid_eval_init(int id, inout ClosureEvalCommon cl_common)
|
|
{
|
|
ClosureGridData grid;
|
|
grid.id = id;
|
|
grid.data = grids_data[id];
|
|
grid.attenuation = probe_attenuation_grid(grid.data, cl_common.P, grid.local_pos);
|
|
grid.attenuation = min(grid.attenuation, cl_common.diffuse_accum);
|
|
cl_common.diffuse_accum -= grid.attenuation;
|
|
return grid;
|
|
}
|
|
|
|
/** \} */
|