Browse Source

Added triplanar uniform texture node to visual shaders

Chaosus 6 years ago
parent
commit
0727caadd1

+ 3 - 2
editor/plugins/visual_shader_editor_plugin.cpp

@@ -2229,8 +2229,9 @@ VisualShaderEditor::VisualShaderEditor() {
 	add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubeMap", TTR("Perform the cubic texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
 	add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubeMap", TTR("Perform the cubic texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
 	add_options.push_back(AddOption("Texture", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
 	add_options.push_back(AddOption("Texture", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
 
 
-	add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubeMapUniform", TTR("Cubic texture uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR));
-	add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+	add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubeMapUniform", TTR("Cubic texture uniform lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+	add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR));
+	add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, VisualShaderNode::PORT_TYPE_COLOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL));
 
 
 	// TRANSFORM
 	// TRANSFORM
 
 

+ 1 - 0
scene/register_scene_types.cpp

@@ -522,6 +522,7 @@ void register_scene_types() {
 	ClassDB::register_class<VisualShaderNodeVec3Uniform>();
 	ClassDB::register_class<VisualShaderNodeVec3Uniform>();
 	ClassDB::register_class<VisualShaderNodeTransformUniform>();
 	ClassDB::register_class<VisualShaderNodeTransformUniform>();
 	ClassDB::register_class<VisualShaderNodeTextureUniform>();
 	ClassDB::register_class<VisualShaderNodeTextureUniform>();
+	ClassDB::register_class<VisualShaderNodeTextureUniformTriplanar>();
 	ClassDB::register_class<VisualShaderNodeCubeMapUniform>();
 	ClassDB::register_class<VisualShaderNodeCubeMapUniform>();
 	ClassDB::register_class<VisualShaderNodeIf>();
 	ClassDB::register_class<VisualShaderNodeIf>();
 	ClassDB::register_class<VisualShaderNodeSwitch>();
 	ClassDB::register_class<VisualShaderNodeSwitch>();

+ 36 - 5
scene/resources/visual_shader.cpp

@@ -67,6 +67,14 @@ String VisualShaderNode::generate_global(Shader::Mode p_mode, VisualShader::Type
 	return String();
 	return String();
 }
 }
 
 
+String VisualShaderNode::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+	return String();
+}
+
+String VisualShaderNode::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+	return String();
+}
+
 Vector<StringName> VisualShaderNode::get_editable_properties() const {
 Vector<StringName> VisualShaderNode::get_editable_properties() const {
 	return Vector<StringName>();
 	return Vector<StringName>();
 }
 }
@@ -449,7 +457,10 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
 	ERR_FAIL_COND_V(node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_TRANSFORM, String());
 	ERR_FAIL_COND_V(node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_TRANSFORM, String());
 
 
 	StringBuilder global_code;
 	StringBuilder global_code;
+	StringBuilder global_code_per_node;
+	Map<Type, StringBuilder> global_code_per_func;
 	StringBuilder code;
 	StringBuilder code;
+	Set<StringName> classes;
 
 
 	global_code += String() + "shader_type canvas_item;\n";
 	global_code += String() + "shader_type canvas_item;\n";
 
 
@@ -474,7 +485,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
 	code += "\nvoid fragment() {\n";
 	code += "\nvoid fragment() {\n";
 
 
 	Set<int> processed;
 	Set<int> processed;
-	Error err = _write_node(p_type, global_code, code, default_tex_params, input_connections, output_connections, p_node, processed, true);
+	Error err = _write_node(p_type, global_code, global_code_per_node, global_code_per_func, code, default_tex_params, input_connections, output_connections, p_node, processed, true, classes);
 	ERR_FAIL_COND_V(err != OK, String());
 	ERR_FAIL_COND_V(err != OK, String());
 
 
 	if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_SCALAR) {
 	if (node->get_output_port_type(p_port) == VisualShaderNode::PORT_TYPE_SCALAR) {
@@ -489,6 +500,7 @@ String VisualShader::generate_preview_shader(Type p_type, int p_node, int p_port
 	//set code secretly
 	//set code secretly
 	global_code += "\n\n";
 	global_code += "\n\n";
 	String final_code = global_code;
 	String final_code = global_code;
+	final_code += global_code_per_node;
 	final_code += code;
 	final_code += code;
 	return final_code;
 	return final_code;
 }
 }
@@ -833,7 +845,7 @@ void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const {
 	}
 	}
 }
 }
 
 
-Error VisualShader::_write_node(Type type, StringBuilder &global_code, 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) 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;
 	const Ref<VisualShaderNode> vsnode = graph[type].nodes[node].node;
 
 
@@ -850,7 +862,7 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
 				continue;
 				continue;
 			}
 			}
 
 
-			Error err = _write_node(type, global_code, code, def_tex_params, input_connections, output_connections, from_node, processed, for_preview);
+			Error err = _write_node(type, global_code, global_code_per_node, global_code_per_func, code, def_tex_params, input_connections, output_connections, from_node, processed, for_preview, r_classes);
 			if (err)
 			if (err)
 				return err;
 				return err;
 		}
 		}
