Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Billboard Node to Visual Shaders #49157

Merged
merged 1 commit into from
May 31, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions doc/classes/VisualShaderNodeBillboard.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeBillboard" inherits="VisualShaderNode" version="4.0">
<brief_description>
A node that controls how the object faces the camera to be used within the visual shader graph.
</brief_description>
<description>
The output port of this node needs to be connected to [code]Model View Matrix[/code] port of [VisualShaderNodeOutput].
</description>
<tutorials>
</tutorials>
<methods>
</methods>
<members>
<member name="billboard_type" type="int" setter="set_billboard_type" getter="get_billboard_type" enum="VisualShaderNodeBillboard.BillboardType" default="1">
Controls how the object faces the camera. See [enum BillboardType].
</member>
<member name="keep_scale" type="bool" setter="set_keep_scale_enabled" getter="is_keep_scale_enabled" default="false">
If [code]true[/code], the shader will keep the scale set for the mesh. Otherwise, the scale is lost when billboarding.
</member>
</members>
<constants>
<constant name="BILLBOARD_TYPE_DISABLED" value="0" enum="BillboardType">
Billboarding is disabled and the node does nothing.
</constant>
<constant name="BILLBOARD_TYPE_ENABLED" value="1" enum="BillboardType">
A standard billboarding algorithm is enabled.
</constant>
<constant name="BILLBOARD_TYPE_FIXED_Y" value="2" enum="BillboardType">
A billboarding algorithm to rotate around Y-axis is enabled.
</constant>
<constant name="BILLBOARD_TYPE_PARTICLES" value="3" enum="BillboardType">
A billboarding algorithm designed to use on particles is enabled.
</constant>
<constant name="BILLBOARD_TYPE_MAX" value="4" enum="BillboardType">
Represents the size of the [enum BillboardType] enum.
</constant>
</constants>
</class>
1 change: 1 addition & 0 deletions editor/plugins/visual_shader_editor_plugin.cpp
Original file line number Diff line number Diff line change
@@ -4260,6 +4260,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("TransformDecompose", "Transform", "Composition", "VisualShaderNodeTransformDecompose", TTR("Decomposes transform to four vectors.")));

