Modular Snap System (MSS) plugin aligns actors by looking at sockets present in those actors. Those sockets are also called “snap points” in this documentation.
After you move or rotate one or more Actors in the Level Editor the plugin will look around all sockets defined in those Actors (called source sockets). It will search for matching sockets in other Actors in the level (target sockets). If a couple of matching sockets (source, target) is found then all the source Actors will be moved and rotated in such a way that both source and target socket have the same location and orientation in world space. It’s important to note that by default the moved Actors will not be attached to the matching socket.
MSS works with any component that can contain sockets: static meshes, skeletal meshes, etc. Splines are also supported, spline endpoints are seen as sockets. Actors owning those components can be of any class or blueprint.
MSS uses collision queries, so it’s very important that all involved components have simple collision defined and enabled, otherwise the plugin will not see them.
Parameters of the plugin can be accessed from Level Editor toolbar “Settings” menu or in “Plugins” section of Project Settings. Parameters are saved in EditorPerProjectUserSettings.ini config file.
How MSS works: Search and Snap
When you finished moving or rotating actors in the level editor and released the mouse button the plugin will activate and try to make things snap. This operation can be divided in two steps: searching for matching sockets and calculating the new transforms of snapped actors.
Search: Socket matching rules
Before the search start we have to identify all source actors and their sockets. There are 3 possible cases depending of what is selected in the level editor:
- If one or many actors are selected, then we will consider the sockets from the components of those actors.
- If we selected one or many components of an actor we will only look at those.
- Finally, if we moved a spline endpoint we will consider it as a socket and search around it. The name of the spline component will be used as socket name.
Source and Target Component Classes. Only components of those classes will be considered by the plugin, the components not in those lists will be ignored. Source and Target classes can be specified in the plugin parameters.
Snap Attached Too. This parameter tells the plugin if it should also consider the actors attached to the selected actors as source actors, even if they are not selected in the editor. If this parameter is false then the plugin will not search around the attached actors sockets, nor consider them as possible targets. It works the same way if the selection consists of components (case 2).
Use “nosnap” tag. If you want to hide a particular component from the plugin, you can add a “nosnap” tag to the list of component tags. This way the plugin will not look in this component for sockets, both source or target.
Once the list of source sockets is made we will start to search around each of those sockets. We will make sphere collision traces and consider all sockets of all found target components.
While searching for matching target socket three things are considered: socket name, distance between sockets and angle between socket’s forward vectors. Only sockets in range with matching names and angles are considered, from those the nearest socket is chosen.
Distance. The radius of the search around each source socket is defined by the SearchDist plugin parameter. MSS will do a sphere collision query around each source socket and Search Distance is the radius of this query.
Angle. Source and target socket’s forward vectors (X axis, red) should be pointing in more or less opposite directions in World Space. The tolerance is defined by the MaxAngle parameter. MaxAngle = 0° means that the forward vectors should be exactly opposing each other, while MaxAngle = 180° means that they can be oriented in any direction. Default is 75°.
Name. Sockets can be named like “SnapPointName_TheRest“. Only “SnapPointName” – the part before the first “_” – is compared. “_TheRest” part is optional and not taken into account. Comparison is case insensitive. For example, sockets named Socket, Socket_0, Socket_XYZ_123 can snap, because the plugin will only compare the part before the “_”. Sockets named Socket1 and Socket2 will never snap.
Name matching can be disabled using bIgnoreSocketName plugin parameter. In this case all names are considered matching.
Polarity. Snap point name can have “polarity”: positive, negative or neutral (tutorial). Socket named Door+ is positive, Door- is negative and Door is neutral. If both sockets have the same name and opposite polarity they will match. If both have the same name and the same polarity they will not match. If one snap point has polarity and other has not, then the polarity is discarded and only names are compared.
Therefore Door+ matches Door-, Door matches both Door+ and Door-, but Door+ doesn’t match another Door+ and Door- doesn’t match Door-
Polarity is specified before the “_”, for example Door+_1
Snap open only. This parameter forces the plugin to make an additional check around the source or target socket to see if it’s not blocked by some other component. The check consists in running a sphere trace in front of the socket. The radius of the sphere is specified by the OpenCheckRadius parameter, which is set to 2 cm by default.
“Snap open only” will only consider components from the Target Component Classes as blockers. If the trace returns nothing or it returns only components which are not in this list, the socket is considered open for snapping. Otherwise it’s discarded. Limiting blockers to the Target Component Classes ensures that stuff not in the list, like blocking volumes, will not interfere with the plugin.
Note about splines. Spline component does not have collision, therefore, in order to be discovered, some other component should act as collider. So if Target Component Classes list contains Spline Component, then the plugin will make a special additional check and look for spline components among all components of target actors (target actors = owners of components discovered using collision trace).
Splines are often used together with spline mesh components, so one possibility is to use the collision of those. Another possibility is to add a small sphere collision component around endpoints. In both cases, the corresponding class should be added to the Target Component Classes list, otherwise it will not be discovered.
Snap: New transform calculation rules
Once a couple of matching sockets is found we calculate the new location and rotation for the snapped actors. The following rules and parameters apply during this calculation.
Most of the snap parameters are defined in plugin settings, but some can be defined directly in the socket name. As said above, sockets can be named “SnapPointName_TheRest “. “TheRest” part of the socket name is ignored during search but can contain parameters applied during the calculation of the snap transform. Socket parameters can be ignored by setting IgnoreSocketParams plugin setting.
Rotation snap step. Specified globally by the DefaultRotSnap plugin parameter or by adding
_RZn to the socket name, where n is an angle in degrees. For example: Window_RX180.
By default, snapped actors will be rotated to make source socket rotation match the target socket rotation. This parameter allows to align the source socket to the nearest increment of the specified angle around specified target axis instead.
Any angle can be used. For example, 180° means the source socket can be aligned exactly to the target socket or flipped 180° around. Value of 0° means no rotation snap is applied and the world rotation is preserved, while 360° means the socket is aligned exactly to the target socket.
The rotation can be specified for each axis separately, but the X axis (forward axis, the red one) is the most useful.
If no rotation step is specified in the socket name, then the default value defined by the DefaultRotSnap plugin parameter is used. By default it’s set to (RX=90°, RY=360°, RZ=360°) which means the source socket YZ plane will be exactly aligned with the target YZ plane, but the socket can be rotated at 90° increments around X axis.
If all three angles are set to 0° then no rotation will be applied to source actors at all.
Scale snap on/off. Specified using Default Scale Snap plugin parameter or by adding
_SZn to the socket name, where n is either 0 or 1. For example: Window_SX0_SY0_SZ0.
Similar to the rotation snap, scale snap is applied to the source actors to make them match target scale. If you snap an actor to something that was scaled down and this parameter is enabled your actor will be scaled down too. The value of 0 means that the scale snap is disabled and the scale of the source actors is left as it is.
Attention! Even if you can have different scale snap per axis it’s recommend to have it either totally disabled or enabled for all 3 axis. Scale is always in the local space, so the result of non-uniform scaling can be weird. Use with caution.
Attach to parent. If the plugin parameter AttachToParent is true, then MSS will attach the moved Actor to the parent Actor of the target Actor (if there is one). This is useful when you want to “group” many actors under one common root Actor. For example, an entire modular house can be attached to an “house root” actor, which enables to move and scale the house as one.
Snap pivot. If the plugin parameter Snap to Pivot is enabled then the selection pivot (translate or rotate gizmo in the level editor) will be moved to the last snap point. The change of pivot is temporary: pivot location will return to normal when the selection is changed. This is useful if you want to rotate snapped actor around the snap point and not around its origin.
No Snap back. This parameter will force the plugin to abort the snap operation if the new transform of the source socket is nearly equal to the old one. The tolerance is specified in NoSnapbackTolerance parameter.
Attach to target socket parameter. By default the moved Actor will not be attached to the matching Actor. But if the target socket has the “_A” parameter, then it will be. It only works when one actor is moved and only if the target socket has “_A” parameter.
In case when the target component is a skeletal mesh the source actor will be attached to the target socket, which enables to move it with the skeleton. Example: attach a gun to a hand.
It the target is a static mesh, the source will always be attached to the component itself. This is because attaching to a static mesh socket is not really meaningful and also currently buggy in UE4.
Attaching to a socket can be disabled using bAttachToSocket parameter, in this case we always attach to component root for both static or skeletal meshes.
Ignore spline socket scale. When attaching an actor to a spline endpoint the scale of the endpoint is ignored. This is useful because spline endpoint scale is something different from the normal actor scale, so scaling the actor to it is almost always meaningless.
When attaching endpoint to another endpoint the scale is applied if allowed by global or socket scale settings.
Export/Import Sockets Tool
Allows to export and import socket definitions from multiple Static Meshes to a text file. To use the tool select some Static Meshes in the Content Browser, then right click and choose “Snap System” sub-menu in the Asset Actions section. You can select meshes from many folders by using Content Browser filters.
Export option will write sockets from the selected assets to a text file. Import will read the text file then add or modify sockets in the selected assets which match the entries of the file. Delete will remove all sockets from selected assets.
The export file is a simple text file that can be edited with a text editor or pasted in a web page. The file is composed of asset names followed by one or more socket definitions. Example:
StaticMesh /Game/Meshes/SomeMesh S SomeSocket 0.0,-25.0,0.0|0.0,-90.0,0.0|1.0,1.0,1.0 S OtherSocket 0.0,25.0,0.0|0.0, 90.0,0.0|1.0,1.0,1.0
The import tool can manage the case when the assets were moved to another folder. In this case it will try to find an asset with the same name and the most similar path, then ask the user for confirmation.