浏览代码

Merge pull request #42225 from Chaosus/vs_fix_bugs

Fix some bugs in visual shader editor
Yuri Roubinsky 5 年之前
父节点
当前提交
160ad23e5d

+ 157 - 82
editor/plugins/visual_shader_editor_plugin.cpp

@@ -82,9 +82,10 @@ void VisualShaderGraphPlugin::_bind_methods() {
 	ClassDB::bind_method("set_node_position", &VisualShaderGraphPlugin::set_node_position);
 	ClassDB::bind_method("set_node_size", &VisualShaderGraphPlugin::set_node_size);
 	ClassDB::bind_method("show_port_preview", &VisualShaderGraphPlugin::show_port_preview);
-	ClassDB::bind_method("update_property_editor", &VisualShaderGraphPlugin::update_property_editor);
-	ClassDB::bind_method("update_property_editor_deferred", &VisualShaderGraphPlugin::update_property_editor_deferred);
+	ClassDB::bind_method("update_node", &VisualShaderGraphPlugin::update_node);
+	ClassDB::bind_method("update_node_deferred", &VisualShaderGraphPlugin::update_node_deferred);
 	ClassDB::bind_method("set_input_port_default_value", &VisualShaderGraphPlugin::set_input_port_default_value);
+	ClassDB::bind_method("set_uniform_name", &VisualShaderGraphPlugin::set_uniform_name);
 }
 
 void VisualShaderGraphPlugin::register_shader(VisualShader *p_shader) {
@@ -134,11 +135,11 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
 	}
 }
 
-void VisualShaderGraphPlugin::update_property_editor_deferred(VisualShader::Type p_type, int p_node_id) {
-	call_deferred("update_property_editor", p_type, p_node_id);
+void VisualShaderGraphPlugin::update_node_deferred(VisualShader::Type p_type, int p_node_id) {
+	call_deferred("update_node", p_type, p_node_id);
 }
 
-void VisualShaderGraphPlugin::update_property_editor(VisualShader::Type p_type, int p_node_id) {
+void VisualShaderGraphPlugin::update_node(VisualShader::Type p_type, int p_node_id) {
 	if (p_type != visual_shader->get_shader_type() || !links.has(p_node_id)) {
 		return;
 	}
@@ -176,10 +177,26 @@ void VisualShaderGraphPlugin::set_input_port_default_value(VisualShader::Type p_
 	}
 }
 
+void VisualShaderGraphPlugin::set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name) {
+	if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].uniform_name != nullptr) {
+		links[p_node_id].uniform_name->set_text(p_name);
+	}
+}
+
 void VisualShaderGraphPlugin::register_default_input_button(int p_node_id, int p_port_id, Button *p_button) {
 	links[p_node_id].input_ports.insert(p_port_id, { p_button });
 }
 
+void VisualShaderGraphPlugin::update_uniform_refs() {
+	for (Map<int, Link>::Element *E = links.front(); E; E = E->next()) {
+		VisualShaderNodeUniformRef *ref = Object::cast_to<VisualShaderNodeUniformRef>(E->get().visual_node);
+		if (ref) {
+			remove_node(E->get().type, E->key());
+			add_node(E->get().type, E->key());
+		}
+	}
+}
+
 VisualShader::Type VisualShaderGraphPlugin::get_shader_type() const {
 	return visual_shader->get_shader_type();
 }
@@ -213,13 +230,17 @@ void VisualShaderGraphPlugin::make_dirty(bool p_enabled) {
 }
 
 void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node) {
-	links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr });
+	links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, Map<int, InputPort>(), Map<int, Port>(), nullptr, nullptr });
 }
 
 void VisualShaderGraphPlugin::register_output_port(int p_node_id, int p_port, TextureButton *p_button) {
 	links[p_node_id].output_ports.insert(p_port, { p_button });
 }
 
