Skip to content

Commit

Permalink
Implemented preview resolution for curves to alleviate performance is…
Browse files Browse the repository at this point in the history
…sues of long curves.

Curves now preview in editor with a fixed resolution per curve section that can be defined by the user.
  • Loading branch information
AyyZerrAsa committed Apr 9, 2024
1 parent e5b4ef8 commit 1e6ebed
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 87 deletions.
3 changes: 3 additions & 0 deletions doc/classes/Curve2D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,8 @@
<member name="point_count" type="int" setter="set_point_count" getter="get_point_count" default="0">
The number of points describing the curve.
</member>
<member name="debug_preview_resolution" type="int" setter="set_debug_preview_resolution" getter="get_debug_preview_resolution" default="32">
The number of intervals between two spline points. The larger the resolution, the more preview items are drawn. Lowering this value can help with responsiveness when editing the curve.
</member>
</members>
</class>
3 changes: 3 additions & 0 deletions doc/classes/Curve3D.xml
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,9 @@
<member name="point_count" type="int" setter="set_point_count" getter="get_point_count" default="0">
The number of points describing the curve.
</member>
<member name="debug_preview_resolution" type="int" setter="set_debug_preview_resolution" getter="get_debug_preview_resolution" default="32">
The number of intervals between two spline points. The larger the resolution, the more preview primitives are generated. Lowering this value can help with responsiveness when editing the curve.
</member>
<member name="up_vector_enabled" type="bool" setter="set_up_vector_enabled" getter="is_up_vector_enabled" default="true">
If [code]true[/code], the curve will bake up vectors used for orientation. This is used when [member PathFollow3D.rotation_mode] is set to [constant PathFollow3D.ROTATION_ORIENTED]. Changing it forces the cache to be recomputed.
</member>
Expand Down
104 changes: 54 additions & 50 deletions editor/plugins/path_3d_editor_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,70 +288,74 @@ void Path3DGizmo::redraw() {
return;
}

real_t interval = 0.1;
const real_t length = c->get_baked_length();

