Explorar o código

Merge pull request #64044 from Calinou/add-torusmesh-3.x

Rémi Verschelde %!s(int64=3) %!d(string=hai) anos
pai
achega
4f1dc83b0d

+ 29 - 0
doc/classes/TorusMesh.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TorusMesh" inherits="PrimitiveMesh" version="3.6" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+	<brief_description>
+		Class representing a torus [PrimitiveMesh].
+	</brief_description>
+	<description>
+		Class representing a torus [PrimitiveMesh].
+	</description>
+	<tutorials>
+	</tutorials>
+	<methods>
+	</methods>
+	<members>
+		<member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="0.5">
+			The inner radius of the torus.
+		</member>
+		<member name="outer_radius" type="float" setter="set_outer_radius" getter="get_outer_radius" default="1.0">
+			The outer radius of the torus.
+		</member>
+		<member name="ring_segments" type="int" setter="set_ring_segments" getter="get_ring_segments" default="32">
+			The number of edges each ring of the torus is constructed of.
+		</member>
+		<member name="rings" type="int" setter="set_rings" getter="get_rings" default="64">
+			The number of slices the torus is constructed of.
+		</member>
+	</members>
+	<constants>
+	</constants>
+</class>

+ 1 - 0
editor/icons/icon_torus_mesh.svg

@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="8" cy="7.5" fill="none" rx="6" ry="3.5" stroke="#ffd684" stroke-linecap="square" stroke-linejoin="round" stroke-width="2"/></svg>

+ 1 - 0
scene/register_scene_types.cpp

