Eevee: SSS: Add cubic profile for the sake of completeness.
It wasnt really hard except from the wierd sharpness 0.5 multiplication.
This commit is contained in:
parent
fcbb8e71c5
commit
936ddde35c
|
@ -235,7 +235,7 @@ void GPU_material_enable_alpha(GPUMaterial *material);
|
|||
GPUBuiltin GPU_get_material_builtins(GPUMaterial *material);
|
||||
GPUBlendMode GPU_material_alpha_blend(GPUMaterial *material, float obcol[4]);
|
||||
|
||||
void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, int *falloff_type);
|
||||
void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short int *falloff_type, float *sharpness);
|
||||
struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_ct);
|
||||
|
||||
/* High level functions to create and use GPU materials */
|
||||
|
|
|
@ -145,7 +145,8 @@ struct GPUMaterial {
|
|||
GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */
|
||||
float *sss_radii; /* UBO containing SSS profile. */
|
||||
int sss_samples;
|
||||
int *sss_falloff;
|
||||
short int *sss_falloff;
|
||||
float *sss_sharpness;
|
||||
bool sss_dirty;
|
||||
};
|
||||
|
||||
|
@ -560,7 +561,44 @@ static float burley_integral(float x0, float x1, float d)
|
|||
return integral;
|
||||
}
|
||||
|
||||
static void compute_sss_kernel(GPUSssKernelData *kd, float *radii, int sample_ct, int falloff_type)
|
||||
static float cubic_profile(float r, float radius, float sharpness)
|
||||
{
|
||||
float Rm = radius * (1.0f + sharpness);
|
||||
|
||||
if(r >= Rm)
|
||||
return 0.0f;
|
||||
|
||||
/* custom variation with extra sharpness, to match the previous code */
|
||||
const float y = 1.0f/(1.0f + sharpness);
|
||||
float Rmy, ry, ryinv;
|
||||
|
||||
Rmy = powf(Rm, y);
|
||||
ry = powf(r, y);
|
||||
ryinv = (r > 0.0f)? powf(r, y - 1.0f): 0.0f;
|
||||
|
||||
const float Rmy5 = (Rmy*Rmy) * (Rmy*Rmy) * Rmy;
|
||||
const float f = Rmy - ry;
|
||||
const float num = f*(f*f)*(y*ryinv);
|
||||
|
||||
return (10.0f * num) / (Rmy5 * M_PI);
|
||||
}
|
||||
|
||||
static float cubic_integral(float x0, float x1, float radius, float sharpness)
|
||||
{
|
||||
const float range = x1 - x0;
|
||||
const float step = range / INTEGRAL_RESOLUTION;
|
||||
float integral = 0.0f;
|
||||
|
||||
for(int i = 0; i < INTEGRAL_RESOLUTION; ++i) {
|
||||
float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION;
|
||||
float y = cubic_profile(fabsf(x), radius, sharpness);
|
||||
integral += y * step;
|
||||
}
|
||||
|
||||
return integral;
|
||||
}
|
||||
|
||||
static void compute_sss_kernel(GPUSssKernelData *kd, float *radii, int sample_ct, int falloff_type, float sharpness)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
/* Minimum radius */
|
||||
|
@ -578,6 +616,12 @@ static void compute_sss_kernel(GPUSssKernelData *kd, float *radii, int sample_ct
|
|||
mul_v3_v3fl(d, l, 0.6f / s);
|
||||
mul_v3_v3fl(kd->radii_n, d, BURLEY_TRUNCATE);
|
||||
}
|
||||
else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
|
||||
/* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */
|
||||
sharpness *= 0.5f;
|
||||
|
||||
mul_v3_fl(kd->radii_n, 1.0f + sharpness);
|
||||
}
|
||||
|
||||
/* Normalize size */
|
||||
kd->max_radius = MAX3(kd->radii_n[0], kd->radii_n[1], kd->radii_n[2]);
|
||||
|
@ -616,6 +660,13 @@ static void compute_sss_kernel(GPUSssKernelData *kd, float *radii, int sample_ct
|
|||
kd->kernel[i][1] = burley_integral(x0, x1, d[1]);
|
||||
kd->kernel[i][2] = burley_integral(x0, x1, d[2]);
|
||||
}
|
||||
else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
|
||||
x0 *= kd->max_radius;
|
||||
x1 *= kd->max_radius;
|
||||
kd->kernel[i][0] = cubic_integral(x0, x1, radii[0], sharpness);
|
||||
kd->kernel[i][1] = cubic_integral(x0, x1, radii[1], sharpness);
|
||||
kd->kernel[i][2] = cubic_integral(x0, x1, radii[2], sharpness);
|
||||
}
|
||||
else {
|
||||
kd->kernel[i][0] = gaussian_integral(x0 / kd->radii_n[0], x1 / kd->radii_n[0]);
|
||||
kd->kernel[i][1] = gaussian_integral(x0 / kd->radii_n[1], x1 / kd->radii_n[1]);
|
||||
|
@ -649,10 +700,11 @@ static void compute_sss_kernel(GPUSssKernelData *kd, float *radii, int sample_ct
|
|||
copy_v4_v4(kd->kernel[0], tmpv);
|
||||
}
|
||||
|
||||
void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, int *falloff_type)
|
||||
void GPU_material_sss_profile_create(GPUMaterial *material, float *radii, short int *falloff_type, float *sharpness)
|
||||
{
|
||||
material->sss_radii = radii;
|
||||
material->sss_falloff = falloff_type;
|
||||
material->sss_sharpness = sharpness;
|
||||
material->sss_dirty = true;
|
||||
|
||||
/* Update / Create UBO */
|
||||
|
@ -672,7 +724,9 @@ struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int
|
|||
if (material->sss_dirty || (material->sss_samples != sample_ct)) {
|
||||
GPUSssKernelData kd;
|
||||
|
||||
compute_sss_kernel(&kd, material->sss_radii, sample_ct, *material->sss_falloff);
|
||||
float sharpness = (material->sss_sharpness != NULL) ? *material->sss_sharpness : 0.0f;
|
||||
|
||||
compute_sss_kernel(&kd, material->sss_radii, sample_ct, *material->sss_falloff, sharpness);
|
||||
|
||||
/* Update / Create UBO */
|
||||
GPU_uniformbuffer_update(material->sss_profile, &kd);
|
||||
|
|
|
@ -104,7 +104,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, bNode *node, bNodeE
|
|||
bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
|
||||
bNodeSocketValueRGBA *socket_data = socket->default_value;
|
||||
/* For some reason it seems that the socket value is in ARGB format. */
|
||||
GPU_material_sss_profile_create(mat, &socket_data->value[1], &profile);
|
||||
GPU_material_sss_profile_create(mat, &socket_data->value[1], &profile, NULL);
|
||||
}
|
||||
|
||||
return GPU_stack_link(mat, node, "node_bsdf_principled_clearcoat", in, out, GPU_builtin(GPU_VIEW_POSITION),
|
||||
|
|
|
@ -57,8 +57,12 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, bNode *node,
|
|||
if (node->sss_id == 0) {
|
||||
bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2);
|
||||
bNodeSocketValueRGBA *socket_data = socket->default_value;
|
||||
bNodeSocket *socket_sharp = BLI_findlink(&node->original->inputs, 3);
|
||||
bNodeSocketValueFloat *socket_data_sharp = socket_sharp->default_value;
|
||||
/* For some reason it seems that the socket value is in ARGB format. */
|
||||
GPU_material_sss_profile_create(mat, &socket_data->value[1], &node->original->custom1);
|
||||
GPU_material_sss_profile_create(mat, &socket_data->value[1],
|
||||
&node->original->custom1,
|
||||
&socket_data_sharp->value);
|
||||
}
|
||||
|
||||
return GPU_stack_link(mat, node, "node_subsurface_scattering", in, out, GPU_uniform(&node->sss_id));
|
||||
|
|
Loading…
Reference in New Issue