2
0
Эх сурвалжийг харах

Enchance `VisualShaderNodeMeshEmitter`, add more ports and fix bugs

Yuri Roubinsky 3 жил өмнө
parent
commit
0270144644

+ 1 - 0
scene/resources/visual_shader.cpp

@@ -1835,6 +1835,7 @@ void VisualShader::_update_shader() const {
 			code += "	float __scalar_buff1;\n";
 			code += "	float __scalar_buff2;\n";
 			code += "	int __scalar_ibuff;\n";
+			code += "	vec4 __vec4_buff;\n";
 			code += "	vec3 __ndiff = normalize(__diff);\n\n";
 		}
 		if (has_start) {

+ 218 - 71
scene/resources/visual_shader_particle_nodes.cpp

@@ -264,7 +264,7 @@ String VisualShaderNodeParticleMeshEmitter::get_caption() const {
 }
 
 int VisualShaderNodeParticleMeshEmitter::get_output_port_count() const {
-	return 2;
+	return 6;
 }
 
 VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleMeshEmitter::get_output_port_type(int p_port) const {
@@ -273,6 +273,14 @@ VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleMeshEmitter
 			return PORT_TYPE_VECTOR; // position
 		case 1:
 			return PORT_TYPE_VECTOR; // normal
+		case 2:
+			return PORT_TYPE_VECTOR; // color
+		case 3:
+			return PORT_TYPE_SCALAR; // alpha
+		case 4:
+			return PORT_TYPE_VECTOR; // uv
+		case 5:
+			return PORT_TYPE_VECTOR; // uv2
 	}
 	return PORT_TYPE_SCALAR;
 }
@@ -283,6 +291,14 @@ String VisualShaderNodeParticleMeshEmitter::get_output_port_name(int p_port) con
 			return "position";
 		case 1:
 			return "normal";
+		case 2:
+			return "color";
+		case 3:
+			return "alpha";
+		case 4:
+			return "uv";
+		case 5:
+			return "uv2";
 	}
 	return String();
 }
@@ -299,135 +315,263 @@ String VisualShaderNodeParticleMeshEmitter::get_input_port_name(int p_port) cons
 	return String();
 }
 
-String VisualShaderNodeParticleMeshEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+String VisualShaderNodeParticleMeshEmitter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
 	String code;
 
 	if (mesh.is_valid()) {
-		code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_vx") + ";\n";
-		code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_nm") + ";\n";
+		if (is_output_port_connected(0)) { // position
+			code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_vx") + ";\n";
+		}
+
+		if (is_output_port_connected(1)) { // normal
+			code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_nm") + ";\n";
+		}
+
+		if (is_output_port_connected(2) || is_output_port_connected(3)) { // color & alpha
+			code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_col") + ";\n";
+		}
+
+		if (is_output_port_connected(4)) { // uv
+			code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_uv") + ";\n";
+		}
+
+		if (is_output_port_connected(5)) { // uv2
+			code += "uniform sampler2D " + make_unique_id(p_type, p_id, "mesh_uv2") + ";\n";
+		}
 	}
 
 	return code;
 }
 
