Getting lag by creating Unity Meshes - c#

In Unity3D, 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 where my suspicion arises. 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. 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);
}
}
Thanks for any feedback!

Solved it. Unity garbage collector has a problem. I had to make sure I was manually deleting the meshes after they were created. I put them in an array of length (however long you want them to exist for) and then delete old elements once they exceeded then length.

Related

Bug with Unity3D's LookAt function in AR Foundation for Android

I'm having a problem regarding my simple shooting game in AR using AR foundation.
First of all i need to explain how the app works:
-> it detects 5 planes and puts in the centre of them a cube, then saves the cube and the related plane in a struct:
`
public void PlaneUpdated(ARPlanesChangedEventArgs args)
{
if (args.added != null && planes.Count < maxObjects)
{
ARPlane arPlane = args.added[0];
PlaneObj temp = new PlaneObj(arPlane, (Instantiate(PlaceablePrefab, arPlane.transform.position, Quaternion.identity)));
planes.Add(temp);
}
}
`
-> after 5 blocks are placed a button appears which, when clicked, calls the function Update Size which moves a trigger block collider in the position of the camera and calls for updateObjects function
`
public void UpdateSize()
{
if (canUpdate)
{
canUpdate = false;
lookPoint.transform.position = Camera.main.transform.position;
this.GetComponent<UpdateObjects>().updateObjects(planes, lookPoint); //changed to lookPoint
}
}
`
-> the updateObjects function takes everyn object placed, scales them with a fixed ratio and then calls the LookAt function which turns every block towards the position of lookPoint
`
public void updateObjects(List<PlaceObjectsAutomated.PlaneObj> planes , GameObject lookPoint)
{
foreach(PlaceObjectsAutomated.PlaneObj planeObj in planes)
{
// var scaling = new Vector3(planeObj.plane.size.x * 2, planeObj.plane.size.y * 2, 0); //planeObj.obj.transform.localScale.z);
var scaling = new Vector3(1, 1, 1); /////////
planeObj.obj.transform.localScale += scaling;
planeObj.obj.transform.LookAt(lookPoint.transform.position);
}
this.GetComponent<SpawnEnemy>().spawnEnemy(planes, lookPoint);
}
`
Here's what the bug is: at this point i have 5 scaled blocks that look towards that point, but then after a while, without any other code except these snippets that controls the cubes rotation, they go back to their original rotation and will not rotate anymore, even if i try to call for LookAt again.
Does anyone knows why is it doing this? this problem happens only in AR, because
The things i know for sure are:
-This is not caused by the struct, it happened even before i used that
-The LookAt function isn't called anywhere else nor i manipulate the block's size and rotation except for the updateObjects function
-This is not cause by the scaling, because it happens even if i don't scale the blocks
-The functions aren't called except when i need them to, so there's no instances where it might go through them a second time
-This is not affected by the Quaternion.Identity because in the dummy 3d project i used to test the features the blocks stay rotated even with Identity as the initial spawn rotation
-I know they can't be rotated after they snap back to their original rotations because i actually tried to call the LookAt function afterwards but it doesn't work

BulletPhysics - Door object spins uncontrollably when placed on ground

I am trying to simulate a door in BulletPhysics using a HingeConstraint. The following code works as intended, in that the cube pivots on its corner around the Y-axis, effectively swinging open like a door, but as soon as I place the object on the ground it begins flying around uncontrollably.
RigidBody body = physics.LocalCreateRigidBody(mass, Matrix4.CreateTranslation(new Vector3(0, 0.5f, 0)), new BoxShape(1, 1, 1));
body.UserObject = "Door";
Vector3 pivotInA = new Vector3(1, 1, 1);
Vector3 axisInA = new Vector3(0, 1, 0);
var hinge = new HingeConstraint(body, pivotInA, axisInA);
const float targetVelocity = 1.0f;
const float maxMotorImpulse = 1.0f;
hinge.EnableAngularMotor(true, targetVelocity, maxMotorImpulse);
physics.World.AddConstraint(hinge);
Disabling collisions between the door and ground would solve the problem but I am struggling to achieve this also. The documentation says you can set a collision type and mask for a body but only the World.AddRigidBody() constructor appears
to take such parameters and as far as I can tell my door is added to the world as a Hinge and the ground is added automagically when calling LocalCreateRigidBody(), shown below.
CollisionShape groundShape = new BoxShape(10, 1, 10);
CollisionObject ground = LocalCreateRigidBody(0, Matrix4.CreateTranslation(0, -1, 0), groundShape);
ground.UserObject = "Ground";
How can I stop the door spinning out when it sits atop the ground?
You can write your own version of LocalCreateRigidBody that sets up the collision mask. LocalCreateRigidBody is a helper function in the BulletSharp demos and not a built-in function in Bullet.
Here is one way to set up the collision filter:
const CollisionFilterGroups groundGroup = (CollisionFilterGroups)0x40000000;
var groundMask = CollisionFilterGroups.AllFilter ^ CollisionFilterGroups.StaticFilter;
World.AddRigidBody(ground, groundGroup, groundMask);
var doorMask = CollisionFilterGroups.AllFilter ^ groundGroup;
World.AddRigidBody(door, CollisionFilterGroups.DefaultFilter, doorMask);
Another way to solve this is to make the door shorter so it's not close enough to the ground to generate collisions. Then render a larger graphics object in place of the smaller physics object. If you are using the BulletSharp demo framework, then you will have to modify the framework to support this.

Can't change transform.position of Instantiated GameObject

