Path3D Documentation (v1.1.0)

This post is for the documentation related to the Path3D module, for information regarding the editor, demos, or a general overview, see here.

Get the module here.

Get the editor (not required) here.


Changes Since v1.0.0

Changelog
  • Added Path3D.newAnchorTable(), an easier way to create Path3DAnchorTables
  • Added Path3D.fromAnchorTables(), an alternate constructor that uses Vector3’s and as such is less dependant on the editor
  • Added Path3D:GetRotationOnCurve() and Path3D:GetUnadjustedRotationOnCurve() which allow you to get the rotation at a given point on the Path3D, removing the need for any “look aheads” in order to find your desired rotation
  • Added Path3D:GetCFrameOnCurve() and Path3D:GetUnadjustedCFrameOnCurve() allowing you get the position and rotation of a point on a Path3D with a single method call, once again removing the need for any “look aheads”
  • Added Path3D.Version, Path3D.VersionMajor, Path3D.VersionMinor, and Path3D.VersionPatch allowing code to dynamically check what version of Path3D it is using and adjust its method calls accordingly
  • Fixed a bug where Path3D.fromPathString() could be passed a path string containing less than two anchor points, resulting in issues when making later method calls
  • Added version numbers to every property and method in the documentation stating which version that property or method was first introduced in
  • Fixed a typo in the Path3DAnchorTable section which claimed that the prior and next control points were recorded as offsets from the anchor point. This is not the case, they are recorded as offsets from the pivot, only in the path string are these positions recorded as offsets from their anchor point.
  • Added more examples to some of the methods and properties
  • Fixed some grammatical typos in the documentation

Static Properties

These properties are all contained within the Path3D module returned from require(). Note that although some of these list Read Only they will not through an error when written to, so don't modify these read only values.
Static Properties

Path3D.Version: string

Read Only v1.1.0 This property will always equal "1.1.0" or whatever the latest version currently is. This value follows semantic versioning practices.

IMPORTANT: This property was not introduced until v1.1.0, so although most modules will contain this, v1.0.0 will not have this property!

Path3D.VersionMajor: number

Read Only v1.1.0 This value will always be equal to the major version component of the module's current version (currently 1). This value follows semantic versioning practices.

IMPORTANT: This property was not introduced until v1.1.0, so although most modules will contain this, v1.0.0 will not have this property!

Path3D.VersionMinor: number

Read Only v1.1.0 This value will always be equal to the minor version component of the module's current version (currently 1). This value follows semantic versioning practices.

IMPORTANT: This property was not introduced until v1.1.0, so although most modules will contain this, v1.0.0 will not have this property!

Path3D.VersionPatch: number

Read Only v1.1.0 This value will always be equal to the patch version component of the module's current version (currently 0). This value follows semantic versioning practices.

IMPORTANT: This property was not introduced until v1.1.0, so although most modules will contain this, v1.0.0 will not have this property!


Static Methods

These methods are all contained within the Path3D module returned from require().
Static Methods

Path3D.fromPathString(pathString, position, lengthOptions): Path3D

Path3D.fromPathString()

v1.0.0

This method creates a new Path3D instance from the given path string, positioning it at the given position and evaluating its length using the given length options.

The following code sample demonstrates how, assuming a StringValue named PathString is parented to the script, Path3D.fromPathString() can be used to create a Path3D instance

local PATH_STRING = script.PathString.Value
local PATH_CENTER = Vector3.new(12, 15, 0)
local LENGTH_OPTIONS = Path3D.newLengthOptions(
	35,
	0.5,
	2,
	0,
	0
)

local path = Path3D.fromPathString(PATH_STRING, PATH_CENTER, LENGTH_OPTIONS)

pathString: string

This is the string representation of the Path3D, typically generated by the Path3DEditor. Further information on the formatting of the path string can be found at the end of this post.

position: Vector3

(Defaults to 0, 0, 0)
This is the location of the Path3D's pivot point. Changing this changes the location of all the anchors and control points as well.

lengthOptions: Path3DLengthOptions

(Defaults to:
recordedSplits = 35
minimumLength = 0.5
minimumSuccesses = 2
minimumSplits = 0
maximumSplits = 0)

This parameter controls how the length of the Path3D will be evaluated, further details on what each setting does can be found under Path3D.newLengthOptions()

Return: Path3D

This is the Path3D that the path string represents, located at the given position, and with its length evaluated using the given length options

Path3D.fromAnchorTables(anchorTables, position, lengthOptions): Path3D

Path3D.fromAnchorTables()

v1.1.0

This function creates a new Path3D instance from a series of Path3DAnchorTables. This function expects the anchor tables to be given, then the position, then the length options.

This code creates the path pictured below using anchor tables.
image

local PATH_CENTER = Vector3.new(-101.57, 0.75, 142.111)
local LENGTH_OPTIONS = Path3D.newLengthOptions(
	35,
	0.5,
	2,
	0,
	0
)

