diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h index 0d4560207ea..d52fd91ccdd 100644 --- a/source/blender/blenkernel/BKE_colortools.h +++ b/source/blender/blenkernel/BKE_colortools.h @@ -129,6 +129,36 @@ bool BKE_curvemapping_RGBA_does_something(const struct CurveMapping *cumap); void BKE_curvemapping_table_F(const struct CurveMapping *cumap, float **array, int *size); void BKE_curvemapping_table_RGBA(const struct CurveMapping *cumap, float **array, int *size); +/** Get the minimum x value of each curve map table. */ +void BKE_curvemapping_get_range_minimums(const struct CurveMapping *curve_mapping, + float minimums[4]); + +/** Get the reciprocal of the difference between the maximum and the minimum x value of each curve + * map table. Evaluation parameters can be multiplied by this value to be normalized. If the + * difference is zero, 1^8 is returned. */ +void BKE_curvemapping_compute_range_dividers(const struct CurveMapping *curve_mapping, + float dividers[4]); + +/** Compute the slopes at the start and end points of each curve map. The slopes are multiplied by + * the range of the curve map to compensate for parameter normalization. If the slope is vertical, + * 1^8 is returned. */ +void BKE_curvemapping_compute_slopes(const struct CurveMapping *curve_mapping, + float start_slopes[4], + float end_slopes[4]); + +/** Check if the curve map at the index is identity, that is, does nothing. A curve map is said to + * be identity if: + * - The curve mapping uses extrapolation. + * - Its range is 1. + * - The slope at its start point is 1. + * - The slope at its end point is 1. + * - The number of points is 2. + * - The start point is at (0, 0). + * - The end point is at (1, 1). + * Note that this could return false even if the curve map is identity, this happens in the case + * when more than 2 points exist in the curve map but all points are collinear. */ +bool BKE_curvemapping_is_map_identity(const struct CurveMapping *curve_mapping, int index); + /** * Call when you do images etc, needs restore too. also verifies tables. * non-const (these modify the curve). diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index c3d66d4463d..e4c46703f8a 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -1158,6 +1158,80 @@ bool BKE_curvemapping_RGBA_does_something(const CurveMapping *cumap) return false; } +void BKE_curvemapping_get_range_minimums(const CurveMapping *curve_mapping, float minimums[CM_TOT]) +{ + for (int i = 0; i < CM_TOT; i++) { + minimums[i] = curve_mapping->cm[i].mintable; + } +} + +void BKE_curvemapping_compute_range_dividers(const CurveMapping *curve_mapping, + float dividers[CM_TOT]) +{ + for (int i = 0; i < CM_TOT; i++) { + const CurveMap *curve_map = &curve_mapping->cm[i]; + dividers[i] = 1.0f / max_ff(1e-8f, curve_map->maxtable - curve_map->mintable); + } +} + +void BKE_curvemapping_compute_slopes(const CurveMapping *curve_mapping, + float start_slopes[CM_TOT], + float end_slopes[CM_TOT]) +{ + float range_dividers[CM_TOT]; + BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers); + for (int i = 0; i < CM_TOT; i++) { + const CurveMap *curve_map = &curve_mapping->cm[i]; + /* If extrapolation is not enabled, the slopes are horizontal. */ + if (!(curve_mapping->flag & CUMA_EXTEND_EXTRAPOLATE)) { + start_slopes[i] = 0.0f; + end_slopes[i] = 0.0f; + continue; + } + + if (curve_map->ext_in[0] != 0.0f) { + start_slopes[i] = curve_map->ext_in[1] / (curve_map->ext_in[0] * range_dividers[i]); + } + else { + start_slopes[i] = 1e8f; + } + + if (curve_map->ext_out[0] != 0.0f) { + end_slopes[i] = curve_map->ext_out[1] / (curve_map->ext_out[0] * range_dividers[i]); + } + else { + end_slopes[i] = 1e8f; + } + } +} + +bool BKE_curvemapping_is_map_identity(const CurveMapping *curve_mapping, int index) +{ + if (!(curve_mapping->flag & CUMA_EXTEND_EXTRAPOLATE)) { + return false; + } + const CurveMap *curve_map = &curve_mapping->cm[index]; + if (curve_map->maxtable - curve_map->mintable != 1.0f) { + return false; + } + if (curve_map->ext_in[0] != curve_map->ext_in[1]) { + return false; + } + if (curve_map->ext_out[0] != curve_map->ext_out[1]) { + return false; + } + if (curve_map->totpoint != 2) { + return false; + } + if (curve_map->curve[0].x != 0 || curve_map->curve[0].y != 0) { + return false; + } + if (curve_map->curve[1].x != 0 || curve_map->curve[1].y != 0) { + return false; + } + return true; +} + void BKE_curvemapping_init(CurveMapping *cumap) { int a; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index dc542411596..5fee9167362 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -305,6 +305,7 @@ set(GLSL_SRC shaders/common/gpu_shader_common_color_ramp.glsl shaders/common/gpu_shader_common_color_utils.glsl + shaders/common/gpu_shader_common_curves.glsl shaders/common/gpu_shader_common_hash.glsl shaders/common/gpu_shader_common_math.glsl shaders/common/gpu_shader_common_math_utils.glsl @@ -330,7 +331,6 @@ set(GLSL_SRC shaders/material/gpu_shader_material_displacement.glsl shaders/material/gpu_shader_material_eevee_specular.glsl shaders/material/gpu_shader_material_emission.glsl - shaders/material/gpu_shader_material_float_curve.glsl shaders/material/gpu_shader_material_fractal_noise.glsl shaders/material/gpu_shader_material_fresnel.glsl shaders/material/gpu_shader_material_gamma.glsl @@ -359,7 +359,6 @@ set(GLSL_SRC shaders/material/gpu_shader_material_point_info.glsl shaders/material/gpu_shader_material_principled.glsl shaders/material/gpu_shader_material_refraction.glsl - shaders/material/gpu_shader_material_rgb_curves.glsl shaders/material/gpu_shader_material_rgb_to_bw.glsl shaders/material/gpu_shader_material_separate_color.glsl shaders/material/gpu_shader_material_separate_hsv.glsl @@ -388,7 +387,6 @@ set(GLSL_SRC shaders/material/gpu_shader_material_translucent.glsl shaders/material/gpu_shader_material_transparent.glsl shaders/material/gpu_shader_material_uv_map.glsl - shaders/material/gpu_shader_material_vector_curves.glsl shaders/material/gpu_shader_material_vector_displacement.glsl shaders/material/gpu_shader_material_vector_math.glsl shaders/material/gpu_shader_material_vector_rotate.glsl diff --git a/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl b/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl new file mode 100644 index 00000000000..8948ed77557 --- /dev/null +++ b/source/blender/gpu/shaders/common/gpu_shader_common_curves.glsl @@ -0,0 +1,162 @@ +vec4 white_balance(vec4 color, vec4 black_level, vec4 white_level) +{ + vec4 range = max(white_level - black_level, vec4(1e-5f)); + return (color - black_level) / range; +} + +float extrapolate_if_needed(float parameter, float value, float start_slope, float end_slope) +{ + if (parameter < 0.0) { + return value + parameter * start_slope; + } + + if (parameter > 1.0) { + return value + (parameter - 1.0) * end_slope; + } + + return value; +} + +/* Same as extrapolate_if_needed but vectorized. */ +vec3 extrapolate_if_needed(vec3 parameters, vec3 values, vec3 start_slopes, vec3 end_slopes) +{ + vec3 end_or_zero_slopes = mix(vec3(0.0), end_slopes, greaterThan(parameters, vec3(1.0))); + vec3 slopes = mix(end_or_zero_slopes, start_slopes, lessThan(parameters, vec3(0.0))); + parameters = parameters - mix(vec3(0.0), vec3(1.0), greaterThan(parameters, vec3(1.0))); + return values + parameters * slopes; +} + +/* Curve maps are stored in sampler objects that are evaluated in the [0, 1] range, so normalize + * parameters accordingly. */ +#define NORMALIZE_PARAMETER(parameter, minimum, range) ((parameter - minimum) * range) + +void curves_combined_rgb(float factor, + vec4 color, + vec4 black_level, + vec4 white_level, + sampler1DArray curve_map, + const float layer, + vec4 range_minimums, + vec4 range_dividers, + vec4 start_slopes, + vec4 end_slopes, + out vec4 result) +{ + vec4 balanced = white_balance(color, black_level, white_level); + + /* First, evaluate alpha curve map at all channels. The alpha curve is the Combined curve in the + * UI. */ + vec3 parameters = NORMALIZE_PARAMETER(balanced.rgb, range_minimums.aaa, range_dividers.aaa); + result.r = texture(curve_map, vec2(parameters.x, layer)).a; + result.g = texture(curve_map, vec2(parameters.y, layer)).a; + result.b = texture(curve_map, vec2(parameters.z, layer)).a; + + /* Then, extrapolate if needed. */ + result.rgb = extrapolate_if_needed(parameters, result.rgb, start_slopes.aaa, end_slopes.aaa); + + /* Then, evaluate each channel on its curve map. */ + parameters = NORMALIZE_PARAMETER(result.rgb, range_minimums.rgb, range_dividers.rgb); + result.r = texture(curve_map, vec2(parameters.r, layer)).r; + result.g = texture(curve_map, vec2(parameters.g, layer)).g; + result.b = texture(curve_map, vec2(parameters.b, layer)).b; + + /* Then, extrapolate again if needed. */ + result.rgb = extrapolate_if_needed(parameters, result.rgb, start_slopes.rgb, end_slopes.rgb); + result.a = color.a; + + result = mix(color, result, factor); +} + +void curves_combined_only(float factor, + vec4 color, + vec4 black_level, + vec4 white_level, + sampler1DArray curve_map, + const float layer, + float range_minimum, + float range_divider, + float start_slope, + float end_slope, + out vec4 result) +{ + vec4 balanced = white_balance(color, black_level, white_level); + + /* Evaluate alpha curve map at all channels. The alpha curve is the Combined curve in the + * UI. */ + vec3 parameters = NORMALIZE_PARAMETER(balanced.rgb, range_minimum, range_divider); + result.r = texture(curve_map, vec2(parameters.x, layer)).a; + result.g = texture(curve_map, vec2(parameters.y, layer)).a; + result.b = texture(curve_map, vec2(parameters.z, layer)).a; + + /* Then, extrapolate if needed. */ + result.rgb = extrapolate_if_needed(parameters, result.rgb, vec3(start_slope), vec3(end_slope)); + result.a = color.a; + + result = mix(color, result, factor); +} + +void curves_vector(vec3 vector, + sampler1DArray curve_map, + const float layer, + vec3 range_minimums, + vec3 range_dividers, + vec3 start_slopes, + vec3 end_slopes, + out vec3 result) +{ + /* Evaluate each component on its curve map. */ + vec3 parameters = NORMALIZE_PARAMETER(vector, range_minimums, range_dividers); + result.x = texture(curve_map, vec2(parameters.x, layer)).x; + result.y = texture(curve_map, vec2(parameters.y, layer)).y; + result.z = texture(curve_map, vec2(parameters.z, layer)).z; + + /* Then, extrapolate if needed. */ + result = extrapolate_if_needed(parameters, result, start_slopes, end_slopes); +} + +void curves_vector_mixed(float factor, + vec3 vector, + sampler1DArray curve_map, + const float layer, + vec3 range_minimums, + vec3 range_dividers, + vec3 start_slopes, + vec3 end_slopes, + out vec3 result) +{ + curves_vector( + vector, curve_map, layer, range_minimums, range_dividers, start_slopes, end_slopes, result); + result = mix(vector, result, factor); +} + +void curves_float(float value, + sampler1DArray curve_map, + const float layer, + float range_minimum, + float range_divider, + float start_slope, + float end_slope, + out float result) +{ + /* Evaluate the normalized value on the first curve map. */ + float parameter = NORMALIZE_PARAMETER(value, range_minimum, range_divider); + result = texture(curve_map, vec2(parameter, layer)).x; + + /* Then, extrapolate if needed. */ + result = extrapolate_if_needed(parameter, result, start_slope, end_slope); +} + +void curves_float_mixed(float factor, + float value, + sampler1DArray curve_map, + const float layer, + float range_minimum, + float range_divider, + float start_slope, + float end_slope, + out float result) +{ + curves_float( + value, curve_map, layer, range_minimum, range_divider, start_slope, end_slope, result); + result = mix(value, result, factor); +} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl deleted file mode 100644 index 514409f7fdf..00000000000 --- a/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl +++ /dev/null @@ -1,33 +0,0 @@ -/* ext is vec4(in_x, in_dy, out_x, out_dy). */ -float curve_float_extrapolate(float x, float y, vec4 ext) -{ - if (x < 0.0) { - return y + x * ext.y; - } - else if (x > 1.0) { - return y + (x - 1.0) * ext.w; - } - else { - return y; - } -} - -#define RANGE_RESCALE(x, min, range) ((x - min) * range) - -void curve_float(float fac, - float vec, - sampler1DArray curvemap, - float layer, - float range, - vec4 ext, - out float outvec) -{ - float xyz_min = ext.x; - vec = RANGE_RESCALE(vec, xyz_min, range); - - outvec = texture(curvemap, vec2(vec, layer)).x; - - outvec = curve_float_extrapolate(vec, outvec, ext); - - outvec = mix(vec, outvec, fac); -} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl deleted file mode 100644 index 054fdddf7c3..00000000000 --- a/source/blender/gpu/shaders/material/gpu_shader_material_rgb_curves.glsl +++ /dev/null @@ -1,73 +0,0 @@ -/* ext is vec4(in_x, in_dy, out_x, out_dy). */ -float curve_extrapolate(float x, float y, vec4 ext) -{ - if (x < 0.0) { - return y + x * ext.y; - } - else if (x > 1.0) { - return y + (x - 1.0) * ext.w; - } - else { - return y; - } -} - -#define RANGE_RESCALE(x, min, range) ((x - min) * range) - -void curves_rgb(float fac, - vec4 col, - sampler1DArray curvemap, - float layer, - vec4 range, - vec4 ext_r, - vec4 ext_g, - vec4 ext_b, - vec4 ext_a, - out vec4 outcol) -{ - vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer); - vec3 samp; - samp.r = texture(curvemap, co.xw).a; - samp.g = texture(curvemap, co.yw).a; - samp.b = texture(curvemap, co.zw).a; - - samp.r = curve_extrapolate(co.x, samp.r, ext_a); - samp.g = curve_extrapolate(co.y, samp.g, ext_a); - samp.b = curve_extrapolate(co.z, samp.b, ext_a); - - vec3 rgb_min = vec3(ext_r.x, ext_g.x, ext_b.x); - co.xyz = RANGE_RESCALE(samp.rgb, rgb_min, range.rgb); - - samp.r = texture(curvemap, co.xw).r; - samp.g = texture(curvemap, co.yw).g; - samp.b = texture(curvemap, co.zw).b; - - outcol.r = curve_extrapolate(co.x, samp.r, ext_r); - outcol.g = curve_extrapolate(co.y, samp.g, ext_g); - outcol.b = curve_extrapolate(co.z, samp.b, ext_b); - outcol.a = col.a; - - outcol = mix(col, outcol, fac); -} - -void curves_rgb_opti(float fac, - vec4 col, - sampler1DArray curvemap, - float layer, - vec4 range, - vec4 ext_a, - out vec4 outcol) -{ - vec4 co = vec4(RANGE_RESCALE(col.rgb, ext_a.x, range.a), layer); - vec3 samp; - samp.r = texture(curvemap, co.xw).a; - samp.g = texture(curvemap, co.yw).a; - samp.b = texture(curvemap, co.zw).a; - - outcol.r = curve_extrapolate(co.x, samp.r, ext_a); - outcol.g = curve_extrapolate(co.y, samp.g, ext_a); - outcol.b = curve_extrapolate(co.z, samp.b, ext_a); - outcol.a = col.a; - - outcol = mix(col, outcol, fac); -} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl deleted file mode 100644 index f6dec1b24e2..00000000000 --- a/source/blender/gpu/shaders/material/gpu_shader_material_vector_curves.glsl +++ /dev/null @@ -1,41 +0,0 @@ -/* ext is vec4(in_x, in_dy, out_x, out_dy). */ -float curve_vec_extrapolate(float x, float y, vec4 ext) -{ - if (x < 0.0) { - return y + x * ext.y; - } - else if (x > 1.0) { - return y + (x - 1.0) * ext.w; - } - else { - return y; - } -} - -#define RANGE_RESCALE(x, min, range) ((x - min) * range) - -void curves_vec(float fac, - vec3 vec, - sampler1DArray curvemap, - float layer, - vec3 range, - vec4 ext_x, - vec4 ext_y, - vec4 ext_z, - out vec3 outvec) -{ - vec4 co = vec4(vec, layer); - - vec3 xyz_min = vec3(ext_x.x, ext_y.x, ext_z.x); - co.xyz = RANGE_RESCALE(co.xyz, xyz_min, range); - - outvec.x = texture(curvemap, co.xw).x; - outvec.y = texture(curvemap, co.yw).y; - outvec.z = texture(curvemap, co.zw).z; - - outvec.x = curve_vec_extrapolate(co.x, outvec.r, ext_x); - outvec.y = curve_vec_extrapolate(co.y, outvec.g, ext_y); - outvec.z = curve_vec_extrapolate(co.z, outvec.b, ext_z); - - outvec = mix(vec, outvec, fac); -} diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index b1db0248d9f..eb47059063d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -28,48 +28,34 @@ static int gpu_shader_curve_vec(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - float *array, layer; - int size; + CurveMapping *curve_mapping = (CurveMapping *)node->storage; - CurveMapping *cumap = (CurveMapping *)node->storage; + BKE_curvemapping_init(curve_mapping); + float *band_values; + int band_size; + BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size); + float band_layer; + GPUNodeLink *band_texture = GPU_color_band(mat, band_size, band_values, &band_layer); - BKE_curvemapping_init(cumap); - BKE_curvemapping_table_RGBA(cumap, &array, &size); - GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer); - - float ext_xyz[3][4]; - float range_xyz[3]; - - for (int a = 0; a < 3; a++) { - const CurveMap *cm = &cumap->cm[a]; - ext_xyz[a][0] = cm->mintable; - ext_xyz[a][2] = cm->maxtable; - range_xyz[a] = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable); - /* Compute extrapolation gradients. */ - if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) { - ext_xyz[a][1] = (cm->ext_in[0] != 0.0f) ? (cm->ext_in[1] / (cm->ext_in[0] * range_xyz[a])) : - 1e8f; - ext_xyz[a][3] = (cm->ext_out[0] != 0.0f) ? - (cm->ext_out[1] / (cm->ext_out[0] * range_xyz[a])) : - 1e8f; - } - else { - ext_xyz[a][1] = 0.0f; - ext_xyz[a][3] = 0.0f; - } - } + float start_slopes[CM_TOT]; + float end_slopes[CM_TOT]; + BKE_curvemapping_compute_slopes(curve_mapping, start_slopes, end_slopes); + float range_minimums[CM_TOT]; + BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums); + float range_dividers[CM_TOT]; + BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers); return GPU_stack_link(mat, node, - "curves_vec", + "curves_vector_mixed", in, out, - tex, - GPU_constant(&layer), - GPU_uniform(range_xyz), - GPU_uniform(ext_xyz[0]), - GPU_uniform(ext_xyz[1]), - GPU_uniform(ext_xyz[2])); + band_texture, + GPU_constant(&band_layer), + GPU_uniform(range_minimums), + GPU_uniform(range_dividers), + GPU_uniform(start_slopes), + GPU_uniform(end_slopes)); } class CurveVecFunction : public fn::MultiFunction { @@ -157,72 +143,59 @@ static int gpu_shader_curve_rgb(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - float *array, layer; - int size; - bool use_opti = true; + CurveMapping *curve_mapping = (CurveMapping *)node->storage; - CurveMapping *cumap = (CurveMapping *)node->storage; + BKE_curvemapping_init(curve_mapping); + float *band_values; + int band_size; + BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size); + float band_layer; + GPUNodeLink *band_texture = GPU_color_band(mat, band_size, band_values, &band_layer); - BKE_curvemapping_init(cumap); - BKE_curvemapping_table_RGBA(cumap, &array, &size); - GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer); + float start_slopes[CM_TOT]; + float end_slopes[CM_TOT]; + BKE_curvemapping_compute_slopes(curve_mapping, start_slopes, end_slopes); + float range_minimums[CM_TOT]; + BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums); + float range_dividers[CM_TOT]; + BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers); - float ext_rgba[4][4]; - float range_rgba[4]; + /* Shader nodes don't do white balancing. */ + float black_level[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + float white_level[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - for (int a = 0; a < CM_TOT; a++) { - const CurveMap *cm = &cumap->cm[a]; - ext_rgba[a][0] = cm->mintable; - ext_rgba[a][2] = cm->maxtable; - range_rgba[a] = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable); - /* Compute extrapolation gradients. */ - if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) { - ext_rgba[a][1] = (cm->ext_in[0] != 0.0f) ? - (cm->ext_in[1] / (cm->ext_in[0] * range_rgba[a])) : - 1e8f; - ext_rgba[a][3] = (cm->ext_out[0] != 0.0f) ? - (cm->ext_out[1] / (cm->ext_out[0] * range_rgba[a])) : - 1e8f; - } - else { - ext_rgba[a][1] = 0.0f; - ext_rgba[a][3] = 0.0f; - } - - /* Check if rgb comps are just linear. */ - if (a < 3) { - if (range_rgba[a] != 1.0f || ext_rgba[a][1] != 1.0f || ext_rgba[a][2] != 1.0f || - cm->totpoint != 2 || cm->curve[0].x != 0.0f || cm->curve[0].y != 0.0f || - cm->curve[1].x != 1.0f || cm->curve[1].y != 1.0f) { - use_opti = false; - } - } - } - - if (use_opti) { + /* If the RGB curves do nothing, use a function that skips RGB computations. */ + if (BKE_curvemapping_is_map_identity(curve_mapping, 0) && + BKE_curvemapping_is_map_identity(curve_mapping, 1) && + BKE_curvemapping_is_map_identity(curve_mapping, 2)) { return GPU_stack_link(mat, node, - "curves_rgb_opti", + "curves_combined_only", in, out, - tex, - GPU_constant(&layer), - GPU_uniform(range_rgba), - GPU_uniform(ext_rgba[3])); + GPU_constant(black_level), + GPU_constant(white_level), + band_texture, + GPU_constant(&band_layer), + GPU_uniform(&range_minimums[3]), + GPU_uniform(&range_dividers[3]), + GPU_uniform(&start_slopes[3]), + GPU_uniform(&end_slopes[3])); } return GPU_stack_link(mat, node, - "curves_rgb", + "curves_combined_rgb", in, out, - tex, - GPU_constant(&layer), - GPU_uniform(range_rgba), - GPU_uniform(ext_rgba[0]), - GPU_uniform(ext_rgba[1]), - GPU_uniform(ext_rgba[2]), - GPU_uniform(ext_rgba[3])); + GPU_constant(black_level), + GPU_constant(white_level), + band_texture, + GPU_constant(&band_layer), + GPU_uniform(range_minimums), + GPU_uniform(range_dividers), + GPU_uniform(start_slopes), + GPU_uniform(end_slopes)); } class CurveRGBFunction : public fn::MultiFunction { @@ -316,40 +289,34 @@ static int gpu_shader_curve_float(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - float *array, layer; - int size; + CurveMapping *curve_mapping = (CurveMapping *)node->storage; - CurveMapping *cumap = (CurveMapping *)node->storage; + BKE_curvemapping_init(curve_mapping); + float *band_values; + int band_size; + BKE_curvemapping_table_RGBA(curve_mapping, &band_values, &band_size); + float band_layer; + GPUNodeLink *band_texture = GPU_color_band(mat, band_size, band_values, &band_layer); - BKE_curvemapping_init(cumap); - BKE_curvemapping_table_F(cumap, &array, &size); - GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer); + float start_slopes[CM_TOT]; + float end_slopes[CM_TOT]; + BKE_curvemapping_compute_slopes(curve_mapping, start_slopes, end_slopes); + float range_minimums[CM_TOT]; + BKE_curvemapping_get_range_minimums(curve_mapping, range_minimums); + float range_dividers[CM_TOT]; + BKE_curvemapping_compute_range_dividers(curve_mapping, range_dividers); - float ext_xyz[4]; - float range_x; - - const CurveMap *cm = &cumap->cm[0]; - ext_xyz[0] = cm->mintable; - ext_xyz[2] = cm->maxtable; - range_x = 1.0f / max_ff(1e-8f, cm->maxtable - cm->mintable); - /* Compute extrapolation gradients. */ - if ((cumap->flag & CUMA_EXTEND_EXTRAPOLATE) != 0) { - ext_xyz[1] = (cm->ext_in[0] != 0.0f) ? (cm->ext_in[1] / (cm->ext_in[0] * range_x)) : 1e8f; - ext_xyz[3] = (cm->ext_out[0] != 0.0f) ? (cm->ext_out[1] / (cm->ext_out[0] * range_x)) : 1e8f; - } - else { - ext_xyz[1] = 0.0f; - ext_xyz[3] = 0.0f; - } return GPU_stack_link(mat, node, - "curve_float", + "curves_float_mixed", in, out, - tex, - GPU_constant(&layer), - GPU_uniform(&range_x), - GPU_uniform(ext_xyz)); + band_texture, + GPU_constant(&band_layer), + GPU_uniform(range_minimums), + GPU_uniform(range_dividers), + GPU_uniform(start_slopes), + GPU_uniform(end_slopes)); } class CurveFloatFunction : public fn::MultiFunction {