Pivot Points - Studio Beta

We’re introducing pivot points to Roblox Studio. With this change you will be able to set the point around which each part and model in Roblox Studio is translated / rotated. You can enable pivot points via the Pivot Editor beta feature now available in the Beta Features panel:

image

Sounds simple right? Well, strap in, because there’s actually a lot to unpack between the feature’s visuals, tooling, APIs, and future implications.

Team Create Restriction

For the time being, the beta is not available in Team Create: The pivot functionality will be disabled while you’re in a team create place. We want a chance to potentially change some aspects of the pivot system in response to developer feedback, and due to the implementation details of this feature that would be much more difficult if we made it available in live Team Create places immediately.

Once we’re confident that we won’t be further modifying any core aspects of the feature we’ll allow the beta in Team Create as well and update the announcement post.

The Visuals

The first thing you will notice after enabling the beta is that some things in Roblox Studio will be visually different even before you explicitly edit any pivots.

  1. The selection box for models and parts now includes a “Pivot Indicator” showing where the pivot for each object is:
    image

  2. The Move tool now shows its handles directly around the pivot of an object rather than out at the extents. The cases that were previously best served by having the move handles out at the edges of an object can be better served by temporarily modifying the pivot:

  3. There’s a Pivot section in the Model tab of the ribbon bar.
    image

The Tooling

Edit Pivot Tool

The primary way to work with pivots is the Edit Pivot tool now present in the Model tab of the ribbon bar. With this tool selected, you will be editing the pivot of the selected object, rather than the changing the location of the object itself. There are three ways you can edit the pivot using this tool:

image

  1. Use the Move handles to move the pivot along an axis.

  2. Use the Rotate handles to rotate the pivot.

  3. Click and drag on the Pivot Indicator to freeform drag the pivot similar to how you can freeform drag Attachments

  4. (Secret extra method) If you click and drag anywhere else on the part you will also freeform drag the pivot. This can help you quickly get the pivot where you want it if you “lost” it somewhere off in the distance without having to reach up for the reset pivot button.

All three of these options respect a “Snap” toggle located next to the Edit Pivot tool. When checked, this “Snap” toggle tells the Edit Pivot tool to snap the pivot to interesting “hotspots” on the bounding box of the hovered object.

  • Snap is checked: Try to snap the pivot to interesting “hotspots” on the bounding box of the object (that is, vertices, face center, and edge centers):
    image

  • Snap is not checked: Move the pivot in the same way that Attachments are currently moved.

Properties Pane Support

The pivot also has full properties pane support, meaning you can finally move and rotate models precisely using the properties pane just like you previously could for parts!

image

The new “Origin Position” and “Origin Orientation” properties on parts and models represent the current location of the part or model’s pivot. Editing them will move the object just like editing the Position / Orientation properties will, but will move the object via the pivot rather than via the center of the bounding box.

You can also precisely edit the location of the pivot relative to the object (without moving the object) by editing the PivotOffset property for parts, or the WorldPivot property for models.

Pivot Behavior Details

The “Cascading” pivot

The most important thing to understand is the “cascading” pivot behavior that models have. For models without a PrimaryPart, the pivot is simply a world space CFrame (model.WorldPivot). However, for models with a PrimaryPart, the pivot of the model is exactly equal to the pivot of the PrimaryPart of that model.

Thus, for models with a PrimaryPart, the pivot will naturally move along with the model when it physically simulates. This breaks models into two categories:

  • “Static” models that don’t have a PrimaryPart: These models either don’t move at all at run-time, or are moved into position via code and left at that position thereafter.

  • “Dynamic” models that do have a PrimaryPart: These models may be moved by physical simulation. Thanks to the cascading pivot behavior, the pivot of these models will follow the PrimaryPart.

This means that it will now be important to set a PrimaryPart on models that you intend to move / check the location of with both physics and scripting.

What happens when PrimaryPart get set?

When you set the PrimaryPart of a model, the cascading pivot behavior will naturally kick in: The old WorldPivot will be ignored, and the model’s pivot will be equal to the PrimaryPart’s pivot instead.

What happens when the PrimaryPart gets removed?

Okay, but what happens when the PrimaryPart gets removed for some reason? For instance if I blow up the car and the PrimaryPart gets deleted?

