Преглед изворни кода

[3.2] Optimizations for Fresnel and Texture nodes in visual shaders

Yuri Roubinsky пре 5 година
родитељ
комит
ec7228a675

+ 74 - 27
scene/resources/visual_shader.cpp

@@ -64,6 +64,40 @@ bool VisualShaderNode::is_port_separator(int p_index) const {
 	return false;
 }
 
+bool VisualShaderNode::is_output_port_connected(int p_port) const {
+	if (connected_output_ports.has(p_port)) {
+		return connected_output_ports[p_port] > 0;
+	}
+	return false;
+}
+
+void VisualShaderNode::set_output_port_connected(int p_port, bool p_connected) {
+	if (p_connected) {
+		connected_output_ports[p_port]++;
+	} else {
+		connected_output_ports[p_port]--;
+	}
+}
+
+bool VisualShaderNode::is_input_port_connected(int p_port) const {
+	if (connected_input_ports.has(p_port)) {
+		return connected_input_ports[p_port];
+	}
+	return false;
+}
+
+void VisualShaderNode::set_input_port_connected(int p_port, bool p_connected) {
+	connected_input_ports[p_port] = p_connected;
+}
+
+bool VisualShaderNode::is_generate_input_var(int p_port) const {
+	return true;
+}
+
+bool VisualShaderNode::is_code_generated() const {
+	return true;
+}
+
 Vector<VisualShader::DefaultTextureParam> VisualShaderNode::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
 	return Vector<VisualShader::DefaultTextureParam>();
 }
@@ -387,6 +421,7 @@ void VisualShader::remove_node(Type p_type, int p_id) {
 			g->connections.erase(E);
 			if (E->get().from_node == p_id) {
 				g->nodes[E->get().to_node].prev_connected_nodes.erase(p_id);
+				g->nodes[E->get().to_node].node->set_input_port_connected(E->get().to_port, false);
 			}
 		}
 		E = N;
@@ -482,6 +517,8 @@ void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from
 	c.to_port = p_to_port;
 	g->connections.push_back(c);
 	g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
+	g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
+	g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
 
 	_queue_update();
 }
@@ -514,6 +551,8 @@ Error VisualShader::connect_nodes(Type p_type, int p_from_node, int p_from_port,
 	c.to_port = p_to_port;
 	g->connections.push_back(c);
 	g->nodes[p_to_node].prev_connected_nodes.push_back(p_from_node);
+	g->nodes[p_from_node].node->set_output_port_connected(p_from_port, true);
+	g->nodes[p_to_node].node->set_input_port_connected(p_to_port, true);
 
 	_queue_update();
 	return OK;
@@ -528,6 +567,8 @@ void VisualShader::disconnect_nodes(Type p_type, int p_from_node, int p_from_por
 		if (E->get().from_node == p_from_node && E->get().from_port == p_from_port && E->get().to_node == p_to_node && E->get().to_port == p_to_port) {
 			g->connections.erase(E);
 			g->nodes[p_to_node].prev_connected_nodes.erase(p_from_node);
+			g->nodes[p_from_node].node->set_output_port_connected(p_from_port, false);
+			g->nodes[p_to_node].node->set_input_port_connected(p_to_port, false);
 			_queue_update();
 			return;
 		}
@@ -1078,6 +1119,36 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
 
 	// then this node
 
+	Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node);
+	for (int i = 0; i < params.size(); i++) {
+		def_tex_params.push_back(params[i]);
+	}
+
+	Ref<VisualShaderNodeInput> input = vsnode;
+	bool skip_global = input.is_valid() && for_preview;
+
+	if (!skip_global) {
+
+		global_code += vsnode->generate_global(get_mode(), type, node);
+
+		String class_name = vsnode->get_class_name();
+		if (class_name == "VisualShaderNodeCustom") {
+			class_name = vsnode->get_script_instance()->get_script()->get_path();
+		}
+		if (!r_classes.has(class_name)) {
+			global_code_per_node += vsnode->generate_global_per_node(get_mode(), type, node);
+			for (int i = 0; i < TYPE_MAX; i++) {
+				global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node);
+			}
+			r_classes.insert(class_name);
+		}
+	}
+
+	if (!vsnode->is_code_generated()) { // just generate globals and ignore locals
+		processed.insert(node);
+		return OK;
+	}
+
 	code += "// " + vsnode->get_caption() + ":" + itos(node) + "\n";
 	Vector<String> input_vars;
 
@@ -1124,6 +1195,9 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
 				inputs[i] = "vec3(" + src_var + " ? 1.0 : 0.0)";
 			}
 		} else {
+			if (!vsnode->is_generate_input_var(i)) {
+				continue;
+			}
 
 			Variant defval = vsnode->get_input_port_default_value(i);
 			if (defval.get_type() == Variant::REAL || defval.get_type() == Variant::INT) {
@@ -1191,33 +1265,6 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
 		}
 	}
 
-	Vector<VisualShader::DefaultTextureParam> params = vsnode->get_default_texture_parameters(type, node);
-	for (int i = 0; i < params.size(); i++) {
-		def_tex_params.push_back(params[i]);
-	}
-
-	Ref<VisualShaderNodeInput> input = vsnode;
-	bool skip_global = input.is_valid() && for_preview;
-
-	if (!skip_global) {
-		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") {
-			class_name = vsnode->get_script_instance()->get_script()->get_path();
-		}
-		if (!r_classes.has(class_name)) {
-			global_code_per_node += vsnode->generate_global_per_node(get_mode(), type, node);
-			for (int i = 0; i < TYPE_MAX; i++) {
-				global_code_per_func[Type(i)] += vsnode->generate_global_per_func(get_mode(), Type(i), node);
-			}
-			r_classes.insert(class_name);
-		}
-	}
-
 	code += vsnode->generate_code(get_mode(), type, node, inputs, outputs, for_preview);
 
 	code += "\n"; //

+ 10 - 0
scene/resources/visual_shader.h

@@ -174,6 +174,8 @@ class VisualShaderNode : public Resource {
 	int port_preview;
 
 	Map<int, Variant> default_input_values;
+	Map<int, bool> connected_input_ports;
+	Map<int, int> connected_output_ports;
 
 protected:
 	bool simple_decl;
@@ -213,6 +215,14 @@ public:
 
 	virtual bool is_port_separator(int p_index) const;
 
+	bool is_output_port_connected(int p_port) const;
+	void set_output_port_connected(int p_port, bool p_connected);
+	bool is_input_port_connected(int p_port) const;
+	void set_input_port_connected(int p_port, bool p_connected);
+	virtual bool is_generate_input_var(int p_port) const;
+
+	virtual bool is_code_generated() const;
+
 	virtual Vector<StringName> get_editable_properties() const;
 
 	virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;

+ 20 - 1
scene/resources/visual_shader_nodes.cpp

@@ -3266,6 +3266,10 @@ String VisualShaderNodeTextureUniform::get_output_port_name(int p_port) const {
 	}
 }
 
+bool VisualShaderNodeTextureUniform::is_code_generated() const {
+	return is_output_port_connected(0) || is_output_port_connected(1); // rgb or alpha
+}
+
 String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
 	String code = "uniform sampler2D " + get_uniform_name();
 
@@ -3749,6 +3753,13 @@ String VisualShaderNodeFresnel::get_output_port_name(int p_port) const {
 	return "result";
 }
 
+bool VisualShaderNodeFresnel::is_generate_input_var(int p_port) const {
+	if (p_port == 2) {
+		return false;
+	}
+	return true;
+}
+
 String VisualShaderNodeFresnel::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 normal;
@@ -3764,7 +3775,15 @@ String VisualShaderNodeFresnel::generate_code(Shader::Mode p_mode, VisualShader:
 		view = p_input_vars[1];
 	}
 
-	return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n";
+	if (is_input_port_connected(2)) {
+		return "\t" + p_output_vars[0] + " = " + p_input_vars[2] + " ? (pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ")) : (pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + "));\n";
+	} else {
+		if (get_input_port_default_value(2)) {
+			return "\t" + p_output_vars[0] + " = pow(clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n";
+		} else {
+			return "\t" + p_output_vars[0] + " = pow(1.0 - clamp(dot(" + normal + ", " + view + "), 0.0, 1.0), " + p_input_vars[3] + ");\n";
+		}
+	}
 }
 
 String VisualShaderNodeFresnel::get_input_port_default_hint(int p_port) const {

+ 3 - 0
scene/resources/visual_shader_nodes.h

@@ -1445,6 +1445,8 @@ public:
 	virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
 	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; //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_code_generated() const;
+
 	Vector<StringName> get_editable_properties() const;
 
 	void set_texture_type(TextureType p_type);
@@ -1580,6 +1582,7 @@ public:
 	virtual String get_output_port_name(int p_port) const;
 
 	virtual String get_input_port_default_hint(int p_port) const;
+	virtual bool is_generate_input_var(int p_port) const;
 	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;
 
 	VisualShaderNodeFresnel();