local path = Path3D.fromAnchorTables(
	Path3D.newAnchorTable(
		nil,
		Vector3.new(0, 0, -10),
		Vector3.new(10, 0, -10)
	),
	Path3D.newAnchorTable(
		Vector3.new(-10, 0, 10),
		Vector3.new(0, 0, 10),
		Vector3.new(10, 0, 10)
	),
	Path3D.newAnchorTable(
		Vector3.new(10, 0, 5),
		Vector3.new(10, 0, 0),
		Vector3.new(10, 0, -10)
	),
	Path3D.newAnchorTable(
		Vector3.new(10, 0, -20),
		Vector3.new(20, 0, -20),
		nil --This could be omitted, I just find this more readable
	),
	PATH_CENTER, --Leave as nil if you just want the default
	LENGTH_OPTIONS --Leave as nil if you just want the default
)

anchorTables: Tuple<Path3DAnchorTable>

These are each of the anchor tables that will make up the Path3D in order from first to last.

position: Vector3

(Defaults to 0, 0, 0) This is the position of the path's pivot point, or where each of the anchor and control points should be offset from.

lengthOptions

(Defaults to:
recordedSplits = 35
minimumLength = 0.5
minimumSuccesses = 2
minimumSplits = 0
maximumSplits = 0)

These are the settings that should be used when the length of the Path3D is being evaluated, but for the vast majority of use cases you can simply leave this as the default. For more information on what each of these does see Path3D.newLengthOptions().

Return: Path3D

This function returns a new Path3D instance comprised of the given Path3DAnchorTables.

Path3D.newAnchorTable(priorControlPoint, anchorPoint, nextControlPoint): Path3DAnchorTable

Path3D.newAnchorTable()

v1.1.0
This function creates a new Path3DAnchorTable with the given anchor point, prior control point, and anchor point. All of these values are expressed as offsets from the path’s pivot point. See Path3D.fromAnchorTables() for an example of how these are used.

priorControlPoint: Vector3

(Optional) This parameter determines the prior control point's offset from the pivot point. Leave as nil if there is no prior control point.

anchorPoint: Vector3

This parameter determines the anchor point's offset from the pivot point. Unlike the prior and next control points, the anchor point is not optional.

nextControlPoint: Vector3

(Optional) This parameter determines the next control point's offset from the pivot point. Leave as nil if there is no next control point.

Return: Path3DAnchorTable

This function returns a Path3DAnchorTable with the given priorControlPoint, anchor, and nextControlPoint properties set to the given values.

Path3D.newLengthOptions(recodedSplits, minimumLength, minimumSuccesses, minimumSplits, maximumSplits): Path3DLengthOptions

Path3D.newLengthOptions()

v1.0.0

This function creates a new length options table which will tell Path3D.fromPathString() how to evaluate the length of the path. When evaluating the length of a path, the module will first split the path into the individual Bézier curves that make it up. From there, each curve will be split into a number of segments determined by recordedSplits, and these individual splits are then used to linearise the distribution of t values when using Path3D:GetPositionOnCurve() or other linearised functions. Each individual split is then recursively split in half, with the minimum and maximum depth of the function being controlled by minimumSplits and maximumSplits. This is continued until the distance between the start and the ending point that the function is evaluating has been less than minimumLength minimumSuccesses times in a row, at which point the function will return the distance between the two points, summing each individual segment, and determining the length of the Path3D. For most purposes, you can just leave this as the default and it’ll work fine.

recordedSplits: number

(Defaults to 35, must be greater than 0)
This is the total amount of splits that will be in each segment, being used by Path3D:GetPositionOnCurve() to linearise t values. If you notice that parts travelling along your Path3D tend to "slow down" around corners and "speed up" on straight sections, this could be caused by this value being too small.

minimumLength: number

(Defaults to 0.5, must be greater than 0)
This is the minimum distance that two points on the curve must be from each other before the length evaluator will simply return the distance between the two points instead of splitting the curve in half once more.

minimumSucces: number

(Defaults to 2, must be greater than or equal to 0)
This is the amount of times that the length evaluator must concurrently find that the distance between two points is less than minimumLength before it will stop splitting the curve. Setting this too low or disabling it can result in cases where the evaluator may mistake the intersection formed by a cusp to simply be a normal part of the curve, causing the length of the cusp to skipped, resulting in issues with the length of the Path3D. Setting this to 0 disables this.

minimumSplits: number

(Defaults to 0, must be greater than or equal to 0)
This is the minimum recursion depth that the length evaluator must reach before it will stop splitting the curve. This helps solve edge cases where the start and end of the curve are next to each, causing the evaluator to believe them to on the curve, stopping immediately. In practice this is largely replaced by minimumSuccess which is why it is disabled by default, however it is included in case you want more control over the length evaluator. Setting this to 0 disables this.

maximumSplits: number

