Author Topic: clipped panel optimization  (Read 9607 times)

gtoxast

  • Guest
clipped panel optimization
« on: January 21, 2013, 10:05:11 AM »
Hello.

I have that list of over hundred items, which i need to scroll through. I am using clipped panel for it.
But in the scene during the drag, i see that it renders meshes of all items. Even the ones out of clipped view.
I think this is what causes significant performance loss.

Any advice on optimizing the situation?
Thanks.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: clipped panel optimization
« Reply #1 on: January 21, 2013, 11:30:28 AM »
The performance loss of bounds-checking of every single widget and filling the buffer based on that information is much greater than drawing everything while the object is being dragged. Either way, the number of drawn triangles is not that large.

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: clipped panel optimization
« Reply #2 on: January 21, 2013, 01:17:10 PM »
I would think making a "smart" list, where you could remove elements in a list that were outside the clipping would be better.

Maybe you could setup a constant size of "chunks" that should be enabled/disabled at any one time, so for instance 3-4 chunks with each a certain number of your list entries were inside were active at any one time.

It would require some hacking of the way NGUI works with scroll panels now, but I think it could work.

gtoxast

  • Guest
Re: clipped panel optimization
« Reply #3 on: January 22, 2013, 01:40:11 AM »
ArenMook,
Bounds -checking sure are faster than actual drawing, but if every scroll item contain 5 widgets within, it lags a lot. Especially on mobile platforms.

Nicki, thanks for advice, i ll try that.

I appreciate your replies guys =)

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: clipped panel optimization
« Reply #4 on: January 22, 2013, 11:17:24 AM »
If you do make a good solution to it, gtoxast, I'm sure there's a lot of people here that would love an optimization like that. I sure would. :)

gtoxast

  • Guest
Re: clipped panel optimization
« Reply #5 on: January 23, 2013, 01:02:06 AM »
Yes, i've done it,  have no more lags, even on mobiles.
I''ll post the source code later after some cleaning =)

Nicki

  • Global Moderator
  • Hero Member
  • *****
  • Thank You
  • -Given: 33
  • -Receive: 141
  • Posts: 1,768
    • View Profile
Re: clipped panel optimization
« Reply #6 on: January 23, 2013, 03:33:32 AM »

PoN

  • Full Member
  • ***
  • Thank You
  • -Given: 1
  • -Receive: 4
  • Posts: 111
    • View Profile
Re: clipped panel optimization
« Reply #7 on: January 23, 2013, 06:56:51 AM »
+1
Worked on Doc&DogAge Of Fury 3D. Actually working on WarMach.

gtoxast

  • Guest
Re: clipped panel optimization
« Reply #8 on: January 23, 2013, 08:31:42 AM »
Ok, try this.
1) Place this script on your clipping scroll object (having UIPanel and UIDraggablePanel attached)
2) Make prefab with UIGrid, assign to m_pGridPrefab field (just for UIGrid settings)
3) Assign your scroll item prefab to m_pItemPrefab
4) Ready To Go

U can call Show method for showing items from beginning.
Or Show with item index to focus on that item.

U also can play around with m_iGridDestroyRange and m_iGridItemsCount. I am sure u can figure it out =)
But be carefull - do not assign to iGridCreateTreshold large values. (more than hlalf of clipping view)