// 1. Draw curve and bones.
if (length > CMP_EPSILON) {
const int sample_count = int(length / interval) + 2;
interval = length / (sample_count - 1); // Recalculate real interval length.

Vector<Transform3D> frames;
frames.resize(sample_count);

{
Transform3D *w = frames.ptrw();

for (int i = 0; i < sample_count; i++) {
w[i] = c->sample_baked_with_rotation(i * interval, true, true);
const int point_count = c->get_point_count();
const int sample_count = c->get_debug_preview_resolution() + 2;
for (int point = 0; point < point_count - 1; point++) {
const real_t section_length = c->get_baked_distance_at_point(point + 1) - c->get_baked_distance_at_point(point);
const real_t interval = section_length / (sample_count - 1); // Recalculate real interval length of section.
Vector<Transform3D> frames;
frames.resize(sample_count);

real_t offset;
point == 0 ? offset = 0 : offset = c->get_baked_distance_at_point(point);

// Get info at sample point
{
Transform3D *w = frames.ptrw();

for (int i = 0; i < sample_count; i++) {
w[i] = c->sample_baked_with_rotation(offset + (i * interval), true, true);
}
}
}
const Transform3D *r = frames.ptr();

const Transform3D *r = frames.ptr();
Vector<Vector3> _collision_segments;
_collision_segments.resize((sample_count - 1) * 2);
Vector3 *_collisions_ptr = _collision_segments.ptrw();

Vector<Vector3> _collision_segments;
_collision_segments.resize((sample_count - 1) * 2);
Vector3 *_collisions_ptr = _collision_segments.ptrw();
Vector<Vector3> bones;
bones.resize(sample_count * 4);
Vector3 *bones_ptr = bones.ptrw();

Vector<Vector3> bones;
bones.resize(sample_count * 4);
Vector3 *bones_ptr = bones.ptrw();
Vector<Vector3> ribbon;
ribbon.resize(sample_count);
Vector3 *ribbon_ptr = ribbon.ptrw();

Vector<Vector3> ribbon;
ribbon.resize(sample_count);
Vector3 *ribbon_ptr = ribbon.ptrw();
for (int i = 0; i < sample_count; i++) {
const Vector3 p1 = r[i].origin;
const Vector3 side = r[i].basis.get_column(0);
const Vector3 up = r[i].basis.get_column(1);
const Vector3 forward = r[i].basis.get_column(2);

// Collision segments.
if (i != sample_count - 1) {
const Vector3 p2 = r[i + 1].origin;
_collisions_ptr[(i * 2)] = p1;
_collisions_ptr[(i * 2) + 1] = p2;
}

for (int i = 0; i < sample_count; i++) {
const Vector3 p1 = r[i].origin;
const Vector3 side = r[i].basis.get_column(0);
const Vector3 up = r[i].basis.get_column(1);
const Vector3 forward = r[i].basis.get_column(2);
// Path3D as a ribbon.
ribbon_ptr[i] = p1;

// Collision segments.
if (i != sample_count - 1) {
const Vector3 p2 = r[i + 1].origin;
_collisions_ptr[(i * 2)] = p1;
_collisions_ptr[(i * 2) + 1] = p2;
}
// Fish Bone.
const Vector3 p_left = p1 + (side + forward - up * 0.3) * 0.06;
const Vector3 p_right = p1 + (-side + forward - up * 0.3) * 0.06;

// Path3D as a ribbon.
ribbon_ptr[i] = p1;
const int bone_idx = i * 4;

// Fish Bone.
const Vector3 p_left = p1 + (side + forward - up * 0.3) * 0.06;
const Vector3 p_right = p1 + (-side + forward - up * 0.3) * 0.06;

const int bone_idx = i * 4;
bones_ptr[bone_idx] = p1;
bones_ptr[bone_idx + 1] = p_left;
bones_ptr[bone_idx + 2] = p1;
bones_ptr[bone_idx + 3] = p_right;
}

bones_ptr[bone_idx] = p1;
bones_ptr[bone_idx + 1] = p_left;
bones_ptr[bone_idx + 2] = p1;
bones_ptr[bone_idx + 3] = p_right;
add_collision_segments(_collision_segments);
add_lines(bones, path_material);
add_vertices(ribbon, path_material, Mesh::PRIMITIVE_LINE_STRIP);
}

add_collision_segments(_collision_segments);
add_lines(bones, path_material);
add_vertices(ribbon, path_material, Mesh::PRIMITIVE_LINE_STRIP);
}

// 2. Draw handles when selected.
Expand Down
1 change: 0 additions & 1 deletion editor/plugins/path_3d_editor_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ class Path3DEditorPlugin : public EditorPlugin {
Path3D *path = nullptr;

void _update_theme();

void _mode_changed(int p_mode);
void _close_curve();
void _handle_option_pressed(int p_option);
Expand Down
77 changes: 42 additions & 35 deletions scene/2d/path_2d.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,54 +107,61 @@ void Path2D::_notification(int p_what) {
#else
const real_t line_width = get_tree()->get_debug_paths_width();
#endif
real_t interval = 10;
const real_t length = curve->get_baked_length();

if (length > CMP_EPSILON) {
const int sample_count = int(length / interval) + 2;
interval = length / (sample_count - 1); // Recalculate real interval length.
const int point_count = curve->get_point_count();
const int sample_count = curve->get_debug_preview_resolution() + 2;

Vector<Transform2D> frames;
frames.resize(sample_count);
for (int point = 0; point < point_count - 1; point++) {
const real_t section_length = curve->get_baked_distance_at_point(point + 1) - curve->get_baked_distance_at_point(point);
real_t interval = section_length / (sample_count - 1); // Recalculate real interval length.

{
Transform2D *w = frames.ptrw();
Vector<Transform2D> frames;
frames.resize(sample_count);
real_t offset;
point == 0 ? offset = 0 : offset = curve->get_baked_distance_at_point(point);

for (int i = 0; i < sample_count; i++) {
w[i] = curve->sample_baked_with_rotation(i * interval, false);
}
}
// Get info at sample point
{
Transform2D *w = frames.ptrw();

const Transform2D *r = frames.ptr();
// Draw curve segments
{
PackedVector2Array v2p;
v2p.resize(sample_count);
Vector2 *w = v2p.ptrw();
for (int i = 0; i < sample_count; i++) {
w[i] = curve->sample_baked_with_rotation(offset + (i * interval), false);
}
}

for (int i = 0; i < sample_count; i++) {
w[i] = r[i].get_origin();
const Transform2D *r = frames.ptr();
// Draw curve segments
{
PackedVector2Array v2p;
v2p.resize(sample_count);
Vector2 *w = v2p.ptrw();

for (int i = 0; i < sample_count; i++) {
w[i] = r[i].get_origin();
}
draw_polyline(v2p, get_tree()->get_debug_paths_color(), line_width, false);
}
draw_polyline(v2p, get_tree()->get_debug_paths_color(), line_width, false);
}

// Draw fish bones
{
PackedVector2Array v2p;
v2p.resize(3);
Vector2 *w = v2p.ptrw();
// Draw fish bones
{
PackedVector2Array v2p;
v2p.resize(3);
Vector2 *w = v2p.ptrw();

for (int i = 0; i < sample_count; i++) {
const Vector2 p = r[i].get_origin();
const Vector2 side = r[i].columns[1];
const Vector2 forward = r[i].columns[0];
for (int i = 0; i < sample_count; i++) {
const Vector2 p = r[i].get_origin();
const Vector2 side = r[i].columns[1];
const Vector2 forward = r[i].columns[0];

// Fish Bone.
w[0] = p + (side - forward) * 5;
w[1] = p;
w[2] = p + (-side - forward) * 5;
// Fish Bone.
w[0] = p + (side - forward) * 5;
w[1] = p;
w[2] = p + (-side - forward) * 5;

draw_polyline(v2p, get_tree()->get_debug_paths_color(), line_width * 0.5, false);
draw_polyline(v2p, get_tree()->get_debug_paths_color(), line_width * 0.5, false);
}
}
}
}
Expand Down
Loading

0 comments on commit 1e6ebed

Please sign in to comment.