+void VisualShaderGraphPlugin::register_uniform_name(int p_node_id, LineEdit *p_uniform_name) {
+	links[p_node_id].uniform_name = p_uniform_name;
+}
+
 void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 	if (p_type != visual_shader->get_shader_type()) {
 		return;
@@ -280,43 +301,22 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 	}
 
 	Ref<VisualShaderNodeUniform> uniform = vsnode;
-
-	if (uniform.is_valid()) {
-		VisualShaderEditor::get_singleton()->call_deferred("_update_uniforms");
-	}
-
-	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;
 	if (uniform.is_valid()) {
 		VisualShaderEditor::get_singleton()->graph->add_child(node);
 		VisualShaderEditor::get_singleton()->_update_created_node(node);
 
 		LineEdit *uniform_name = memnew(LineEdit);
+		register_uniform_name(p_id, uniform_name);
 		uniform_name->set_text(uniform->get_uniform_name());
 		node->add_child(uniform_name);
 		uniform_name->connect("text_entered", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_line_edit_changed), varray(uniform_name, p_id));
 		uniform_name->connect("focus_exited", callable_mp(VisualShaderEditor::get_singleton(), &VisualShaderEditor::_line_edit_focus_out), varray(uniform_name, p_id));
 
-		String error = vsnode->get_warning(visual_shader->get_mode(), p_type);
-		if (error != String()) {
-			offset = memnew(Control);
-			offset->set_custom_minimum_size(Size2(0, 4 * EDSCALE));
-			node->add_child(offset);
-			Label *error_label = memnew(Label);
-			error_label->add_theme_color_override("font_color", VisualShaderEditor::get_singleton()->get_theme_color("error_color", "Editor"));
-			error_label->set_text(error);
-			node->add_child(error_label);
-		}
-
 		if (vsnode->get_input_port_count() == 0 && vsnode->get_output_port_count() == 1 && vsnode->get_output_port_name(0) == "") {
 			//shortcut
 			VisualShaderNode::PortType port_right = vsnode->get_output_port_type(0);
 			node->set_slot(0, false, VisualShaderNode::PORT_TYPE_SCALAR, Color(), true, port_right, type_color[port_right]);
-			if (!float_uniform.is_valid() && !int_uniform.is_valid() && !vec3_uniform.is_valid() && !color_uniform.is_valid() && !bool_uniform.is_valid() && !transform_uniform.is_valid()) {
+			if (!vsnode->is_use_prop_slots()) {
 				return;
 			}
 		}
@@ -330,20 +330,19 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 		vsnode->remove_meta("id");
 		vsnode->remove_meta("shader_type");
 		if (custom_editor) {
+			if (vsnode->is_show_prop_names()) {
+				custom_editor->call_deferred("_show_prop_names", true);
+			}
 			break;
 		}
 	}
 