In the case where the PrimaryPart gets removed from the model, there is a special behavior: The WorldPivot will be set equal to what the PrimaryPart’s pivot was just before it got removed. Effectively, when the PrimaryPart gets removed, the pivot stays where it was just prior to that removal. The goal of this behavior is to prevent ever seeing a sudden “jump” in where the pivot is as parts get deleted out from underneath the model due to game logic, streaming, or any other reason.

Newly Created Models

When you first create a model, how does the pivot get set?

Models actually have a special behavior that applies specifically when they are first created: When a model is first created, it will be in a special state where its pivot will be equal to the center of the bounding box of the model’s contents.

This special state only lasts up to the first time that you do anything to move the model or explicitly set the pivot such as editing the WorldPivot property. This still gives you an opportunity to create a model, parent some objects underneath it, and get a sensible pivot.

This means that the following code will work nicely:

local model = Instance.new("Model")
thing1:Clone().Parent = model
thing2:Clone().Parent = model
model:PivotTo(CFrame.new(...))
model.Parent = workspace

The API

The API for pivot point comes in the form of two methods and two properties.

The two methods represent the primary way that you will interact with object pivots in your game code:

Part/Model:GetPivot()
Part/Model:PivotTo(targetCFrame)
  • GetPivot() lets you query the current world space location of an object’s pivot as a CFrame. This provides an uniform way to get a physical object’s position in 3d space regardless of whether it’s an individual part or a model.

  • PivotTo(targetCFrame) lets you move the object, such that its pivot is now located exactly at a target CFrame. This provides a uniform object movement API that applies to both individual parts and models. If you’re already familiar with SetPrimaryPartCFrame, this works very similarly to that, only operating on parts as well as models, and operating on the pivot instead of the PrimaryPart, giving you more freedom over what point is being transformed.

Two properties let you configure the pivot at run-time (or at edit time in your community plugins):

Property CFrame BasePart.PivotOffset
Property CFrame Model.WorldPivot
  • The pivot of a model without a PrimaryPart is set using the WorldPivot property, which represents the pivot of that model in world space.

  • The pivot of a part is set using the PivotOffset property, which represents the offset of the pivot from the CFrame of the part.

  • The pivot of a model with a PrimaryPart is set by setting the PivotOffset of the PrimaryPart thanks to the cascading pivot behavior.

Potentially Breaking Change To GetBoundingBox()

This is a new API, so how could it have breaking changes? There is actually one small edge case, where the changes under this beta can actually change the behavior of the results you get back from calling GetBoundingBox().

The bounding box orientation of models is now based off of their pivot, rather than inferred from their contents. In most cases, this doesn’t change anything. For models that have a PrimaryPart, the bounding box orientation will always be exactly the same as before. The same is true for static models that don’t move at all, their bounding box orientation will also be the same as before.

However, if you have a model which is physically simulated, and does not have a PrimaryPart, and you call GetBoundingBox() on that model, you will get a different result than before. The position part of the returned CFrame will still be the same as before, however, the orientation part may be different. The orientation part will stay equal to the initial orientation of the model even as it moves since the pivot will not be moving along with the model.

To correct this you can simply set a PrimaryPart on the model. Please let us know if you find a case in case your code that would be broken by this behavior change.

Other API Changes

ResetOrientationToIdentity is being soft-removed – calling it will not error, but will no longer do anything. Making this function have sensible behavior when existing alongside pivot would have been too messy to be useful, so we’re choosing to remove it instead. Don’t worry though, this won’t effect your code at all! It’s an extremely obscure function that only a dozen places still use and we’re individually contacting the owners of those places.

We will be deprecating GetPrimaryPartCFrame / SetPrimaryPartCFrame once pivot comes out of beta (don’t worry though, enough code depends on them that they’ll never be removed). GetPivot / PivotTo can be used as a drop-in replacement for them that preserves the current behavior, but offers more future flexibility. Note: This works because of the cascading pivot behavior. To have been using SetPrimaryPartCFrame, the model must have had a PrimaryPart, and if it has a PrimaryPart, then the pivot will be equal to the pivot of the PrimaryPart, which by default is equal to the CFrame of the PrimaryPart. Thus, PivotTo will have the same effect as SetPrimaryPartCFrame did.

Community Building Plugins

Many existing community building plugins unfortunately won’t “just work” with pivot, and will need to be updated to maintain it and / or respect it.

The key thing that needs to happen is that existing building plugins must make sure to update the pivot when moving models that do not have a PrimaryPart set. For those models, as described above in the Behavior Details section, the pivot will not automatically move along with the parts in the model when they move. If you use building plugins that have not been updated with models that don’t have a PrimaryPart, the pivot will become “out of sync” with the parts, staying where it was.

