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
Show file tree
Hide file tree
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
Expand Up @@ -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));

Expand Down
1 change: 1 addition & 0 deletions scene/register_scene_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
Expand Down
27 changes: 26 additions & 1 deletion scene/resources/visual_shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
}
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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" },
Expand Down Expand Up @@ -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;
}
Expand Down
5 changes: 5 additions & 0 deletions scene/resources/visual_shader.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ class VisualShaderNode : public Resource {

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

static void _bind_methods();

public:
Expand Down Expand Up @@ -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;
Expand Down
124 changes: 124 additions & 0 deletions scene/resources/visual_shader_nodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Up @@ -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