Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Maximizing performance of
3D user-generated
assets in Unity
Max Pixel
Freeform Labs
DBA since May 2015
Incorporated March 2016
Your Speaker
2003
Games & Websites as a hobby
2008
Freelance
web development
20...
Q: Why is it
freezing?
A: GARBAGE
COLLECTIO
N
The Agenda
Optimization principles
Real examples
???
PROFIT
Hands-on Demonstration!
Starting Point:
http://wiki.unity3d.com/index.php/OptimizedTrailRenderer
https://github.com/M-Pixe...
Encapsulation grumble grumble
public float maxAngle → [SerializeField] private float _maxAngle
Hold down alt for magic Buy...
Start
private void Start()
{
_trailObj = new GameObject("Trail"); // Why have a game object that just controls another one...
Avoid Reflection
if (_pointCnt < 2)
{
_trailObj.GetComponent<Renderer>().enabled = false;
return;
}
_trailObj.GetComponent...
Optimize by actually optimizing, not reducing quality
// Optimization
if (_pointCnt > _optimizeCount)
{
_maxAngle += _opti...
Heap vs Stack
Long-term, Garbage Collected
● Class instances
● Arrays
○ Even tiny ones (ノಥ益ಥ)ノ
Very short-term
● POD
● Str...
Points are being deleted and reallocated at runtime
for (var i = _pointCnt - 1; i >= 0; i--) {
var point = _points[i];
if ...
indices > _pointCnt are ignored anyways
for (var i = _pointCnt - 1; i >= 0; i--) {
var point = _points[i];
if (point == nu...
RAM & Speed
Putting things away and taking
them out again takes a lot of time
Shifting is unnecessarily expensive
Removing old points
for (var i = _pointCnt - 1; i >= 0; i--){
var point = _points[i];
...
using (var e = _ints.GetEnumerator()) {
while (e.MoveNext()) {
_current += e.Current;
}
}
for (var i = 0; i < _ints.Count;...
Temporary Arrays
// Rebuild it
var vertices = new Vector3[pointCount * 2];
var uvs = new Vector2[pointCount * 2];
var tria...
Comparing Distance
var sqrDistance = (
_points[1].Position -
_source.transform.position
).sqrMagnitude;
if (sqrDistance > ...
Comparing Distance
a2 + b2 = c2
a2 + b2 + c2 = d2
d = sqrt ( a2 + b2 + c2 )
Square root is a relatively expensive operatio...
Other Optimizations
Use arrays for vertex, color, uv buffers (triangle buffer must be a List)
Make Point a struct (Pre-all...
What about extra vertices?
It turns out, any number of extra
verts/colors/etc. have negligible impact
Only triangles matte...
The final result...
34 to 60KB garbage + .41ms
vs
0B garbage + .24ms
(per frame)
Takeaways
Use the Unity Profiler’s gcalloc column to find out where heap allocation occurs
First use utilities like Queue,...
Thank you!
max@freeformlabs.xyz
Maximizing performance of 3 d user generated assets in unity
Maximizing performance of 3 d user generated assets in unity
Upcoming SlideShare
Loading in …5
×

0

Share

Download to read offline

Maximizing performance of 3 d user generated assets in unity

Download to read offline

Maximizing performance of 3 d user generated assets in unity

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all
  • Be the first to like this

Maximizing performance of 3 d user generated assets in unity

  1. 1. Maximizing performance of 3D user-generated assets in Unity Max Pixel Freeform Labs
  2. 2. DBA since May 2015 Incorporated March 2016 Your Speaker 2003 Games & Websites as a hobby 2008 Freelance web development 2011 - 2014 - 2015 USC Film Production → Interactive Entertainment Freeform Labs Inception Feb 2014 Funded March 2016
  3. 3. Q: Why is it freezing?
  4. 4. A: GARBAGE COLLECTIO N
  5. 5. The Agenda Optimization principles Real examples ??? PROFIT
  6. 6. Hands-on Demonstration! Starting Point: http://wiki.unity3d.com/index.php/OptimizedTrailRenderer https://github.com/M-Pixel/unity-procedural-mesh-optimization-presentation
  7. 7. Encapsulation grumble grumble public float maxAngle → [SerializeField] private float _maxAngle Hold down alt for magic Buy ReSharper for more magic Full disclosure: I have no affiliation with ReSharper. They don’t give me money. I just really like it.
  8. 8. Start private void Start() { _trailObj = new GameObject("Trail"); // Why have a game object that just controls another one? _trailObj.transform.parent = null; _trailObj.transform.position = Vector3.zero; _trailObj.transform.rotation = Quaternion.identity; _trailObj.transform.localScale = Vector3.one; var meshFilter = (MeshFilter)_trailObj.AddComponent(typeof(MeshFilter)); _mesh = meshFilter.mesh; _trailObj.AddComponent(typeof(MeshRenderer)); _instanceMaterial = new Material(_material); _fadeOutRatio = 1f / _instanceMaterial.GetColor("_TintColor").a; _trailObj.GetComponent<Renderer>().material = _instanceMaterial; } Prefer Observation [SerializeField] private Transform _source; RequireComponent [RequireComponent(typeof(MeshFilter))] [RequireComponent(typeof(MeshRenderer))] public class Trail : MonoBehaviour { Destroy(_trailObj); Destroy(this); // ??? New Start private void Start() { _mesh = GetComponent<MeshFilter>().mesh; _instanceMaterial = new Material(_material); _fadeOutRatio = 1f / _instanceMaterial.GetColor("_TintColor").a; _renderer = GetComponent<MeshRenderer>(); _renderer.material = _instanceMaterial; } (because the mesh origin needs to be stationary, that’s why)
  9. 9. Avoid Reflection if (_pointCnt < 2) { _trailObj.GetComponent<Renderer>().enabled = false; return; } _trailObj.GetComponent<Renderer>().enabled = true; Revised if (_pointCnt < 2) { _renderer.enabled = false; return; } _renderer.enabled = true; Add to Class private MeshRenderer _renderer; In Start _renderer = GetComponent<MeshRenderer>();
  10. 10. Optimize by actually optimizing, not reducing quality // Optimization if (_pointCnt > _optimizeCount) { _maxAngle += _optimizeAngleInterval; _maxVertexDistance += _optimizeDistanceInterval; _optimizeCount += 1; }
  11. 11. Heap vs Stack Long-term, Garbage Collected ● Class instances ● Arrays ○ Even tiny ones (ノಥ益ಥ)ノ Very short-term ● POD ● Structs ○ … sometimes
  12. 12. Points are being deleted and reallocated at runtime for (var i = _pointCnt - 1; i >= 0; i--) { var point = _points[i]; if (point == null || point.TimeAlive > _segmentLifetime) { _points[i] = null; _pointCnt--; } else break; } if (_emit) { if (_pointCnt == 0) { _points[_pointCnt++] = new Point(_source.transform); _points[_pointCnt++] = new Point(_source.transform); } ...
  13. 13. indices > _pointCnt are ignored anyways for (var i = _pointCnt - 1; i >= 0; i--) { var point = _points[i]; if (point == null || point.TimeAlive > _segmentLifetime) { _points[i] = null; _pointCnt--; } else break; } if (_emit) { // Make sure there are always at least 2 points when emitting if (_pointCnt < 2) { if (_pointCnt < 1) InsertPoint(); InsertPoint(); } ...
  14. 14. RAM & Speed Putting things away and taking them out again takes a lot of time
  15. 15. Shifting is unnecessarily expensive Removing old points for (var i = _pointCnt - 1; i >= 0; i--){ var point = _points[i]; if (point.TimeAlive > _segmentLifetime) { _pointCnt--; } else break; } Adding new points for(int i = pointCnt; i > 0; i--) points[i] = points[i-1]; points[0] = new Point(transform); pointCnt++; What about adding new points on top of the array? Just reverses problem What about a Queue? Yes!
  16. 16. using (var e = _ints.GetEnumerator()) { while (e.MoveNext()) { _current += e.Current; } } for (var i = 0; i < _ints.Count; i++) { var item = _ints.Dequeue(); _current += item; _ints.Enqueue(item); } Unity’s Enumerator Problem
  17. 17. Temporary Arrays // Rebuild it var vertices = new Vector3[pointCount * 2]; var uvs = new Vector2[pointCount * 2]; var triangles = new int[(pointCount - 1) * 6]; var meshColors = new Color[pointCount * 2]; 5.3 MB/s
  18. 18. Comparing Distance var sqrDistance = ( _points[1].Position - _source.transform.position ).sqrMagnitude; if (sqrDistance > _minVertexDistance * _minVertexDistance) { … } if (Vector3.Dot(a, b) > _preSquaredBasis) …
  19. 19. Comparing Distance a2 + b2 = c2 a2 + b2 + c2 = d2 d = sqrt ( a2 + b2 + c2 ) Square root is a relatively expensive operation Dot == a2 + b2 + c2 Vector3.Distance == Sqrt ( Dot ( A , B ) ) Comparing dots is faster than comparing distances Double trouble: Unity’s Vector3.Dot uses doubles
  20. 20. Other Optimizations Use arrays for vertex, color, uv buffers (triangle buffer must be a List) Make Point a struct (Pre-allocate) Eliminate (inline) pool Eliminate Points altogether, work directly with vertices?
  21. 21. What about extra vertices? It turns out, any number of extra verts/colors/etc. have negligible impact Only triangles matter! mesh.SetTriangles takes a List
  22. 22. The final result...
  23. 23. 34 to 60KB garbage + .41ms vs 0B garbage + .24ms (per frame)
  24. 24. Takeaways Use the Unity Profiler’s gcalloc column to find out where heap allocation occurs First use utilities like Queue, List to eliminate GC, then once your pattern is confirmed to work and the design is locked down, you can refactor to naked arrays Reuse Arrays, Delegates, G.O.s whenever possible Start/end indexes Pool unused instances Don’t use IEnumerators, find a workaround When comparing distances, use Dot instead of Distance
  25. 25. Thank you! max@freeformlabs.xyz

Maximizing performance of 3 d user generated assets in unity

Views

Total views

792

On Slideshare

0

From embeds

0

Number of embeds

0

Actions

Downloads

9

Shares

0

Comments

0

Likes

0

×