(Defaults to 0, must be greater than or equal to 0)
This setting allows you to determine the maximum recursion depth that the length evaluator may reach before simply returning the distance between two points. Setting this to low values may result in segments of the curve being "skipped," resulting in the given length being inaccurate, potentially causing more problems. Using this isn't recommended due to the potential problems it can cause, so this acts more as an intermediary solution should the length evaluator get stuck in an infinite loop. If you do encounter something like this, please report it to me immediately so I can fix it. Setting this to 0 disables this.

Return: Path3DLengthOptions

This returns a Path3DLengthOptions table with the provided settings.


Path3D Instance Properties

These properties are all contained within a Path3D instance, returned from Path3D.fromPathString() or Path3D.fromAnchorTables().

Path3D Instance Properties

Path3D.Length: number

Read Only
v1.0.0 This contains the length of the Path3D, calculated when it was created using the provided length options

This code sample shows how this property can be used to make a part move at a constant speed along the Path3D by calculating the length of the tween depending on the length of the path

local PATH_STRING = script.PathString.Value
local SPEED = 10 --Studs per second

local path = Path3D.fromPathString(PATH_STRING)

local tweenDuration = path.Length / SPEED

Path3D.Position: Vector3

v1.0.0 This is the position of the pivot point of the Path3D, changing this also changes the position of all anchor and control points to maintain their offsets.

Path3D.ClassName: "Path3D"

Read Only
v1.0.0 Although a Path3D is not technically an Instance, ClassName is included to allow you to dynamically check if something is or isn't a Path3D

Path3D.__type: "Path3D"

Read Only
v1.0.0 Identical to Path3D.ClassName, included to allow you to check types however you prefer.

Path3D._internalData

Read Only
v1.0.0 Internal data used to run the Path3D's functions. Don't use this at all, it is subject to change without notice and any information within it is also provided through other methods. Just forget I even mentioned it.


Path3D Instance Methods

These methods are contained within a Path3D instance created using Path3D.fromPathString() or Path3D.fromAnchorTables() and are accessed using instance notation.

Path3D Instance Methods

Path3D:GetPositionOnCurve(t): Vector3

Path3D:GetPositionOnCurce()

v1.0.0
This function evaluates the Path3D, taking in a percentage of how far along the path the point should be sampled at and returning where in the world that point is. Note that traditionally t values in Bézier curves are not distributed linearly across the curve, however this function applies an adjustment to the provided t value to ensure they are distributed linearly. If you notice parts following a Path3D are “slowing down” and “speeding up” throughout their journey despite t increasing linearly, it may be because your Path3DLengthOptions.recordedSplits is too small. For an alternative that does not adjust the provided t value, see Path3D:GetUnadjustedPositionOnCurve().

t: number

(Must be in the range of 0-1) This is the percentage as a decimal of how far across the path the point should be sampled at. For example, a t value of 0.5 would return a point halfway along the curve.

Return: Vector3

This returns where in the world the point at the given t value is, accounting for the Path3D's position.

Path3D:GetUnadjustedPositionOnCurve(t): Vector3

Path3D:GetUnadjustedPositionOnCurve()

v1.0.0
This function is nearly identical to Path3D:GetPositionOnCurve(), however it does not apply any adjustments to the provided t value, instead feeding the directly into the Bézier formulas. In practice this means that, for example, a t value of 0.9 will not necessarily return the point 90% of the way along the Path3D.

t: number

(Must be in the range of 0-1) This is the percentage along the curve that the point will be sampled at as a decimal.

Return: Vector3

This is the point along the Path3D at the given t value.

Path3D:GetRotationOnCurve(t): CFrame

Path3D:GetRotationOnCurve()

v1.1.0
This method calculates and returns a rotated CFrame without any translation facing “forwards” along the Path3D at the given point. This could also be thought of as getting the tangent along the curve. This function linearises the t values that it is given, see Path3D:GetPositionOnCurve() for more information about what this does and potential problems you might face.

This code sample uses Path3D:GetRotationOnCurve() along with Path3D:GetPositionOnCurve() to make a part follow the path, continuously looking “forwards”. See Path3D:GetCFrameOnCurve() for a simpler way of achieving this.

local PATH_STRING = script.PathString.Value
local PATH_CENTER = Vector3.new(12, 15, 0)
local LENGTH_OPTIONS = Path3D.newLengthOptions(
	35,
	0.5,
	2,
	0,
	0
)

local path = Path3D.fromPathString(PATH_STRING, PATH_CENTER, LENGTH_OPTIONS)

local tweenPart = Instance.new("Part")
tweenPart.Anchored = true
tweenPart.Parent = game.Workspace

local tweenValue = Instance.new("NumberValue")
tweenValue.Value = 0

tweenValue.Changed:Connect(function(newValue)
	tweenPart.CFrame = CFrame.new(path:GetPositionOnCurve(newValue)) * path:GetRotationOnCurve(newValue)
end)

local pathTweenInfo = TweenInfo.new(
	path.Length / 10,
	Enum.EasingStyle.Linear,
	Enum.EasingDirection.In,
	0,
	false,
	0
)

