Merge pull request #68860 from xiongyaohua/path3d_fishbones
Draw fish bones for Path3D and Path2D in the Editor
This commit is contained in:
commit
14861c45b5
4 changed files with 116 additions and 35 deletions
|
@ -240,38 +240,63 @@ void Path3DGizmo::redraw() {
|
|||
return;
|
||||
}
|
||||
|
||||
Vector<Vector3> v3a = c->tessellate();
|
||||
//Vector<Vector3> v3a=c->get_baked_points();
|
||||
real_t interval = 0.1;
|
||||
const real_t length = c->get_baked_length();
|
||||
|
||||
int v3s = v3a.size();
|
||||
if (v3s == 0) {
|
||||
return;
|
||||
}
|
||||
Vector<Vector3> v3p;
|
||||
const Vector3 *r = v3a.ptr();
|
||||
// 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.
|
||||
|
||||
// BUG: the following won't work when v3s, avoid drawing as a temporary workaround.
|
||||
for (int i = 0; i < v3s - 1; i++) {
|
||||
v3p.push_back(r[i]);
|
||||
v3p.push_back(r[i + 1]);
|
||||
//v3p.push_back(r[i]);
|
||||
//v3p.push_back(r[i]+Vector3(0,0.2,0));
|
||||
}
|
||||
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 Transform3D *r = frames.ptr();
|
||||
Vector<Vector3> v3p;
|
||||
for (int i = 0; i < sample_count - 1; i++) {
|
||||
const Vector3 p1 = r[i].origin;
|
||||
const Vector3 p2 = r[i + 1].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);
|
||||
|
||||
// Curve segment.
|
||||
v3p.push_back(p1);
|
||||
v3p.push_back(p2);
|
||||
|
||||
// Fish Bone.
|
||||
v3p.push_back(p1);
|
||||
v3p.push_back(p1 + (side - forward) * 0.06);
|
||||
|
||||
v3p.push_back(p1);
|
||||
v3p.push_back(p1 + (-side - forward) * 0.06);
|
||||
|
||||
v3p.push_back(p1);
|
||||
v3p.push_back(p1 + up * 0.03);
|
||||
}
|
||||
|
||||
if (v3p.size() > 1) {
|
||||
add_lines(v3p, path_material);
|
||||
add_collision_segments(v3p);
|
||||
}
|
||||
|
||||
// 2. Draw handles.
|
||||
if (Path3DEditorPlugin::singleton->get_edited_path() == path) {
|
||||
v3p.clear();
|
||||
Vector<Vector3> v3p;
|
||||
Vector<Vector3> handle_points;
|
||||
Vector<Vector3> sec_handle_points;
|
||||
|
||||
for (int i = 0; i < c->get_point_count(); i++) {
|
||||
Vector3 p = c->get_point_position(i);
|
||||
handle_points.push_back(p);
|
||||
// push Out points first so they get selected if the In and Out points are on top of each other.
|
||||
// Push out points first so they get selected if the In and Out points are on top of each other.
|
||||
if (i < c->get_point_count() - 1) {
|
||||
v3p.push_back(p);
|
||||
v3p.push_back(p + c->get_point_out(i));
|
||||
|
|
|
@ -106,18 +106,57 @@ void Path2D::_notification(int p_what) {
|
|||
#else
|
||||
const real_t line_width = get_tree()->get_debug_paths_width();
|
||||
#endif
|
||||
_cached_draw_pts.resize(curve->get_point_count() * 8);
|
||||
int count = 0;
|
||||
real_t interval = 10;
|
||||
const real_t length = curve->get_baked_length();
|
||||
|
||||
for (int i = 0; i < curve->get_point_count(); i++) {
|
||||
for (int j = 0; j < 8; j++) {
|
||||
real_t frac = j * (1.0 / 8.0);
|
||||
Vector2 p = curve->sample(i, frac);
|
||||
_cached_draw_pts.set(count++, p);
|
||||
if (length > CMP_EPSILON) {
|
||||
const int sample_count = int(length / interval) + 2;
|
||||
interval = length / (sample_count - 1); // Recalculate real interval length.
|
||||
|
||||
Vector<Transform2D> frames;
|
||||
frames.resize(sample_count);
|
||||
|
||||
{
|
||||
Transform2D *w = frames.ptrw();
|
||||
|
||||
for (int i = 0; i < sample_count; i++) {
|
||||
w[i] = curve->sample_baked_with_rotation(i * interval, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
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 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[0];
|
||||
const Vector2 forward = r[i].columns[1];
|
||||
|
||||
// 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(_cached_draw_pts, get_tree()->get_debug_paths_color(), line_width, true);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@ class Path2D : public Node2D {
|
|||
GDCLASS(Path2D, Node2D);
|
||||
|
||||
Ref<Curve2D> curve;
|
||||
Vector<Vector2> _cached_draw_pts;
|
||||
|
||||
void _curve_changed();
|
||||
|
||||
|
|
|
@ -1075,18 +1075,36 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
|
|||
|
||||
void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
|
||||
ERR_FAIL_COND(p_points.size() < 2);
|
||||
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_COND(!canvas_item);
|
||||
|
||||
Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
|
||||
ERR_FAIL_COND(!pline);
|
||||
|
||||
if (true || p_width <= 1) {
|
||||
#define TODO make thick lines possible
|
||||
// TODO: `canvas_item_add_line`(`multiline`, `polyline`) share logic, should factor out.
|
||||
if (p_width <= 1) {
|
||||
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
|
||||
ERR_FAIL_COND(!canvas_item);
|
||||
|
||||
Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
|
||||
ERR_FAIL_COND(!pline);
|
||||
pline->primitive = RS::PRIMITIVE_LINES;
|
||||
pline->polygon.create(Vector<int>(), p_points, p_colors);
|
||||
} else {
|
||||
if (p_colors.size() == 1) {
|
||||
Color color = p_colors[0];
|
||||
for (int i = 0; i < p_points.size() >> 1; i++) {
|
||||
Vector2 from = p_points[i * 2 + 0];
|
||||
Vector2 to = p_points[i * 2 + 1];
|
||||
|
||||
canvas_item_add_line(p_item, from, to, color, p_width);
|
||||
}
|
||||
} else if (p_colors.size() == p_points.size() >> 1) {
|
||||
for (int i = 0; i < p_points.size() >> 1; i++) {
|
||||
Color color = p_colors[i];
|
||||
Vector2 from = p_points[i * 2 + 0];
|
||||
Vector2 to = p_points[i * 2 + 1];
|
||||
|
||||
canvas_item_add_line(p_item, from, to, color, p_width);
|
||||
}
|
||||
} else {
|
||||
ERR_FAIL_MSG("Length of p_colors is invalid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue