From be70827e6f62763d524f00652f61da6fc86e2714 Mon Sep 17 00:00:00 2001 From: Charlie Jolly Date: Thu, 30 Sep 2021 19:05:08 +0100 Subject: Nodes: Add Float Curve for GN and Shader nodes. Replacement for float curve in legacy Attribute Curve Map node. Float Curve defaults to [0.0-1.0] range. Reviewed By: JacquesLucke, brecht Differential Revision: https://developer.blender.org/D12683 --- source/blender/blenkernel/BKE_colortools.h | 1 + source/blender/blenkernel/BKE_node.h | 1 + source/blender/blenkernel/intern/colortools.c | 14 +++ source/blender/blenkernel/intern/node.cc | 4 +- source/blender/editors/space_node/drawnode.cc | 8 ++ source/blender/gpu/CMakeLists.txt | 1 + source/blender/gpu/intern/gpu_material_library.c | 7 ++ .../material/gpu_shader_material_float_curve.glsl | 33 +++++ source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_nodetree.c | 11 ++ source/blender/nodes/NOD_shader.h | 1 + source/blender/nodes/NOD_static_types.h | 1 + .../nodes/shader/nodes/node_shader_curves.cc | 139 +++++++++++++++++++++ 13 files changed, 221 insertions(+), 1 deletion(-) create mode 100644 source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl (limited to 'source') diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h index ec2262d4f60..109947cece4 100644 --- a/source/blender/blenkernel/BKE_colortools.h +++ b/source/blender/blenkernel/BKE_colortools.h @@ -97,6 +97,7 @@ void BKE_curvemapping_evaluate_premulRGBF(const struct CurveMapping *cumap, float vecout[3], const float vecin[3]); 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); /* non-const, these modify the curve */ diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 76a3e75d285..a4fc4800fd2 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1102,6 +1102,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, #define SH_NODE_VERTEX_COLOR 706 #define SH_NODE_OUTPUT_AOV 707 #define SH_NODE_VECTOR_ROTATE 708 +#define SH_NODE_CURVE_FLOAT 709 /* custom defines options for Material node */ // #define SH_NODE_MAT_DIFF 1 diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index f2c2e552a9f..62b817487fc 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -1212,6 +1212,20 @@ void BKE_curvemapping_init(CurveMapping *cumap) } } +void BKE_curvemapping_table_F(const CurveMapping *cumap, float **array, int *size) +{ + int a; + + *size = CM_TABLE + 1; + *array = MEM_callocN(sizeof(float) * (*size) * 4, "CurveMapping"); + + for (a = 0; a < *size; a++) { + if (cumap->cm[0].table) { + (*array)[a * 4 + 0] = cumap->cm[0].table[a].y; + } + } +} + void BKE_curvemapping_table_RGBA(const CurveMapping *cumap, float **array, int *size) { int a; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index a3a82bee8dc..66f917ffd96 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -538,7 +538,7 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) if (node->storage) { /* could be handlerized at some point, now only 1 exception still */ if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) && - ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) { + ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) { BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); } else if ((ntree->type == NTREE_GEOMETRY) && @@ -714,6 +714,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) switch (node->type) { case SH_NODE_CURVE_VEC: case SH_NODE_CURVE_RGB: + case SH_NODE_CURVE_FLOAT: case CMP_NODE_TIME: case CMP_NODE_CURVE_VEC: case CMP_NODE_CURVE_RGB: @@ -5574,6 +5575,7 @@ static void registerShaderNodes() register_node_type_sh_shadertorgb(); register_node_type_sh_normal(); register_node_type_sh_mapping(); + register_node_type_sh_curve_float(); register_node_type_sh_curve_vec(); register_node_type_sh_curve_rgb(); register_node_type_sh_map_range(); diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index b4a9b90434c..8d6d56fc383 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -164,6 +164,11 @@ static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false, false); } +static void node_buts_curvefloat(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiTemplateCurveMapping(layout, ptr, "mapping", 0, false, false, false, false); +} + #define SAMPLE_FLT_ISNONE FLT_MAX /* Bad bad, 2.5 will do better? ... no it won't! */ static float _sample_col[4] = {SAMPLE_FLT_ISNONE}; @@ -1183,6 +1188,9 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_CURVE_RGB: ntype->draw_buttons = node_buts_curvecol; break; + case SH_NODE_CURVE_FLOAT: + ntype->draw_buttons = node_buts_curvefloat; + break; case SH_NODE_MAPPING: ntype->draw_buttons = node_shader_buts_mapping; break; diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index df370c7079b..7a072900473 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -296,6 +296,7 @@ data_to_c_simple(shaders/material/gpu_shader_material_diffuse.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_displacement.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_eevee_specular.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_emission.glsl SRC) +data_to_c_simple(shaders/material/gpu_shader_material_float_curve.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_fractal_noise.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_fresnel.glsl SRC) data_to_c_simple(shaders/material/gpu_shader_material_gamma.glsl SRC) diff --git a/source/blender/gpu/intern/gpu_material_library.c b/source/blender/gpu/intern/gpu_material_library.c index 73a80c62bdc..74e0270c42a 100644 --- a/source/blender/gpu/intern/gpu_material_library.c +++ b/source/blender/gpu/intern/gpu_material_library.c @@ -62,6 +62,7 @@ extern char datatoc_gpu_shader_material_diffuse_glsl[]; extern char datatoc_gpu_shader_material_displacement_glsl[]; extern char datatoc_gpu_shader_material_eevee_specular_glsl[]; extern char datatoc_gpu_shader_material_emission_glsl[]; +extern char datatoc_gpu_shader_material_float_curve_glsl[]; extern char datatoc_gpu_shader_material_fractal_noise_glsl[]; extern char datatoc_gpu_shader_material_fresnel_glsl[]; extern char datatoc_gpu_shader_material_gamma_glsl[]; @@ -262,6 +263,11 @@ static GPUMaterialLibrary gpu_shader_material_emission_library = { .dependencies = {NULL}, }; +static GPUMaterialLibrary gpu_shader_material_float_curve_library = { + .code = datatoc_gpu_shader_material_float_curve_glsl, + .dependencies = {NULL}, +}; + static GPUMaterialLibrary gpu_shader_material_fresnel_library = { .code = datatoc_gpu_shader_material_fresnel_glsl, .dependencies = {NULL}, @@ -591,6 +597,7 @@ static GPUMaterialLibrary *gpu_material_libraries[] = { &gpu_shader_material_color_util_library, &gpu_shader_material_hash_library, &gpu_shader_material_noise_library, + &gpu_shader_material_float_curve_library, &gpu_shader_material_fractal_noise_library, &gpu_shader_material_add_shader_library, &gpu_shader_material_ambient_occlusion_library, 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 new file mode 100644 index 00000000000..514409f7fdf --- /dev/null +++ b/source/blender/gpu/shaders/material/gpu_shader_material_float_curve.glsl @@ -0,0 +1,33 @@ +/* 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/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index ce53e3390e1..188f933dba5 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -558,6 +558,7 @@ extern StructRNA RNA_ShaderFxWave; extern StructRNA RNA_ShaderNode; extern StructRNA RNA_ShaderNodeCameraData; extern StructRNA RNA_ShaderNodeCombineRGB; +extern StructRNA RNA_ShaderNodeFloatCurve; extern StructRNA RNA_ShaderNodeGamma; extern StructRNA RNA_ShaderNodeHueSaturation; extern StructRNA RNA_ShaderNodeInvert; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 8fb55d37375..894a8bad6da 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4900,6 +4900,17 @@ static void def_vector_curve(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_float_curve(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "mapping", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "storage"); + RNA_def_property_struct_type(prop, "CurveMapping"); + RNA_def_property_ui_text(prop, "Mapping", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_time(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 2911e0fbea6..76c174201e8 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -49,6 +49,7 @@ void register_node_type_sh_normal(void); void register_node_type_sh_gamma(void); void register_node_type_sh_brightcontrast(void); void register_node_type_sh_mapping(void); +void register_node_type_sh_curve_float(void); void register_node_type_sh_curve_vec(void); void register_node_type_sh_curve_rgb(void); void register_node_type_sh_map_range(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 3ee3faf6122..7972609aa27 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -132,6 +132,7 @@ DefNode(ShaderNode, SH_NODE_VECTOR_DISPLACEMENT,def_sh_vector_displacement," DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX_IES", TexIES, "IES Texture", "" ) DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "" ) DefNode(ShaderNode, SH_NODE_OUTPUT_AOV, def_sh_output_aov, "OUTPUT_AOV", OutputAOV, "AOV Output", "" ) +DefNode(ShaderNode, SH_NODE_CURVE_FLOAT, def_float_curve, "CURVE_FLOAT", FloatCurve, "Float Curve", "" ) DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" ) DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" ) diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index 887cc84bb76..253bb3cc4b6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -343,3 +343,142 @@ void register_node_type_sh_curve_rgb(void) nodeRegisterType(&ntype); } + +/* **************** CURVE FLOAT ******************** */ + +namespace blender::nodes { + +static void sh_node_curve_float_declare(NodeDeclarationBuilder &b) +{ + b.add_input("Factor").min(0.0f).max(1.0f).default_value(1.0f).subtype(PROP_FACTOR); + b.add_input("Value").default_value(1.0f); + b.add_output("Value"); +}; + +} // namespace blender::nodes + +static void node_shader_exec_curve_float(void *UNUSED(data), + int UNUSED(thread), + bNode *node, + bNodeExecData *UNUSED(execdata), + bNodeStack **in, + bNodeStack **out) +{ + float value; + float fac; + + nodestack_get_vec(&fac, SOCK_FLOAT, in[0]); + nodestack_get_vec(&value, SOCK_FLOAT, in[1]); + out[0]->vec[0] = BKE_curvemapping_evaluateF((CurveMapping *)node->storage, 0, value); + if (fac != 1.0f) { + out[0]->vec[0] = (1.0f - fac) * value + fac * out[0]->vec[0]; + } +} + +static void node_shader_init_curve_float(bNodeTree *ntree, bNode *node) +{ + node->storage = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); +} + +static int gpu_shader_curve_float(GPUMaterial *mat, + bNode *node, + bNodeExecData *UNUSED(execdata), + GPUNodeStack *in, + GPUNodeStack *out) +{ + float *array, layer; + int size; + + CurveMapping *cumap = (CurveMapping *)node->storage; + + BKE_curvemapping_table_F(cumap, &array, &size); + GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer); + + 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", + in, + out, + tex, + GPU_constant(&layer), + GPU_uniform(&range_x), + GPU_uniform(ext_xyz)); +} + +class CurveFloatFunction : public blender::fn::MultiFunction { + private: + const CurveMapping &cumap_; + + public: + CurveFloatFunction(const CurveMapping &cumap) : cumap_(cumap) + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Curve Float"}; + signature.single_input("Factor"); + signature.single_input("Value"); + signature.single_output("Value"); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray &fac = params.readonly_single_input(0, "Factor"); + const blender::VArray &val_in = params.readonly_single_input(1, "Value"); + blender::MutableSpan val_out = params.uninitialized_single_output(2, "Value"); + + for (int64_t i : mask) { + val_out[i] = BKE_curvemapping_evaluateF(&cumap_, 0, val_in[i]); + if (fac[i] != 1.0f) { + val_out[i] = (1.0f - fac[i]) * val_in[i] + fac[i] * val_out[i]; + } + } + } +}; + +static void sh_node_curve_float_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) +{ + bNode &bnode = builder.node(); + CurveMapping *cumap = (CurveMapping *)bnode.storage; + BKE_curvemapping_init(cumap); + builder.construct_and_set_matching_fn(*cumap); +} + +void register_node_type_sh_curve_float(void) +{ + static bNodeType ntype; + + sh_fn_node_type_base(&ntype, SH_NODE_CURVE_FLOAT, "Float Curve", NODE_CLASS_CONVERTER, 0); + ntype.declare = blender::nodes::sh_node_curve_float_declare; + node_type_init(&ntype, node_shader_init_curve_float); + node_type_size_preset(&ntype, NODE_SIZE_LARGE); + node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); + node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_float); + node_type_gpu(&ntype, gpu_shader_curve_float); + ntype.build_multi_function = sh_node_curve_float_build_multi_function; + + nodeRegisterType(&ntype); +} -- cgit v1.2.3