-String VisualShaderNodeParticleMeshEmitter::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 VisualShaderNodeParticleMeshEmitter::_generate_code(VisualShader::Type p_type, int p_id, const String *p_output_vars, int p_index, const String &p_texture_name, bool p_ignore_mode2d) const {
 	String code;
-
-	code += "	__scalar_ibuff = int(__rand_from_seed(__seed) * 65535.0) % " + itos(position_texture->get_width()) + ";\n";
-
-	if (position_texture->get_width() == 0) {
-		code += "		" + p_output_vars[0] + " = vec3(0.0);\n";
-	} else {
-		if (mode_2d) {
-			code += "	" + p_output_vars[0] + " = vec3(";
+	if (is_output_port_connected(p_index)) {
+		if (mode_2d && !p_ignore_mode2d) {
+			code += "	" + p_output_vars[p_index] + " = vec3(";
 			code += "texelFetch(";
-			code += make_unique_id(p_type, p_id, "mesh_vx") + ", ";
+			code += make_unique_id(p_type, p_id, p_texture_name) + ", ";
 			code += "ivec2(__scalar_ibuff, 0), 0).xy, 0.0);\n";
 		} else {
-			code += "	" + p_output_vars[0] + " = texelFetch(";
-			code += make_unique_id(p_type, p_id, "mesh_vx") + ", ";
+			code += "	" + p_output_vars[p_index] + " = texelFetch(";
+			code += make_unique_id(p_type, p_id, p_texture_name) + ", ";
 			code += "ivec2(__scalar_ibuff, 0), 0).xyz;\n";
 		}
 	}
+	return code;
+}
 
-	if (normal_texture->get_width() == 0) {
-		code += "		" + p_output_vars[1] + " = vec3(0.0);\n";
-	} else {
-		if (mode_2d) {
-			code += "	" + p_output_vars[1] + " = vec3(";
-			code += "texelFetch(";
-			code += make_unique_id(p_type, p_id, "mesh_nm") + ", ";
-			code += "ivec2(__scalar_ibuff, 0), 0).xy, 0.0);\n";
+String VisualShaderNodeParticleMeshEmitter::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;
+	code += "	__scalar_ibuff = int(__rand_from_seed(__seed) * 65535.0) % " + itos(position_texture->get_width()) + ";\n";
+
+	code += _generate_code(p_type, p_id, p_output_vars, 0, "mesh_vx");
+	code += _generate_code(p_type, p_id, p_output_vars, 1, "mesh_nm");
+
+	if (is_output_port_connected(2) || is_output_port_connected(3)) {
+		code += "	__vec4_buff = texelFetch(";
+		code += make_unique_id(p_type, p_id, "mesh_col") + ", ";
+		code += "ivec2(__scalar_ibuff, 0), 0);\n";
+		if (is_output_port_connected(2)) {
+			code += "	" + p_output_vars[2] + " = __vec4_buff.rgb;\n";
 		} else {
-			code += "	" + p_output_vars[1] + " = texelFetch(";
-			code += make_unique_id(p_type, p_id, "mesh_nm") + ", ";
-			code += "ivec2(__scalar_ibuff, 0), 0).xyz;\n";
+			code += "	" + p_output_vars[2] + " = vec3(0.0);\n";
+		}
+		if (is_output_port_connected(3)) {
+			code += "	" + p_output_vars[3] + " = __vec4_buff.a;\n";
+		} else {
+			code += "	" + p_output_vars[3] + " = 0.0;\n";
 		}
 	}
 
+	code += _generate_code(p_type, p_id, p_output_vars, 4, "mesh_uv", true);
+	code += _generate_code(p_type, p_id, p_output_vars, 5, "mesh_uv2", true);
+
 	return code;
 }
 
 Vector<VisualShader::DefaultTextureParam> VisualShaderNodeParticleMeshEmitter::get_default_texture_parameters(VisualShader::Type p_type, int p_id) const {
-	VisualShader::DefaultTextureParam dtp_vx;
-	dtp_vx.name = make_unique_id(p_type, p_id, "mesh_vx");
-	dtp_vx.params.push_back(position_texture);
+	Vector<VisualShader::DefaultTextureParam> ret;
 
-	VisualShader::DefaultTextureParam dtp_nm;
-	dtp_nm.name = make_unique_id(p_type, p_id, "mesh_nm");
-	dtp_nm.params.push_back(normal_texture);
+	if (is_output_port_connected(0)) {
+		VisualShader::DefaultTextureParam dtp;
+		dtp.name = make_unique_id(p_type, p_id, "mesh_vx");
+		dtp.params.push_back(position_texture);
+		ret.push_back(dtp);
+	}
+
+	if (is_output_port_connected(1)) {
+		VisualShader::DefaultTextureParam dtp;
+		dtp.name = make_unique_id(p_type, p_id, "mesh_nm");
+		dtp.params.push_back(normal_texture);
+		ret.push_back(dtp);
+	}
+
+	if (is_output_port_connected(2) || is_output_port_connected(3)) {
+		VisualShader::DefaultTextureParam dtp;
+		dtp.name = make_unique_id(p_type, p_id, "mesh_col");
+		dtp.params.push_back(color_texture);
+		ret.push_back(dtp);
+	}
+
+	if (is_output_port_connected(4)) {
+		VisualShader::DefaultTextureParam dtp;
+		dtp.name = make_unique_id(p_type, p_id, "mesh_uv");
+		dtp.params.push_back(uv_texture);
+		ret.push_back(dtp);
+	}
+
+	if (is_output_port_connected(5)) {
+		VisualShader::DefaultTextureParam dtp;
+		dtp.name = make_unique_id(p_type, p_id, "mesh_uv2");
+		dtp.params.push_back(uv2_texture);
+		ret.push_back(dtp);
+	}
 
-	Vector<VisualShader::DefaultTextureParam> ret;
-	ret.push_back(dtp_vx);
-	ret.push_back(dtp_nm);
 	return ret;
 }
 
-void VisualShaderNodeParticleMeshEmitter::update_texture() {
+void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector2> &p_array, Ref<ImageTexture> &r_texture) {
+	Ref<Image> image;
+	image.instantiate();
+
+	if (p_array.size() == 0) {
+		image->create(1, 1, false, Image::Format::FORMAT_RGBF);
+	} else {
+		image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
+	}
+
+	for (int i = 0; i < p_array.size(); i++) {
+		Vector2 v = p_array[i];
+		image->set_pixel(i, 0, Color(v.x, v.y, 0));
+	}
+	if (r_texture->get_width() != p_array.size() || p_array.size() == 0) {
+		r_texture->create_from_image(image);
+	} else {
+		r_texture->update(image);
+	}
+}
+
+void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Vector3> &p_array, Ref<ImageTexture> &r_texture) {
+	Ref<Image> image;
+	image.instantiate();
+
+	if (p_array.size() == 0) {
+		image->create(1, 1, false, Image::Format::FORMAT_RGBF);
+	} else {
+		image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBF);
+	}
+
+	for (int i = 0; i < p_array.size(); i++) {
+		Vector3 v = p_array[i];
+		image->set_pixel(i, 0, Color(v.x, v.y, v.z));
+	}
+	if (r_texture->get_width() != p_array.size() || p_array.size() == 0) {
+		r_texture->create_from_image(image);
+	} else {
+		r_texture->update(image);
+	}
+}
+
+void VisualShaderNodeParticleMeshEmitter::_update_texture(const Vector<Color> &p_array, Ref<ImageTexture> &r_texture) {
+	Ref<Image> image;
+	image.instantiate();
+
+	if (p_array.size() == 0) {
+		image->create(1, 1, false, Image::Format::FORMAT_RGBA8);
+	} else {
+		image->create(p_array.size(), 1, false, Image::Format::FORMAT_RGBA8);
+	}
+
+	for (int i = 0; i < p_array.size(); i++) {
+		image->set_pixel(i, 0, p_array[i]);
+	}
+	if (r_texture->get_width() != p_array.size() || p_array.size() == 0) {
+		r_texture->create_from_image(image);
+	} else {
+		r_texture->update(image);
+	}
+}
+
+void VisualShaderNodeParticleMeshEmitter::_update_textures() {
 	if (!mesh.is_valid()) {
 		return;
 	}
 
 	Vector<Vector3> vertices;
 	Vector<Vector3> normals;
+	Vector<Color> colors;
+	Vector<Vector2> uvs;
+	Vector<Vector2> uvs2;
 
 	if (use_all_surfaces) {
 		for (int i = 0; i < max_surface_index; i++) {
+			// position
 			Array vertex_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_VERTEX];
 			for (int j = 0; j < vertex_array.size(); j++) {
 				vertices.push_back((Vector3)vertex_array[j]);
 			}
 
+			// normal
 			Array normal_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_NORMAL];
-			for (int j = 0; j < vertex_array.size(); j++) {
-				normals.push_back((Vector3)vertex_array[j]);
+			for (int j = 0; j < normal_array.size(); j++) {
+				normals.push_back((Vector3)normal_array[j]);
+			}
+
+			// color
+			Array color_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_COLOR];
+			for (int j = 0; j < color_array.size(); j++) {
+				colors.push_back((Color)color_array[j]);
+			}
+
+			// uv
+			Array uv_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_TEX_UV];
+			for (int j = 0; j < uv_array.size(); j++) {
+				uvs.push_back((Vector2)uv_array[j]);
+			}
+
+			// uv2
+			Array uv2_array = mesh->surface_get_arrays(i)[Mesh::ARRAY_TEX_UV2];
+			for (int j = 0; j < uv2_array.size(); j++) {
+				uvs2.push_back((Vector2)uv2_array[j]);
 			}
 		}
 	} else {
+		// position
 		Array vertex_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_VERTEX];
 		for (int i = 0; i < vertex_array.size(); i++) {
 			vertices.push_back((Vector3)vertex_array[i]);
 		}
 
