diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-11-17 04:00:48 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-11-17 04:00:48 +0300 |
commit | 936ddde35cabc7f694bf0e83b3c8e505f0385532 (patch) | |
tree | e6d5bb1e6cdd34e7dcf911d9af33eb490c6be26f /source/blender/gpu | |
parent | fcbb8e71c56a413dda47c233a35d6091e34dbdae (diff) |
Eevee: SSS: Add cubic profile for the sake of completeness.
It wasnt really hard except from the wierd sharpness 0.5 multiplication.
Diffstat (limited to 'source/blender/gpu')
-rw-r--r-- | source/blender/gpu/GPU_material.h | 2 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_material.c | 62 |
2 files changed, 59 insertions, 5 deletions
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 2a72b6996c4..aeb268cef36 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -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 */ diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index 8946c124738..3f7fe68b20b 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -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); |