From eb5a9c3b332e1709286068df0c888b5836c2cec5 Mon Sep 17 00:00:00 2001 From: tetrapod00 <145553014+tetrapod00@users.noreply.github.com> Date: Sat, 21 Sep 2024 17:22:51 -0700 Subject: [PATCH] Visual Shader: Add vector operations to Remap node --- doc/classes/VisualShaderNodeRemap.xml | 30 +++ .../plugins/visual_shader_editor_plugin.cpp | 18 +- scene/resources/visual_shader_nodes.cpp | 177 ++++++++++++++++-- scene/resources/visual_shader_nodes.h | 35 +++- 4 files changed, 243 insertions(+), 17 deletions(-) diff --git a/doc/classes/VisualShaderNodeRemap.xml b/doc/classes/VisualShaderNodeRemap.xml index 102672ff603..d4ecb2dd317 100644 --- a/doc/classes/VisualShaderNodeRemap.xml +++ b/doc/classes/VisualShaderNodeRemap.xml @@ -8,4 +8,34 @@ + + + + + + + A floating-point scalar type. + + + A 2D vector type. + + + The [code]value[/code] port uses a 2D vector type, while the [code]input min[/code], [code]input max[/code], [code]output min[/code], and [code]output max[/code] ports use a floating-point scalar type. + + + A 3D vector type. + + + The [code]value[/code] port uses a 3D vector type, while the [code]input min[/code], [code]input max[/code], [code]output min[/code], and [code]output max[/code] ports use a floating-point scalar type. + + + A 4D vector type. + + + The [code]value[/code] port uses a 4D vector type, while the [code]input min[/code], [code]input max[/code], [code]output min[/code], and [code]output max[/code] ports use a floating-point scalar type. + + + Represents the size of the [enum OpType] enum. + + diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index c378bf315bc..f98a30ebb3d 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -3600,6 +3600,16 @@ void VisualShaderEditor::_setup_node(VisualShaderNode *p_node, const Vectorset_op_type((VisualShaderNodeMultiplyAdd::OpType)(int)p_ops[0]); } } + + // REMAP + { + VisualShaderNodeRemap *remap_func = Object::cast_to(p_node); + + if (remap_func) { + ERR_FAIL_COND(p_ops[0].get_type() != Variant::INT); + remap_func->set_op_type((VisualShaderNodeRemap::OpType)(int)p_ops[0]); + } + } } void VisualShaderEditor::_add_node(int p_idx, const Vector &p_ops, const String &p_resource_path, int p_node_idx) { @@ -7089,6 +7099,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Pow", "Scalar/Functions", "VisualShaderNodeFloatOp", TTR("Returns the value of the first parameter raised to the power of the second."), { VisualShaderNodeFloatOp::OP_POW }, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Radians", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Converts a quantity in degrees to radians."), { VisualShaderNodeFloatFunc::FUNC_RADIANS }, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Reciprocal", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("1.0 / scalar"), { VisualShaderNodeFloatFunc::FUNC_RECIPROCAL }, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Remap", "Scalar/Functions", "VisualShaderNodeRemap", TTR("Remaps a value from the input range to the output range."), { VisualShaderNodeRemap::OP_TYPE_SCALAR }, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Round", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeFloatFunc::FUNC_ROUND }, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("RoundEven", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Finds the nearest even integer to the parameter."), { VisualShaderNodeFloatFunc::FUNC_ROUNDEVEN }, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Saturate", "Scalar/Functions", "VisualShaderNodeFloatFunc", TTR("Clamps the value between 0.0 and 1.0."), { VisualShaderNodeFloatFunc::FUNC_SATURATE }, VisualShaderNode::PORT_TYPE_SCALAR)); @@ -7206,7 +7217,6 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("DistanceFade", "Utility", "VisualShaderNodeDistanceFade", TTR("The distance fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("ProximityFade", "Utility", "VisualShaderNodeProximityFade", TTR("The proximity fade effect fades out each pixel based on its distance to another object."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("RandomRange", "Utility", "VisualShaderNodeRandomRange", TTR("Returns a random value between the minimum and maximum input values."), {}, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Remap", "Utility", "VisualShaderNodeRemap", TTR("Remaps a given input from the input range to the output range."), {}, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("RotationByAxis", "Utility", "VisualShaderNodeRotationByAxis", TTR("Builds a rotation matrix from the given axis and angle, multiply the input vector by it and returns both this vector and a matrix."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D)); // VECTOR @@ -7340,6 +7350,12 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_2D)); add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D)); add_options.push_back(AddOption("Refract", "Vector/Functions", "VisualShaderNodeVectorRefract", TTR("Returns the vector that points in the direction of refraction."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D)); + add_options.push_back(AddOption("Remap", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D)); + add_options.push_back(AddOption("Remap", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); + add_options.push_back(AddOption("Remap", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D)); + add_options.push_back(AddOption("RemapS", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range. Ranges defined with scalars."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_2D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_2D)); + add_options.push_back(AddOption("RemapS", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range. Ranges defined with scalars."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_3D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); + add_options.push_back(AddOption("RemapS", "Vector/Functions", "VisualShaderNodeRemap", TTR("Remaps a vector from the input range to the output range. Ranges defined with scalars."), { VisualShaderNodeRemap::OP_TYPE_VECTOR_4D_SCALAR }, VisualShaderNode::PORT_TYPE_VECTOR_4D)); add_options.push_back(AddOption("Round", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_2D }, VisualShaderNode::PORT_TYPE_VECTOR_2D)); add_options.push_back(AddOption("Round", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_3D }, VisualShaderNode::PORT_TYPE_VECTOR_3D)); add_options.push_back(AddOption("Round", "Vector/Functions", "VisualShaderNodeVectorFunc", TTR("Finds the nearest integer to the parameter."), { VisualShaderNodeVectorFunc::FUNC_ROUND, VisualShaderNodeVectorFunc::OP_TYPE_VECTOR_4D }, VisualShaderNode::PORT_TYPE_VECTOR_4D)); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 26666538af4..3db1ab93380 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -8081,17 +8081,28 @@ int VisualShaderNodeRemap::get_input_port_count() const { } VisualShaderNodeRemap::PortType VisualShaderNodeRemap::get_input_port_type(int p_port) const { - switch (p_port) { - case 0: - return PORT_TYPE_SCALAR; - case 1: - return PORT_TYPE_SCALAR; - case 2: - return PORT_TYPE_SCALAR; - case 3: - return PORT_TYPE_SCALAR; - case 4: - return PORT_TYPE_SCALAR; + switch (op_type) { + case OP_TYPE_VECTOR_2D: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_2D_SCALAR: + if (p_port == 0) { + return PORT_TYPE_VECTOR_2D; + } + break; + case OP_TYPE_VECTOR_3D: + return PORT_TYPE_VECTOR_3D; + case OP_TYPE_VECTOR_3D_SCALAR: + if (p_port == 0) { + return PORT_TYPE_VECTOR_3D; + } + break; + case OP_TYPE_VECTOR_4D: + return PORT_TYPE_VECTOR_4D; + case OP_TYPE_VECTOR_4D_SCALAR: + if (p_port == 0) { + return PORT_TYPE_VECTOR_4D; + } + break; default: break; } @@ -8123,23 +8134,159 @@ int VisualShaderNodeRemap::get_output_port_count() const { } VisualShaderNodeRemap::PortType VisualShaderNodeRemap::get_output_port_type(int p_port) const { - return PORT_TYPE_SCALAR; + switch (op_type) { + case OP_TYPE_VECTOR_2D: + case OP_TYPE_VECTOR_2D_SCALAR: + return PORT_TYPE_VECTOR_2D; + case OP_TYPE_VECTOR_3D: + case OP_TYPE_VECTOR_3D_SCALAR: + return PORT_TYPE_VECTOR_3D; + case OP_TYPE_VECTOR_4D: + case OP_TYPE_VECTOR_4D_SCALAR: + return PORT_TYPE_VECTOR_4D; + default: + return PORT_TYPE_SCALAR; + } } String VisualShaderNodeRemap::get_output_port_name(int p_port) const { return "value"; } +void VisualShaderNodeRemap::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX)); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: { + set_input_port_default_value(0, 0.0, get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 1.0, get_input_port_default_value(2)); + set_input_port_default_value(3, 0.0, get_input_port_default_value(3)); + set_input_port_default_value(4, 1.0, get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_2D: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector2(), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector2(1.0, 1.0), get_input_port_default_value(2)); + set_input_port_default_value(3, Vector2(), get_input_port_default_value(3)); + set_input_port_default_value(4, Vector2(1.0, 1.0), get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_2D_SCALAR: { + set_input_port_default_value(0, Vector2(), get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 1.0, get_input_port_default_value(2)); + set_input_port_default_value(3, 0.0, get_input_port_default_value(3)); + set_input_port_default_value(4, 1.0, get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_3D: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + set_input_port_default_value(1, Vector3(), get_input_port_default_value(1)); + set_input_port_default_value(2, Vector3(1.0, 1.0, 1.0), get_input_port_default_value(2)); + set_input_port_default_value(3, Vector3(), get_input_port_default_value(3)); + set_input_port_default_value(4, Vector3(1.0, 1.0, 1.0), get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_3D_SCALAR: { + set_input_port_default_value(0, Vector3(), get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 1.0, get_input_port_default_value(2)); + set_input_port_default_value(3, 0.0, get_input_port_default_value(3)); + set_input_port_default_value(4, 1.0, get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_4D: { + set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0)); + set_input_port_default_value(1, Quaternion(), get_input_port_default_value(1)); + set_input_port_default_value(2, Quaternion(1.0, 1.0, 1.0, 1.0), get_input_port_default_value(2)); + set_input_port_default_value(3, Quaternion(), get_input_port_default_value(3)); + set_input_port_default_value(4, Quaternion(1.0, 1.0, 1.0, 1.0), get_input_port_default_value(4)); + } break; + case OP_TYPE_VECTOR_4D_SCALAR: { + set_input_port_default_value(0, Quaternion(), get_input_port_default_value(0)); + set_input_port_default_value(1, 0.0, get_input_port_default_value(1)); + set_input_port_default_value(2, 1.0, get_input_port_default_value(2)); + set_input_port_default_value(3, 0.0, get_input_port_default_value(3)); + set_input_port_default_value(4, 1.0, get_input_port_default_value(4)); + } break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + +VisualShaderNodeRemap::OpType VisualShaderNodeRemap::get_op_type() const { + return op_type; +} + String VisualShaderNodeRemap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; code += " {\n"; - code += vformat(" float __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); - code += vformat(" float __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); - code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + switch (op_type) { + case OP_TYPE_SCALAR: { + code += vformat(" float __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" float __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_2D: { + code += vformat(" vec2 __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec2 __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_2D_SCALAR: { + code += vformat(" vec2 __input_range = vec2(%s - %s);\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec2 __output_range = vec2(%s - %s);\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = vec2(%s) + __output_range * ((%s - vec2(%s)) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_3D: { + code += vformat(" vec3 __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec3 __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_3D_SCALAR: { + code += vformat(" vec3 __input_range = vec3(%s - %s);\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec3 __output_range = vec3(%s - %s);\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = vec3(%s) + __output_range * ((%s - vec3(%s)) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_4D: { + code += vformat(" vec4 __input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec4 __output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = %s + __output_range * ((%s - %s) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + case OP_TYPE_VECTOR_4D_SCALAR: { + code += vformat(" vec4 __input_range = vec4(%s - %s);\n", p_input_vars[2], p_input_vars[1]); + code += vformat(" vec4 __output_range = vec4(%s - %s);\n", p_input_vars[4], p_input_vars[3]); + code += vformat(" %s = vec4(%s) + __output_range * ((%s - vec4(%s)) / __input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]); + } break; + default: + break; + } code += " }\n"; return code; } +Vector VisualShaderNodeRemap::get_editable_properties() const { + Vector props; + props.push_back("op_type"); + return props; +} + +void VisualShaderNodeRemap::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "op_type"), &VisualShaderNodeRemap::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeRemap::get_op_type); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector2,Vector2Scalar,Vector3,Vector3Scalar,Vector4,Vector4Scalar"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_2D_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_3D_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_4D_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); +} + VisualShaderNodeRemap::VisualShaderNodeRemap() { set_input_port_default_value(1, 0.0); set_input_port_default_value(2, 1.0); diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index ff02e55fb2c..67dc8f73537 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -3068,9 +3068,29 @@ public: VisualShaderNodeRandomRange(); }; +/////////////////////////////////////// +/// Remap +/////////////////////////////////////// + class VisualShaderNodeRemap : public VisualShaderNode { GDCLASS(VisualShaderNodeRemap, VisualShaderNode); +public: + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR_2D, + OP_TYPE_VECTOR_2D_SCALAR, + OP_TYPE_VECTOR_3D, + OP_TYPE_VECTOR_3D_SCALAR, + OP_TYPE_VECTOR_4D, + OP_TYPE_VECTOR_4D_SCALAR, + OP_TYPE_MAX, + }; + +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); + public: virtual String get_caption() const override; @@ -3082,13 +3102,26 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + void set_op_type(OpType p_op_type); + OpType get_op_type() const; + + virtual Vector get_editable_properties() const override; + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; - virtual Category get_category() const override { return CATEGORY_UTILITY; } + virtual Category get_category() const override { + if (op_type == OP_TYPE_SCALAR) { + return CATEGORY_SCALAR; + } else { + return CATEGORY_VECTOR; + } + } VisualShaderNodeRemap(); }; +VARIANT_ENUM_CAST(VisualShaderNodeRemap::OpType) + class VisualShaderNodeRotationByAxis : public VisualShaderNode { GDCLASS(VisualShaderNodeRotationByAxis, VisualShaderNode);