add_options.push_back(AddOption("Determinant", "Transform", "Functions", "VisualShaderNodeDeterminant", TTR("Calculates the determinant of a transform."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("GetBillboardMatrix", "Transform", "Functions", "VisualShaderNodeBillboard", TTR("Calculates how the object should face the camera to be applied on Model View Matrix output port for 3D objects."), -1, VisualShaderNode::PORT_TYPE_TRANSFORM, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Inverse", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the inverse of a transform."), VisualShaderNodeTransformFunc::FUNC_INVERSE, VisualShaderNode::PORT_TYPE_TRANSFORM));
add_options.push_back(AddOption("Transpose", "Transform", "Functions", "VisualShaderNodeTransformFunc", TTR("Calculates the transpose of a transform."), VisualShaderNodeTransformFunc::FUNC_TRANSPOSE, VisualShaderNode::PORT_TYPE_TRANSFORM));

1 change: 1 addition & 0 deletions scene/register_scene_types.cpp
Original file line number Diff line number Diff line change
@@ -597,6 +597,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeIs>();
ClassDB::register_class<VisualShaderNodeCompare>();
ClassDB::register_class<VisualShaderNodeMultiplyAdd>();
ClassDB::register_class<VisualShaderNodeBillboard>();

ClassDB::register_class<VisualShaderNodeSDFToScreenUV>();
ClassDB::register_class<VisualShaderNodeScreenUVToSDF>();
27 changes: 26 additions & 1 deletion scene/resources/visual_shader.cpp
Original file line number Diff line number Diff line change
@@ -152,6 +152,14 @@ bool VisualShaderNode::is_use_prop_slots() const {
return false;
}

bool VisualShaderNode::is_disabled() const {
return disabled;
}

void VisualShaderNode::set_disabled(bool p_disabled) {
disabled = p_disabled;
}

Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
return Vector<VisualShader::DefaultTextureParam>();
}
@@ -1260,6 +1268,12 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBuilder &global_code_per_node, Map<Type, StringBuilder> &global_code_per_func, StringBuilder &code, Vector<VisualShader::DefaultTextureParam> &def_tex_params, const VMap<ConnectionKey, const List<Connection>::Element *> &input_connections, const VMap<ConnectionKey, const List<Connection>::Element *> &output_connections, int node, Set<int> &processed, bool for_preview, Set<StringName> &r_classes) const {
const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node;

if (vsnode->is_disabled()) {
code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
code += "\t// Node is disabled and code is not generated.\n";
return OK;
}

//check inputs recursively first
int input_count = vsnode->get_input_port_count();
for (int i = 0; i < input_count; i++) {
@@ -1328,6 +1342,11 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
if (input_connections.has(ck)) {
//connected to something, use that output
int from_node = input_connections[ck]->get().from_node;

if (graph[type].nodes[from_node].node->is_disabled()) {
continue;
}

int from_port = input_connections[ck]->get().from_port;

VisualShaderNode::PortType in_type = vsnode->get_input_port_type(i);
@@ -2531,6 +2550,8 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_view_matrix", "MODELVIEW_MATRIX" },

// Spatial, Fragment

{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "albedo", "ALBEDO" },
@@ -2670,9 +2691,13 @@ String VisualShaderNodeOutput::get_output_port_name(int p_port) const {
}

bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_VERTEX) {
String name = get_input_port_name(p_index);
return bool(name == "Model View Matrix");
}
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) {
String name = get_input_port_name(p_index);
return (name == "Normal" || name == "Rim" || name == "Alpha Scissor Threshold");
return bool(name == "Normal" || name == "Rim" || name == "Alpha Scissor Threshold");
}
return false;
}
5 changes: 5 additions & 0 deletions scene/resources/visual_shader.h
Original file line number Diff line number Diff line change
@@ -203,6 +203,8 @@ class VisualShaderNode : public Resource {

protected:
bool simple_decl = true;
bool disabled = false;

static void _bind_methods();

public:
@@ -257,6 +259,9 @@ class VisualShaderNode : public Resource {
virtual bool is_show_prop_names() const;
virtual bool is_use_prop_slots() const;

bool is_disabled() const;
void set_disabled(bool p_disabled = true);

virtual Vector<StringName> get_editable_properties() const;

virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;
124 changes: 124 additions & 0 deletions scene/resources/visual_shader_nodes.cpp
Original file line number Diff line number Diff line change
@@ -5579,3 +5579,127 @@ VisualShaderNodeMultiplyAdd::VisualShaderNodeMultiplyAdd() {
set_input_port_default_value(1, 0.0);
set_input_port_default_value(2, 0.0);
}

////////////// Billboard

String VisualShaderNodeBillboard::get_caption() const {
return "GetBillboardMatrix";
}

int VisualShaderNodeBillboard::get_input_port_count() const {
return 0;
}

VisualShaderNodeBillboard::PortType VisualShaderNodeBillboard::get_input_port_type(int p_port) const {
return PORT_TYPE_SCALAR;
}

String VisualShaderNodeBillboard::get_input_port_name(int p_port) const {
return "";
}

int VisualShaderNodeBillboard::get_output_port_count() const {
return 1;
}

VisualShaderNodeBillboard::PortType VisualShaderNodeBillboard::get_output_port_type(int p_port) const {
return PORT_TYPE_TRANSFORM;
}

String VisualShaderNodeBillboard::get_output_port_name(int p_port) const {
return "model_view_matrix";
}

String VisualShaderNodeBillboard::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;

switch (billboard_type) {
case BILLBOARD_TYPE_ENABLED:
code += "\t{\n";
code += "\t\tmat4 __mvm = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0], CAMERA_MATRIX[1], CAMERA_MATRIX[2], WORLD_MATRIX[3]);\n";
if (keep_scale) {
code += "\t\t__mvm = __mvm * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
code += "\t\t" + p_output_vars[0] + " = __mvm;\n";
code += "\t}\n";
break;
case BILLBOARD_TYPE_FIXED_Y:
code += "\t{\n";
code += "\t\tmat4 __mvm = INV_CAMERA_MATRIX * mat4(CAMERA_MATRIX[0], WORLD_MATRIX[1], vec4(normalize(cross(CAMERA_MATRIX[0].xyz, WORLD_MATRIX[1].xyz)), 0.0), WORLD_MATRIX[3]);\n";
if (keep_scale) {
code += "\t\t__mvm = __mvm * mat4(vec4(length(WORLD_MATRIX[0].xyz), 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, length(WORLD_MATRIX[2].xyz), 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
} else {
code += "\t\t__mvm = __mvm * mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0 / length(WORLD_MATRIX[1].xyz), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
}
code += "\t\t" + p_output_vars[0] + " = __mvm;\n";
code += "\t}\n";
break;
case BILLBOARD_TYPE_PARTICLES:
code += "\t{\n";
code += "\t\tmat4 __wm = mat4(normalize(CAMERA_MATRIX[0]) * length(WORLD_MATRIX[0]), normalize(CAMERA_MATRIX[1]) * length(WORLD_MATRIX[0]), normalize(CAMERA_MATRIX[2]) * length(WORLD_MATRIX[2]), WORLD_MATRIX[3]);\n";
code += "\t\t__wm = __wm * mat4(vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
code += "\t\t" + p_output_vars[0] + " = INV_CAMERA_MATRIX * __wm;\n";
code += "\t}\n";
break;
default:
code += "\t" + p_output_vars[0] + " = mat4(1.0);\n";
break;
}

return code;
}

bool VisualShaderNodeBillboard::is_show_prop_names() const {
return true;
}

void VisualShaderNodeBillboard::set_billboard_type(BillboardType p_billboard_type) {
ERR_FAIL_INDEX((int)p_billboard_type, BILLBOARD_TYPE_MAX);
billboard_type = p_billboard_type;
simple_decl = bool(billboard_type == BILLBOARD_TYPE_DISABLED);
set_disabled(simple_decl);
emit_changed();
}

VisualShaderNodeBillboard::BillboardType VisualShaderNodeBillboard::get_billboard_type() const {
return billboard_type;
}

void VisualShaderNodeBillboard::set_keep_scale_enabled(bool p_enabled) {
keep_scale = p_enabled;
emit_changed();
}

bool VisualShaderNodeBillboard::is_keep_scale_enabled() const {
return keep_scale;
}

Vector<StringName> VisualShaderNodeBillboard::get_editable_properties() const {
Vector<StringName> props;
props.push_back("billboard_type");
if (billboard_type == BILLBOARD_TYPE_ENABLED || billboard_type == BILLBOARD_TYPE_FIXED_Y) {
props.push_back("keep_scale");
}
return props;
}

void VisualShaderNodeBillboard::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_billboard_type", "billboard_type"), &VisualShaderNodeBillboard::set_billboard_type);
ClassDB::bind_method(D_METHOD("get_billboard_type"), &VisualShaderNodeBillboard::get_billboard_type);

ClassDB::bind_method(D_METHOD("set_keep_scale_enabled", "enabled"), &VisualShaderNodeBillboard::set_keep_scale_enabled);
ClassDB::bind_method(D_METHOD("is_keep_scale_enabled"), &VisualShaderNodeBillboard::is_keep_scale_enabled);

ADD_PROPERTY(PropertyInfo(Variant::INT, "billboard_type", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard,Particles"), "set_billboard_type", "get_billboard_type");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_scale"), "set_keep_scale_enabled", "is_keep_scale_enabled");

BIND_ENUM_CONSTANT(BILLBOARD_TYPE_DISABLED);
BIND_ENUM_CONSTANT(BILLBOARD_TYPE_ENABLED);
BIND_ENUM_CONSTANT(BILLBOARD_TYPE_FIXED_Y);
BIND_ENUM_CONSTANT(BILLBOARD_TYPE_PARTICLES);
BIND_ENUM_CONSTANT(BILLBOARD_TYPE_MAX);
}

VisualShaderNodeBillboard::VisualShaderNodeBillboard() {
simple_decl = false;
}
47 changes: 47 additions & 0 deletions scene/resources/visual_shader_nodes.h
Original file line number Diff line number Diff line change
@@ -2217,4 +2217,51 @@ class VisualShaderNodeMultiplyAdd : public VisualShaderNode {

VARIANT_ENUM_CAST(VisualShaderNodeMultiplyAdd::OpType)

class VisualShaderNodeBillboard : public VisualShaderNode {
GDCLASS(VisualShaderNodeBillboard, VisualShaderNode);

public:
enum BillboardType {
BILLBOARD_TYPE_DISABLED,
BILLBOARD_TYPE_ENABLED,
BILLBOARD_TYPE_FIXED_Y,
BILLBOARD_TYPE_PARTICLES,
BILLBOARD_TYPE_MAX,
};

protected:
BillboardType billboard_type = BILLBOARD_TYPE_ENABLED;
bool keep_scale = false;

protected:
static void _bind_methods();

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 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 bool is_show_prop_names() const override;

void set_billboard_type(BillboardType p_billboard_type);
BillboardType get_billboard_type() const;

void set_keep_scale_enabled(bool p_enabled);
bool is_keep_scale_enabled() const;

virtual Vector<StringName> get_editable_properties() const override;

VisualShaderNodeBillboard();
};

VARIANT_ENUM_CAST(VisualShaderNodeBillboard::BillboardType)

#endif // VISUAL_SHADER_NODES_H