@@ -665,6 +665,7 @@ void register_scene_types() {
 	ClassDB::register_class<QuadMesh>();
 	ClassDB::register_class<SphereMesh>();
 	ClassDB::register_class<TextMesh>();
+	ClassDB::register_class<TorusMesh>();
 	ClassDB::register_class<PointMesh>();
 	ClassDB::register_virtual_class<Material>();
 	ClassDB::register_class<SpatialMaterial>();

+ 128 - 0
scene/resources/primitive_meshes.cpp

@@ -1622,6 +1622,134 @@ SphereMesh::SphereMesh() {
 	is_hemisphere = default_is_hemisphere;
 }
 
+/**
+  TorusMesh
+*/
+
+void TorusMesh::_create_mesh_array(Array &p_arr) const {
+	// set our bounding box
+
+	Vector<Vector3> points;
+	Vector<Vector3> normals;
+	Vector<float> tangents;
+	Vector<Vector2> uvs;
+	Vector<int> indices;
+
+#define ADD_TANGENT(m_x, m_y, m_z, m_d) \
+	tangents.push_back(m_x);            \
+	tangents.push_back(m_y);            \
+	tangents.push_back(m_z);            \
+	tangents.push_back(m_d);
+
+	ERR_FAIL_COND_MSG(inner_radius == outer_radius, "Inner radius and outer radius cannot be the same.");
+
+	float min_radius = inner_radius;
+	float max_radius = outer_radius;
+
+	if (min_radius > max_radius) {
+		SWAP(min_radius, max_radius);
+	}
+
+	float radius = (max_radius - min_radius) * 0.5;
+
+	for (int i = 0; i <= rings; i++) {
+		int prevrow = (i - 1) * (ring_segments + 1);
+		int thisrow = i * (ring_segments + 1);
+		float inci = float(i) / rings;
+		float angi = inci * Math_TAU;
+
+		Vector2 normali = Vector2(-Math::sin(angi), -Math::cos(angi));
+
+		for (int j = 0; j <= ring_segments; j++) {
+			float incj = float(j) / ring_segments;
+			float angj = incj * Math_TAU;
+
+			Vector2 normalj = Vector2(-Math::cos(angj), Math::sin(angj));
+			Vector2 normalk = normalj * radius + Vector2(min_radius + radius, 0);
+
+			points.push_back(Vector3(normali.x * normalk.x, normalk.y, normali.y * normalk.x));
+			normals.push_back(Vector3(normali.x * normalj.x, normalj.y, normali.y * normalj.x));
+			ADD_TANGENT(-Math::cos(angi), 0.0, Math::sin(angi), 1.0);
+			uvs.push_back(Vector2(inci, incj));
+
+			if (i > 0 && j > 0) {
+				indices.push_back(thisrow + j - 1);
+				indices.push_back(prevrow + j);
+				indices.push_back(prevrow + j - 1);
+
+				indices.push_back(thisrow + j - 1);
+				indices.push_back(thisrow + j);
+				indices.push_back(prevrow + j);
+			}
+		}
+	}
+
+	p_arr[VS::ARRAY_VERTEX] = points;
+	p_arr[VS::ARRAY_NORMAL] = normals;
+	p_arr[VS::ARRAY_TANGENT] = tangents;
+	p_arr[VS::ARRAY_TEX_UV] = uvs;
+	p_arr[VS::ARRAY_INDEX] = indices;
+}
+
+void TorusMesh::_bind_methods() {
+	ClassDB::bind_method(D_METHOD("set_inner_radius", "radius"), &TorusMesh::set_inner_radius);
+	ClassDB::bind_method(D_METHOD("get_inner_radius"), &TorusMesh::get_inner_radius);
+
+	ClassDB::bind_method(D_METHOD("set_outer_radius", "radius"), &TorusMesh::set_outer_radius);
+	ClassDB::bind_method(D_METHOD("get_outer_radius"), &TorusMesh::get_outer_radius);
+
+	ClassDB::bind_method(D_METHOD("set_rings", "rings"), &TorusMesh::set_rings);
+	ClassDB::bind_method(D_METHOD("get_rings"), &TorusMesh::get_rings);
+
+	ClassDB::bind_method(D_METHOD("set_ring_segments", "rings"), &TorusMesh::set_ring_segments);
+	ClassDB::bind_method(D_METHOD("get_ring_segments"), &TorusMesh::get_ring_segments);
+
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "inner_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater"), "set_inner_radius", "get_inner_radius");
+	ADD_PROPERTY(PropertyInfo(Variant::REAL, "outer_radius", PROPERTY_HINT_RANGE, "0.001,1000.0,0.001,or_greater"), "set_outer_radius", "get_outer_radius");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "3,128,1"), "set_rings", "get_rings");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "ring_segments", PROPERTY_HINT_RANGE, "3,64,1"), "set_ring_segments", "get_ring_segments");
+}
+
+void TorusMesh::set_inner_radius(const float p_inner_radius) {
+	inner_radius = p_inner_radius;
+	_request_update();
+}
+
+float TorusMesh::get_inner_radius() const {
+	return inner_radius;
+}
+
+void TorusMesh::set_outer_radius(const float p_outer_radius) {
+	outer_radius = p_outer_radius;
+	_request_update();
+}
+
+float TorusMesh::get_outer_radius() const {
+	return outer_radius;
+}
+
+void TorusMesh::set_rings(const int p_rings) {
+	ERR_FAIL_COND(p_rings < 3);
+	rings = p_rings;
+	_request_update();
+}
+
+int TorusMesh::get_rings() const {
+	return rings;
+}
+
+void TorusMesh::set_ring_segments(const int p_ring_segments) {
+	ERR_FAIL_COND(p_ring_segments < 3);
+	ring_segments = p_ring_segments;
+	_request_update();
+}
+
+int TorusMesh::get_ring_segments() const {
+	return ring_segments;
+}
+
+TorusMesh::TorusMesh() {}
+
 /**
   PointMesh
 */

+ 32 - 0
scene/resources/primitive_meshes.h

@@ -351,6 +351,38 @@ public:
 	SphereMesh();
 };
 
+/**
+	Big donut
+*/
+class TorusMesh : public PrimitiveMesh {
+	GDCLASS(TorusMesh, PrimitiveMesh);
+
+private:
+	float inner_radius = 0.5;
+	float outer_radius = 1.0;
+	int rings = 64;
+	int ring_segments = 32;
+
+protected:
+	static void _bind_methods();
+	virtual void _create_mesh_array(Array &p_arr) const;
+
+public:
+	void set_inner_radius(const float p_inner_radius);
+	float get_inner_radius() const;
+
+	void set_outer_radius(const float p_outer_radius);
+	float get_outer_radius() const;
+
+	void set_rings(const int p_rings);
+	int get_rings() const;
+
+	void set_ring_segments(const int p_ring_segments);
+	int get_ring_segments() const;
+
+	TorusMesh();
+};
+
 /**
 	A single point for use in particle systems
 */