-	if (custom_editor && !float_uniform.is_valid() && !int_uniform.is_valid() && !vec3_uniform.is_valid() && !bool_uniform.is_valid() && !transform_uniform.is_valid() && vsnode->get_output_port_count() > 0 && vsnode->get_output_port_name(0) == "" && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == "")) {
+	if (custom_editor && !vsnode->is_use_prop_slots() && vsnode->get_output_port_count() > 0 && vsnode->get_output_port_name(0) == "" && (vsnode->get_input_port_count() == 0 || vsnode->get_input_port_name(0) == "")) {
 		//will be embedded in first port
 	} else if (custom_editor) {
 		port_offset++;
 		node->add_child(custom_editor);
-		if (color_uniform.is_valid()) {
-			custom_editor->call_deferred("_show_prop_names", true);
-		}
-		if (float_uniform.is_valid() || int_uniform.is_valid() || vec3_uniform.is_valid() || bool_uniform.is_valid() || transform_uniform.is_valid()) {
-			custom_editor->call_deferred("_show_prop_names", true);
+		if (vsnode->is_use_prop_slots()) {
 			return;
 		}
 		custom_editor = nullptr;
@@ -597,12 +596,6 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id) {
 
 void VisualShaderGraphPlugin::remove_node(VisualShader::Type p_type, int p_id) {
 	if (visual_shader->get_shader_type() == p_type && links.has(p_id)) {
-		Ref<VisualShaderNodeUniform> uniform = Ref<VisualShaderNode>(links[p_id].visual_node);
-
-		if (uniform.is_valid()) {
-			VisualShaderEditor::get_singleton()->call_deferred("_update_uniforms");
-		}
-
 		links[p_id].graph_node->get_parent()->remove_child(links[p_id].graph_node);
 		memdelete(links[p_id].graph_node);
 		links.erase(p_id);
@@ -1015,7 +1008,7 @@ void VisualShaderEditor::_update_created_node(GraphNode *node) {
 	}
 }
 
-void VisualShaderEditor::_update_uniforms() {
+void VisualShaderEditor::_update_uniforms(bool p_update_refs) {
 	VisualShaderNodeUniformRef::clear_uniforms();
 
 	for (int t = 0; t < VisualShader::TYPE_MAX; t++) {
@@ -1052,6 +1045,30 @@ void VisualShaderEditor::_update_uniforms() {
 			}
 		}
 	}
+	if (p_update_refs) {
+		graph_plugin->update_uniform_refs();
+	}
+}
+
+void VisualShaderEditor::_update_uniform_refs(Set<String> &p_deleted_names) {
+	for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
+		VisualShader::Type type = VisualShader::Type(i);
+
+		Vector<int> nodes = visual_shader->get_node_list(type);
+		for (int j = 0; j < nodes.size(); j++) {
+			if (j > 0) {
+				Ref<VisualShaderNodeUniformRef> ref = visual_shader->get_node(type, nodes[j]);
+				if (ref.is_valid()) {
+					if (p_deleted_names.has(ref->get_uniform_name())) {
+						undo_redo->add_do_method(ref.ptr(), "set_uniform_name", "[None]");
+						undo_redo->add_undo_method(ref.ptr(), "set_uniform_name", ref->get_uniform_name());
+						undo_redo->add_do_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);
+						undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", VisualShader::Type(i), nodes[j]);
+					}
+				}
+			}
+		}
+	}
 }
 
 void VisualShaderEditor::_update_graph() {
@@ -1084,7 +1101,7 @@ void VisualShaderEditor::_update_graph() {
 
 	Vector<int> nodes = visual_shader->get_node_list(type);
 
-	_update_uniforms();
+	_update_uniforms(false);
 
 	graph_plugin->clear_links();
 	graph_plugin->make_dirty(true);
@@ -1411,16 +1428,20 @@ void VisualShaderEditor::_line_edit_changed(const String &p_text, Object *line_e
 
 	String validated_name = visual_shader->validate_uniform_name(p_text, node);
 
-	updating = true;
 	undo_redo->create_action(TTR("Set Uniform Name"));
 	undo_redo->add_do_method(node.ptr(), "set_uniform_name", validated_name);
 	undo_redo->add_undo_method(node.ptr(), "set_uniform_name", node->get_uniform_name());
-	undo_redo->add_do_method(this, "_update_graph");
-	undo_redo->add_undo_method(this, "_update_graph");
-	undo_redo->commit_action();
-	updating = false;
+	undo_redo->add_do_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, validated_name);
+	undo_redo->add_undo_method(graph_plugin.ptr(), "set_uniform_name", type, p_node_id, node->get_uniform_name());
 
-	Object::cast_to<LineEdit>(line_edit)->set_text(validated_name);
+	undo_redo->add_do_method(this, "_update_uniforms", true);
+	undo_redo->add_undo_method(this, "_update_uniforms", true);
+
+	Set<String> changed_names;
+	changed_names.insert(node->get_uniform_name());
+	_update_uniform_refs(changed_names);
+
+	undo_redo->commit_action();
 }
 
 void VisualShaderEditor::_line_edit_focus_out(Object *line_edit, int p_node_id) {
@@ -1704,6 +1725,12 @@ VisualShaderNode *VisualShaderEditor::_add_node(int p_idx, int p_op_idx) {
 		}
 	}
 
+	VisualShaderNodeUniform *uniform = Object::cast_to<VisualShaderNodeUniform>(vsnode.ptr());
+	if (uniform) {
+		undo_redo->add_do_method(this, "_update_uniforms", true);
+		undo_redo->add_undo_method(this, "_update_uniforms", true);
+	}
+
 	undo_redo->commit_action();
 	return vsnode.ptr();
 }
@@ -1823,6 +1850,18 @@ void VisualShaderEditor::_delete_request(int which) {
 	}
 	// delete a node from the graph
 	undo_redo->add_do_method(graph_plugin.ptr(), "remove_node", type, which);
+
+	VisualShaderNodeUniform *uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
+	if (uniform) {
+		undo_redo->add_do_method(this, "_update_uniforms", true);
+		undo_redo->add_undo_method(this, "_update_uniforms", true);
+
+		Set<String> uniform_names;
+		uniform_names.insert(uniform->get_uniform_name());
+
+		_update_uniform_refs(uniform_names);
+	}
+
 	undo_redo->commit_action();
 }
 
@@ -2222,6 +2261,8 @@ void VisualShaderEditor::_delete_nodes() {
 		}
 	}
 
