- Home /
Creating Lag with DrawMesh
I created this sort of prediction path for some kind of missile in 3D. First I was just using line render, until I quickly realized it was very limiting. So I switched to drawing my own meshes and it's rather beautiful. I just have one problem. In the scene when I'm running the drawMesh function everything runs quickly, but as soon as I switch to another scene there's about a 2 second lag and then everything resumes as normal. Line render didn't present any lag whatsoever, so I must have messed something up because drawing your own meshes should be more efficient.
I suspect somehow when creating my meshes the old ones never get delete, therefore when I change the scene it takes a bit to clear them all away. I'd expect the garbage collector to take care of this, but I'm probably setting something up slightly wrong. The longer you stay in the scene the longer the lag is so that's why I think this. This is just speculation though.
If anyone could take a look at my code and suggest a fix I'd appreciate it greatly.
Here's the code. It's a little complicated, but not much can be done about that. I'll include the area of code that I think is the culprit because the same code with line render worked. I'll also include the whole script in case you want to peek at it. It runs about 30 times per frame.
void drawMesh(Vector3[] vertices, Material m)
{
var mf = GetComponent<MeshFilter>();
var mesh = new Mesh();
mf.mesh = mesh;
mesh.vertices = vertices;
var tris = new int[6]
{
// lower left triangle
0, 2, 1,
// upper right triangle
2, 3, 1
};
mesh.triangles = tris;
var normals = new Vector3[4]
{
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
mesh.normals = normals;
var uv = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
mesh.uv = uv;
Graphics.DrawMesh(mesh, Vector3.zero, Quaternion.identity, m, 0, null, 0, null, false, false);
}
}
Here's the complete file. I separated the function "Visualize Aim" because I don't think anything else useful is going on outside of that.
using System.Collections;
using UnityEngine;
public class AimCannon : MonoBehaviour
{
public static bool cannonActive;
[SerializeField] private Transform cannonY;
// Calculating Aim Variables
private Vector3 last_mouse_pos, mouse_pos;
private float aimSpeed = 10;
private int trailDensity = 30;
private float trail_timeDistance = 4;
private int thrustMultiple = 5;
private float baseThrust = 70;
private int lnSegments;
private DistanceData closestPlane;
private DistanceData lastClosestPlane;
private float stickToPlane = 10f;
// Draw mesh
[SerializeField] private Material grey, red;
private float startWidth = .05f;
private float endWidth = 1.5f;
void Start()
{
cannonActive = true;
Physics.gravity = Vector3.down * 5f;
}
void Update()
{
if(InstNewPlanes.allPlanes.Count > 0)
{
updateTarget();
visualizeAim();
updateThrust();
}
}
private void FixedUpdate()
{
isStillFiring();
aimCannon();
}
/// <summary>
/// Uses user input to aim cannonY
/// </summary>
void aimCannon()
{
Vector3 difference = last_mouse_pos - mouse_pos;
float y_dif = difference.y;
float x_dif = difference.x;
float y_rot = y_dif * aimSpeed;
float x_rot = -x_dif * aimSpeed;
cannonY.Rotate(Vector3.right, y_rot, Space.Self);
transform.Rotate(Vector3.up, x_rot, Space.Self);
}
/// <summary>
/// Updates some target, idk
/// </summary>
void updateTarget()
{
if(Input.touchCount == 1)
{
Touch touch = Input.GetTouch(0);
if(touch.phase == TouchPhase.Began)
{
mouse_pos = mouseToWorldPosition();
last_mouse_pos = mouse_pos;
}
else if(touch.phase == TouchPhase.Moved)
{
last_mouse_pos = mouse_pos;
mouse_pos = mouseToWorldPosition();
}
else if(touch.phase == TouchPhase.Stationary)
{
last_mouse_pos = mouse_pos;
}
else if(touch.phase == TouchPhase.Ended)
{
last_mouse_pos = new Vector3(0, 0, 0);
mouse_pos = new Vector3(0, 0, 0);
}
}
}
class DistanceData
{
public GameObject plane;
public float distance;
public bool closest;
public DistanceData(GameObject p, float d)
{
plane = p;
distance = d;
closest = false;
}
public DistanceData(GameObject p, float d, bool c)
{
plane = p;
distance = d;
closest = c;
}
}
/// <summary>
/// Gets the closest plane to the aim
/// </summary>
/// <param name="posns"></param>
/// <returns></returns>
DistanceData findClosestPlane(ArrayList posns)
{
ArrayList planeDataArray = new ArrayList();
IEnumerator ienum = InstNewPlanes.allPlanes.GetEnumerator();
while (ienum.MoveNext())
{
float dis = 1000;
GameObject currentPlane = (GameObject)ienum.Current;
foreach(Vector3 posn in posns)
{
if(Vector3.Distance(posn, currentPlane.transform.position)<(dis))
{
dis = Vector3.Distance(posn, currentPlane.transform.position);
}
}
planeDataArray.Add(new DistanceData(currentPlane, dis));
}
return returnClosestPlane(planeDataArray);
}
/// <summary>
/// Finds the closest plane to the aim
/// </summary>
/// <param name="l"></param>
/// <returns></returns>
DistanceData returnClosestPlane(ArrayList l)
{
float dis = 1000;
DistanceData data = null;
foreach(DistanceData d in l)
{
if (d.distance < dis)
{
dis = d.distance;
data = d;
}
}
if (closestPlane != null)
{
if (data.distance < closestPlane.distance / stickToPlane)
return closestPlane;
}
return data;
}
/// <summary>
/// Ends the aim visualization as the right distance
/// </summary>
/// <param name="closest"></param>
/// <param name="pos1"></param>
/// <param name="pos2"></param>
/// <returns></returns>
bool endTrial(Vector3 closest, Vector3 pos1, Vector3 pos2)
{
if(Vector3.Distance(closest, pos1) <
Vector3.Distance(closest, pos2))
{
return true;
}
return false;
}
/// <summary>
/// Helps visualize aim so you can hit your targets
/// </summary>
void visualizeAim()
{
if (InstNewPlanes.allPlanes.Count == 0)
return;
//Line render set up variables
float cannonYangle = (210 - getAngle(cannonY).y)*Mathf.PI/180;
int lnSize = 0;
ArrayList lnPositions = new ArrayList();
ArrayList vectorPoints = new ArrayList();
float x_angle = -cannonY.transform.rotation.eulerAngles.x * Mathf.PI / 180;
float y_angle = getAngle(cannonY).y * Mathf.PI / 180;
float y_vel = FireCannon.thrust * Mathf.Sin(x_angle);
float flat_vel = FireCannon.thrust * Mathf.Cos(x_angle);
float x_vel = Mathf.Cos(y_angle) * flat_vel;
float z_vel = Mathf.Sin(y_angle) * flat_vel;
for (int i = 0; i < trailDensity; i += 1)
{
lnSize++;
Vector3 trail_pos;
float t = i / (trailDensity / trail_timeDistance);
float x = x_vel * t;
float z = z_vel * t;
float y = y_vel * t - 5f * t * t / 2;
trail_pos = new Vector3(x, y, z);
lnPositions.Add(trail_pos);
}
closestPlane = findClosestPlane(lnPositions);
for (int i = 0; i < lnSize-1; i++)
{
float fi = i;
float w1 = Mathf.Lerp(startWidth, endWidth, fi / (lnSize - 1));
float w2 = Mathf.Lerp(startWidth, endWidth, (fi+1) / (lnSize - 1));
Vector3 lnPos1 = (Vector3) lnPositions[i];
Vector3 lnPos2 = (Vector3)lnPositions[i+1];
Vector3 bl = new Vector3(
lnPos1.x - Mathf.Cos(cannonYangle) * w1,
lnPos1.y,
lnPos1.z - Mathf.Sin(cannonYangle) * w1);
Vector3 br = new Vector3(
lnPos1.x + Mathf.Cos(cannonYangle) * w1,
lnPos1.y,
lnPos1.z + Mathf.Sin(cannonYangle) * w1);
Vector3 tl = new Vector3(
lnPos2.x - Mathf.Cos(cannonYangle) * w2,
lnPos2.y,
lnPos2.z - Mathf.Sin(cannonYangle) * w2);
Vector3 tr = new Vector3(
lnPos2.x + Mathf.Cos(cannonYangle) * w2,
lnPos2.y,
lnPos2.z + Mathf.Sin(cannonYangle) * w2);
var vertices = new Vector3[4]
{
bl,
br,
tl,
tr
};
vectorPoints.Add(vertices);
if (endTrial(closestPlane.plane.transform.position, lnPos1, lnPos2))
{
lnSegments = i;
int j = 0;
foreach(Vector3[] verts in vectorPoints)
{
if (j > lnSegments / 3)
drawMesh(verts, red);
else
drawMesh(verts, grey);
j++;
}
return;
}
}
}
/// <summary>
/// Updates the thrust of the plane dependant on distance of planes
/// </summary>
void updateThrust()
{
if(lastClosestPlane == null)
lastClosestPlane = closestPlane;
else if(lastClosestPlane.plane != closestPlane.plane)
{
FireCannon.thrust = baseThrust + lnSegments * 3;
lastClosestPlane = closestPlane;
}
}
/// <summary>
/// When the play shoots down 10 planes this object is destroyed
/// </summary>
void isStillFiring()
{
if (!cannonActive)
{
Destroy(this);
}
}
/// <summary>
/// Mouse to World Position
/// </summary>
/// <returns></returns>
Vector3 mouseToWorldPosition()
{
Vector3 mouse_pos = Input.mousePosition;
mouse_pos.z = 5;
Vector3 world_pos = Camera.main.ScreenToWorldPoint(mouse_pos);
return world_pos;
}
/// <summary>
/// Helper function to get angles becasue... Unity
/// </summary>
/// <param name="trans"></param>
/// <param name="direction"></param>
/// <returns></returns>
public Vector3 getAngle(Transform transform)
{
Vector3 forward = transform.forward;
float angleInDegreesZ = Mathf.Atan2(transform.right.y, transform.right.x) * Mathf.Rad2Deg;
float angleInDegreesX = Mathf.Atan2(forward.y, forward.z) * Mathf.Rad2Deg;
float angleInDegreesY = Mathf.Atan2(forward.z, forward.x) * Mathf.Rad2Deg;
Vector3 returnAngle = new Vector3(angleInDegreesX, angleInDegreesY, angleInDegreesZ);
return returnAngle;
}
void drawMesh(Vector3[] vertices, Material m)
{
var mf = GetComponent<MeshFilter>();
var mesh = new Mesh();
mf.mesh = mesh;
mesh.vertices = vertices;
var tris = new int[6]
{
// lower left triangle
0, 2, 1,
// upper right triangle
2, 3, 1
};
mesh.triangles = tris;
var normals = new Vector3[4]
{
-Vector3.forward,
-Vector3.forward,
-Vector3.forward,
-Vector3.forward
};
mesh.normals = normals;
var uv = new Vector2[4]
{
new Vector2(0, 0),
new Vector2(1, 0),
new Vector2(0, 1),
new Vector2(1, 1)
};
mesh.uv = uv;
Graphics.DrawMesh(mesh, Vector3.zero, Quaternion.identity, m, 0, null, 0, null, false, false);
}
}
Your answer
Follow this Question
Related Questions
Bounds of dynamic mesh not updating 1 Answer
Why zero height mesh gets black independent of shader 1 Answer
How to Cut a Mesh - The Forest Style Tree Cutting 0 Answers
Particle System: Material doesn't cover the entire sphere mesh 1 Answer
How to change one child object to another with the same armature? 0 Answers