Supports both horizontal and vertical scrolls. (takes UIPanel scale field for identification)

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4.  
  5. /// <summary>
  6. /// Grids list.
  7. /// This script, having m_pItemPrefab and m_pGridPrefab attached
  8. /// allows to manage the scroll dynamically (via multiple grid components)
  9. /// </summary>
  10. [System.Serializable]
  11. public class ScrollGridsView : MonoBehaviour
  12. {
  13.         /// <summary>
  14.         /// Data about Grid
  15.         /// Only its gameObject for now
  16.         /// </summary>
  17.         [System.Serializable]
  18.         private class GridData
  19.         {
  20.                 public UIGrid grid;
  21.                 public Vector3 m_vPosition
  22.                 {
  23.                         get {return grid.gameObject.transform.localPosition;}
  24.                         set {grid.gameObject.transform.localPosition = value;}
  25.                 }
  26.         }
  27.        
  28.         //item prefab to be created in the grid
  29.         public GameObject m_pItemPrefab;
  30.         //prefab of the UIGrid, that will contain m_pItemPrefab-s in quantity of m_iGridItemsCount
  31.         public GameObject m_pGridPrefab;
  32.         //items quantity inside the each grid
  33.         public int m_iGridItemsCount = 12;
  34.        
  35.         //existing grid index and its data
  36.         private Dictionary<int, GridData> _grids = new Dictionary<int, GridData>();
  37.        
  38.         //how close grid border to the view the next grid should be created
  39.         //the larger the TRESHOLD, the earlier the grid will be created
  40.         public int m_iGridCreateTreshold = 100;
  41.        
  42.         //When new grid is created, the grids, standing by distance of _gridDestroyRange will be destroyed
  43.         public int m_iGridDestroyRange = 2;  
  44.        
  45.         //Todo: generic
  46.         protected int _itemsCount;
  47.        
  48.         //view position parameters
  49.         private Vector3 _startingPosition;
  50.         private float _clipRange;
  51.         private UIGrid _grid;
  52.         private UIPanel _panel;
  53.         private Transform _transform;
  54.        
  55.         //how many items in line (considering UIGrid maxPerLine prop.)
  56.         private int _gridItemsLen;
  57.        
  58.         //width of each grid
  59.         private float _gridLen;
  60.        
  61.         //the first created grid,
  62.         //other grids positions will be counted from it
  63.         private bool firstGridExists = false;
  64.         private int _firstGridIndx = 0;
  65.        
  66.         //this is set on Awake
  67.         private bool Horisontal = true;
  68.         private Vector3 _vGridOffest;
  69.        
  70.         /// <summary>
  71.         /// Get UIPanel and UIGrid properties
  72.         /// </summary>
  73.         void Awake()
  74.         {
  75.                 //save transform for optimization
  76.                 _transform = transform;
  77.                
  78.                 //set if list is horisontal
  79.                 UIDraggablePanel dragPanel = gameObject.GetComponent<UIDraggablePanel>();
  80.                 Horisontal = dragPanel.scale.x > 0;
  81.                
  82.                 _panel = gameObject.GetComponent<UIPanel>();
  83.                 _startingPosition = transform.localPosition + new Vector3(_panel.clipRange.x, _panel.clipRange.y, 0f);
  84.                 _clipRange = (Horisontal)? _panel.clipRange.z : _panel.clipRange.w;
  85.                
  86.                 //round up
  87.                 _grid = m_pGridPrefab.GetComponent<UIGrid>();
  88.                 if(_grid.maxPerLine != 0)
  89.                         _gridItemsLen = (m_iGridItemsCount + _grid.maxPerLine - 1)/_grid.maxPerLine;
  90.                 else
  91.                         _gridItemsLen = m_iGridItemsCount;
  92.                 _gridLen = _gridItemsLen * ((Horisontal)? _grid.cellWidth : _grid.cellHeight);
  93.                 _vGridOffest =(Horisontal)? new Vector3(_gridLen, 0, 0) : new Vector3(0, -_gridLen, 0);
  94.         }
  95.        
  96.         /// <summary>
  97.         /// Check if user scrolled to the border of the grid
  98.         /// </summary>
  99.         void LateUpdate ()
  100.         {
  101.                 if (!Application.isPlaying) return;
  102.                
  103.  
  104.                 //delta is panel offset relative to original position.
  105.                 float delta = (Horisontal) ?    //scrolling right-left
  106.                         (_transform.localPosition.x - _startingPosition.x) :
  107.                         -(_transform.localPosition.y - _startingPosition.y);
  108.                
  109.                 //grids will be created later (after foreach)
  110.                 List<int> GridsToCreate = new List<int>();
  111.                
  112.                 foreach(int indx in _grids.Keys)
  113.                 {
  114.                         //left(up) and right(left) edges relative to the view (depending on Horisontal property)
  115.                         float firstPos = delta + (indx - _firstGridIndx)*_gridLen;
  116.                         float secondPos = firstPos  + _gridLen;
  117.                         if(firstPos > -m_iGridCreateTreshold)
  118.                         {
  119.                                 GridsToCreate.Add(indx - 1);
  120.                         }
  121.                         if(secondPos < m_iGridCreateTreshold  + _clipRange)
  122.                         {
  123.                                 GridsToCreate.Add(indx + 1);
  124.                         }
  125.                 }
  126.                
  127.                 foreach(int indx in GridsToCreate)
  128.                 {
  129.                         CreateGrid(indx);
  130.                 }
  131.         }
  132.        
  133.         /// <summary>
  134.         /// Creates the grid
  135.         /// Destroyes distant grids
  136.         /// </summary>
  137.         private void CreateGrid(int indx)
  138.         {
  139.                 if(indx >= 0 && !_grids.ContainsKey(indx))
  140.                 {
  141.                         GridData newGridData = CreateGridGameObject(indx);
  142.                         if(newGridData == null) return;
  143.                        
  144.                         //add new grid
  145.                         _grids.Add(indx, newGridData);
  146.                        
  147.                        
  148.                         //one of the adjasent grids should exist and have the position
  149.                         if(_grids.ContainsKey(indx-1))
  150.                                 newGridData.m_vPosition = _grids[indx-1].m_vPosition + _vGridOffest;
  151.                         else
  152.                                 newGridData.m_vPosition = _grids[indx+1].m_vPosition - _vGridOffest;
  153.                        
  154.                         //destroy distant grids
  155.                         DestroyGrid(indx - m_iGridDestroyRange);
  156.                         DestroyGrid(indx + m_iGridDestroyRange);
  157.                 }
  158.         }
  159.        
  160.         /// <summary>
  161.         /// Destroies the grid.
  162.         /// </summary>
  163.         private void DestroyGrid(int indx)
  164.         {
  165.                 if(_grids.ContainsKey(indx))
  166.                 {
  167.                         _grids[indx].grid.gameObject.SetActiveRecursively(false);
  168.                         Destroy(_grids[indx].grid.gameObject);
  169.                         _grids.Remove(indx);
  170.                 }
  171.         }
  172.        
  173.         /// <summary>
  174.         /// Shows the first grid of items
  175.         /// </summary>
  176.         public void Show(int itemsCount)
  177.         {
  178.                 _itemsCount = itemsCount;
  179.                
  180.                 GridData newGrid = CreateGridGameObject(0);
  181.                
  182.                 if(newGrid != null)
  183.                         _grids.Add(0, newGrid);
  184.         }
  185.        
  186.         /// <summary>
  187.         /// Shows the grid of items, that contains item from the data with passed index
  188.         /// </summary>
  189.         public void Show(int itemsCount, int indexToFocusOn)
  190.         {
  191.                 int indx = indexToFocusOn / m_iGridItemsCount;
  192.                 _itemsCount = itemsCount;
  193.                
  194.                 GridData newGrid = CreateGridGameObject(indx);
  195.                
  196.                 if(newGrid != null)
  197.                         _grids.Add(indx, newGrid);
  198.         }
  199.        
  200.         /// <summary>
  201.         /// Creates the grid with index.
  202.         /// </summary>
  203.         /// <returns>
  204.         /// GridData or null if no items left to show
  205.         /// </returns>
  206.         private GridData CreateGridGameObject(int gridIndx)
  207.         {
  208.                 //get the items range
  209.                 int startIndx = gridIndx * m_iGridItemsCount;
  210.                 int lastIndx = startIndx + m_iGridItemsCount;
  211.                 int min = (_itemsCount < lastIndx) ? _itemsCount : lastIndx;
  212.                
  213.                 //no items for the grid
  214.                 if(startIndx >= min) return null;
  215.                        
  216.                 GameObject nextGridObj = UIToolsInstantiate(m_pGridPrefab, this.gameObject);
  217.             nextGridObj.name = "Grid " + gridIndx.ToString();
  218.                 UIGrid nextGrid = nextGridObj.GetComponent<UIGrid>();
  219.                
  220.                 for(int i = startIndx; i < min; i++)
  221.                 {
  222.                         UIToolsInstantiate(m_pItemPrefab, nextGridObj);
  223.                 }
  224.  
  225.                 GridData gridData = new GridData
  226.                 {
  227.                         grid = nextGrid,
  228.                 };
  229.                
  230.                 //position items on the grid
  231.                 nextGrid.Reposition();
  232.                
  233.                 //get indx if it is the first created grid
  234.                 if(!firstGridExists)
  235.                 {
  236.                         firstGridExists = true;
  237.                         _firstGridIndx = gridIndx;
  238.                 }
  239.                
  240.                 return gridData;
  241.         }
  242.        
  243.        
  244.         static public GameObject UIToolsInstantiate(GameObject prefab, GameObject parent)
  245.     {
  246.         if(prefab != null)
  247.         {
  248.             var obj = UnityEngine.Object.Instantiate(prefab) as GameObject;
  249.             if(obj != null)
  250.             {
  251.                 if(parent != null)
  252.                 {
  253.                     obj.transform.parent = parent.transform;
  254.                 }
  255.                 obj.transform.localPosition = prefab.transform.position;
  256.                                 obj.transform.localScale = Vector3.one;
  257.                 return obj;
  258.             }
  259.         }
  260.         return null;
  261.     }
  262. }
  263.  
  264.  
« Last Edit: January 24, 2013, 02:00:38 AM by gtoxast »