+		// normal
 		Array normal_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_NORMAL];
 		for (int i = 0; i < normal_array.size(); i++) {
 			normals.push_back((Vector3)normal_array[i]);
 		}
-	}
 
-	// vertices
-	{
-		Ref<Image> image;
-		image.instantiate();
-		image->create(vertices.size(), 1, false, Image::Format::FORMAT_RGBF);
-
-		for (int i = 0; i < vertices.size(); i++) {
-			Vector3 v = vertices[i];
-			image->set_pixel(i, 0, Color(v.x, v.y, v.z));
-		}
-		if (position_texture->get_width() != vertices.size()) {
-			position_texture->create_from_image(image);
-		} else {
-			position_texture->update(image);
+		// color
+		Array color_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_COLOR];
+		for (int i = 0; i < color_array.size(); i++) {
+			colors.push_back((Color)color_array[i]);
 		}
-	}
-
-	// normals
-	{
-		Ref<Image> image;
-		image.instantiate();
-		image->create(normals.size(), 1, false, Image::Format::FORMAT_RGBF);
 
-		for (int i = 0; i < normals.size(); i++) {
-			Vector3 v = normals[i];
-			image->set_pixel(i, 0, Color(v.x, v.y, v.z));
+		// uv
+		Array uv_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_TEX_UV];
+		for (int j = 0; j < uv_array.size(); j++) {
+			uvs.push_back((Vector2)uv_array[j]);
 		}
-		if (normal_texture->get_width() != normals.size()) {
-			normal_texture->create_from_image(image);
-		} else {
-			normal_texture->update(image);
+
+		// uv2
+		Array uv2_array = mesh->surface_get_arrays(surface_index)[Mesh::ARRAY_TEX_UV2];
+		for (int j = 0; j < uv2_array.size(); j++) {
+			uvs2.push_back((Vector2)uv2_array[j]);
 		}
 	}
+
+	_update_texture(vertices, position_texture);
+	_update_texture(normals, normal_texture);
+	_update_texture(colors, color_texture);
+	_update_texture(uvs, uv_texture);
+	_update_texture(uvs2, uv2_texture);
 }
 
 void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref<Mesh> p_mesh) {
@@ -442,7 +586,7 @@ void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref<Mesh> p_mesh) {
 	}
 
 	if (mesh.is_valid()) {
-		Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::update_texture);
+		Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures);
 
 		if (mesh->is_connected(CoreStringNames::get_singleton()->changed, callable)) {
 			mesh->disconnect(CoreStringNames::get_singleton()->changed, callable);
@@ -452,7 +596,7 @@ void VisualShaderNodeParticleMeshEmitter::set_mesh(Ref<Mesh> p_mesh) {
 	mesh = p_mesh;
 
 	if (mesh.is_valid()) {
-		Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::update_texture);
+		Callable callable = callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures);
 
 		if (!mesh->is_connected(CoreStringNames::get_singleton()->changed, callable)) {
 			mesh->connect(CoreStringNames::get_singleton()->changed, callable);
@@ -528,10 +672,13 @@ void VisualShaderNodeParticleMeshEmitter::_bind_methods() {
 }
 
 VisualShaderNodeParticleMeshEmitter::VisualShaderNodeParticleMeshEmitter() {
-	connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &VisualShaderNodeParticleMeshEmitter::update_texture));
+	connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &VisualShaderNodeParticleMeshEmitter::_update_textures));
 
 	position_texture.instantiate();
 	normal_texture.instantiate();
