My procedural road, based on the Splines package from Unity, turns 2 times faster than the object itself to which the road creation script is attached. The problem is not only that it rotates 2 times faster, but it is also positioned 2 times faster, but I was able to solve this by adding - new float3(transform.position)
to the vertex position. The script is not finished and looks bad, but it works. It is enough to place it on an object that has a Unity spline on it, and the road will be built along the spline
Script
[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
[ExecuteInEditMode()]
public class SplineRoad : MonoBehaviour
{
[SerializeField] int splineIndex;
[SerializeField] int resolution;
[SerializeField] float roadWidth = 15f;
[SerializeField] bool sidewalk = true;
[SerializeField] float sidewalkWidth = 5f;
[SerializeField] float sidewalkHeight = 0.25f;
[SerializeField] float sidewalkOffset;
[SerializeField] bool sidewalkBackPart = true;
[SerializeField] float step;
float time;
public float tiling = 1;
float3 position;
float3 tangent;
float3 upVector;
float3 forward;
float3 left;
[SerializeField] Vector3[] vertices;
[SerializeField] int[] triangles;
[SerializeField] int[] sidewalkTriangles;
[SerializeField] Vector2[] roadUvs;
[SerializeField] Vector2[] sidewalkUvs;
Mesh mesh;
SplineContainer splineContainer;
int verticesOnCell = 42;
private void Start()
{
splineContainer = GetComponent<SplineContainer>();
mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
mesh.name = "RoadProceduralMesh";
}
private void Update()
{
if(!sidewalk)
sidewalkBackPart = false;
GenerateMesh();
}
void GenerateMesh()
{
time = 0;
step = 1f / resolution;
tiling = GetComponent<SplineContainer>().CalculateLength(0) / roadWidth / resolution;
vertices = new Vector3[(verticesOnCell) * resolution];
triangles = new int[(verticesOnCell) * resolution];
sidewalkTriangles = new int[verticesOnCell * resolution];
roadUvs = new Vector2[vertices.Length];
sidewalkUvs = new Vector2[vertices.Length];
for (int i = 0; i < resolution; i++)
{
time = step * i;
splineContainer.Evaluate(splineIndex, time, out position, out forward, out upVector);
left = Vector3.Cross(forward, upVector).normalized;
vertices[i * verticesOnCell + 0] = position + (left * roadWidth / 2) - new float3(transform.position);
vertices[i * verticesOnCell + 2] = position + (-left * roadWidth / 2) - new float3(transform.position);
vertices[i * verticesOnCell + 4] = position + (-left * roadWidth / 2) - new float3(transform.position);
roadUvs[i * verticesOnCell + 0] = new Vector2(0, 0 * tiling);
roadUvs[i * verticesOnCell + 1] = new Vector2(0, 1 * tiling);
roadUvs[i * verticesOnCell + 2] = new Vector2(1, 0 * tiling);
if (sidewalk)
{
GenerateSidewalkFirstTriangle(i, left, 0);
GenerateSidewalkSecondTriangle(i, -left, 18);
}
time += step;
splineContainer.Evaluate(splineIndex, time, out position, out forward, out upVector);
left = Vector3.Cross(forward, upVector).normalized;
vertices[i * verticesOnCell + 1] = position + (left * roadWidth / 2) - new float3(transform.position);
vertices[i * verticesOnCell + 3] = position + (-left * roadWidth / 2) - new float3(transform.position);
vertices[i * verticesOnCell + 5] = position + (left * roadWidth / 2) - new float3(transform.position);
roadUvs[i * verticesOnCell + 3] = new Vector2(1, 1 * tiling);
roadUvs[i * verticesOnCell + 4] = new Vector2(1, 0 * tiling);
roadUvs[i * verticesOnCell + 5] = new Vector2(0, 1 * tiling);
if (sidewalk)
{
GenerateSidewalkSecondTriangle(i, left, 0);
GenerateSidewalkFirstTriangle(i, -left, 18);
}
}
for (int i = 0; i < verticesOnCell * resolution; i++)
{
triangles[i] = i;
}
mesh.Clear();
mesh.subMeshCount = sidewalk ? 2 : 1;
mesh.SetVertices(vertices);
mesh.SetTriangles(triangles, 0);
mesh.SetUVs(0, roadUvs);
mesh.RecalculateNormals();
mesh.Optimize();
}
void GenerateSidewalkFirstTriangle(int i, float3 side, int offset)
{
vertices[i * verticesOnCell + 6 + offset] = position + (side * roadWidth / 2) + (upVector * sidewalkHeight) - new float3(transform.position);
vertices[i * verticesOnCell + 8 + offset] = position + (side * roadWidth / 2) - new float3(transform.position);
vertices[i * verticesOnCell + 10 + offset] = position + (side * roadWidth / 2) - new float3(transform.position);
vertices[i * verticesOnCell + 12 + offset] = position + (side * roadWidth / 2 + side * sidewalkWidth) + (upVector * sidewalkHeight) - new float3(transform.position);
vertices[i * verticesOnCell + 14 + offset] = position + (side * roadWidth / 2) + (upVector * sidewalkHeight) - new float3(transform.position);
vertices[i * verticesOnCell + 16 + offset] = position + (side * roadWidth / 2) + (upVector * sidewalkHeight) - new float3(transform.position);
if (sidewalkBackPart)
{
vertices[i * verticesOnCell + 18 + offset] = position + (side * roadWidth / 2 + side * sidewalkWidth) - new float3(transform.position);
vertices[i * verticesOnCell + 20 + offset] = position + (side * roadWidth / 2 + side * sidewalkWidth) + (upVector * sidewalkHeight) - new float3(transform.position);
vertices[i * verticesOnCell + 22 + offset] = position + (side * roadWidth / 2 + side * sidewalkWidth) + (upVector * sidewalkHeight) - new float3(transform.position);
}
}
void GenerateSidewalkSecondTriangle(int i, float3 side, int offset)
{
vertices[i * verticesOnCell + 7 + offset] = position + (side * roadWidth / 2) + (upVector * sidewalkHeight) - new float3(transform.position);
vertices[i * verticesOnCell + 9 + offset] = position + (side * roadWidth / 2) - new float3(transform.position);
vertices[i * verticesOnCell + 11 + offset] = position + (side * roadWidth / 2) + (upVector * sidewalkHeight) - new float3(transform.position);
vertices[i * verticesOnCell + 13 + offset] = position + (side * roadWidth / 2 + side * sidewalkWidth) + (upVector * sidewalkHeight) - new float3(transform.position);
vertices[i * verticesOnCell + 15 + offset] = position + (side * roadWidth / 2) + (upVector * sidewalkHeight) - new float3(transform.position);
vertices[i * verticesOnCell + 17 + offset] = position + (side * roadWidth / 2 + side * sidewalkWidth) + (upVector * sidewalkHeight) - new float3(transform.position);
if (sidewalkBackPart)
{
vertices[i * verticesOnCell + 19 + offset] = position + (side * roadWidth / 2 + side * sidewalkWidth) - new float3(transform.position);
vertices[i * verticesOnCell + 21 + offset] = position + (side * roadWidth / 2 + side * sidewalkWidth) + (upVector * sidewalkHeight) - new float3(transform.position);
vertices[i * verticesOnCell + 23 + offset] = position + (side * roadWidth / 2 + side * sidewalkWidth) - new float3(transform.position);
}
}
}