Added UniformRef visual shader node

This commit is contained in:
Yuri Roubinsky 2020-07-28 11:02:57 +03:00
parent 303515981b
commit 7ddaff47a3
6 changed files with 439 additions and 1 deletions

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="VisualShaderNodeUniformRef" inherits="VisualShaderNode" version="4.0">
<brief_description>
A reference to an existing [VisualShaderNodeUniform].
</brief_description>
<description>
Creating a reference to a [VisualShaderNodeUniform] allows you to reuse this uniform in different shaders or shader stages easily.
</description>
<tutorials>
</tutorials>
<methods>
</methods>
<members>
<member name="uniform_name" type="String" setter="set_uniform_name" getter="get_uniform_name" default="&quot;[None]&quot;">
The name of the uniform which this reference points to.
</member>
</members>
<constants>
</constants>
</class>

View file

@ -489,6 +489,45 @@ void VisualShaderEditor::_update_graph() {
Vector<int> nodes = visual_shader->get_node_list(type);
VisualShaderNodeUniformRef::clear_uniforms();
// scan for all uniforms
for (int t = 0; t < VisualShader::TYPE_MAX; t++) {
Vector<int> tnodes = visual_shader->get_node_list((VisualShader::Type)t);
for (int i = 0; i < tnodes.size(); i++) {
Ref<VisualShaderNode> vsnode = visual_shader->get_node((VisualShader::Type)t, tnodes[i]);
Ref<VisualShaderNodeUniform> uniform = vsnode;
if (uniform.is_valid()) {
Ref<VisualShaderNodeFloatUniform> float_uniform = vsnode;
Ref<VisualShaderNodeIntUniform> int_uniform = vsnode;
Ref<VisualShaderNodeVec3Uniform> vec3_uniform = vsnode;
Ref<VisualShaderNodeColorUniform> color_uniform = vsnode;
Ref<VisualShaderNodeBooleanUniform> bool_uniform = vsnode;
Ref<VisualShaderNodeTransformUniform> transform_uniform = vsnode;
VisualShaderNodeUniformRef::UniformType uniform_type;
if (float_uniform.is_valid()) {
uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_FLOAT;
} else if (int_uniform.is_valid()) {
uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_INT;
} else if (bool_uniform.is_valid()) {
uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_BOOLEAN;
} else if (vec3_uniform.is_valid()) {
uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_VECTOR;
} else if (transform_uniform.is_valid()) {
uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_TRANSFORM;
} else if (color_uniform.is_valid()) {
uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_COLOR;
} else {
uniform_type = VisualShaderNodeUniformRef::UniformType::UNIFORM_TYPE_SAMPLER;
}
VisualShaderNodeUniformRef::add_uniform(uniform->get_uniform_name(), uniform_type);
}
}
}
Control *offset;
for (int n_i = 0; n_i < nodes.size(); n_i++) {
@ -2035,6 +2074,41 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> input, St
undo_redo->commit_action();
}
void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform_ref, String p_name) {
String prev_name = p_uniform_ref->get_uniform_name();
if (p_name == prev_name) {
return;
}
bool type_changed = p_uniform_ref->get_uniform_type_by_name(p_name) != p_uniform_ref->get_uniform_type_by_name(prev_name);
UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(TTR("UniformRef Name Changed"));
undo_redo->add_do_method(p_uniform_ref.ptr(), "set_uniform_name", p_name);
undo_redo->add_undo_method(p_uniform_ref.ptr(), "set_uniform_name", prev_name);
if (type_changed) {
//restore connections if type changed
VisualShader::Type type = VisualShader::Type(edit_type->get_selected());
int id = visual_shader->find_node_id(type, p_uniform_ref);
List<VisualShader::Connection> conns;
visual_shader->get_node_connections(type, &conns);
for (List<VisualShader::Connection>::Element *E = conns.front(); E; E = E->next()) {
if (E->get().from_node == id) {
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
}
}
}
undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_update_graph");
undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_update_graph");
undo_redo->commit_action();
}
void VisualShaderEditor::_member_filter_changed(const String &p_text) {
_update_options_menu();
}
@ -2260,6 +2334,7 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_add_node", &VisualShaderEditor::_add_node);
ClassDB::bind_method("_node_changed", &VisualShaderEditor::_node_changed);
ClassDB::bind_method("_input_select_item", &VisualShaderEditor::_input_select_item);
ClassDB::bind_method("_uniform_select_item", &VisualShaderEditor::_uniform_select_item);
ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size);
ClassDB::bind_method("_clear_buffer", &VisualShaderEditor::_clear_buffer);
@ -2862,6 +2937,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside.")));
add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR));
add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which is placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants.")));
add_options.push_back(AddOption("UniformRef", "Special", "", "VisualShaderNodeUniformRef", TTR("A reference to an existing uniform.")));
add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true));
@ -2980,6 +3056,54 @@ public:
}
};
////////////////
class VisualShaderNodePluginUniformRefEditor : public OptionButton {
GDCLASS(VisualShaderNodePluginUniformRefEditor, OptionButton);
Ref<VisualShaderNodeUniformRef> uniform_ref;
public:
void _notification(int p_what) {
if (p_what == NOTIFICATION_READY) {
connect("item_selected", callable_mp(this, &VisualShaderNodePluginUniformRefEditor::_item_selected));
}
}
void _item_selected(int p_item) {
VisualShaderEditor::get_singleton()->call_deferred("_uniform_select_item", uniform_ref, get_item_text(p_item));
}
void setup(const Ref<VisualShaderNodeUniformRef> &p_uniform_ref) {
uniform_ref = p_uniform_ref;
Ref<Texture2D> type_icon[7] = {
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("float", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("int", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("bool", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Vector3", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Transform", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("Color", "EditorIcons"),
EditorNode::get_singleton()->get_gui_base()->get_theme_icon("ImageTexture", "EditorIcons"),
};
add_item("[None]");
int to_select = -1;
for (int i = 0; i < p_uniform_ref->get_uniforms_count(); i++) {
if (p_uniform_ref->get_uniform_name() == p_uniform_ref->get_uniform_name_by_index(i)) {
to_select = i + 1;
}
add_icon_item(type_icon[p_uniform_ref->get_uniform_type_by_index(i)], p_uniform_ref->get_uniform_name_by_index(i));
}
if (to_select >= 0) {
select(to_select);
}
}
};
////////////////
class VisualShaderNodePluginDefaultEditor : public VBoxContainer {
GDCLASS(VisualShaderNodePluginDefaultEditor, VBoxContainer);
Ref<Resource> parent_resource;
@ -3095,6 +3219,13 @@ public:
};
Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_parent_resource, const Ref<VisualShaderNode> &p_node) {
if (p_node->is_class("VisualShaderNodeUniformRef")) {
//create input
VisualShaderNodePluginUniformRefEditor *uniform_editor = memnew(VisualShaderNodePluginUniformRefEditor);
uniform_editor->setup(p_node);
return uniform_editor;
}
if (p_node->is_class("VisualShaderNodeInput")) {
//create input
VisualShaderNodePluginInputEditor *input_editor = memnew(VisualShaderNodePluginInputEditor);

View file

@ -232,6 +232,7 @@ class VisualShaderEditor : public VBoxContainer {
void _rebuild();
void _input_select_item(Ref<VisualShaderNodeInput> input, String name);
void _uniform_select_item(Ref<VisualShaderNodeUniformRef> p_uniform, String p_name);
void _add_input_port(int p_node, int p_port, int p_port_type, const String &p_name);
void _remove_input_port(int p_node, int p_port);

View file

@ -547,6 +547,7 @@ void register_scene_types() {
ClassDB::register_class<VisualShaderNodeTexture2DArray>();
ClassDB::register_class<VisualShaderNodeCubemap>();
ClassDB::register_virtual_class<VisualShaderNodeUniform>();
ClassDB::register_class<VisualShaderNodeUniformRef>();
ClassDB::register_class<VisualShaderNodeFloatUniform>();
ClassDB::register_class<VisualShaderNodeIntUniform>();
ClassDB::register_class<VisualShaderNodeBooleanUniform>();

View file

@ -1151,7 +1151,10 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
bool skip_global = input.is_valid() && for_preview;
if (!skip_global) {
global_code += vsnode->generate_global(get_mode(), type, node);
Ref<VisualShaderNodeUniform> uniform = vsnode;
if (!uniform.is_valid() || !uniform->is_global_code_generated()) {
global_code += vsnode->generate_global(get_mode(), type, node);
}
String class_name = vsnode->get_class_name();
if (class_name == "VisualShaderNodeCustom") {
@ -1398,6 +1401,9 @@ void VisualShader::_update_shader() const {
static const char *func_name[TYPE_MAX] = { "vertex", "fragment", "light" };
String global_expressions;
Set<String> used_uniform_names;
List<VisualShaderNodeUniform *> uniforms;
for (int i = 0, index = 0; i < TYPE_MAX; i++) {
if (!ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader_mode)).has(func_name[i])) {
continue;
@ -1413,6 +1419,24 @@ void VisualShader::_update_shader() const {
expr += "\n";
global_expressions += expr;
}
Ref<VisualShaderNodeUniformRef> uniform_ref = Object::cast_to<VisualShaderNodeUniformRef>(E->get().node.ptr());
if (uniform_ref.is_valid()) {
used_uniform_names.insert(uniform_ref->get_uniform_name());
}
Ref<VisualShaderNodeUniform> uniform = Object::cast_to<VisualShaderNodeUniform>(E->get().node.ptr());
if (uniform.is_valid()) {
uniforms.push_back(uniform.ptr());
}
}
}
for (int i = 0; i < uniforms.size(); i++) {
VisualShaderNodeUniform *uniform = uniforms[i];
if (used_uniform_names.has(uniform->get_uniform_name())) {
global_code += uniform->generate_global(get_mode(), Type(i), -1);
const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(true);
} else {
const_cast<VisualShaderNodeUniform *>(uniform)->set_global_code_generated(false);
}
}
@ -2002,6 +2026,199 @@ VisualShaderNodeInput::VisualShaderNodeInput() {
shader_mode = Shader::MODE_MAX;
}
////////////// UniformRef
List<VisualShaderNodeUniformRef::Uniform> uniforms;
void VisualShaderNodeUniformRef::add_uniform(const String &p_name, UniformType p_type) {
uniforms.push_back({ p_name, p_type });
}
void VisualShaderNodeUniformRef::clear_uniforms() {
uniforms.clear();
}
String VisualShaderNodeUniformRef::get_caption() const {
return "UniformRef";
}
int VisualShaderNodeUniformRef::get_input_port_count() const {
return 0;
}
VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_input_port_type(int p_port) const {
return PortType::PORT_TYPE_SCALAR;
}
String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const {
return "";
}
int VisualShaderNodeUniformRef::get_output_port_count() const {
if (uniform_name == "[None]") {
return 0;
}
switch (uniform_type) {
case UniformType::UNIFORM_TYPE_FLOAT:
return 1;
case UniformType::UNIFORM_TYPE_INT:
return 1;
case UniformType::UNIFORM_TYPE_BOOLEAN:
return 1;
case UniformType::UNIFORM_TYPE_VECTOR:
return 1;
case UniformType::UNIFORM_TYPE_TRANSFORM:
return 1;
case UniformType::UNIFORM_TYPE_COLOR:
return 2;
case UniformType::UNIFORM_TYPE_SAMPLER:
return 1;
default:
break;
}
return 0;
}
VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const {
switch (uniform_type) {
case UniformType::UNIFORM_TYPE_FLOAT:
return PortType::PORT_TYPE_SCALAR;
case UniformType::UNIFORM_TYPE_INT:
return PortType::PORT_TYPE_SCALAR_INT;
case UniformType::UNIFORM_TYPE_BOOLEAN:
return PortType::PORT_TYPE_BOOLEAN;
case UniformType::UNIFORM_TYPE_VECTOR:
return PortType::PORT_TYPE_VECTOR;
case UniformType::UNIFORM_TYPE_TRANSFORM:
return PortType::PORT_TYPE_TRANSFORM;
case UniformType::UNIFORM_TYPE_COLOR:
if (p_port == 0) {
return PortType::PORT_TYPE_VECTOR;
} else if (p_port == 1) {
return PORT_TYPE_SCALAR;
}
break;
case UniformType::UNIFORM_TYPE_SAMPLER:
return PortType::PORT_TYPE_SAMPLER;
default:
break;
}
return PORT_TYPE_SCALAR;
}
String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
switch (uniform_type) {
case UniformType::UNIFORM_TYPE_FLOAT:
return "";
case UniformType::UNIFORM_TYPE_INT:
return "";
case UniformType::UNIFORM_TYPE_BOOLEAN:
return "";
case UniformType::UNIFORM_TYPE_VECTOR:
return "";
case UniformType::UNIFORM_TYPE_TRANSFORM:
return "";
case UniformType::UNIFORM_TYPE_COLOR:
if (p_port == 0) {
return "rgb";
} else if (p_port == 1) {
return "alpha";
}
break;
case UniformType::UNIFORM_TYPE_SAMPLER:
return "";
break;
default:
break;
}
return "";
}
void VisualShaderNodeUniformRef::set_uniform_name(const String &p_name) {
uniform_name = p_name;
if (p_name != "[None]") {
uniform_type = get_uniform_type_by_name(p_name);
} else {
uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
}
emit_changed();
}
String VisualShaderNodeUniformRef::get_uniform_name() const {
return uniform_name;
}
int VisualShaderNodeUniformRef::get_uniforms_count() const {
return uniforms.size();
}
String VisualShaderNodeUniformRef::get_uniform_name_by_index(int p_idx) const {
if (p_idx >= 0 && p_idx < uniforms.size()) {
return uniforms[p_idx].name;
}
return "";
}
VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_name(const String &p_name) const {
for (int i = 0; i < uniforms.size(); i++) {
if (uniforms[i].name == p_name) {
return uniforms[i].type;
}
}
return UniformType::UNIFORM_TYPE_FLOAT;
}
VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_type_by_index(int p_idx) const {
if (p_idx >= 0 && p_idx < uniforms.size()) {
return uniforms[p_idx].type;
}
return UniformType::UNIFORM_TYPE_FLOAT;
}
String VisualShaderNodeUniformRef::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 {
switch (uniform_type) {
case UniformType::UNIFORM_TYPE_FLOAT:
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
case UniformType::UNIFORM_TYPE_INT:
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
case UniformType::UNIFORM_TYPE_BOOLEAN:
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
case UniformType::UNIFORM_TYPE_VECTOR:
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
case UniformType::UNIFORM_TYPE_TRANSFORM:
return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
case UniformType::UNIFORM_TYPE_COLOR: {
String code = "\t" + p_output_vars[0] + " = " + get_uniform_name() + ".rgb;\n";
code += "\t" + p_output_vars[1] + " = " + get_uniform_name() + ".a;\n";
return code;
} break;
case UniformType::UNIFORM_TYPE_SAMPLER:
break;
default:
break;
}
return "";
}
void VisualShaderNodeUniformRef::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniformRef::set_uniform_name);
ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniformRef::get_uniform_name);
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name");
}
Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const {
Vector<StringName> props;
props.push_back("uniform_name");
return props;
}
VisualShaderNodeUniformRef::VisualShaderNodeUniformRef() {
uniform_name = "[None]";
uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
}
////////////////////////////////////////////
const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
@ -2195,6 +2412,14 @@ VisualShaderNodeUniform::Qualifier VisualShaderNodeUniform::get_qualifier() cons
return qualifier;
}
void VisualShaderNodeUniform::set_global_code_generated(bool p_enabled) {
global_code_generated = p_enabled;
}
bool VisualShaderNodeUniform::is_global_code_generated() const {
return global_code_generated;
}
void VisualShaderNodeUniform::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_uniform_name", "name"), &VisualShaderNodeUniform::set_uniform_name);
ClassDB::bind_method(D_METHOD("get_uniform_name"), &VisualShaderNodeUniform::get_uniform_name);

View file

@ -388,6 +388,7 @@ public:
private:
String uniform_name;
Qualifier qualifier;
bool global_code_generated = false;
protected:
static void _bind_methods();
@ -400,6 +401,9 @@ public:
void set_qualifier(Qualifier p_qual);
Qualifier get_qualifier() const;
void set_global_code_generated(bool p_enabled);
bool is_global_code_generated() const;
virtual bool is_qualifier_supported(Qualifier p_qual) const = 0;
virtual Vector<StringName> get_editable_properties() const override;
@ -410,6 +414,62 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeUniform::Qualifier)
class VisualShaderNodeUniformRef : public VisualShaderNode {
GDCLASS(VisualShaderNodeUniformRef, VisualShaderNode);
public:
enum UniformType {
UNIFORM_TYPE_FLOAT,
UNIFORM_TYPE_INT,
UNIFORM_TYPE_BOOLEAN,
UNIFORM_TYPE_VECTOR,
UNIFORM_TYPE_TRANSFORM,
UNIFORM_TYPE_COLOR,
UNIFORM_TYPE_SAMPLER,
};
struct Uniform {
String name;
UniformType type;
};
private:
String uniform_name;
UniformType uniform_type;
protected:
static void _bind_methods();
public:
static void add_uniform(const String &p_name, UniformType p_type);
static void clear_uniforms();
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;
void set_uniform_name(const String &p_name);
String get_uniform_name() const;
int get_uniforms_count() const;
String get_uniform_name_by_index(int p_idx) const;
UniformType get_uniform_type_by_name(const String &p_name) const;
UniformType get_uniform_type_by_index(int p_idx) const;
virtual Vector<StringName> 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;
VisualShaderNodeUniformRef();
};
class VisualShaderNodeGroupBase : public VisualShaderNode {
GDCLASS(VisualShaderNodeGroupBase, VisualShaderNode);