+	Set<String> uniform_names;
+
 	for (List<int>::Element *F = to_erase.front(); F; F = F->next()) {
 		Ref<VisualShaderNode> node = visual_shader->get_node(type, F->get());
 
@@ -2245,6 +2286,11 @@ void VisualShaderEditor::_delete_nodes() {
 		if (expression) {
 			undo_redo->add_undo_method(expression, "set_expression", expression->get_expression());
 		}
+
+		VisualShaderNodeUniform *uniform = Object::cast_to<VisualShaderNodeUniform>(node.ptr());
+		if (uniform) {
+			uniform_names.insert(uniform->get_uniform_name());
+		}
 	}
 
 	List<VisualShader::Connection> used_conns;
@@ -2272,6 +2318,14 @@ void VisualShaderEditor::_delete_nodes() {
 		undo_redo->add_do_method(graph_plugin.ptr(), "remove_node", type, F->get());
 	}
 
+	// update uniform refs if any uniform has been deleted
+	if (uniform_names.size() > 0) {
+		undo_redo->add_do_method(this, "_update_uniforms", true);
+		undo_redo->add_undo_method(this, "_update_uniforms", true);
+
+		_update_uniform_refs(uniform_names);
+	}
+
 	undo_redo->commit_action();
 }
 
@@ -2281,37 +2335,49 @@ void VisualShaderEditor::_mode_selected(int p_id) {
 	_update_graph();
 }
 
