diff --git a/doc/classes/VisualShaderNodeRotationByAxis.xml b/doc/classes/VisualShaderNodeRotationByAxis.xml new file mode 100644 index 00000000000..8a4fbc89d8e --- /dev/null +++ b/doc/classes/VisualShaderNodeRotationByAxis.xml @@ -0,0 +1,11 @@ + + + + A visual shader node that modifies the rotation of the object using a rotation matrix. + + + RotationByAxis node will transform the vertices of a mesh with specified axis and angle in radians. It can be used to rotate an object in an arbitrary axis. + + + + diff --git a/doc/classes/VisualShaderNodeScreenNormalWorldSpace.xml b/doc/classes/VisualShaderNodeScreenNormalWorldSpace.xml new file mode 100644 index 00000000000..ccffb621382 --- /dev/null +++ b/doc/classes/VisualShaderNodeScreenNormalWorldSpace.xml @@ -0,0 +1,11 @@ + + + + A visual shader node that unpacks the screen normal texture in World Space. + + + The ScreenNormalWorldSpace node allows to create outline effects. + + + + diff --git a/doc/classes/VisualShaderNodeWorldPositionFromDepth.xml b/doc/classes/VisualShaderNodeWorldPositionFromDepth.xml new file mode 100644 index 00000000000..9c9016e8898 --- /dev/null +++ b/doc/classes/VisualShaderNodeWorldPositionFromDepth.xml @@ -0,0 +1,11 @@ + + + + A visual shader node that calculates the position of the pixel in world space using the depth texture. + + + The WorldPositionFromDepth node reconstructs the depth position of the pixel in world space. This can be used to obtain world space UVs for projection mapping like Caustics. + + + + diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index f667ffeaa8a..30620590017 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -5875,6 +5875,10 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("CurveXYZTexture", "Textures/Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D)); add_options.push_back(AddOption("LinearSceneDepth", "Textures/Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value obtained from the depth prepass in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); texture2d_node_option_idx = add_options.size(); + add_options.push_back(AddOption("WorldPositionFromDepth", "Textures/Functions", "VisualShaderNodeWorldPositionFromDepth", TTR("Reconstructs the World Position of the Node from the depth texture."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + texture2d_node_option_idx = add_options.size(); + add_options.push_back(AddOption("ScreenNormalWorldSpace", "Textures/Functions", "VisualShaderNodeScreenNormalWorldSpace", TTR("Unpacks the Screen Normal Texture in World Space"), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + texture2d_node_option_idx = add_options.size(); add_options.push_back(AddOption("Texture2D", "Textures/Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D)); texture2d_array_node_option_idx = add_options.size(); add_options.push_back(AddOption("Texture2DArray", "Textures/Functions", "VisualShaderNodeTexture2DArray", TTR("Perform the 2D-array texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D)); @@ -5919,6 +5923,8 @@ VisualShaderEditor::VisualShaderEditor() { 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("Rotates an input vector by a given angle."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("RotationByAxis", "Utility", "VisualShaderNodeRotationByAxis", TTR("Rotates an input vector by a given angle."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); // VECTOR diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 1c2ed16e63c..803afcf9f8d 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -675,6 +675,8 @@ void register_scene_types() { GDREGISTER_CLASS(VisualShaderNodeTexture3DParameter); GDREGISTER_CLASS(VisualShaderNodeCubemapParameter); GDREGISTER_CLASS(VisualShaderNodeLinearSceneDepth); + GDREGISTER_CLASS(VisualShaderNodeWorldPositionFromDepth); + GDREGISTER_CLASS(VisualShaderNodeScreenNormalWorldSpace); GDREGISTER_CLASS(VisualShaderNodeIf); GDREGISTER_CLASS(VisualShaderNodeSwitch); GDREGISTER_CLASS(VisualShaderNodeFresnel); @@ -688,6 +690,7 @@ void register_scene_types() { GDREGISTER_CLASS(VisualShaderNodeProximityFade); GDREGISTER_CLASS(VisualShaderNodeRandomRange); GDREGISTER_CLASS(VisualShaderNodeRemap); + GDREGISTER_CLASS(VisualShaderNodeRotationByAxis); GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeVarying); GDREGISTER_CLASS(VisualShaderNodeVaryingSetter); GDREGISTER_CLASS(VisualShaderNodeVaryingGetter); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index 9d568957202..4023de9023c 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -1727,6 +1727,135 @@ VisualShaderNodeLinearSceneDepth::VisualShaderNodeLinearSceneDepth() { simple_decl = false; } +////////////// World Position from Depth + +String VisualShaderNodeWorldPositionFromDepth::get_caption() const { + return "WorldPositionFromDepth"; +} + +int VisualShaderNodeWorldPositionFromDepth::get_input_port_count() const { + return 1; +} + +VisualShaderNodeWorldPositionFromDepth::PortType VisualShaderNodeWorldPositionFromDepth::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR_2D; +} + +String VisualShaderNodeWorldPositionFromDepth::get_input_port_name(int p_port) const { + return "screen uv"; +} + +bool VisualShaderNodeWorldPositionFromDepth::is_input_port_default(int p_port, Shader::Mode p_mode) const { + if (p_port == 0) { + return true; + } + return false; +} + +int VisualShaderNodeWorldPositionFromDepth::get_output_port_count() const { + return 1; +} + +VisualShaderNodeWorldPositionFromDepth::PortType VisualShaderNodeWorldPositionFromDepth::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR_3D; +} + +String VisualShaderNodeWorldPositionFromDepth::get_output_port_name(int p_port) const { + return "world position"; +} + +bool VisualShaderNodeWorldPositionFromDepth::has_output_port_preview(int p_port) const { + return false; +} + +String VisualShaderNodeWorldPositionFromDepth::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform sampler2D " + make_unique_id(p_type, p_id, "depth_tex") + " : hint_depth_texture, repeat_disable, filter_nearest;\n"; +} + +String VisualShaderNodeWorldPositionFromDepth::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; + String uv = p_input_vars[0].is_empty() ? "SCREEN_UV" : p_input_vars[0]; + code += " {\n"; + + code += " float __log_depth = textureLod(" + make_unique_id(p_type, p_id, "depth_tex") + ", " + uv + ", 0.0).x;\n"; + if (!RenderingServer::get_singleton()->is_low_end()) { + code += " vec4 __depth_view = INV_PROJECTION_MATRIX * vec4(" + uv + " * 2.0 - 1.0, __log_depth, 1.0);\n"; + } else { + code += " vec4 __depth_view = INV_PROJECTION_MATRIX * vec4(vec3(" + uv + ", __log_depth) * 2.0 - 1.0, 1.0);\n"; + } + code += " __depth_view.xyz /= __depth_view.w;\n"; + code += vformat(" %s = (INV_VIEW_MATRIX * __depth_view).xyz;\n", p_output_vars[0]); + + code += " }\n"; + return code; +} + +VisualShaderNodeWorldPositionFromDepth::VisualShaderNodeWorldPositionFromDepth() { + simple_decl = false; +} + +////////////// Unpack Normals in World Space + +String VisualShaderNodeScreenNormalWorldSpace::get_caption() const { + return "ScreenNormalWorldSpace"; +} + +int VisualShaderNodeScreenNormalWorldSpace::get_input_port_count() const { + return 1; +} + +VisualShaderNodeScreenNormalWorldSpace::PortType VisualShaderNodeScreenNormalWorldSpace::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR_2D; +} + +String VisualShaderNodeScreenNormalWorldSpace::get_input_port_name(int p_port) const { + return "screen uv"; +} + +bool VisualShaderNodeScreenNormalWorldSpace::is_input_port_default(int p_port, Shader::Mode p_mode) const { + if (p_port == 0) { + return true; + } + return false; +} + +int VisualShaderNodeScreenNormalWorldSpace::get_output_port_count() const { + return 1; +} + +VisualShaderNodeScreenNormalWorldSpace::PortType VisualShaderNodeScreenNormalWorldSpace::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR_3D; +} + +String VisualShaderNodeScreenNormalWorldSpace::get_output_port_name(int p_port) const { + return "screen normal"; +} + +bool VisualShaderNodeScreenNormalWorldSpace::has_output_port_preview(int p_port) const { + return false; +} + +String VisualShaderNodeScreenNormalWorldSpace::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const { + return "uniform sampler2D " + make_unique_id(p_type, p_id, "normal_rough_tex") + " : hint_normal_roughness_texture, repeat_disable, filter_nearest;\n"; +} + +String VisualShaderNodeScreenNormalWorldSpace::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; + String uv = p_input_vars[0].is_empty() ? "SCREEN_UV" : p_input_vars[0]; + code += " {\n"; + + code += " vec3 __normals = textureLod(" + make_unique_id(p_type, p_id, "normal_rough_tex") + ", " + uv + ", 0.0).xyz;\n"; + code += " __normals = __normals * 2.0 - 1.0;\n"; + code += vformat(" %s = mat3(INV_VIEW_MATRIX) * __normals;\n", p_output_vars[0]); + + code += " }\n"; + return code; +} + +VisualShaderNodeScreenNormalWorldSpace::VisualShaderNodeScreenNormalWorldSpace() { + simple_decl = false; +} + ////////////// Float Op String VisualShaderNodeFloatOp::get_caption() const { @@ -7971,3 +8100,100 @@ VisualShaderNodeRemap::VisualShaderNodeRemap() { simple_decl = false; } + +////////////// RotationByAxis + +String VisualShaderNodeRotationByAxis::get_caption() const { + return "RotationByAxis"; +} + +int VisualShaderNodeRotationByAxis::get_input_port_count() const { + return 3; +} + +VisualShaderNodeRotationByAxis::PortType VisualShaderNodeRotationByAxis::get_input_port_type(int p_port) const { + switch (p_port) { + case 0: + return PORT_TYPE_VECTOR_3D; + case 1: + return PORT_TYPE_SCALAR; + case 2: + return PORT_TYPE_VECTOR_3D; + default: + break; + } + + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeRotationByAxis::get_input_port_name(int p_port) const { + switch (p_port) { + case 0: + return "input"; + case 1: + return "angle"; + case 2: + return "axis"; + default: + break; + } + + return ""; +} + +int VisualShaderNodeRotationByAxis::get_output_port_count() const { + return 2; +} + +VisualShaderNodeRotationByAxis::PortType VisualShaderNodeRotationByAxis::get_output_port_type(int p_port) const { + switch (p_port) { + case 0: + return PORT_TYPE_VECTOR_3D; + case 1: + return PORT_TYPE_TRANSFORM; + default: + break; + } + + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeRotationByAxis::get_output_port_name(int p_port) const { + switch (p_port) { + case 0: + return "output"; + case 1: + return "rotationMat"; + default: + break; + } + + return ""; +} + +bool VisualShaderNodeRotationByAxis::has_output_port_preview(int p_port) const { + return false; +} + +String VisualShaderNodeRotationByAxis::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 __angle = %s;\n", p_input_vars[1]); + code += vformat(" vec3 __axis = normalize(%s);\n", p_input_vars[2]); + code += vformat(" mat3 __rot_matrix = mat3(\n"); + code += vformat(" vec3( cos(__angle)+__axis.x*__axis.x*(1.0 - cos(__angle)), __axis.x*__axis.y*(1.0-cos(__angle))-__axis.z*sin(__angle), __axis.x*__axis.z*(1.0-cos(__angle))+__axis.y*sin(__angle) ),\n"); + code += vformat(" vec3( __axis.y*__axis.x*(1.0-cos(__angle))+__axis.z*sin(__angle), cos(__angle)+__axis.y*__axis.y*(1.0-cos(__angle)), __axis.y*__axis.z*(1.0-cos(__angle))-__axis.x*sin(__angle) ),\n"); + code += vformat(" vec3( __axis.z*__axis.x*(1.0-cos(__angle))-__axis.y*sin(__angle), __axis.z*__axis.y*(1.0-cos(__angle))+__axis.x*sin(__angle), cos(__angle)+__axis.z*__axis.z*(1.0-cos(__angle)) )\n"); + code += vformat(" );\n"); + code += vformat(" %s = %s * __rot_matrix;\n", p_output_vars[0], p_input_vars[0]); + code += vformat(" %s = mat4(__rot_matrix);\n", p_output_vars[1]); + code += " }\n"; + return code; +} + +VisualShaderNodeRotationByAxis::VisualShaderNodeRotationByAxis() { + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); + + simple_decl = false; +} diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 4973db0a220..97d8df3c0b8 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -680,6 +680,50 @@ public: VisualShaderNodeLinearSceneDepth(); }; +class VisualShaderNodeWorldPositionFromDepth : public VisualShaderNode { + GDCLASS(VisualShaderNodeWorldPositionFromDepth, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) 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; + + VisualShaderNodeWorldPositionFromDepth(); +}; + +class VisualShaderNodeScreenNormalWorldSpace : public VisualShaderNode { + GDCLASS(VisualShaderNodeScreenNormalWorldSpace, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) const override; + + virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) 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; + + VisualShaderNodeScreenNormalWorldSpace(); +}; + /////////////////////////////////////// /// OPS /////////////////////////////////////// @@ -2913,4 +2957,24 @@ public: VisualShaderNodeRemap(); }; +class VisualShaderNodeRotationByAxis : public VisualShaderNode { + GDCLASS(VisualShaderNodeRotationByAxis, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + virtual bool has_output_port_preview(int p_port) 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; + + VisualShaderNodeRotationByAxis(); +}; + #endif // VISUAL_SHADER_NODES_H