I would like to deform an already existing mesh to a beziér curve (spline).
I can create new meshes with pre-defined vertices for the top, left, right, front, back etc., but I would like an already existing mesh to deform to a given path.
Example:
Here’s the “original model” I would like to deform. It isn’t deformed yet and is completely straight. (note that the model has sides, Y-axis thickness and may have other geometry)
I utilized Beziér Path Creator on the Asset Store to create the above example. This works, but it creates the entire mesh, with all of the points, brand new. I would like to use an existing mesh instead.
Shouldn’t be too difficult, assuming your mesh:
A) is in a reasonable orientation to start with. By this I mean, (0,0,0) is the first point of the mesh, and the mesh essentially is a long straightaway going forward in the Z direction.
B) has enough density. The technique I’m going to describe here is NOT going to add vertices, so if you have a long straightaway that’s composed of large triangles, it may get mangled when it goes around a curve. So keep that in mind.
Here’s some boilerplate code you’ll need to start off:
public void AlterMeshForSpline(Mesh m) {
Vector3[] vertices = m.vertices;
for (int v=0; v<vertices.Length; v++) {
vertices[v] = TransformVertex(vertices[v]);
}
m.vertices = vertices;
m.RecalculateNormals();
m.RecalculateBounds();
}
public Vector3 TransformVertex(Vector3 meshVertex) {
//TODO
}
That’s the easy part. Now we just need to implement TransformVertex. For this, we’ll need to consider what our 3 numbers in the Vector3 actually represent: Z is by far the most important, and is associated with “how far along the spline it is”. X and Y basically form a 2D point on an imaginary plane.
I’ll assume you have some method that can get you the point along your spline at distance Z - that’s really all you’ll need from your spline generator for this to work.
Basically, we’re going to create an imaginary “plane” that sort of moves along the spline, always facing the spline’s “forward” direction. Then this plane will be used to work out where the X and Y go, and from there you’ll have your final vertex.
“deform to a given path” doesn’t really have meaning: if it truly deforms to the path, just put all the points on a path, but I know that’s not what you mean.
what you probably mean is “deflect geometry according to the difference between a straight line and this bezier curve.”
what that entails is probably studying each point on the original straight line, finding out how much it deflects to become the curved point, deciding how you want to handle linear scaling (such as if portions of the curve are crunched or stretched), and then come up with a list of distortions at given spatial points.
NOW … with that info you can probably go back and come up with a way to deform the original verts in the mesh according to each of those local distortions.
NOTE: you might need to subdivide the original mesh to provide more intermediate points, depending on the curvature and frequency of deflection in the curve.
Thanks for the quick answer!
I tried implementing your solution and it creates a very deformed, long version of the mesh.
It does not follow the spline. Through debugging, I noticed that the mesh’s vertices variable contains and TransformVertex() returns very individually similar values.
You’ve covered up most of your code, but: what does your equivalent of GetPointAlong Spline take? It’s possible it takes a normalized number (0 for 0, 1 for the end of the spline). It needs to be something that takes a distance along the spline, or the distance needs to be divided by the total length of the spline before you pass in the parameter.
I have a GetPointAtDistance(float dst) method that takes in a distance and returns the appropriate Vector3 along the path for the given distance.
I use it for camera movement and I’ve had no problems with it so far.
This is my implementation of your idea:
public class MeshDeformTest : MonoBehaviour
{
public GameObject targetObject;
public TrackMeshCreator pathcreator;
Mesh mesh;
VertexPath path { get { return pathcreator.path; } }
void Awake() => GetMesh();
void GetMesh() => mesh = targetObject.GetComponent<MeshFilter>().mesh;
public void DeformMesh() {
GetMesh();
Vector3[] vertices = mesh.vertices;
for (int i = 0; i < vertices.Length; i++)
vertices[i] = TransformVertex(vertices[i]);
mesh.vertices = vertices;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
}
public Vector3 TransformVertex(Vector3 meshVertex) {
Vector3 splinePoint = path.GetPointAtDistance(meshVertex.z);
Vector3 futureSplinePoint = path.GetPointAtDistance(meshVertex.z + 0.01f);
Vector3 forwardVector = futureSplinePoint - splinePoint;
Quaternion imaginaryPlaneRotation = Quaternion.LookRotation(forwardVector, Vector3.up);
Vector3 pointWithinPlane = new Vector3(meshVertex.x, meshVertex.y, 0f);
return splinePoint + imaginaryPlaneRotation * pointWithinPlane;
}
Hello,
i’m working on a suspended monorail, and i need to deform the rail properly to reduce the numbers of mesh needed to fill the spline. Because for the moment i use small “rail” to make the rail way look smooth and make good curve…
Can you explain how you manage to do it ? (i know it’s been long time since you have done this but it will be helpfull…)
Hi, while I cannot present a concrete implementation for an example, I would summarize it like this:
Have a curve/spline system that allows you to define splines and grab a position/rotation point anywhere along it.
Then, iterate through the vertices of the mesh and offset each point by the position/rotation along the spline, relative to the given vertex position.
It is relatively simple math once you realize what this is about.
Do note that this implementation is for deforming the mesh as-is, without generating new vertices. As such, the “smoothness” of the curve within the mesh is reliant on the count of vertices and your spline system providing precise values.
If you want a really smooth implementation, you should consider generating new vertices within the mesh (a.k.a “extruding a 2D mesh”).
Freya Holmér (Acegikmo) has some really good content regarding mesh deformation along splines, as well as general overviews on how Beziér and other types of curves work. https://www.youtube.com/acegikmo
Thanks for informations
I managed to add more verticles on the mesh but his position not follow the curve, when i start the game it moves from his position to an other …
I would like to know if it’s possible to see the changement directly in the editor view, that i don’t have to start the game to see the changes