Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCampbell Barton <ideasman42@gmail.com>2019-04-17 07:17:24 +0300
committerCampbell Barton <ideasman42@gmail.com>2019-04-17 07:21:24 +0300
commite12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch)
tree8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/gpu/intern/gpu_material.c
parentb3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff)
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211. For details on usage and instructions for migrating branches without conflicts, see: https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/gpu/intern/gpu_material.c')
-rw-r--r--source/blender/gpu/intern/gpu_material.c1004
1 files changed, 509 insertions, 495 deletions
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index af8fcf6164e..cae60351bd5 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -54,182 +54,185 @@
#define MAX_COLOR_BAND 128
typedef struct GPUColorBandBuilder {
- float pixels[MAX_COLOR_BAND][CM_TABLE + 1][4];
- int current_layer;
+ float pixels[MAX_COLOR_BAND][CM_TABLE + 1][4];
+ int current_layer;
} GPUColorBandBuilder;
struct GPUMaterial {
- Scene *scene; /* DEPRECATED was only useful for lights. */
- Material *ma;
-
- eGPUMaterialStatus status;
-
- const void *engine_type; /* attached engine type */
- int options; /* to identify shader variations (shadow, probe, world background...) */
-
- /* for creating the material */
- ListBase nodes;
- GPUNodeLink *outlink;
-
- /* for binding the material */
- GPUPass *pass;
- ListBase inputs; /* GPUInput */
- GPUVertAttrLayers attrs;
- int builtins;
- int alpha, obcolalpha;
- int dynproperty;
-
- /* for passing uniforms */
- int viewmatloc, invviewmatloc;
- int obmatloc, invobmatloc;
- int localtoviewmatloc, invlocaltoviewmatloc;
- int obcolloc, obautobumpscaleloc;
- int cameratexcofacloc;
-
- int partscalarpropsloc;
- int partcoloc;
- int partvel;
- int partangvel;
-
- int objectinfoloc;
-
- /* XXX: Should be in Material. But it depends on the output node
- * used and since the output selection is difference for GPUMaterial...
- */
- int domain;
-
- /* Only used by Eevee to know which bsdf are used. */
- int flag;
-
- /* Used by 2.8 pipeline */
- GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */
-
- /* Eevee SSS */
- GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */
- GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
- float sss_enabled;
- float sss_radii[3];
- int sss_samples;
- short int sss_falloff;
- float sss_sharpness;
- bool sss_dirty;
-
- GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */
- GPUColorBandBuilder *coba_builder;
+ Scene *scene; /* DEPRECATED was only useful for lights. */
+ Material *ma;
+
+ eGPUMaterialStatus status;
+
+ const void *engine_type; /* attached engine type */
+ int options; /* to identify shader variations (shadow, probe, world background...) */
+
+ /* for creating the material */
+ ListBase nodes;
+ GPUNodeLink *outlink;
+
+ /* for binding the material */
+ GPUPass *pass;
+ ListBase inputs; /* GPUInput */
+ GPUVertAttrLayers attrs;
+ int builtins;
+ int alpha, obcolalpha;
+ int dynproperty;
+
+ /* for passing uniforms */
+ int viewmatloc, invviewmatloc;
+ int obmatloc, invobmatloc;
+ int localtoviewmatloc, invlocaltoviewmatloc;
+ int obcolloc, obautobumpscaleloc;
+ int cameratexcofacloc;
+
+ int partscalarpropsloc;
+ int partcoloc;
+ int partvel;
+ int partangvel;
+
+ int objectinfoloc;
+
+ /* XXX: Should be in Material. But it depends on the output node
+ * used and since the output selection is difference for GPUMaterial...
+ */
+ int domain;
+
+ /* Only used by Eevee to know which bsdf are used. */
+ int flag;
+
+ /* Used by 2.8 pipeline */
+ GPUUniformBuffer *ubo; /* UBOs for shader uniforms. */
+
+ /* Eevee SSS */
+ GPUUniformBuffer *sss_profile; /* UBO containing SSS profile. */
+ GPUTexture *sss_tex_profile; /* Texture containing SSS profile. */
+ float sss_enabled;
+ float sss_radii[3];
+ int sss_samples;
+ short int sss_falloff;
+ float sss_sharpness;
+ bool sss_dirty;
+
+ GPUTexture *coba_tex; /* 1D Texture array containing all color bands. */
+ GPUColorBandBuilder *coba_builder;
#ifndef NDEBUG
- char name[64];
+ char name[64];
#endif
};
enum {
- GPU_DOMAIN_SURFACE = (1 << 0),
- GPU_DOMAIN_VOLUME = (1 << 1),
- GPU_DOMAIN_SSS = (1 << 2),
+ GPU_DOMAIN_SURFACE = (1 << 0),
+ GPU_DOMAIN_VOLUME = (1 << 1),
+ GPU_DOMAIN_SSS = (1 << 2),
};
/* Functions */
/* Returns the address of the future pointer to coba_tex */
-GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat, int size, float *pixels, float *row)
+GPUTexture **gpu_material_ramp_texture_row_set(GPUMaterial *mat,
+ int size,
+ float *pixels,
+ float *row)
{
- /* In order to put all the colorbands into one 1D array texture,
- * we need them to be the same size. */
- BLI_assert(size == CM_TABLE + 1);
- UNUSED_VARS_NDEBUG(size);
+ /* In order to put all the colorbands into one 1D array texture,
+ * we need them to be the same size. */
+ BLI_assert(size == CM_TABLE + 1);
+ UNUSED_VARS_NDEBUG(size);
- if (mat->coba_builder == NULL) {
- mat->coba_builder = MEM_mallocN(sizeof(GPUColorBandBuilder), "GPUColorBandBuilder");
- mat->coba_builder->current_layer = 0;
- }
+ if (mat->coba_builder == NULL) {
+ mat->coba_builder = MEM_mallocN(sizeof(GPUColorBandBuilder), "GPUColorBandBuilder");
+ mat->coba_builder->current_layer = 0;
+ }
- int layer = mat->coba_builder->current_layer;
- *row = (float)layer;
+ int layer = mat->coba_builder->current_layer;
+ *row = (float)layer;
- if (*row == MAX_COLOR_BAND) {
- printf("Too many color band in shader! Remove some Curve, Black Body or Color Ramp Node.\n");
- }
- else {
- float *dst = (float *)mat->coba_builder->pixels[layer];
- memcpy(dst, pixels, sizeof(float) * (CM_TABLE + 1) * 4);
- mat->coba_builder->current_layer += 1;
- }
+ if (*row == MAX_COLOR_BAND) {
+ printf("Too many color band in shader! Remove some Curve, Black Body or Color Ramp Node.\n");
+ }
+ else {
+ float *dst = (float *)mat->coba_builder->pixels[layer];
+ memcpy(dst, pixels, sizeof(float) * (CM_TABLE + 1) * 4);
+ mat->coba_builder->current_layer += 1;
+ }
- return &mat->coba_tex;
+ return &mat->coba_tex;
}
static void gpu_material_ramp_texture_build(GPUMaterial *mat)
{
- if (mat->coba_builder == NULL)
- return;
+ if (mat->coba_builder == NULL)
+ return;
- GPUColorBandBuilder *builder = mat->coba_builder;
+ GPUColorBandBuilder *builder = mat->coba_builder;
- mat->coba_tex = GPU_texture_create_1d_array(CM_TABLE + 1, builder->current_layer, GPU_RGBA16F,
- (float *)builder->pixels, NULL);
+ mat->coba_tex = GPU_texture_create_1d_array(
+ CM_TABLE + 1, builder->current_layer, GPU_RGBA16F, (float *)builder->pixels, NULL);
- MEM_freeN(builder);
- mat->coba_builder = NULL;
+ MEM_freeN(builder);
+ mat->coba_builder = NULL;
}
static void gpu_material_free_single(GPUMaterial *material)
{
- /* Cancel / wait any pending lazy compilation. */
- DRW_deferred_shader_remove(material);
-
- GPU_pass_free_nodes(&material->nodes);
- GPU_inputs_free(&material->inputs);
-
- if (material->pass != NULL) {
- GPU_pass_release(material->pass);
- }
- if (material->ubo != NULL) {
- GPU_uniformbuffer_free(material->ubo);
- }
- if (material->sss_tex_profile != NULL) {
- GPU_texture_free(material->sss_tex_profile);
- }
- if (material->sss_profile != NULL) {
- GPU_uniformbuffer_free(material->sss_profile);
- }
- if (material->coba_tex != NULL) {
- GPU_texture_free(material->coba_tex);
- }
+ /* Cancel / wait any pending lazy compilation. */
+ DRW_deferred_shader_remove(material);
+
+ GPU_pass_free_nodes(&material->nodes);
+ GPU_inputs_free(&material->inputs);
+
+ if (material->pass != NULL) {
+ GPU_pass_release(material->pass);
+ }
+ if (material->ubo != NULL) {
+ GPU_uniformbuffer_free(material->ubo);
+ }
+ if (material->sss_tex_profile != NULL) {
+ GPU_texture_free(material->sss_tex_profile);
+ }
+ if (material->sss_profile != NULL) {
+ GPU_uniformbuffer_free(material->sss_profile);
+ }
+ if (material->coba_tex != NULL) {
+ GPU_texture_free(material->coba_tex);
+ }
}
void GPU_material_free(ListBase *gpumaterial)
{
- for (LinkData *link = gpumaterial->first; link; link = link->next) {
- GPUMaterial *material = link->data;
- gpu_material_free_single(material);
- MEM_freeN(material);
- }
- BLI_freelistN(gpumaterial);
+ for (LinkData *link = gpumaterial->first; link; link = link->next) {
+ GPUMaterial *material = link->data;
+ gpu_material_free_single(material);
+ MEM_freeN(material);
+ }
+ BLI_freelistN(gpumaterial);
}
eGPUBuiltin GPU_get_material_builtins(GPUMaterial *material)
{
- return material->builtins;
+ return material->builtins;
}
Scene *GPU_material_scene(GPUMaterial *material)
{
- return material->scene;
+ return material->scene;
}
GPUPass *GPU_material_get_pass(GPUMaterial *material)
{
- return material->pass;
+ return material->pass;
}
ListBase *GPU_material_get_inputs(GPUMaterial *material)
{
- return &material->inputs;
+ return &material->inputs;
}
GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material)
{
- return material->ubo;
+ return material->ubo;
}
/**
@@ -239,7 +242,7 @@ GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material)
*/
void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
{
- material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL);
+ material->ubo = GPU_uniformbuffer_dynamic_create(inputs, NULL);
}
/* Eevee Subsurface scattering. */
@@ -249,313 +252,319 @@ void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs)
#define SSS_EXPONENT 2.0f /* Importance sampling exponent */
typedef struct GPUSssKernelData {
- float kernel[SSS_SAMPLES][4];
- float param[3], max_radius;
- int samples;
+ float kernel[SSS_SAMPLES][4];
+ float param[3], max_radius;
+ int samples;
} GPUSssKernelData;
static void sss_calculate_offsets(GPUSssKernelData *kd, int count, float exponent)
{
- float step = 2.0f / (float)(count - 1);
- for (int i = 0; i < count; i++) {
- float o = ((float)i) * step - 1.0f;
- float sign = (o < 0.0f) ? -1.0f : 1.0f;
- float ofs = sign * fabsf(powf(o, exponent));
- kd->kernel[i][3] = ofs;
- }
+ float step = 2.0f / (float)(count - 1);
+ for (int i = 0; i < count; i++) {
+ float o = ((float)i) * step - 1.0f;
+ float sign = (o < 0.0f) ? -1.0f : 1.0f;
+ float ofs = sign * fabsf(powf(o, exponent));
+ kd->kernel[i][3] = ofs;
+ }
}
#define GAUSS_TRUNCATE 12.46f
static float gaussian_profile(float r, float radius)
{
- const float v = radius * radius * (0.25f * 0.25f);
- const float Rm = sqrtf(v * GAUSS_TRUNCATE);
+ const float v = radius * radius * (0.25f * 0.25f);
+ const float Rm = sqrtf(v * GAUSS_TRUNCATE);
- if (r >= Rm) {
- return 0.0f;
- }
- return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v);
+ if (r >= Rm) {
+ return 0.0f;
+ }
+ return expf(-r * r / (2.0f * v)) / (2.0f * M_PI * v);
}
-#define BURLEY_TRUNCATE 16.0f
-#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
+#define BURLEY_TRUNCATE 16.0f
+#define BURLEY_TRUNCATE_CDF 0.9963790093708328f // cdf(BURLEY_TRUNCATE)
static float burley_profile(float r, float d)
{
- float exp_r_3_d = expf(-r / (3.0f * d));
- float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
- return (exp_r_d + exp_r_3_d) / (4.0f * d);
+ float exp_r_3_d = expf(-r / (3.0f * d));
+ float exp_r_d = exp_r_3_d * exp_r_3_d * exp_r_3_d;
+ return (exp_r_d + exp_r_3_d) / (4.0f * d);
}
static float cubic_profile(float r, float radius, float sharpness)
{
- float Rm = radius * (1.0f + 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;
+ 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;
+ 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);
+ 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);
+ return (10.0f * num) / (Rmy5 * M_PI);
}
static float eval_profile(float r, short falloff_type, float sharpness, float param)
{
- r = fabsf(r);
+ r = fabsf(r);
- if (falloff_type == SHD_SUBSURFACE_BURLEY ||
- falloff_type == SHD_SUBSURFACE_RANDOM_WALK)
- {
- return burley_profile(r, param) / BURLEY_TRUNCATE_CDF;
- }
- else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
- return cubic_profile(r, param, sharpness);
- }
- else {
- return gaussian_profile(r, param);
- }
+ if (falloff_type == SHD_SUBSURFACE_BURLEY || falloff_type == SHD_SUBSURFACE_RANDOM_WALK) {
+ return burley_profile(r, param) / BURLEY_TRUNCATE_CDF;
+ }
+ else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
+ return cubic_profile(r, param, sharpness);
+ }
+ else {
+ return gaussian_profile(r, param);
+ }
}
/* Resolution for each sample of the precomputed kernel profile */
#define INTEGRAL_RESOLUTION 32
static float eval_integral(float x0, float x1, short falloff_type, float sharpness, float param)
{
- const float range = x1 - x0;
- const float step = range / INTEGRAL_RESOLUTION;
- float integral = 0.0f;
+ 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 = eval_profile(x, falloff_type, sharpness, param);
- integral += y * step;
- }
+ for (int i = 0; i < INTEGRAL_RESOLUTION; ++i) {
+ float x = x0 + range * ((float)i + 0.5f) / (float)INTEGRAL_RESOLUTION;
+ float y = eval_profile(x, falloff_type, sharpness, param);
+ integral += y * step;
+ }
- return integral;
+ return integral;
}
#undef INTEGRAL_RESOLUTION
static void compute_sss_kernel(
- GPUSssKernelData *kd, float radii[3], int sample_len, int falloff_type, float sharpness)
-{
- float rad[3];
- /* Minimum radius */
- rad[0] = MAX2(radii[0], 1e-15f);
- rad[1] = MAX2(radii[1], 1e-15f);
- rad[2] = MAX2(radii[2], 1e-15f);
-
- /* Christensen-Burley fitting */
- float l[3], d[3];
-
- if (falloff_type == SHD_SUBSURFACE_BURLEY ||
- falloff_type == SHD_SUBSURFACE_RANDOM_WALK)
- {
- mul_v3_v3fl(l, rad, 0.25f * M_1_PI);
- const float A = 1.0f;
- const float s = 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f);
- /* XXX 0.6f Out of nowhere to match cycles! Empirical! Can be tweak better. */
- mul_v3_v3fl(d, l, 0.6f / s);
- mul_v3_v3fl(rad, d, BURLEY_TRUNCATE);
- kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
-
- copy_v3_v3(kd->param, d);
- }
- else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
- copy_v3_v3(kd->param, rad);
- mul_v3_fl(rad, 1.0f + sharpness);
- kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
- }
- else {
- kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
-
- copy_v3_v3(kd->param, rad);
- }
-
- /* Compute samples locations on the 1d kernel [-1..1] */
- sss_calculate_offsets(kd, sample_len, SSS_EXPONENT);
-
- /* Weights sum for normalization */
- float sum[3] = {0.0f, 0.0f, 0.0f};
-
- /* Compute integral of each sample footprint */
- for (int i = 0; i < sample_len; i++) {
- float x0, x1;
-
- if (i == 0) {
- x0 = kd->kernel[0][3] - fabsf(kd->kernel[0][3] - kd->kernel[1][3]) / 2.0f;
- }
- else {
- x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f;
- }
-
- if (i == sample_len - 1) {
- x1 = kd->kernel[sample_len - 1][3] + fabsf(kd->kernel[sample_len - 2][3] - kd->kernel[sample_len - 1][3]) / 2.0f;
- }
- else {
- x1 = (kd->kernel[i][3] + kd->kernel[i + 1][3]) / 2.0f;
- }
-
- x0 *= kd->max_radius;
- x1 *= kd->max_radius;
-
- kd->kernel[i][0] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[0]);
- kd->kernel[i][1] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[1]);
- kd->kernel[i][2] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[2]);
-
- sum[0] += kd->kernel[i][0];
- sum[1] += kd->kernel[i][1];
- sum[2] += kd->kernel[i][2];
- }
-
- for (int i = 0; i < 3; ++i) {
- if (sum[i] > 0.0f) {
- /* Normalize */
- for (int j = 0; j < sample_len; j++) {
- kd->kernel[j][i] /= sum[i];
- }
- }
- else {
- /* Avoid 0 kernel sum. */
- kd->kernel[sample_len / 2][i] = 1.0f;
- }
- }
-
- /* Put center sample at the start of the array (to sample first) */
- float tmpv[4];
- copy_v4_v4(tmpv, kd->kernel[sample_len / 2]);
- for (int i = sample_len / 2; i > 0; i--) {
- copy_v4_v4(kd->kernel[i], kd->kernel[i - 1]);
- }
- copy_v4_v4(kd->kernel[0], tmpv);
-
- kd->samples = sample_len;
+ GPUSssKernelData *kd, float radii[3], int sample_len, int falloff_type, float sharpness)
+{
+ float rad[3];
+ /* Minimum radius */
+ rad[0] = MAX2(radii[0], 1e-15f);
+ rad[1] = MAX2(radii[1], 1e-15f);
+ rad[2] = MAX2(radii[2], 1e-15f);
+
+ /* Christensen-Burley fitting */
+ float l[3], d[3];
+
+ if (falloff_type == SHD_SUBSURFACE_BURLEY || falloff_type == SHD_SUBSURFACE_RANDOM_WALK) {
+ mul_v3_v3fl(l, rad, 0.25f * M_1_PI);
+ const float A = 1.0f;
+ const float s = 1.9f - A + 3.5f * (A - 0.8f) * (A - 0.8f);
+ /* XXX 0.6f Out of nowhere to match cycles! Empirical! Can be tweak better. */
+ mul_v3_v3fl(d, l, 0.6f / s);
+ mul_v3_v3fl(rad, d, BURLEY_TRUNCATE);
+ kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
+
+ copy_v3_v3(kd->param, d);
+ }
+ else if (falloff_type == SHD_SUBSURFACE_CUBIC) {
+ copy_v3_v3(kd->param, rad);
+ mul_v3_fl(rad, 1.0f + sharpness);
+ kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
+ }
+ else {
+ kd->max_radius = MAX3(rad[0], rad[1], rad[2]);
+
+ copy_v3_v3(kd->param, rad);
+ }
+
+ /* Compute samples locations on the 1d kernel [-1..1] */
+ sss_calculate_offsets(kd, sample_len, SSS_EXPONENT);
+
+ /* Weights sum for normalization */
+ float sum[3] = {0.0f, 0.0f, 0.0f};
+
+ /* Compute integral of each sample footprint */
+ for (int i = 0; i < sample_len; i++) {
+ float x0, x1;
+
+ if (i == 0) {
+ x0 = kd->kernel[0][3] - fabsf(kd->kernel[0][3] - kd->kernel[1][3]) / 2.0f;
+ }
+ else {
+ x0 = (kd->kernel[i - 1][3] + kd->kernel[i][3]) / 2.0f;
+ }
+
+ if (i == sample_len - 1) {
+ x1 = kd->kernel[sample_len - 1][3] +
+ fabsf(kd->kernel[sample_len - 2][3] - kd->kernel[sample_len - 1][3]) / 2.0f;
+ }
+ else {
+ x1 = (kd->kernel[i][3] + kd->kernel[i + 1][3]) / 2.0f;
+ }
+
+ x0 *= kd->max_radius;
+ x1 *= kd->max_radius;
+
+ kd->kernel[i][0] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[0]);
+ kd->kernel[i][1] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[1]);
+ kd->kernel[i][2] = eval_integral(x0, x1, falloff_type, sharpness, kd->param[2]);
+
+ sum[0] += kd->kernel[i][0];
+ sum[1] += kd->kernel[i][1];
+ sum[2] += kd->kernel[i][2];
+ }
+
+ for (int i = 0; i < 3; ++i) {
+ if (sum[i] > 0.0f) {
+ /* Normalize */
+ for (int j = 0; j < sample_len; j++) {
+ kd->kernel[j][i] /= sum[i];
+ }
+ }
+ else {
+ /* Avoid 0 kernel sum. */
+ kd->kernel[sample_len / 2][i] = 1.0f;
+ }
+ }
+
+ /* Put center sample at the start of the array (to sample first) */
+ float tmpv[4];
+ copy_v4_v4(tmpv, kd->kernel[sample_len / 2]);
+ for (int i = sample_len / 2; i > 0; i--) {
+ copy_v4_v4(kd->kernel[i], kd->kernel[i - 1]);
+ }
+ copy_v4_v4(kd->kernel[0], tmpv);
+
+ kd->samples = sample_len;
}
#define INTEGRAL_RESOLUTION 512
-static void compute_sss_translucence_kernel(
- const GPUSssKernelData *kd, int resolution, short falloff_type, float sharpness, float **output)
-{
- float (*texels)[4];
- texels = MEM_callocN(sizeof(float) * 4 * resolution, "compute_sss_translucence_kernel");
- *output = (float *)texels;
-
- /* Last texel should be black, hence the - 1. */
- for (int i = 0; i < resolution - 1; ++i) {
- /* Distance from surface. */
- float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution);
-
- /* For each distance d we compute the radiance incoming from an hypothetic parallel plane. */
- /* Compute radius of the footprint on the hypothetic plane */
- float r_fp = sqrtf(kd->max_radius * kd->max_radius - d * d);
- float r_step = r_fp / INTEGRAL_RESOLUTION;
- float area_accum = 0.0f;
- for (float r = 0.0f; r < r_fp; r += r_step) {
- /* Compute distance to the "shading" point through the medium. */
- /* r_step * 0.5f to put sample between the area borders */
- float dist = hypotf(r + r_step * 0.5f, d);
-
- float profile[3];
- profile[0] = eval_profile(dist, falloff_type, sharpness, kd->param[0]);
- profile[1] = eval_profile(dist, falloff_type, sharpness, kd->param[1]);
- profile[2] = eval_profile(dist, falloff_type, sharpness, kd->param[2]);
-
- /* Since the profile and configuration are radially symmetrical we
- * can just evaluate it once and weight it accordingly */
- float r_next = r + r_step;
- float disk_area = (M_PI * r_next * r_next) - (M_PI * r * r);
-
- mul_v3_fl(profile, disk_area);
- add_v3_v3(texels[i], profile);
- area_accum += disk_area;
- }
- /* Normalize over the disk. */
- mul_v3_fl(texels[i], 1.0f / (area_accum));
- }
-
- /* Normalize */
- for (int j = resolution - 2; j > 0; j--) {
- texels[j][0] /= (texels[0][0] > 0.0f) ? texels[0][0] : 1.0f;
- texels[j][1] /= (texels[0][1] > 0.0f) ? texels[0][1] : 1.0f;
- texels[j][2] /= (texels[0][2] > 0.0f) ? texels[0][2] : 1.0f;
- }
-
- /* First texel should be white */
- texels[0][0] = (texels[0][0] > 0.0f) ? 1.0f : 0.0f;
- texels[0][1] = (texels[0][1] > 0.0f) ? 1.0f : 0.0f;
- texels[0][2] = (texels[0][2] > 0.0f) ? 1.0f : 0.0f;
-
- /* dim the last few texels for smoother transition */
- mul_v3_fl(texels[resolution - 2], 0.25f);
- mul_v3_fl(texels[resolution - 3], 0.5f);
- mul_v3_fl(texels[resolution - 4], 0.75f);
+static void compute_sss_translucence_kernel(const GPUSssKernelData *kd,
+ int resolution,
+ short falloff_type,
+ float sharpness,
+ float **output)
+{
+ float(*texels)[4];
+ texels = MEM_callocN(sizeof(float) * 4 * resolution, "compute_sss_translucence_kernel");
+ *output = (float *)texels;
+
+ /* Last texel should be black, hence the - 1. */
+ for (int i = 0; i < resolution - 1; ++i) {
+ /* Distance from surface. */
+ float d = kd->max_radius * ((float)i + 0.00001f) / ((float)resolution);
+
+ /* For each distance d we compute the radiance incoming from an hypothetic parallel plane. */
+ /* Compute radius of the footprint on the hypothetic plane */
+ float r_fp = sqrtf(kd->max_radius * kd->max_radius - d * d);
+ float r_step = r_fp / INTEGRAL_RESOLUTION;
+ float area_accum = 0.0f;
+ for (float r = 0.0f; r < r_fp; r += r_step) {
+ /* Compute distance to the "shading" point through the medium. */
+ /* r_step * 0.5f to put sample between the area borders */
+ float dist = hypotf(r + r_step * 0.5f, d);
+
+ float profile[3];
+ profile[0] = eval_profile(dist, falloff_type, sharpness, kd->param[0]);
+ profile[1] = eval_profile(dist, falloff_type, sharpness, kd->param[1]);
+ profile[2] = eval_profile(dist, falloff_type, sharpness, kd->param[2]);
+
+ /* Since the profile and configuration are radially symmetrical we
+ * can just evaluate it once and weight it accordingly */
+ float r_next = r + r_step;
+ float disk_area = (M_PI * r_next * r_next) - (M_PI * r * r);
+
+ mul_v3_fl(profile, disk_area);
+ add_v3_v3(texels[i], profile);
+ area_accum += disk_area;
+ }
+ /* Normalize over the disk. */
+ mul_v3_fl(texels[i], 1.0f / (area_accum));
+ }
+
+ /* Normalize */
+ for (int j = resolution - 2; j > 0; j--) {
+ texels[j][0] /= (texels[0][0] > 0.0f) ? texels[0][0] : 1.0f;
+ texels[j][1] /= (texels[0][1] > 0.0f) ? texels[0][1] : 1.0f;
+ texels[j][2] /= (texels[0][2] > 0.0f) ? texels[0][2] : 1.0f;
+ }
+
+ /* First texel should be white */
+ texels[0][0] = (texels[0][0] > 0.0f) ? 1.0f : 0.0f;
+ texels[0][1] = (texels[0][1] > 0.0f) ? 1.0f : 0.0f;
+ texels[0][2] = (texels[0][2] > 0.0f) ? 1.0f : 0.0f;
+
+ /* dim the last few texels for smoother transition */
+ mul_v3_fl(texels[resolution - 2], 0.25f);
+ mul_v3_fl(texels[resolution - 3], 0.5f);
+ mul_v3_fl(texels[resolution - 4], 0.75f);
}
#undef INTEGRAL_RESOLUTION
-void GPU_material_sss_profile_create(GPUMaterial *material, float radii[3], short *falloff_type, float *sharpness)
+void GPU_material_sss_profile_create(GPUMaterial *material,
+ float radii[3],
+ short *falloff_type,
+ float *sharpness)
{
- copy_v3_v3(material->sss_radii, radii);
- material->sss_falloff = (falloff_type) ? *falloff_type : 0.0;
- material->sss_sharpness = (sharpness) ? *sharpness : 0.0;
- material->sss_dirty = true;
- material->sss_enabled = true;
+ copy_v3_v3(material->sss_radii, radii);
+ material->sss_falloff = (falloff_type) ? *falloff_type : 0.0;
+ material->sss_sharpness = (sharpness) ? *sharpness : 0.0;
+ material->sss_dirty = true;
+ material->sss_enabled = true;
- /* Update / Create UBO */
- if (material->sss_profile == NULL) {
- material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL);
- }
+ /* Update / Create UBO */
+ if (material->sss_profile == NULL) {
+ material->sss_profile = GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL);
+ }
}
-struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material, int sample_len, GPUTexture **tex_profile)
+struct GPUUniformBuffer *GPU_material_sss_profile_get(GPUMaterial *material,
+ int sample_len,
+ GPUTexture **tex_profile)
{
- if (!material->sss_enabled)
- return NULL;
+ if (!material->sss_enabled)
+ return NULL;
- if (material->sss_dirty || (material->sss_samples != sample_len)) {
- GPUSssKernelData kd;
+ if (material->sss_dirty || (material->sss_samples != sample_len)) {
+ GPUSssKernelData kd;
- float sharpness = material->sss_sharpness;
+ float sharpness = material->sss_sharpness;
- /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */
- sharpness *= 0.5f;
+ /* XXX Black magic but it seems to fit. Maybe because we integrate -1..1 */
+ sharpness *= 0.5f;
- compute_sss_kernel(&kd, material->sss_radii, sample_len, material->sss_falloff, sharpness);
+ compute_sss_kernel(&kd, material->sss_radii, sample_len, material->sss_falloff, sharpness);
- /* Update / Create UBO */
- GPU_uniformbuffer_update(material->sss_profile, &kd);
+ /* Update / Create UBO */
+ GPU_uniformbuffer_update(material->sss_profile, &kd);
- /* Update / Create Tex */
- float *translucence_profile;
- compute_sss_translucence_kernel(&kd, 64, material->sss_falloff, sharpness, &translucence_profile);
+ /* Update / Create Tex */
+ float *translucence_profile;
+ compute_sss_translucence_kernel(
+ &kd, 64, material->sss_falloff, sharpness, &translucence_profile);
- if (material->sss_tex_profile != NULL) {
- GPU_texture_free(material->sss_tex_profile);
- }
+ if (material->sss_tex_profile != NULL) {
+ GPU_texture_free(material->sss_tex_profile);
+ }
- material->sss_tex_profile = GPU_texture_create_1d(64, GPU_RGBA16F, translucence_profile, NULL);
+ material->sss_tex_profile = GPU_texture_create_1d(64, GPU_RGBA16F, translucence_profile, NULL);
- MEM_freeN(translucence_profile);
+ MEM_freeN(translucence_profile);
- material->sss_samples = sample_len;
- material->sss_dirty = false;
- }
+ material->sss_samples = sample_len;
+ material->sss_dirty = false;
+ }
- if (tex_profile != NULL) {
- *tex_profile = material->sss_tex_profile;
- }
- return material->sss_profile;
+ if (tex_profile != NULL) {
+ *tex_profile = material->sss_tex_profile;
+ }
+ return material->sss_profile;
}
struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void)
{
- return GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL);
+ return GPU_uniformbuffer_create(sizeof(GPUSssKernelData), NULL, NULL);
}
#undef SSS_EXPONENT
@@ -563,69 +572,68 @@ struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void)
void GPU_material_vertex_attrs(GPUMaterial *material, GPUVertAttrLayers *r_attrs)
{
- *r_attrs = material->attrs;
+ *r_attrs = material->attrs;
}
void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link)
{
- if (!material->outlink)
- material->outlink = link;
+ if (!material->outlink)
+ material->outlink = link;
}
void gpu_material_add_node(GPUMaterial *material, GPUNode *node)
{
- BLI_addtail(&material->nodes, node);
+ BLI_addtail(&material->nodes, node);
}
/* Return true if the material compilation has not yet begin or begin. */
eGPUMaterialStatus GPU_material_status(GPUMaterial *mat)
{
- return mat->status;
+ return mat->status;
}
/* Code generation */
bool GPU_material_do_color_management(GPUMaterial *mat)
{
- if (!BKE_scene_check_color_management_enabled(mat->scene))
- return false;
+ if (!BKE_scene_check_color_management_enabled(mat->scene))
+ return false;
- return true;
+ return true;
}
bool GPU_material_use_domain_surface(GPUMaterial *mat)
{
- return (mat->domain & GPU_DOMAIN_SURFACE);
+ return (mat->domain & GPU_DOMAIN_SURFACE);
}
bool GPU_material_use_domain_volume(GPUMaterial *mat)
{
- return (mat->domain & GPU_DOMAIN_VOLUME);
+ return (mat->domain & GPU_DOMAIN_VOLUME);
}
void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag)
{
- mat->flag |= flag;
+ mat->flag |= flag;
}
bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag)
{
- return (mat->flag & flag);
+ return (mat->flag & flag);
}
-GPUMaterial *GPU_material_from_nodetree_find(
- ListBase *gpumaterials, const void *engine_type, int options)
+GPUMaterial *GPU_material_from_nodetree_find(ListBase *gpumaterials,
+ const void *engine_type,
+ int options)
{
- for (LinkData *link = gpumaterials->first; link; link = link->next) {
- GPUMaterial *current_material = (GPUMaterial *)link->data;
- if (current_material->engine_type == engine_type &&
- current_material->options == options)
- {
- return current_material;
- }
- }
+ for (LinkData *link = gpumaterials->first; link; link = link->next) {
+ GPUMaterial *current_material = (GPUMaterial *)link->data;
+ if (current_material->engine_type == engine_type && current_material->options == options) {
+ return current_material;
+ }
+ }
- return NULL;
+ return NULL;
}
/**
@@ -633,132 +641,138 @@ GPUMaterial *GPU_material_from_nodetree_find(
* This is enforced since constructing other arguments to this function may be expensive
* so only do this when they are needed.
*/
-GPUMaterial *GPU_material_from_nodetree(
- Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, int options,
- const char *vert_code, const char *geom_code, const char *frag_lib, const char *defines, const char *name)
-{
- LinkData *link;
- bool has_volume_output, has_surface_output;
-
- /* Caller must re-use materials. */
- BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
-
- /* allocate material */
- GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
- mat->scene = scene;
- mat->engine_type = engine_type;
- mat->options = options;
+GPUMaterial *GPU_material_from_nodetree(Scene *scene,
+ struct bNodeTree *ntree,
+ ListBase *gpumaterials,
+ const void *engine_type,
+ int options,
+ const char *vert_code,
+ const char *geom_code,
+ const char *frag_lib,
+ const char *defines,
+ const char *name)
+{
+ LinkData *link;
+ bool has_volume_output, has_surface_output;
+
+ /* Caller must re-use materials. */
+ BLI_assert(GPU_material_from_nodetree_find(gpumaterials, engine_type, options) == NULL);
+
+ /* allocate material */
+ GPUMaterial *mat = MEM_callocN(sizeof(GPUMaterial), "GPUMaterial");
+ mat->scene = scene;
+ mat->engine_type = engine_type;
+ mat->options = options;
#ifndef NDEBUG
- BLI_snprintf(mat->name, sizeof(mat->name), "%s", name);
+ BLI_snprintf(mat->name, sizeof(mat->name), "%s", name);
#else
- UNUSED_VARS(name);
+ UNUSED_VARS(name);
#endif
- /* localize tree to create links for reroute and mute */
- bNodeTree *localtree = ntreeLocalize(ntree);
- ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output);
-
- gpu_material_ramp_texture_build(mat);
-
- if (has_surface_output) {
- mat->domain |= GPU_DOMAIN_SURFACE;
- }
- if (has_volume_output) {
- mat->domain |= GPU_DOMAIN_VOLUME;
- }
-
- if (mat->outlink) {
- /* Prune the unused nodes and extract attributes before compiling so the
- * generated VBOs are ready to accept the future shader. */
- GPU_nodes_prune(&mat->nodes, mat->outlink);
- GPU_nodes_get_vertex_attrs(&mat->nodes, &mat->attrs);
- /* Create source code and search pass cache for an already compiled version. */
- mat->pass = GPU_generate_pass(
- mat,
- mat->outlink,
- &mat->attrs,
- &mat->nodes,
- &mat->builtins,
- vert_code,
- geom_code,
- frag_lib,
- defines);
-
- if (mat->pass == NULL) {
- /* We had a cache hit and the shader has already failed to compile. */
- mat->status = GPU_MAT_FAILED;
- }
- else {
- GPUShader *sh = GPU_pass_shader_get(mat->pass);
- if (sh != NULL) {
- /* We had a cache hit and the shader is already compiled. */
- mat->status = GPU_MAT_SUCCESS;
- GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes);
- }
- else {
- mat->status = GPU_MAT_QUEUED;
- }
- }
- }
- else {
- mat->status = GPU_MAT_FAILED;
- }
-
- /* Only free after GPU_pass_shader_get where GPUUniformBuffer
- * read data from the local tree. */
- ntreeFreeLocalTree(localtree);
- MEM_freeN(localtree);
-
- /* note that even if building the shader fails in some way, we still keep
- * it to avoid trying to compile again and again, and simply do not use
- * the actual shader on drawing */
-
- link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
- link->data = mat;
- BLI_addtail(gpumaterials, link);
-
- return mat;
+ /* localize tree to create links for reroute and mute */
+ bNodeTree *localtree = ntreeLocalize(ntree);
+ ntreeGPUMaterialNodes(localtree, mat, &has_surface_output, &has_volume_output);
+
+ gpu_material_ramp_texture_build(mat);
+
+ if (has_surface_output) {
+ mat->domain |= GPU_DOMAIN_SURFACE;
+ }
+ if (has_volume_output) {
+ mat->domain |= GPU_DOMAIN_VOLUME;
+ }
+
+ if (mat->outlink) {
+ /* Prune the unused nodes and extract attributes before compiling so the
+ * generated VBOs are ready to accept the future shader. */
+ GPU_nodes_prune(&mat->nodes, mat->outlink);
+ GPU_nodes_get_vertex_attrs(&mat->nodes, &mat->attrs);
+ /* Create source code and search pass cache for an already compiled version. */
+ mat->pass = GPU_generate_pass(mat,
+ mat->outlink,
+ &mat->attrs,
+ &mat->nodes,
+ &mat->builtins,
+ vert_code,
+ geom_code,
+ frag_lib,
+ defines);
+
+ if (mat->pass == NULL) {
+ /* We had a cache hit and the shader has already failed to compile. */
+ mat->status = GPU_MAT_FAILED;
+ }
+ else {
+ GPUShader *sh = GPU_pass_shader_get(mat->pass);
+ if (sh != NULL) {
+ /* We had a cache hit and the shader is already compiled. */
+ mat->status = GPU_MAT_SUCCESS;
+ GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes);
+ }
+ else {
+ mat->status = GPU_MAT_QUEUED;
+ }
+ }
+ }
+ else {
+ mat->status = GPU_MAT_FAILED;
+ }
+
+ /* Only free after GPU_pass_shader_get where GPUUniformBuffer
+ * read data from the local tree. */
+ ntreeFreeLocalTree(localtree);
+ MEM_freeN(localtree);
+
+ /* note that even if building the shader fails in some way, we still keep
+ * it to avoid trying to compile again and again, and simply do not use
+ * the actual shader on drawing */
+
+ link = MEM_callocN(sizeof(LinkData), "GPUMaterialLink");
+ link->data = mat;
+ BLI_addtail(gpumaterials, link);
+
+ return mat;
}
void GPU_material_compile(GPUMaterial *mat)
{
- /* Only run once! */
- BLI_assert(mat->status == GPU_MAT_QUEUED);
- BLI_assert(mat->pass);
+ /* Only run once! */
+ BLI_assert(mat->status == GPU_MAT_QUEUED);
+ BLI_assert(mat->pass);
- /* NOTE: The shader may have already been compiled here since we are
- * sharing GPUShader across GPUMaterials. In this case it's a no-op. */
+ /* NOTE: The shader may have already been compiled here since we are
+ * sharing GPUShader across GPUMaterials. In this case it's a no-op. */
#ifndef NDEBUG
- GPU_pass_compile(mat->pass, mat->name);
+ GPU_pass_compile(mat->pass, mat->name);
#else
- GPU_pass_compile(mat->pass, __func__);
+ GPU_pass_compile(mat->pass, __func__);
#endif
- GPUShader *sh = GPU_pass_shader_get(mat->pass);
+ GPUShader *sh = GPU_pass_shader_get(mat->pass);
- if (sh != NULL) {
- mat->status = GPU_MAT_SUCCESS;
- GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes);
- }
- else {
- mat->status = GPU_MAT_FAILED;
- GPU_pass_free_nodes(&mat->nodes);
- GPU_pass_release(mat->pass);
- mat->pass = NULL;
- }
+ if (sh != NULL) {
+ mat->status = GPU_MAT_SUCCESS;
+ GPU_nodes_extract_dynamic_inputs(sh, &mat->inputs, &mat->nodes);
+ }
+ else {
+ mat->status = GPU_MAT_FAILED;
+ GPU_pass_free_nodes(&mat->nodes);
+ GPU_pass_release(mat->pass);
+ mat->pass = NULL;
+ }
}
void GPU_materials_free(Main *bmain)
{
- Material *ma;
- World *wo;
- extern Material defmaterial;
+ Material *ma;
+ World *wo;
+ extern Material defmaterial;
- for (ma = bmain->materials.first; ma; ma = ma->id.next)
- GPU_material_free(&ma->gpumaterial);
+ for (ma = bmain->materials.first; ma; ma = ma->id.next)
+ GPU_material_free(&ma->gpumaterial);
- for (wo = bmain->worlds.first; wo; wo = wo->id.next)
- GPU_material_free(&wo->gpumaterial);
+ for (wo = bmain->worlds.first; wo; wo = wo->id.next)
+ GPU_material_free(&wo->gpumaterial);
- GPU_material_free(&defmaterial.gpumaterial);
+ GPU_material_free(&defmaterial.gpumaterial);
}