local pathTweenGoal = {Value = 1}

task.wait(2)
local tween = game:GetService("TweenService"):Create(tweenValue, pathTweenInfo, pathTweenGoal)
tween:Play()

t: number

(Must be in the range of 0-1) This is the percentage along the Path3D that the rotation should be sampled at.

Return: CFrame

This function returns a rotated CFrame with no translation facing "forwards" along the Path3D.

Path3D:GetUnadjustedRotationOnCurve(t): CFrame

Path3D:GetUnadjustedRotationOnCurve()

v1.1.0
This function is identical to Path3D:GetRotationOnCurve() except it doesn’t linearise the t values it is given. See Path3D:GetPositionOnCurve() and Path3D:GetUnadjustedPositionOnCurve() for what linearising these t values does, or see Path3D:GetRotationOnCurve() for further information on this function.

t: number

(Must be in the range of 0-1) This is the percentage along the Path3D that the rotation should be sampled at.

Return: CFrame

This function returns a CFrame with no translation facing "forwards" along the Path3D at the given point.

Path3D:GetCFrameOnCurve(t): CFrame

Path3D:GetCFrameOnCurve()

v1.1.0
This function returns a CFrame at the given percentage along the Path3D facing “forwards” along the path. This is slightly be performant than CFrame.new(Path3D:GetPositionOnCurve(t)) * Path3D:GetRotationOnCurve(t), but the difference is practically non-existent, and is more so for convenience. This function linearises the t values that it is given so that they are evenly distributed along the Path3D, for more information about what this means see Path3D:GetPositionOnCurve().

This code creates a new part and causes it to follow a path, continually facing “forwards.”

local PATH_STRING = script.PathString.Value
local PATH_CENTER = Vector3.new(12, 15, 0)
local LENGTH_OPTIONS = Path3D.newLengthOptions(
	35,
	0.5,
	2,
	0,
	0
)

local path = Path3D.fromPathString(PATH_STRING, PATH_CENTER, LENGTH_OPTIONS)

local tweenPart = Instance.new("Part")
tweenPart.Anchored = true
tweenPart.Parent = game.Workspace

local tweenValue = Instance.new("NumberValue")
tweenValue.Value = 0

tweenValue.Changed:Connect(function(newValue)
	tweenPart.CFrame = path:GetCFrameOnCurve(newValue)
end)

local pathTweenInfo = TweenInfo.new(
	path.Length / 10,
	Enum.EasingStyle.Linear,
	Enum.EasingDirection.In,
	0,
	false,
	0
)

local pathTweenGoal = {Value = 1}

task.wait(2)
local tween = game:GetService("TweenService"):Create(tweenValue, pathTweenInfo, pathTweenGoal)
tween:Play()

t: number

(Must be in the range of 0-1) This is the percentage along the Path3D that the CFrame should be sampled at.

Return: CFrame

This is the position and rotation of the point at the given t value along the Path3D.

Path3D:GetUnadjustedCFrameOnCurve(t): CFrame

Path3D:GetUnadjustedCFrameOnCurve()

v1.1.0
This function is nearly identical to Path3D:GetCFrameOnCurve() except that it does not linearise the t values it is given. See Path3D:GetCFrameOnCurve() for more information on this method, or see Path3D:GetPositionOnCurve() and Path3D:GetUnadjustedPositionOnCurve() for more information on what linearising these t values does.

t: number

(Must be in the range of 0-1) This is the percentage along the curve that the CFrame should be sampled at.

Return: CFrame

This function returns a CFrame at the given t value facing "forwards" along the Path3D.

Path3D:GetSegmentLengths(): {number}

Path3D:GetSegmentLengths()

v1.0.0
This function returns an array containing the length of each individual curve in the Path3D, ordered from the start (t = 0) to the end (t = 1).

Return: {number}

This is an array with the length of the curves in the Path3D

Path3D:GetAnchorTables(): {Path3DAnchorTable}

Path3D:GetAnchorTables()

v1.0.0
This function returns an array of tables representing every single anchor and control point in the Path3D. These tables are what the module uses internally to represent the Path3D, and information on what they contain can be found below.

Return: {Path3DAnchorTable}

This is an array of all the Path3DAnchorTables that make up the given Path3D.



Path3DAnchorTable Properties

v1.0.0
These are all of the properties of the Path3DAnchorTables returned from Path3D:GetAnchorTables().
Path3DAnchorTable Properties

Path3DAnchorTable.priorControlPoint: Vector3

v1.0.0 This is the position of one of the control points (p2) of the previous curve, recorded as an offset from the pivot point. This value may be nil, in which case there is no prior control point.

Path3DAnchorTable.anchor: Vector3

v1.0.0 This is the position of an anchor point in a Path3D, recorded as an offset from the pivot point.

Path3DAnchorTable.nextControlPoint: Vector3