-void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> input, String name) {
-	String prev_name = input->get_input_name();
+void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input, String p_name) {
+	String prev_name = p_input->get_input_name();
 
-	if (name == prev_name) {
+	if (p_name == prev_name) {
 		return;
 	}
 
-	bool type_changed = input->get_input_type_by_name(name) != input->get_input_type_by_name(prev_name);
+	bool type_changed = p_input->get_input_type_by_name(p_name) != p_input->get_input_type_by_name(prev_name);
 
 	UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
 	undo_redo->create_action(TTR("Visual Shader Input Type Changed"));
 
-	undo_redo->add_do_method(input.ptr(), "set_input_name", name);
-	undo_redo->add_undo_method(input.ptr(), "set_input_name", prev_name);
-
-	if (type_changed) {
-		//restore connections if type changed
-		VisualShader::Type type = get_current_shader_type();
-		int id = visual_shader->find_node_id(type, input);
-		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_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(p_input.ptr(), "set_input_name", p_name);
+	undo_redo->add_undo_method(p_input.ptr(), "set_input_name", prev_name);
+
+	// update output port
+	for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
+		VisualShader::Type type = VisualShader::Type(type_id);
+		int id = visual_shader->find_node_id(type, p_input);
+		if (id != VisualShader::NODE_ID_INVALID) {
+			if (type_changed) {
+				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) {
+						if (visual_shader->is_port_types_compatible(p_input->get_input_type_by_name(p_name), visual_shader->get_node(type, E->get().to_node)->get_input_port_type(E->get().to_port))) {
+							undo_redo->add_do_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_undo_method(visual_shader.ptr(), "connect_nodes", type, E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
+							continue;
+						}
+						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(graph_plugin.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(graph_plugin.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(graph_plugin.ptr(), "update_node", type_id, id);
+			undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
+			break;
 		}
 	}
 
-	undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_update_graph");
-	undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_update_graph");
-
 	undo_redo->commit_action();
 }
 
@@ -2330,23 +2396,32 @@ void VisualShaderEditor::_uniform_select_item(Ref<VisualShaderNodeUniformRef> p_
 	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 = get_current_shader_type();
+	// update output port
+	for (int type_id = 0; type_id < VisualShader::TYPE_MAX; type_id++) {
+		VisualShader::Type type = VisualShader::Type(type_id);
 		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);
+		if (id != VisualShader::NODE_ID_INVALID) {
+			if (type_changed) {
+				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) {
+						if (visual_shader->is_port_types_compatible(p_uniform_ref->get_uniform_type_by_name(p_name), visual_shader->get_node(type, E->get().to_node)->get_input_port_type(E->get().to_port))) {
+							continue;
+						}
+						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(graph_plugin.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(graph_plugin.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(graph_plugin.ptr(), "update_node", type_id, id);
+			undo_redo->add_undo_method(graph_plugin.ptr(), "update_node", type_id, id);
+			break;
 		}
 	}
 
-	undo_redo->add_do_method(VisualShaderEditor::get_singleton(), "_update_graph");
-	undo_redo->add_undo_method(VisualShaderEditor::get_singleton(), "_update_graph");
-
 	undo_redo->commit_action();
 }
 
@@ -3434,8 +3509,8 @@ public:
 			}
 		}
 		if (p_property != "constant") {
-			undo_redo->add_do_method(VisualShaderEditor::get_singleton()->get_graph_plugin(), "update_property_editor_deferred", shader_type, node_id);
-			undo_redo->add_undo_method(VisualShaderEditor::get_singleton()->get_graph_plugin(), "update_property_editor_deferred", shader_type, node_id);
+			undo_redo->add_do_method(VisualShaderEditor::get_singleton()->get_graph_plugin(), "update_node_deferred", shader_type, node_id);
+			undo_redo->add_undo_method(VisualShaderEditor::get_singleton()->get_graph_plugin(), "update_node_deferred", shader_type, node_id);
 		}
 		undo_redo->commit_action();
 

+ 10 - 3
editor/plugins/visual_shader_editor_plugin.h

@@ -71,6 +71,7 @@ private:
 		Map<int, InputPort> input_ports;
 		Map<int, Port> output_ports;
 		VBoxContainer *preview_box;
+		LineEdit *uniform_name;
 	};
 
 	Ref<VisualShader> visual_shader;
@@ -86,11 +87,14 @@ public:
 	void set_connections(List<VisualShader::Connection> &p_connections);
 	void register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node);
 	void register_output_port(int p_id, int p_port, TextureButton *p_button);
+	void register_uniform_name(int p_id, LineEdit *p_uniform_name);
 	void clear_links();
 	void set_shader_type(VisualShader::Type p_type);
 	bool is_preview_visible(int p_id) const;
 	bool is_dirty() const;
 	void make_dirty(bool p_enabled);
+	void update_node(VisualShader::Type p_type, int p_id);
+	void update_node_deferred(VisualShader::Type p_type, int p_node_id);
 	void add_node(VisualShader::Type p_type, int p_id);
 	void remove_node(VisualShader::Type p_type, int p_id);
 	void connect_nodes(VisualShader::Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port);
@@ -99,10 +103,10 @@ public:
 	void set_node_position(VisualShader::Type p_type, int p_id, const Vector2 &p_position);
 	void set_node_size(VisualShader::Type p_type, int p_id, const Vector2 &p_size);
 	void refresh_node_ports(VisualShader::Type p_type, int p_node);
-	void update_property_editor(VisualShader::Type p_type, int p_node_id);
-	void update_property_editor_deferred(VisualShader::Type p_type, int p_node_id);
 	void set_input_port_default_value(VisualShader::Type p_type, int p_node_id, int p_port_id, Variant p_value);
 	void register_default_input_button(int p_node_id, int p_port_id, Button *p_button);
+	void update_uniform_refs();
+	void set_uniform_name(VisualShader::Type p_type, int p_node_id, const String &p_name);
 	VisualShader::Type get_shader_type() const;
 
 	VisualShaderGraphPlugin();
@@ -241,6 +245,8 @@ class VisualShaderEditor : public VBoxContainer {
 	int custom_node_option_idx;
 	List<String> keyword_list;
 
+	List<VisualShaderNodeUniformRef> uniform_refs;
+
 	void _draw_color_over_button(Object *obj, Color p_color);
 
 	void _add_custom_node(const String &p_path);
@@ -347,7 +353,8 @@ class VisualShaderEditor : public VBoxContainer {
 
 	bool _is_available(int p_mode);
 	void _update_created_node(GraphNode *node);
-	void _update_uniforms();
+	void _update_uniforms(bool p_update_refs);
+	void _update_uniform_refs(Set<String> &p_names);
 
 protected:
 	void _notification(int p_what);

+ 36 - 7
scene/resources/visual_shader.cpp

@@ -101,6 +101,14 @@ bool VisualShaderNode::is_code_generated() const {
 	return true;
 }
 
+bool VisualShaderNode::is_show_prop_names() const {
+	return false;
+}
+
+bool VisualShaderNode::is_use_prop_slots() const {
+	return false;
+}
+
 Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
 	return Vector<VisualShader::DefaultTextureParam>();
 }
@@ -2123,6 +2131,15 @@ void VisualShaderNodeUniformRef::clear_uniforms() {
 	uniforms.clear();
 }
 
+bool VisualShaderNodeUniformRef::has_uniform(const String &p_name) {
+	for (List<VisualShaderNodeUniformRef::Uniform>::Element *E = uniforms.front(); E; E = E->next()) {
+		if (E->get().name == p_name) {
+			return true;
+		}
+	}
+	return false;
+}
+
 String VisualShaderNodeUniformRef::get_caption() const {
 	return "UniformRef";
 }
@@ -2140,10 +2157,6 @@ String VisualShaderNodeUniformRef::get_input_port_name(int p_port) const {
 }
 
 int VisualShaderNodeUniformRef::get_output_port_count() const {
-	if (uniform_name == "[None]") {
-		return 0;
-	}
-
 	switch (uniform_type) {
 		case UniformType::UNIFORM_TYPE_FLOAT:
 			return 1;
@@ -2162,7 +2175,7 @@ int VisualShaderNodeUniformRef::get_output_port_count() const {
 		default:
 			break;
 	}
-	return 0;
+	return 1;
 }
 
 VisualShaderNodeUniformRef::PortType VisualShaderNodeUniformRef::get_output_port_type(int p_port) const {
@@ -2222,8 +2235,8 @@ String VisualShaderNodeUniformRef::get_output_port_name(int p_port) const {
 
 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);
+	if (uniform_name != "[None]") {
+		uniform_type = get_uniform_type_by_name(uniform_name);
 	} else {
 		uniform_type = UniformType::UNIFORM_TYPE_FLOAT;
 	}
@@ -2264,6 +2277,9 @@ VisualShaderNodeUniformRef::UniformType VisualShaderNodeUniformRef::get_uniform_
 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:
+			if (uniform_name == "[None]") {
+				return "\t" + p_output_vars[0] + " = 0.0;\n";
+			}
 			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";
@@ -2286,16 +2302,29 @@ String VisualShaderNodeUniformRef::generate_code(Shader::Mode p_mode, VisualShad
 	return "";
 }
 
+void VisualShaderNodeUniformRef::_set_uniform_type(int p_uniform_type) {
+	uniform_type = (UniformType)p_uniform_type;
+}
+
+int VisualShaderNodeUniformRef::_get_uniform_type() const {
+	return (int)uniform_type;
+}
+
 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);
 
+	ClassDB::bind_method(D_METHOD("_set_uniform_type", "type"), &VisualShaderNodeUniformRef::_set_uniform_type);
+	ClassDB::bind_method(D_METHOD("_get_uniform_type"), &VisualShaderNodeUniformRef::_get_uniform_type);
+
 	ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "uniform_name", PROPERTY_HINT_ENUM, ""), "set_uniform_name", "get_uniform_name");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "uniform_type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_uniform_type", "_get_uniform_type");
 }
 
 Vector<StringName> VisualShaderNodeUniformRef::get_editable_properties() const {
 	Vector<StringName> props;
 	props.push_back("uniform_name");
+	props.push_back("uniform_type");
 	return props;
 }
 

+ 6 - 0
scene/resources/visual_shader.h

@@ -242,6 +242,8 @@ public:
 	virtual bool is_generate_input_var(int p_port) const;
 
 	virtual bool is_code_generated() const;
+	virtual bool is_show_prop_names() const;
+	virtual bool is_use_prop_slots() const;
 
 	virtual Vector<StringName> get_editable_properties() const;
 
@@ -454,6 +456,7 @@ protected:
 public:
 	static void add_uniform(const String &p_name, UniformType p_type);
 	static void clear_uniforms();
+	static bool has_uniform(const String &p_name);
 
 public:
 	virtual String get_caption() const override;
@@ -469,6 +472,9 @@ public:
 	void set_uniform_name(const String &p_name);
 	String get_uniform_name() const;
 
+	void _set_uniform_type(int p_uniform_type);
+	int _get_uniform_type() 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;

+ 44 - 0
scene/resources/visual_shader_nodes.cpp

@@ -3490,6 +3490,14 @@ String VisualShaderNodeFloatUniform::generate_code(Shader::Mode p_mode, VisualSh
 	return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
 }
 
+bool VisualShaderNodeFloatUniform::is_show_prop_names() const {
+	return true;
+}
+
+bool VisualShaderNodeFloatUniform::is_use_prop_slots() const {
+	return true;
+}
+
 void VisualShaderNodeFloatUniform::set_hint(Hint p_hint) {
 	hint = p_hint;
 	emit_changed();
@@ -3649,6 +3657,14 @@ String VisualShaderNodeIntUniform::generate_code(Shader::Mode p_mode, VisualShad
 	return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
 }
 
+bool VisualShaderNodeIntUniform::is_show_prop_names() const {
+	return true;
+}
+
+bool VisualShaderNodeIntUniform::is_use_prop_slots() const {
+	return true;
+}
+
 void VisualShaderNodeIntUniform::set_hint(Hint p_hint) {
 	hint = p_hint;
 	emit_changed();
@@ -3823,6 +3839,14 @@ String VisualShaderNodeBooleanUniform::generate_code(Shader::Mode p_mode, Visual
 	return "\t" + p_output_vars[0] + " = " + get_uniform_name() + ";\n";
 }
 
+bool VisualShaderNodeBooleanUniform::is_show_prop_names() const {
+	return true;
+}
+
+bool VisualShaderNodeBooleanUniform::is_use_prop_slots() const {
+	return true;
+}
+
 void VisualShaderNodeBooleanUniform::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeBooleanUniform::set_default_value_enabled);
 	ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeBooleanUniform::is_default_value_enabled);
@@ -3913,6 +3937,10 @@ String VisualShaderNodeColorUniform::generate_code(Shader::Mode p_mode, VisualSh
 	return code;
 }
 
+bool VisualShaderNodeColorUniform::is_show_prop_names() const {
+	return true;
+}
+
 void VisualShaderNodeColorUniform::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_default_value_enabled", "enabled"), &VisualShaderNodeColorUniform::set_default_value_enabled);
 	ClassDB::bind_method(D_METHOD("is_default_value_enabled"), &VisualShaderNodeColorUniform::is_default_value_enabled);
@@ -4012,6 +4040,14 @@ void VisualShaderNodeVec3Uniform::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "default_value"), "set_default_value", "get_default_value");
 }
 
+bool VisualShaderNodeVec3Uniform::is_show_prop_names() const {
+	return true;
+}
+
+bool VisualShaderNodeVec3Uniform::is_use_prop_slots() const {
+	return true;
+}
+
 bool VisualShaderNodeVec3Uniform::is_qualifier_supported(Qualifier p_qual) const {
 	return true; // all qualifiers are supported
 }
@@ -4104,6 +4140,14 @@ void VisualShaderNodeTransformUniform::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "default_value"), "set_default_value", "get_default_value");
 }
 
+bool VisualShaderNodeTransformUniform::is_show_prop_names() const {
+	return true;
+}
+
+bool VisualShaderNodeTransformUniform::is_use_prop_slots() const {
+	return true;
+}
+
 bool VisualShaderNodeTransformUniform::is_qualifier_supported(Qualifier p_qual) const {
 	return true; // all qualifiers are supported
 }

+ 17 - 0
scene/resources/visual_shader_nodes.h

@@ -1529,6 +1529,9 @@ public:
 	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; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
 
+	virtual bool is_show_prop_names() const override;
+	virtual bool is_use_prop_slots() const override;
+
 	void set_hint(Hint p_hint);
 	Hint get_hint() const;
 
@@ -1591,6 +1594,9 @@ public:
 	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; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
 