How to update your plugins:

  • If you use the new PivotTo API to move models, then you will naturally be covered, as it updates the pivot.

  • If you use the existing Model:MoveTo / Model:SetPrimaryPartCFrame APIs to move models, then no action is needed. These APIs have also been modified to update the pivot.

  • If you individually move parts, or move parts via BulkMoveTo, then you will have to update your code to set the WorldPivot property of any Models within the selections you are moving. Here’s a sample place file demonstrating an InstanceMover module with several different styles of object movement: PivotSampleModuleTest.rbxl (53.7 KB)

Please DM me if you maintain a building plugin and need advice on the process of updating it.

Future Implications

  1. We plan to set the pivot of imported MeshParts to be initially equal to the mesh origin, so that the mesh origin information that is currently lost is preserved in the form of the pivot. This should be coming soon later in the beta period.

  2. We plan to use the pivot as the key reference point for packages, so that packages will no longer require a PrimaryPart, this will be coming as part of a later packages update (and will be a fully backwards compatible transition).

Thanks for your hard work on this feature: @tnavarts @LuckyKobold @wengawenga @4thchamber @JoshSedai

300 Likes

I’m very excited about this change, however I do have some thoughts:

Why were spaces used in the property names? I understand that there are APIs to programatically edit pivots without editing the property values, but it’s still an odd choice and looks off compared to normal PascalCase properties.

Can we get this “Edit Pivot Tool” for attachments? I believe that moving attachments with these Move/Rotate tools would be nicer than the current attachment editor.

I’m extremely excited about this change! What are the internal performance implications relative to SetPrimaryPartCFrame?

15 Likes

This new feature is pretty life changing for the builders here as it solves many, many annoying moments trying to get a part in the right place with the current 4 primitive tools.


