Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.x] Add TorusMesh #64044

Merged
merged 1 commit into from
Aug 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions doc/classes/TorusMesh.xml
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions editor/icons/icon_torus_mesh.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions scene/register_scene_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>();
Expand Down
128 changes: 128 additions & 0 deletions scene/resources/primitive_meshes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
32 changes: 32 additions & 0 deletions scene/resources/primitive_meshes.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,38 @@ class SphereMesh : public PrimitiveMesh {
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
*/
Expand Down