@@ -958,6 +970,14 @@ Error VisualShader::_write_node(Type type, StringBuilder &global_code, StringBui
 
 
 	if (!skip_global) {
 	if (!skip_global) {
 		global_code += vsnode->generate_global(get_mode(), type, node);
 		global_code += vsnode->generate_global(get_mode(), type, node);
+
+		if (!r_classes.has(vsnode->get_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(vsnode->get_class_name());
+		}
 	}
 	}
 
 
 	//handle normally
 	//handle normally
@@ -976,8 +996,12 @@ void VisualShader::_update_shader() const {
 	dirty = false;
 	dirty = false;
 
 
 	StringBuilder global_code;
 	StringBuilder global_code;
+	StringBuilder global_code_per_node;
+	Map<Type, StringBuilder> global_code_per_func;
 	StringBuilder code;
 	StringBuilder code;
 	Vector<VisualShader::DefaultTextureParam> default_tex_params;
 	Vector<VisualShader::DefaultTextureParam> default_tex_params;
+	Set<StringName> classes;
+	List<int> insertion_pos;
 	static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles" };
 	static const char *shader_mode_str[Shader::MODE_MAX] = { "spatial", "canvas_item", "particles" };
 
 
 	global_code += String() + "shader_type " + shader_mode_str[shader_mode] + ";\n";
 	global_code += String() + "shader_type " + shader_mode_str[shader_mode] + ";\n";
@@ -1056,8 +1080,9 @@ void VisualShader::_update_shader() const {
 		code += "\nvoid " + String(func_name[i]) + "() {\n";
 		code += "\nvoid " + String(func_name[i]) + "() {\n";
 
 
 		Set<int> processed;
 		Set<int> processed;
-		Error err = _write_node(Type(i), global_code, code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false);
+		Error err = _write_node(Type(i), global_code, global_code_per_node, global_code_per_func, code, default_tex_params, input_connections, output_connections, NODE_ID_OUTPUT, processed, false, classes);
 		ERR_FAIL_COND(err != OK);
 		ERR_FAIL_COND(err != OK);
+		insertion_pos.push_back(code.get_string_length());
 
 
 		code += "}\n";
 		code += "}\n";
 	}
 	}
@@ -1065,7 +1090,13 @@ void VisualShader::_update_shader() const {
 	//set code secretly
 	//set code secretly
 	global_code += "\n\n";
 	global_code += "\n\n";
 	String final_code = global_code;
 	String final_code = global_code;
-	final_code += code;
+	final_code += global_code_per_node;
+	String tcode = code;
+	for (int i = 0; i < TYPE_MAX; i++) {
+		tcode = tcode.insert(insertion_pos[i], global_code_per_func[Type(i)]);
+	}
+	final_code += tcode;
+
 	const_cast<VisualShader *>(this)->set_code(final_code);
 	const_cast<VisualShader *>(this)->set_code(final_code);
 	for (int i = 0; i < default_tex_params.size(); i++) {
 	for (int i = 0; i < default_tex_params.size(); i++) {
 		const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].param);
 		const_cast<VisualShader *>(this)->set_default_texture_param(default_tex_params[i].name, default_tex_params[i].param);

+ 3 - 1
scene/resources/visual_shader.h

@@ -103,7 +103,7 @@ private:
 		}
 		}
 	};
 	};
 
 