+	virtual bool is_show_prop_names() const override;
+	virtual bool is_use_prop_slots() const override;
+
 	void set_hint(Hint p_hint);
 	Hint get_hint() const;
 
@@ -1644,6 +1650,9 @@ public:
 	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; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
 
+	virtual bool is_show_prop_names() const override;
+	virtual bool is_use_prop_slots() const override;
+
 	void set_default_value_enabled(bool p_enabled);
 	bool is_default_value_enabled() const;
 
@@ -1683,6 +1692,8 @@ public:
 	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; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
 
+	virtual bool is_show_prop_names() const override;
+
 	void set_default_value_enabled(bool p_enabled);
 	bool is_default_value_enabled() const;
 
@@ -1722,6 +1733,9 @@ public:
 	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; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
 
+	virtual bool is_show_prop_names() const override;
+	virtual bool is_use_prop_slots() const override;
+
 	void set_default_value_enabled(bool p_enabled);
 	bool is_default_value_enabled() const;
 
@@ -1761,6 +1775,9 @@ public:
 	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; //if no output is connected, the output var passed will be empty. if no input is connected and input is NIL, the input var passed will be empty
 
+	virtual bool is_show_prop_names() const override;
+	virtual bool is_use_prop_slots() const override;
+
 	void set_default_value_enabled(bool p_enabled);
 	bool is_default_value_enabled() const;