+	color_texture.instantiate();
+	uv_texture.instantiate();
+	uv2_texture.instantiate();
 }
 
 // VisualShaderNodeParticleMultiplyByAxisAngle

+ 11 - 3
scene/resources/visual_shader_particle_nodes.h

@@ -115,6 +115,16 @@ class VisualShaderNodeParticleMeshEmitter : public VisualShaderNodeParticleEmitt
 
 	Ref<ImageTexture> position_texture;
 	Ref<ImageTexture> normal_texture;
+	Ref<ImageTexture> color_texture;
+	Ref<ImageTexture> uv_texture;
+	Ref<ImageTexture> uv2_texture;
+
+	String _generate_code(VisualShader::Type p_type, int p_id, const String *p_output_vars, int p_index, const String &p_texture_name, bool p_ignore_mode2d = false) const;
+
+	void _update_texture(const Vector<Vector2> &p_array, Ref<ImageTexture> &r_texture);
+	void _update_texture(const Vector<Vector3> &p_array, Ref<ImageTexture> &r_texture);
+	void _update_texture(const Vector<Color> &p_array, Ref<ImageTexture> &r_texture);
+	void _update_textures();
 
 protected:
 	static void _bind_methods();
@@ -130,11 +140,9 @@ public:
 	virtual PortType get_input_port_type(int p_port) const override;
 	virtual String get_input_port_name(int p_port) const override;
 
-	virtual String generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const override;
+	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;
 
-	void update_texture();
-
 	void set_mesh(Ref<Mesh> p_mesh);
 	Ref<Mesh> get_mesh() const;