Hi Everyone,
This is my first post here so please let me know if there is anything I can provide to help answer my question. I am working on creating a script to place a conveyor belt object along a Bezier curve. I am able to create the curve and update it as the end point is moved around. However, when I have started to try and introduce the mesh deformation to the equation, I am running into issues. I followed a tutorial on updating the vertices and triangles for the mesh. However, I am getting wonky results (see image below). Are there any resources that someone could point me to? Or any suggestion on the code below. I am also self taught and fairly new to coding so any suggestions/tips on keeping my code cleaner/more efficient would be greatly appreciated!
Thanks,
using UnityEngine;
public class ConveyorPlacement : MonoBehaviour
{
//Prefab for pole object
[SerializeField] private GameObject conveyorPole;
//Prefab for belt object
[SerializeField] private GameObject beltMesh;
//Width of belt
[SerializeField] private float beltWidth = 1;
//Number of points between starting pole and ending pole
private int numberOfPoints = 20;
//bools to determine logic based on step in process
private bool isPlacing = false;
private bool startPlaced = false;
private bool endPlaced = false;
private GameObject startingPole;
private GameObject endingPole;
private GameObject belt;
private Mesh mesh;
//parent object to hold each pole and the belt object
private GameObject conveyorBelt;
//Speed to rotate the object when placing
private readonly float rotationSpeed = 45f;
//points between starting and ending pole along Bezier curve
private Vector3[] points;
private float placementDistance = 5f;
private readonly float minDistance = 2f;
private readonly float maxDistance = 10f;
private readonly float scrollSensitivity = 1f;
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
if (!isPlacing)
{
StartPlacing();
}
else if (!startPlaced)
{
PlaceStart();
StartPlacingEnd();
}
else
{
PlaceEnd();
}
}
if (isPlacing && !startPlaced)
{
UpdateStart();
}
else if (isPlacing && !endPlaced)
{
UpdateEnd();
}
if (endPlaced)
{
endPlaced = false;
}
}
private void StartPlacing()
{
//Logic to start placing the starting pole
isPlacing = true;
//Create empty game object to hold pieces of conveyor belt
conveyorBelt = new GameObject("Conveyor Belt");
startingPole = Instantiate(conveyorPole, conveyorBelt.transform);
placementDistance = 5f;
startingPole.transform.position = DetermineLocation();
}
private void StartPlacingEnd()
{
//Logic to start placing the ending pole
endingPole = Instantiate(conveyorPole, conveyorBelt.transform);
placementDistance = 5f;
endingPole.transform.position = DetermineLocation();
//Create the belt object and set its position to the starting pole
belt = Instantiate(beltMesh, conveyorBelt.transform);
belt.transform.position = startingPole.transform.position;
mesh = belt.GetComponent<MeshFilter>().mesh;
//Update the points between the starting and ending pole once ending pole is created
points = FindPoints(startingPole.transform, endingPole.transform, numberOfPoints);
//Start udpating the mesh once ending pole is created
CreateMesh(points, mesh);
}
private void UpdateStart()
{
startingPole.transform.position = DetermineLocation();
RotateObject(startingPole.transform);
}
private void UpdateEnd()
{
endingPole.transform.position = DetermineLocation();
RotateObject(endingPole.transform);
//update the points between the starting and ending pole as the ending pole is moved around
points = FindPoints(startingPole.transform, endingPole.transform, numberOfPoints);
//update the mesh based on the updated points
CreateMesh(points, mesh);
}
private void PlaceStart()
{
startPlaced = true;
}
private void PlaceEnd()
{
//Clear all of the variabels that should be reset after ending point is placed
endPlaced = true;
isPlacing = false;
startingPole = null;
points = null;
endingPole = null;
belt = null;
mesh = null;
conveyorBelt = null;
startPlaced = false;
}
//Update the location of the object that is currently being placed
private Vector3 DetermineLocation()
{
Vector3 screenCenter = new(Screen.width / 2, Screen.height / 2, 0f);
UpdateDistanceFromPlayer();
return Camera.main.ScreenToWorldPoint(new Vector3(screenCenter.x, screenCenter.y, placementDistance));
}
//Allow player to use scroll wheel to place object closer or further away
private void UpdateDistanceFromPlayer()
{
float scrollInput = Input.GetAxis("Mouse ScrollWheel");
placementDistance += scrollInput * scrollSensitivity;
placementDistance = Mathf.Clamp(placementDistance, minDistance, maxDistance);
}
private void OnDrawGizmos()
{
Gizmos.color = Color.red;
if (startingPole)
{
Vector3 objectPosition = startingPole.transform.position;
Vector3 objectForward = startingPole.transform.forward;
Gizmos.DrawLine(objectPosition, objectPosition + objectForward * 2f);
Gizmos.color = Color.green;
Gizmos.DrawSphere(startingPole.transform.position, .1f);
}
if (endingPole)
{
Vector3 objectPosition = endingPole.transform.position;
Vector3 objectForward = endingPole.transform.forward;
Gizmos.DrawLine(objectPosition, objectPosition + objectForward * 2f);
Gizmos.color = Color.green;
Gizmos.DrawSphere(endingPole.transform.position, 0.1f);
}
if (startingPole && endingPole)
{
Gizmos.color = Color.blue;
foreach (Vector3 point in points)
{
Gizmos.DrawSphere(point, 0.05f);
}
}
}
private void RotateObject(Transform item)
{
if (Input.GetKey(KeyCode.Q))
{
item.Rotate(Vector3.up, rotationSpeed * Time.deltaTime);
}
if (Input.GetKey(KeyCode.E))
{
item.Rotate(Vector3.up, -rotationSpeed * Time.deltaTime);
}
}
private Vector3[] FindPoints(Transform start, Transform end, int numberOfPoints)
{
float distance = Vector3.Distance(start.position, end.position) / 2;
Vector3 p0 = start.position;
Vector3 p1 = start.position + start.forward * distance;
Vector3 p2 = end.position - end.forward * distance;
Vector3 p3 = end.position;
Vector3[] newPoints = new Vector3[numberOfPoints];
Debug.Log(newPoints);
newPoints[0] = p0;
newPoints[newPoints.Length - 1] = p3;
for (int i = 1; i < newPoints.Length - 2; i++)
{
newPoints[i] = Bezier.CubicCurve(p0, p1, p2, p3, (float)i / (numberOfPoints - 2));
}
return newPoints;
}
private void CreateMesh(Vector3[] points, Mesh mesh)
{
//Create Vector3[] with length twice that of the number of points
// to hold the vertices (Vertices = 2(numberOfPoints))
Vector3[] verts = new Vector3[points.Length * 2];
//Create int[] with length 2n-1 to hold triangles
int[] tris = new int[2 * (points.Length - 1) * 3];
int vertexIndex = 0;
int triIndex = 0;
for (int i = 0; i < points.Length; i++)
{
//Set the intial value of forward to 0
Vector3 forward = Vector3.zero;
if (i < points.Length - 1)
{
//If it is not the last point, add the distance between the current point
//and the following point
forward += points[i + 1] - points[i];
}
if (i > 0)
{
//if it is not the first point, add the distance between the current point
//and the previous point
forward += points[i] - points[i - 1];
}
//Get the average of the forward;
forward.Normalize();
//calculate the position to place the vertices
Vector3 left = new Vector3(-forward.y, points[i].y, forward.x);
verts[vertexIndex] = points[i] + 0.5f * beltWidth * left;
verts[vertexIndex + 1] = points[i] - 0.5f * beltWidth * left;
//Update the triangles array to include appropriate vertices
if (i < points.Length - 1)
{
tris[triIndex] = vertexIndex;
tris[triIndex + 1] = vertexIndex + 2;
tris[triIndex + 2] = vertexIndex + 1;
tris[triIndex + 3] = vertexIndex + 1;
tris[triIndex + 4] = vertexIndex + 2;
tris[triIndex + 5] = vertexIndex + 3;
}
vertexIndex += 2;
triIndex += 6;
}
//assign the vertices and triangles to the mesh and recalculate bounds/normals
mesh.vertices = verts;
mesh.triangles = tris;
mesh.RecalculateBounds();
mesh.RecalculateNormals();
}
}