v1.0.0 This is the position of one of the control points (p1) of the next curve, recorded as an offset from the the pivot point. This value may be nil, in which case there is no next control point.


The Path String

This section goes over the formatting of the path string that is passed to Path3D.fromPathString(), which was formerly the only constructor available. Since v1.1.0 however, Path3D.fromAnchorTables() is also available, which for most use cases will probably work better than constructing your own path strings. Nevertheless, this section is still included just in case anyone needs it.
The Path String

Path String Version 1:

Terminology:

Terminology

This next section uses some terminology, and while they should be fairly intuitive, they’re listed here to make sure everyone understands.

Anchor Point: An anchor point is simply a point where one curve in the Path3D ends and another one begins.

Prior Control Point: The prior control point is the control point for the curve before the anchor it is associated with. For those familiar with cubic Bézier curves, this is p2 in the previous curve.

Next Control Point: The next control point is the control point for the curve after the anchor it is associated with. For those familiar with cubic Bézier curves, this is p1 in the next curve.

Control Point Identifier: This one isn’t really intuitive. and what it means is explained under Anchor Point Groups.

Basic Outline:

Basic Outline

(Version)/(Anchor Point Group 1)/(Anchor Point Group 2)/(Anchor Point Group 3)…

This here is the basic outline of a path string, starting with a version number which indicates what version of the path string format you are using (currently 1). This ensures that even if the formatting of this string does ever change, old path strings will continue to function as they do now without needing to go through and update them. Next up we have the anchor point group. The formatting of this gets a bit more complicated and is explained below, but after the version number you can list as many of these as you would like, with each anchor point group extending the path. Finally, separating all of these, we have forward slashes (/). Omitting the anchor groups for now, an actual path string would look something like this:

1/(Anchor Point Group 1)/(Anchor Point Group 2)/(Anchor Point Group 3)/(Anchor Point Group 4)

The 1 at the very start indicates that this path string is using path string format 1. Then, we have a forward slash to separate it from the first anchor point group. Next, we also include a forward slash in between each anchor point group, separating them from each other. This particular path string has 4 anchor points, meaning that the final Path3D will have 3 segments.

Anchor Point Groups:

Anchor Point Groups

(Control Point Identifier)(Prior Control Point Offset)(Anchor Point Offset)(Next Control Point Offset)

IMPORTANT: This general format has had its spaces ( ) replaced with underscores (
) to make it more readable, the actual path string uses spaces instead of underscores.



Above is a general template for how the anchor point group is formatted. Each anchor point group starts off with a number known as the control point identifier. The control point identifier tells the module how many and which control points have been listed, and it is important that this matches with what is actually listed. The possible values for the control point identifier and what they indicate is listed below.

0: This indicates that there are no control points present, only the anchor point
1: This indicates that only the prior control point and the anchor point are present.
2: This indicates that only the next control point and the anchor point are present.
3: This indicates that both the prior control point, the next control point and the anchor point are present.

Following the control point identifier, a space (not an underscore) is used to separate it from the first offset. The prior control point, anchor point, and next control are always listed in that order (prior, anchor, next). If a point is missing, for example if you only have an anchor point and a next control point, then you simply skip the point that you don’t have. Each anchor point’s position is listed as an offset from the path’s pivot point, and each control point is listed as an offset from its anchor point. A list of how an anchor point group would be structured for each control point identifier is listed below:

Examples

0: 0 (Anchor)
1: 1 (Prior Control Point) (Anchor)
2: 2 (Anchor) (Next Control Point)
3: 3 (Prior Control Point) (Anchor) (Next Control Point)

Offset Format:

Offset Format

(X),(Y),(Z)

By far the simplest part of the path string, each offset is simply listed as x, y, z coordinates separated with commas. One important detail to note however is that there are no spaces between the commas and the next axis. For example, an anchor offset from the pivot by 10, 0, 3 with no control points would have an anchor point group of:

0 10,0,3

Putting it all Together:

Putting it all Together

In order to bring everything about the path string all together, I’ll show how to recreate the path string from the Path3D Editor’s default path.



To start off with, the most recent path string version is 1, and that’s the same one the editor uses, so we’ll start our path string with 1.
1

Next we need to separate our first anchor point group.
1/

Now we start our first anchor point group. Because the default path has both control points, we’ll use 3
1/3

Next up we have the prior control point. The prior control point is offset from the first anchor by 10, 0, 0, so we’ll put that in.
1/3 10,0,0

After that there’s the anchor point. The anchor point is offset from the path’s pivot point by 0, 0, -10, so we put that in.
1/3 10,0,0 0,0,-10

Then we have the next control point. The next control point is offset from the anchor point by -10, 0, 0, so we put that in.
1/3 10,0,0 0,0,-10 -10,0,0

And now we have our first anchor point group done! Since this is the starting anchor, the prior control point doesn’t actually do anything, however the module doesn’t care about that, and the Path3D Editor will still include it. In order to demonstrate different control point identifiers though, the final anchor point will omit the next control point.

Continuing on, we insert our separator and our control point identifier. Because we are listing a prior control point and an anchor point, we’ll use 1.
1/3 10,0,0 0,0,-10 -10,0,0/1

As with the first anchor point group, the prior control point is offset by 10, 0, 0, so we put that in.
1/3 10,0,0 0,0,-10 -10,0,0/1 10,0,0

Finally, we add on the anchor point’s offset from the pivot, that being 0, 0, 10.
1/3 10,0,0 0,0,-10 -10,0,0/1 10,0,0 0,0,10

And that there is the path string for the Path3D Editor’s default path. Since we don’t have a next control point, and we’ve told the module that by using 1 as our control point identifier, we can simply leave out the final control point and the path string will still function. Don’t forget to test your path strings as you go, otherwise you might make a dumb mistake like mixing up your X and Z axis (something I definitely, absolutely did not do in that last section).




And those are the docs! If you encounter any problems, please report them to me on the Path3D announcement post (first link at the top).
3 Likes

OUTDATED (v1.0.0)

This documentation pertains to version 1.0.0 of Path3D, an outdated version of the module. To get the latest version, see the main post.

v1.0.0 is available here.


Static Methods

These methods are all contained within the Path3D module returned from require()

Static Methods

Path3D.fromPathString(pathString, position, lengthOptions): Path3D

Path3D.fromPathString()

This method creates a new Path3D instance from the given path string, positioning it at the given position and evaluating its length using the given length options.

pathString: string

This is the string representation of the Path3D, generated either by the Path3D Editor or by hand. Further information on the formatting of the path string can be found at the end of this post.

position: Vector3

(Defaults to 0, 0, 0)

This is the location of the Path3D’s pivot point. Changing this changes the location of all the anchors and control points as well.

lengthOptions: Path3DLengthOptions

(Defaults to:

recordedSplits = 35

minimumLength = 0.5

minimumSuccesses = 2

minimumSplits = 0

maximumSplits = 0)

This parameter controls how the length of the Path3D will be evaluated, further details on what each setting does can be found under Path3D.newLengthOptions()

Return: Path3D

This is the Path3D that the path string represents, located at the given position, and with its length evaluated using the given length options



Path3D.newLengthOptions(recodedSplits, minimumLength, minimumSuccesses, minimumSplits, maximumSplits): Path3DLengthOptions

Path3D.newLengthOptions()

This function creates a new length options table which will tell Path3D.fromPathString() how to evaluate the length of the path. When evaluating the length of a path, the module will first split the path into the individual Bézier that make it up. From there, each curve will be split into a number of segments determined by recordedSplits, and these individual splits are then used to linearize the distribution of t values when using Path3D:GetPositionOnCurve(). Each individual split is then recursively split in half, with the minimum and maximum depth of the function being controlled by minimumSplits and maximumSplits. This is continued until the distance between the start and the ending point that the function is evaluating has been less than minimumLength minimumSuccesses times in a row, at which point the function will return the distance between the two points, summing each individual segment, and determining the length of the Path3D. For most purposes, you can just leave this as the default and it’ll work fine.

recordedSplits: number

(Defaults to 35, must be greater than 0)

This is the total amount of splits that will be in each segment, being used by Path3D:GetPositionOnCurve() to linearize t values. If you notice that parts travelling along your Path3D tend to “slow down” around corners and “speed up” on straight sections, this could be caused by this value being too small.

minimumLength: number

(Defaults to 0.5, must be greater than 0)

This is the minimum distance that two points on the curve must be from each other before the length evaluator will simply return the distance between the two points instead of splitting the curve in half once more.

minimumSucces: number

(Defaults to 2, must be greater than or equal to 0)

This is the amount of times that the length evaluator must concurrently find that the distance between two points is less than minimumLength before it will stop splitting the curve. Setting this too low or disabling it can result in cases where the evaluator may mistake the intersection formed by a cusp to simply be a normal part of the curve, causing the length of the cusp to skipped, resulting in issues with the length of the Path3D. Setting this to 0 disables this.

minimumSplits: number

(Defaults to 0, must be greater than or equal to 0)

This is the minimum recursion depth that the length evaluator must reach before it will stop splitting the curve. This helps solve edge cases where the start and end of the curve are next to each, causing the evaluator to believe them to on the curve, stopping immediately. In practice this is largely replaced by minimumSuccess which is why it is disabled by default, however it is included in case you want more control over the length evaluator. Setting this to 0 disables this.

maximumSplits: number

(Defaults to 0, must be greater than or equal to 0)

This setting allows you to determine the maximum recursion depth that the length evaluator may reach before simply returning the distance between two points. Setting this to low values may result in segments of the curve being “skipped,” resulting in the given length being inaccurate, potentially causing more problems. Using this isn’t recommended due to the potential problems it can cause, so this acts more as an intermediary solution should the length evaluator get stuck in an infinite loop. If you do encounter something like this, please report it to me immediately so I can fix it. Setting this to 0 disables this.

Return: Path3DLengthOptions

This returns a Path3DLengthOptions table with the provided settings.




Path3D Instance Properties

These properties are all contained within a Path3D instance, returned from Path3D.fromPathString().

Path3D Instance Properties

Path3D.Length: number

Read Only

This contains the length of the Path3D, calculated when it was created using the provided length options


Path3D.Position: Vector3

This is the position of the pivot point of the Path3D, changing this also changes the position of all anchor and control points to maintain their offsets.

Path3D.ClassName: "Path3D"

Read Only

Although a Path3D is not technically an Instance, ClassName is included to allow you to dynamically check if something is or isn’t a Path3D

Path3D.__type: "Path3D"

Read Only

Identical to Path3D.ClassName, included to allow you to check types however you prefer.

Path3D._internalData

Read Only

Internal data used to run the Path3D’s functions. Don’t use this at all, it is subject to change without notice and any information within it is also provided through other methods. Just forget I even mentioned it.




Path3D Instance Methods

These methods are contained within a Path3D instance created using Path3D.fromPathString() and are accessed using instance notation.

Path3D Instance Methods

Path3D:GetPositionOnCurve(t): Vector3

Path3D:GetPositionOnCurce()

This function evaluates the Path3D, taking in a percentage of how far along the path the point should be sampled at and returning where in the world that point is. Note that traditionally t values in Bézier curves are not distributed linearly across the curve, however this function applies an adjustment to the provided t value to ensure they are distributed linearly. If you notice parts following a Path3D are “slowing down” and “speeding up” throughout their journey despite t increasing linearly, it may be because your Path3DLengthOptions.recordedSplits is too small. For an alternative that does not adjust the provided t value, see Path3D:GetUnadjustedPositionOnCurve().

t: number

(Must be in the range of 0-1)

This is the percentage as a decimal of how far across the path the point should be sampled at. For example, a t value of 0.5 would return a point halfway along the curve.

Return: Vector3

This returns where in the world the point at the given t value is, accounting for the Path3D’s position.

Path3D:GetUnadjustedPositionOnCurve(t): Vector3

Path3D:GetUnadjustedPositionOnCurve()

This function is nearly identical to Path3D:GetPositionOnCurve(), however it does not apply any adjustments to the provided t value, instead feeding the directly into the Bézier formulas. In practice this means that, for example, a t value of 0.9 will not necessarily return the point 90% of the way along the Path3D.

t: number

(Must be in the range of 0-1)

This is the percentage along the curve that the point will be sampled at as a decimal.

Return: Vector3

This is the point along the Path3D at the given t value.

Path3D:GetSegmentLengths(): {number}

Path3D:GetSegmentLengths()

This function returns an array containing the length of each individual curve in the Path3D, ordered from the start (t = 0) to the end (t = 1).

Return: {number}

This is an array with the length of curve in the Path3D

Path3D:GetAnchorTables(): {Path3DAnchorTable}

Path3D:GetAnchorTables()

This function returns an array of tables representing every single anchor and control point in the Path3D. These tables are what the module uses internally to represent the Path3D, and information on what they contain can be found below.

Return: {Path3DAnchorTable}

This is an array of all the Path3DAnchorTables that make up the given Path3D.




Path3DAnchorTable Properties

These are all of the properties of the Path3DAnchorTables returned from Path3D:GetAnchorTables().

Path3DAnchorTable Properties

Path3DAnchorTable.priorControlPoint: Vector3

This is the position of one of the control points (p2) of the previous curve, recorded as an offset from the position of its anchor point.

Path3DAnchorTable.anchor: Vector3

This is the position of an anchor point in a Path3D, recorded as an offset from the pivot point.

Path3DAnchorTable.nextControlPoint: Vector3

This is the position of one of the control points (p1) of the next curve, recorded as an offset from the position of its anchor point.




The Path String

The path string. The thing that runs the whole module. I’ve tried to strike a balance between ensuring this string doesn’t get excessively long, while still being easy to create by hand if you don’t own the editor. If you do own the editor, you probably don’t need to worry about this, otherwise, here’s how to format the path string. Future me here, just finished writing this section and I realized it looks really intimidating, but trust me, it’s actually quite simple, this just goes into very thorough detail on exactly what everything does. If you are not familiar with the path string format, I highly recommend going through each section in order, as each one builds off the last.

The Path String

Path String Version 1:

Terminology:

Terminology

This next section uses some terminology, and while they should be fairly intuitive, they’re listed here to make sure everyone understands.

Anchor Point: An anchor point is simply a point where one curve in the Path3D ends and another one begins.

Prior Control Point: The prior control point is the control point for the curve before the anchor it is associated with. For those familiar with cubic Bézier curves, this is p2 in the previous curve.

Next Control Point: The next control point is the control point for the curve after the anchor it is associated with. For those familiar with cubic Bézier curves, this is p1 in the next curve.

Control Point Identifier: This one isn’t really intuitive. and what it means is explained under Anchor Point Groups.

Basic Outline:

Basic Outline

(Version)/(Anchor Point Group 1)/(Anchor Point Group 2)/(Anchor Point Group 3)…

This here is the basic outline of a path string, starting with a version number which indicates what version of the path string format you are using (currently 1). This ensures that even if the formatting of this string does ever change, old path strings will continue to function as they do now without needing to go through and update them. Next up we have the anchor point group. The formatting of this gets a bit more complicated and is explained below, but after the version number you can list as many of these as you would like, with each anchor point group extending the path. Finally, separating all of these, we have forward slashes (/). Omitting the anchor groups for now, an actual path string would look something like this:

1/(Anchor Point Group 1)/(Anchor Point Group 2)/(Anchor Point Group 3)/(Anchor Point Group 4)

The 1 at the very start indicates that this path string is using path string format 1. Then, we have a forward slash to separate it from the first anchor point group. Next, we also include a forward slash in between each anchor point group, separating them from each other. This particular path string has 4 anchor points, meaning that the final Path3D will have 3 segments.

Anchor Point Groups:

Anchor Point Groups

(Control Point Identifier)(Prior Control Point Offset)(Anchor Point Offset)_(Next Control Point Offset)

IMPORTANT: This general format has had its spaces ( ) replaced with underscores (_) to make it more readable, the actual path string uses spaces instead of underscores.


Above is a general template for how the anchor point group is formatted. Each anchor point group starts off with a number known as the control point identifier. The control point identifier tells the module how many and which control points have been listed, and it is important that this matches with what is actually listed. The possible values for the control point identifier and what they indicate is listed below.

0: This indicates that there are no control points present, only the anchor point

1: This indicates that only the prior control point and the anchor point are present.

2: This indicates that only the next control point and the anchor point are present.

3: This indicates that both the prior control point, the next control point and the anchor point are present.

Following the control point identifier, a space (not an underscore) is used to separate it from the first offset. The prior control point, anchor point, and next control are always listed in that order (prior, anchor, next). If a point is missing, for example if you only have an anchor point and a next control point, then you simply skip the point that you don’t have. Each anchor point’s position is listed as an offset from the path’s pivot point, and each control point is listed as an offset from its anchor point. A list of how an anchor point group would be structured for each control point identifier is listed below:

Examples

0: 0 (Anchor)

1: 1 (Prior Control Point) (Anchor)

2: 2 (Anchor) (Next Control Point)

3: 3 (Prior Control Point) (Anchor) (Next Control Point)

Offset Format:

Offset Format

(X),(Y),(Z)

By far the simplest part of the path string, each offset is simply listed as x, y, z coordinates separated with commas. One important detail to note however is that there are no spaces between the commas and the next axis. For example, an anchor offset from the pivot by 10, 0, 3 with no control points would have an anchor point group of:

0 10,0,3

Putting it all Together:

Putting it all Together

In order to bring everything about the path string all together, I’ll show how to recreate the path string from the Path3D Editor’s default path.


To start off with, the most recent path string version is 1, and that’s the same one the editor uses, so we’ll start our path string with 1.

1

Next we need to separate our first anchor point group.

1/

Now we start our first anchor point group. Because the default path has both control points, we’ll use 3

1/3

Next up we have the prior control point. The prior control point is offset from the first anchor by 10, 0, 0, so we’ll put that in.

1/3 10,0,0

After that there’s the anchor point. The anchor point is offset from the path’s pivot point by 0, 0, -10, so we put that in.

1/3 10,0,0 0,0,-10

Then we have the next control point. The next control point is offset from the anchor point by -10, 0, 0, so we put that in.

1/3 10,0,0 0,0,-10 -10,0,0

And now we have our first anchor point group done! Since this is the starting anchor, the prior control point doesn’t actually do anything, however the module doesn’t care about that, and the Path3D Editor will still include it. In order to demonstrate different control point identifiers though, the final anchor point will omit the next control point.

Continuing on, we insert our separator and our control point identifier. Because we are listing a prior control point and an anchor point, we’ll use 1.

1/3 10,0,0 0,0,-10 -10,0,0/1

As with the first anchor point group, the prior control point is offset by 10, 0, 0, so we put that in.

1/3 10,0,0 0,0,-10 -10,0,0/1 10,0,0

Finally, we add on the anchor point’s offset from the pivot, that being 0, 0, 10.

1/3 10,0,0 0,0,-10 -10,0,0/1 10,0,0 0,0,10

And that there is the path string for the Path3D Editor’s default path. Since we don’t have a next control point, and we’ve told the module that by using 1 as our control point identifier, we can simply leave out the final control point and the path string will still function. Don’t forget to test your path strings as you go, otherwise you might make a dumb mistake like mixing up your X and Z axis (something I definitely, absolutely did not do in that last section).




And those are the docs! If you encounter any problems, please report them to me on the Path3D announcement post (first link at the top).

That was a lot to write