I have a random world with some trees that get randomly instantiated.
I use the following code to instantiate them:
GameObject go = Instantiate(treePrefab);
go.name = "Tree";
go.tag = "Wood";
go.layer = 9;
go.transform.position = new Vector3(y + UnityEngine.Random.Range(-0.5f, 0.5f), heightPos, x + UnityEngine.Random.Range(-0.5f, 0.5f));
go.transform.Rotate(0, UnityEngine.Random.Range(0, 360), 0);
x and y are part of a for loop that goes through all positions (like a grid) of my world.
heightPos is the current height of the terrain at the specific point (x/y).
My problem is that the prefab ob the trees has the position 0, 0, 0.
Every tree that get's instantiated gets set to 0, 0, 0 too.
I use the exact same code to instantiate rocks, cactus, feathers, car's and many other things, and it works perfect.
but it always fails at the trees.
I've looked through the code and there is no difference to the other objects, except the prefab (of course).
So i think it has to do something with the settings of the prefab.
But my prefab got no animator, it is not static or something.
This is what my tree-Prefab looks like in the inspector:
and this is what it looks like in scene view:
You can create another gameobject and make this instance as a child of that gameobject so even if the instance is always at (0, 0, 0) you can always change the position of the parent object.

Sprite.OverridePhysicsShape( ? );

Here is the link that says about:
https://docs.unity3d.com/ScriptReference/Sprite.OverridePhysicsShape.html
The part of IList I understand. But Vector2[], I do not understand how I would use it to populate with data and use it here.
I haven't actually used this and I'm not in a position to knock up a quick test at the moment, but this might help. You should be able to define the physics boundaries for your sprite as a collection of shapes.
Imagine you have a single sprite with two separate components and a gap in the middle. Rather than defining a single physics shape around the entire thing, you might choose to define the physics shape in two parts so that it better conforms to the two parts of the image.
Therefore, the IList is your collection of shapes. This could quite likely just contain a single shape. The Vector2 array defines the points (at least three points in sprite space) for that individual shape. All of the Vector2 arrays combined form the overall physics shape.
EDIT: How to set the values? Something like this perhaps?
void Start ()
{
SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
Sprite sprite = spriteRenderer.sprite;
sprite.OverridePhysicsShape(new List<Vector2[]> {
new Vector2[] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1) },
new Vector2[] { new Vector2(2, 2), new Vector2(3, 2), new Vector2(3, 3), new Vector2(2, 3) },
});
}
DISCLAIMER: Not sure if that actually works.
I'm sorry, but the official Unity answer is "Don't bother." Calls to Sprite.OverridePhysicsShape() only work when importing (or reimporting) images and cannot work at runtime (or even in the editor). Please see this link about it:
https://issuetracker.unity3d.com/issues/sprite-dot-overridephysicsshape-raises-an-error-when-using-it-in-editor-mode
The previous answer is correct that this is a list of Vector2[] arrays, but the coordinates of the Vector2 points must all be between [0,0] and [1,1] because the coordinates are parametric to the bounds of the Sprite.
Here is some code that should work. It doesn't throw an error now (in v2020.3.1), but it also doesn't seem to do anything.
public class SpritePhysicsShapeTest : MonoBehaviour {
public Sprite sprite;
// Start is called before the first frame update
void Start() {
List<Vector2[]> pts = new List<Vector2[]>();
pts.Add( new Vector2[] {
new Vector2( 0, 0 ),
new Vector2( 0.5f, 0 ),
new Vector2( 0.5f, 0.5f ),
new Vector2( 0, 0.5f )
} );
sprite.OverridePhysicsShape(pts);
}
}
If you're trying to programmatically affect collision on a Unity Tilemap, my current solution is to have one Tilemap for visuals (with 256 possible Sprites) and a second invisible Tilemap that handles collisions (with only 16 possible Sprites). This seems to work well, though I did have to manually draw those 16 Sprites' collisions in the Sprite Editor.

Unity Physics.OverlapBox just doesn't work

So there is a problem that whenever I use Physics.OverlapBox to check how many objects in that area exist it always output 0.
Here is my stripped down code:
void Update () {
a();
}
void a()
{
Collider[] c = Physics.OverlapBox(new Vector3(10, 10,10), new Vector3(-10, -10, -10));
Debug.Log(c.Length);
}
My scene setup:
A simple cube placed at position(0,0,0) with scale of (1,1,1)
An empty object where I attach this script
As you can see, my OverlapBox bounds are much bigger than my cube, so it should find my cube, right? Well, no. The output I get from the console is 0.
One more thing: if I set the scale of that cube to something higher than 40 in all axis, the script finally detects my cube and outputs 1.
How do I get this working so the script would find my cube with default scale?
I had this same issue. I was using TransformVector to calculate the size of my box:
Vector3 size = itemTransform.TransformVector(itemCollider.size / 2);
Collider[] results = Physics.OverlapBox(itemTransform.position, size);
The results weren't consistent. I realised that TransformVector was returning negative values for the size so I simply had to Mathf.Abs the Vector:
Vector3 size = itemTransform.TransformVector(itemCollider.size / 2);
size.x = Mathf.Abs(size.x);
size.y = Mathf.Abs(size.y);
size.z = Mathf.Abs(size.z);
Collider[] results = Physics.OverlapBox(itemTransform.position, size);
According to the documentation, you are setting the size of the overlapping box to -20, -20, -20, which is not quite logic. It could explain why you have to set the scale of your cube to something bigger than 40, 40, 40.
Also, Physics-related operations should be processed in the FixedUpdate function instead of the Update one

Categories