A few questions: Will there be an API for setting the pivot of a part? Currently we're limited to querying the object's pivot and moving the object on its pivot, but I'd like to see the ability to set an object's pivot when manipulating objects from a script. (Clarification: Editing an object's pivot with Vector3 values? :slight_smile:) My apologies, didn't realise you can edit the offset of the pivot.

Regarding the usage of pivot points in packages, could this affect preexisting animation assets in any way and will using pivot points be the new “method” of manipulating and animating rigs? All and all, this is a pretty good addition.

Something I want added for my slight convenience is to merge the pivot category in the model tab with the “Tools” category so that in the 3 main tabs I use I can easily click.

6 Likes

It was done to hint that they aren’t actual properties in the scripting API for someone who isn’t aware of that. The fact that there’s no clear way to access them as properties thanks to the space may clue people in to the fact that you can’t.

We’ve heard a lot of feedback on this so we may end up changing it.

It will be be better than SetPrimaryPartCFrame, as I’m going to make PivotTo use the same technology as BulkMoveTo does internally. You’ll have to wait a couple weeks to test that perf difference though, it currently just moves the parts the normal way.

12 Likes

It’s about time, was digging around pivots ever since the first news about pivots being added to studio, will be investigating this and testing it out.

What’s with the name of the properties being spaced out, I’d kind of like properties that are mushed together (OriginPosition) so I wouldn’t have my code look like (part[“Origin Position”]), it’s not bugging me right now, although a change I suggest.

Nevermind:

Once this is out of beta, time to make a module (or edit a current module :eyes:) about pivot points.

3 Likes

Definitely a good update. It will make our building experience much, much better!

However, I do have a question regarding the color of the “Snap” part of the pivot points. Like the color of highlighting objects, will we be able to change the color of the snaps to something of our choosing? Unless I’ve skipped over it in the settings, I don’t believe there is an option for that.

6 Likes

Love this feature. This was a feature F3X had but not studio, glad it’s in vanilla studio now as this was an essential update I can’t believe Roblox didn’t have until right now. Thank you.

  1. Do you plan on adding any keyboard shortcuts for editing the pivot? I imagine this will be something I will need to use often, and having to manually click edit pivot on the ribbon for every model would get pretty irritating.

  2. If I were to group two parts together, would the previous pivot points for the previous parts be say averaged out or completely discarded? Or perhaps you maintain the pivot of the first selected part?

  3. Do pivots scale the further your camera moves? I imagine that this is true, but if not it would be very helpful especially when working with very small/large models.

  4. Will we have the option to change the snap colors? This is so that pink models won’t have their snaps be virtually invisible.

That’s all the questions/suggestions. I can’t wait to start using this too when I get back home. It has always bugged me how difficult it is to make a model orient the way I want via dragging, hopefully this solves the issue, thank you.

Will test this beta in-studio later when I get back home.

9 Likes

There is actually an elegant workflow possible for this as is. If you bind a custom shortcut for the Edit Pivot tool, you can hit that shortcut once, edit the pivot, and then hit the shortcut again, and thanks to the way Studio’s tool selection behavior works, the tool you previously had selected will be selected again.

They aren’t “discarded” (they would still be there if you ungrouped the model), but they aren’t used in computing the pivot of the new model. The Group command just uses the center of bounding box as the pivot when creating new models.

The pivot indicator is rendered in 2d, so it’s always the same size on the screen.

I’m interested to see how many people bring this up. You can’t right now, but the current color is one that is pretty unlikely to clash with the color of the content being edited. I didn’t run into anything in testing where I had trouble seeing them.

8 Likes

This is really neat!

I’m already planning on testing it out with doors, I’d imagine it’s easier to simply have them rotate around a pivot position on the side instead of doing additional CFrame magic or manipulating hinge constraints.

3 Likes

Wow, that is great news! Pivots is one of the feature I’ve been wanting the most.

Some comments:

It can get slightly confusing sometimes to know whether you are editing the pivot or the model/part. Maybe having the arrows another color would solve the issue.

I also noticed that we could have both the rotation and pivot arrows at the same time. I don’t know if it is intended that way but it seems like one is in the way of the other.

Ps. I think some key shortcuts would also help a lot.

8 Likes

Love this update so far but will there ever be something for Individual object editing like blender has?

Screen capture - 9338b33dcc1fe1687bd6ad6a6b4e465c - Gyazo | How a model reacts with everything selected

Screen capture - ab6122868be5b1822de5d47e1ac4c1f8 - Gyazo | Individual Origin

If were finally incorporating features F3X has into vanilla studio this is one I’d love to be an addition.

3 Likes

Awesome! The API will make it easier to do things like creating doors without having to either manually calculate the pivoted CFrame or having to insert a pivot part.

3 Likes

No. We decided to go with per-object pivots over some kind of auxiliary global manipulator like Blender has. If you want that kind of behavior you’ll have to temporarily group the objects.

6 Likes

Plugins need a way to detect if one or more Beta features are enabled, so that developers can develop forward compatible solutions for their plugins. Using FFlags is unreliable as they could change at any time.

local StudioService = game:GetService("StudioService")
local PivotPointBetaEnabled = StudioService:IsBetaFeatureEnabled("PivotEditor")

if PivotPointBetaEnabled then
  --load the tools as if pivots existed
else
  --use older builder tools that worked before pivots existed
end
10 Likes

This is not really a comment on the feature itself, but I really appreciate how polished and complete this feature is. Many times, we’ll get studio betas for features that are half-baked or just blatantly missing core functionality. I think I speak for most devs when I say we much prefer features entering beta when they are finished and polished like this one. Another great example was the Attributes feature.

Many thanks to all responsible for this addition!

10 Likes

Been waiting for this forever man! I have one question will these new pivots Points replace old ones cause I’m pretty used to the old ones?

3 Likes

This is a tough one, because this is way more complexity than I feel like we can push on many plugin developers: Consider that to fully support the transition, it’s not as simple as having one if statement like you suggest in the post.

For example, we will be enabling this for Team Create midway through the beta. Once it’s enabled for team create, what happens in your plugin code? There may be both players with the beta enabled and players without the beta enabled in the same team create server. Even the players without the beta enabled will still have to internally update the pivot correctly, but shouldn’t see the pivot visibly being respected by editing operations. We’ve updated the Studio tools to handle this complexity, but I think this is beyond the effort that most plugin developers would be willing to deal with.

Exposing a simple flag somehow would basically lie about how complex handling the transition automatically would be.

6 Likes

This seems very interesting, I liked how it is physics based as well. Could I be provided with a video maybe showcasing this in the works as it is a bit confusing…?

2 Likes

The pivot indicator doesn’t show any orientation information. Currently, you have to judge the orientation by looking at the move handles while editing a pivot, but I can never remember which color goes with which direction. It would be nice to have arrows pointing in the look/up directions of the pivot CFrame.

Second, it would be helpful to be able to toggle between local/global movement and rotation when editing the pivot.

4 Likes