Smooth Points in Curve3D

Godot Version

4.6.2.stable

Question

I’m trying to create a path using the points from a list of nodes. I was able get all the nodes’ positions in the Curve3D of a Path3D but the path has a hard turn and I’m not sure how to round it out.

Node1 (-4.25, 1.0, -2.0) Node2 (-2.75, 1.0, -2.0) Node3 (-2.0, 1.0, -2.0) Node4 (-2.0, 1.0, -2.75)

I think I’m supposed to add in and out for the add_point method but I don’t really know what they are.

For a smooth curve, ‘in’ and ‘out’ points will be on a curve tangent at a specific curve point. So calculate the tangent at each point by averaging the direction vectors of two adjacent linear segments. Then translate the curve point to both side along the tangent vector, by some percentage of the length of the corresponding linear segment.

Would you mind explaining how I could implement each step, I’m not sure how to find the average direction?

To calculate the tangent at point P, take two vectors: from P-1 to P and from P to P+1. Normalize them, add them, and normalize the result.

Is this for both the in and out, will they be the same vector?

for i in point_number:
	var p:Vector3 = points[i]
	var p1:Vector3
	var p2:Vector3
	
	if i > 0 and i < point_number - 1:
		p1 = points[i-1]
		p2 = points[i+1]
		
		var a = p1.direction_to(p).normalized()
		var b = p.direction_to(p2).normalized()
		var c = (a+b).normalized()

This is what I’ve got so far.

in and out are both on the same tangent but in opposite directions. So if c is your tangent, then out point will be offset along c and in point along -c.

It kind of worked but there is a weird bump in the path instead of a smooth curve.

You need to adjust the offset of in/out point to be proportional to the length of their corresponding linear segments.

Here’s a demo. Attach the script to a Path3D node, draw some points and drag the smoothness slider.

@tool extends Path3D

@export_range(0.0, 1.0) var smoothness := 0.25:
	set(value):
		smoothness = value
		smooth_curve()

func smooth_curve():
	for i in range(1, curve.point_count - 1):
		var segment_in := curve.get_point_position(i) - curve.get_point_position(i - 1)
		var segment_out := curve.get_point_position(i + 1) - curve.get_point_position(i)
		var tangent := (segment_in.normalized() + segment_out.normalized()).normalized()
		curve.set_point_in(i, -tangent * segment_in.length() * smoothness)
		curve.set_point_out(i, tangent * segment_out.length() * smoothness)

curve_smooth

3 Likes

Worked great, thank you!

1 Like

That’s some cool code.

Not sure if clean tho :smiley:

1 Like