-	Error _write_node(Type p_type, StringBuilder &global_code, StringBuilder &code, Vector<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) const;
+	Error _write_node(Type p_type, StringBuilder &global_code, StringBuilder &global_code_per_node, Map<Type, StringBuilder> &global_code_per_func, StringBuilder &code, Vector<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;
 
 
 	void _input_type_changed(Type p_type, int p_id);
 	void _input_type_changed(Type p_type, int p_id);
 
 
@@ -208,6 +208,8 @@ public:
 
 
 	virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;
 	virtual Vector<VisualShader::DefaultTextureParam> get_default_texture_parameters(VisualShader::Type p_type, int p_id) const;
 	virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
 	virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+	virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+	virtual String generate_global_per_func(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 = 0; //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 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 = 0; //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 String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const;
 	virtual String get_warning(Shader::Mode p_mode, VisualShader::Type p_type) const;

+ 92 - 0
scene/resources/visual_shader_nodes.cpp

@@ -2968,6 +2968,98 @@ VisualShaderNodeTextureUniform::VisualShaderNodeTextureUniform() {
 	color_default = COLOR_DEFAULT_WHITE;
 	color_default = COLOR_DEFAULT_WHITE;
 }
 }
 
 
+////////////// Texture Uniform (Triplanar)
+
+String VisualShaderNodeTextureUniformTriplanar::get_caption() const {
+	return "TextureUniformTriplanar";
+}
+
+int VisualShaderNodeTextureUniformTriplanar::get_input_port_count() const {
+	return 2;
+}
+
+VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniformTriplanar::get_input_port_type(int p_port) const {
+	if (p_port == 0) {
+		return PORT_TYPE_VECTOR;
+	} else if (p_port == 1) {
+		return PORT_TYPE_VECTOR;
+	}
+	return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeTextureUniformTriplanar::get_input_port_name(int p_port) const {
+	if (p_port == 0) {
+		return "weights";
+	} else if (p_port == 1) {
+		return "pos";
+	}
+	return "";
+}
+
+String VisualShaderNodeTextureUniformTriplanar::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+
+	String code;
+
+	code += "// TRIPLANAR FUNCTION GLOBAL CODE\n";
+	code += "\tvec4 triplanar_texture(sampler2D p_sampler, vec3 p_weights, vec3 p_triplanar_pos) {\n";
+	code += "\t\tvec4 samp = vec4(0.0);\n";
+	code += "\t\tsamp += texture(p_sampler, p_triplanar_pos.xy) * p_weights.z;\n";
+	code += "\t\tsamp += texture(p_sampler, p_triplanar_pos.xz) * p_weights.y;\n";
+	code += "\t\tsamp += texture(p_sampler, p_triplanar_pos.zy * vec2(-1.0, 1.0)) * p_weights.x;\n";
+	code += "\t\treturn samp;\n";
+	code += "\t}\n";
+	code += "\n";
+	code += "\tuniform vec3 triplanar_scale = vec3(1.0, 1.0, 1.0);\n";
+	code += "\tuniform vec3 triplanar_offset;\n";
+	code += "\tuniform float triplanar_sharpness = 0.5;\n";
+	code += "\n";
+	code += "\tvarying vec3 triplanar_power_normal;\n";
+	code += "\tvarying vec3 triplanar_pos;\n";
+
+	return code;
+}
+
+String VisualShaderNodeTextureUniformTriplanar::generate_global_per_func(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+
+	String code;
+
+	if (p_type == VisualShader::TYPE_VERTEX) {
+
+		code += "\t// TRIPLANAR FUNCTION VERTEX CODE\n";
+		code += "\t\ttriplanar_power_normal = pow(abs(NORMAL), vec3(triplanar_sharpness));\n";
+		code += "\t\ttriplanar_power_normal /= dot(triplanar_power_normal, vec3(1.0));\n";
+		code += "\t\ttriplanar_pos = VERTEX * triplanar_scale + triplanar_offset;\n";
+		code += "\t\ttriplanar_pos *= vec3(1.0, -1.0, 1.0);\n";
+	}
+
+	return code;
+}
+
+String VisualShaderNodeTextureUniformTriplanar::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 id = get_uniform_name();
+	String code = "\t{\n";
+
+	if (p_input_vars[0] == String() && p_input_vars[1] == String()) {
+		code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", triplanar_power_normal, triplanar_pos );\n";
+	} else if (p_input_vars[0] != String() && p_input_vars[1] == String()) {
+		code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", " + p_input_vars[0] + ", triplanar_pos );\n";
+	} else if (p_input_vars[0] == String() && p_input_vars[1] != String()) {
+		code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", triplanar_power_normal," + p_input_vars[1] + " );\n";
+	} else {
+		code += "\t\tvec4 n_tex_read = triplanar_texture( " + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + " );\n";
+	}
+
+	code += "\t\t" + p_output_vars[0] + " = n_tex_read.rgb;\n";
+	code += "\t\t" + p_output_vars[1] + " = n_tex_read.a;\n";
+	code += "\t}\n";
+
+	return code;
+}
+
+VisualShaderNodeTextureUniformTriplanar::VisualShaderNodeTextureUniformTriplanar() {
+}
+
 ////////////// CubeMap Uniform
 ////////////// CubeMap Uniform
 
 
 String VisualShaderNodeCubeMapUniform::get_caption() const {
 String VisualShaderNodeCubeMapUniform::get_caption() const {

+ 19 - 0
scene/resources/visual_shader_nodes.h

@@ -1425,6 +1425,25 @@ VARIANT_ENUM_CAST(VisualShaderNodeTextureUniform::ColorDefault)
 
 
 ///////////////////////////////////////
 ///////////////////////////////////////
 
 
+class VisualShaderNodeTextureUniformTriplanar : public VisualShaderNodeTextureUniform {
+	GDCLASS(VisualShaderNodeTextureUniformTriplanar, VisualShaderNodeTextureUniform);
+
+public:
+	virtual String get_caption() const;
+
+	virtual int get_input_port_count() const;
+	virtual PortType get_input_port_type(int p_port) const;
+	virtual String get_input_port_name(int p_port) const;
+
+	virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const;
+	virtual String generate_global_per_func(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
+
+	VisualShaderNodeTextureUniformTriplanar();
+};
+
+///////////////////////////////////////
+
 class VisualShaderNodeCubeMapUniform : public VisualShaderNode {
 class VisualShaderNodeCubeMapUniform : public VisualShaderNode {
 	GDCLASS(VisualShaderNodeCubeMapUniform, VisualShaderNode);
 	GDCLASS(VisualShaderNodeCubeMapUniform, VisualShaderNode);