forum.boolean.name

forum.boolean.name (http://forum.boolean.name/index.php)
-   Общие вопросы (http://forum.boolean.name/forumdisplay.php?f=166)
-   -   C# Быстрый поворот/перемещение множества объектов (http://forum.boolean.name/showthread.php?t=14047)

Evgen 12.01.2011 22:14

Быстрый поворот/перемещение множества объектов
 
Здраствуйте! Язык C#. В Unity новичок, до этого использовал Blitz3D.
Есть массив клонированных объектов, пусть будет 5000 кубов:

Код:

cube = new GameObject[5000];
Обновляю его в Update()

Код:

float tdt=Time.deltaTime;
for(int i=0;i<cube.Length;i++){
        cube[i].transform.Translate(transform.forward * tdt*5);
        cube[i].transform.Rotate(Vector3.up*tdt*Random.Range(-50, 50));
}

Если не обновлять положение кубов счетчик показывает 100 FPS,
А если обновлять то ~18 FPS. Уж очень большая разница.
Неужели расчет занимает так много времени?
Может нужно как-то по другому их перемещать/вращать?

pax 12.01.2011 23:27

Ответ: C# Быстрый поворот/перемещение множества объектов
 
надо получить transform каждого кубика отдельно и самого объекта отдельно в начале работы скрипта (например в Start) а потом работать с ними. Получение transform через свойство скрипта - медленно

Evgen 13.01.2011 00:22

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Вот так?

Код:

GameObject[] cube;
Transform[] cubet;
       
void Start()
{
  cube = new GameObject[5000];
  ...
  cubet = new Transform[5000];
  for(int i=0;i<cube.Length;i++){
      ... 
      cubet[i]=cube[i].transform;
  }       
}


void Update()
{
    float tdt=Time.deltaTime;
    for(int i=0;i<cube.Length;i++){
        cubet[i].Translate(transform.forward * tdt*5);
        cubet[i].Rotate(Vector3.up*tdt*Random.Range(-50, 50));
    }
}

Сделал, но прирост всего 3-5 FPS, это ничтожно мало :(
Может при перемещении кубика, автоматический рассчитываются коллизии или еще чего, поэтому так тормозит?!
Может как-то еще можно?

Вот тут
http://unity3d.com/support/documenta...imization.html
Пишут про Vector3 массивы, говорят очень быстрые,как их использовать вместе с GameObject? Будет ли прирост?

pax 13.01.2011 00:48

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Вот так:
Код:

GameObject[] cube;
Transform[] cubet;
Transform thisTransform;       
void Start()
{
  cube = new GameObject[5000];
  ...
  cubet = new Transform[5000];
  thisTransform = transform;
  for(int i=0;i<cube.Length;i++){
      ... 
      cubet[i]=cube[i].transform;
  }       
}


void Update()
{
    Vector3 translation= thisTransform.forward * tdt*5;
    float tdt=Time.deltaTime;
    for(int i=0;i<cube.Length;i++){
        cubet[i].Translate(translation);
        cubet[i].Rotate(Vector3.up*tdt*Random.Range(-50, 50));
    }
}

Если у тебя Pro версия Unity, то посмотри в профайлер, какая операция больше времени жрет. Update или отрисовка.

pax 13.01.2011 01:04

Ответ: C# Быстрый поворот/перемещение множества объектов
 
А если кубики с коллайдерами, то конечно надо поставить их в режим IsTrigger хотя бы. А если с RigidBody, то в режим IsKinematic.

Evgen 13.01.2011 01:18

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Нет не Pro а бесплатная.
Все дела в двух строчках:

Код:

cubet[i].Translate(tra);
cubet[i].Rotate(0,tdt*Random.Range(-50, 50),0);

Стоит их закомментировать, как FPS возрастает до 200. А пять вызовов опускают производительность до 100 FPS

Полный исходник:

Код:

using UnityEngine;
using System.Collections;

public class NScript : MonoBehaviour {

        public string HelloWorldString;
        GameObject[] cube;
        Transform[] cubet;
        Transform thisTransform;
        public GameObject myPrefab;
        int calls;
    void Start()
    {
                HelloWorldString="Текст из Unity3D!";
                thisTransform = transform;
               
                cube = new GameObject[5000];
                myPrefab=GameObject.CreatePrimitive(PrimitiveType.Cube);
                myPrefab.transform.localScale = new Vector3(10,10,10);
                cubet = new Transform[5000];
        for(int i=0;i<cube.Length;i++){
                        cube[i] = (GameObject)Instantiate(myPrefab);
                        cube[i].transform.position = new Vector3(Random.Range(0, 1024),Random.Range(400, 600),Random.Range(0, 11024));
                        cubet[i]=cube[i].transform;
                }       

    }


    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Escape))Application.Quit();
                calls++;
                float tdt=Time.deltaTime;
                Vector3 tra= thisTransform.forward * tdt*5;               
                for(int i=0;i<cube.Length;i++){
                        cubet[i].Translate(tra);
                        cubet[i].Rotate(0,tdt*Random.Range(-50, 50),0);
                }
    }
       

       
}


pax 13.01.2011 01:38

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Вот тебе две строчки, каждую можешь попробовать после создания префаба:
PHP код:

myPrefab.GetComponent<BoxCollider>().isTrigger true;
DestroyImmediate(myPrefab.GetComponent<BoxCollider>()); 

Результаты с первой:


Результаты со второй строчкой:


Если несколько по иному рассчитывать поворот, то немного можно прибавить кадров:
PHP код:

void Update()
    {
        if (
Input.GetKeyDown(KeyCode.Escape)) Application.Quit();
        
calls++;
        
float tdt Time.deltaTime;
        
Vector3 tra thisTransform.forward tdt 5;
        
Vector3 up Vector3.up;
        for (
int i 0cube.Lengthi++)
        {
            
cubet[i].Translate(tra);
            
cubet[i].rotation *= Quaternion.AngleAxis(tdt Random.Range(-5050), up);
            
//cubet[i].Rotate(0, tdt * Random.Range(-50, 50), 0);
        
}
    } 


pax 13.01.2011 03:44

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Вот еще способ добиться лучшего результата:
PHP код:

private float lastDelta 0;
    private 
bool secondFrame false;

    
void Update()
    {
        
secondFrame = !secondFrame;
        
float newDelta Time.deltaTime;
        if (
Input.GetKeyDown(KeyCode.Escape)) Application.Quit();

        
calls++;
        
float tdt lastDelta newDelta;

        
Vector3 tra thisTransform.forward tdt 5;
        
Vector3 up Vector3.up;
        if (
secondFrame)
        {
            for (
int i 0cube.Length/2i++)
            {
                
cubet[i].Translate(tra);
                
cubet[i].rotation *= Quaternion.AngleAxis(tdt*Random.Range(-5050), up);
             }
        }
        else
        {
            for (
int i cube.Length 2cube.Lengthi++)
            {
                
cubet[i].Translate(tra);
                
cubet[i].rotation *= Quaternion.AngleAxis(tdt Random.Range(-5050), up);
            }
        }
        
lastDelta newDelta;
    } 


Evgen 13.01.2011 10:41

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Код:

DestroyImmediate(myPrefab.GetComponent<BoxCollider>());
Увеличило FPS до 50ти

Код:

myPrefab.GetComponent<BoxCollider>().isTrigger = true;
Хоть true хоть false не влияет.

Наверно для моей системы 50FPS это предел.

.Squid 13.01.2011 11:57

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Когда в блитце такое делал, какой результат был?
Я так подозреваю, что без правильного кода, который время обращения к памяти сводил бы к минимуму, ты вряд ли существенного прироста производительности добьешься.

pax 13.01.2011 13:54

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Цитата:

Сообщение от Evgen (Сообщение 175467)
Наверно для моей системы 50FPS это предел.

Последний вариант не устраивает? У меня показывал 150+ кадров. А результат практически не отличим.

Цитата:

Сообщение от .Squid (Сообщение 175469)
Я так подозреваю, что без правильного кода, который время обращения к памяти сводил бы к минимуму, ты вряд ли существенного прироста производительности добьешься.

Тут есть вариант считать матрицы вручную и вручную выводить кубики на экран. Можно я думаю еще ускорить этот процесс, но это только в Pro версии Unity.

Evgen 13.01.2011 14:35

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Цитата:

Сообщение от pax (Сообщение 175476)
Последний вариант не устраивает? У меня показывал 150+ кадров. А результат практически не отличим.

Тут есть вариант считать матрицы вручную и вручную выводить кубики на экран. Можно я думаю еще ускорить этот процесс, но это только в Pro версии Unity.

Я понял суть вашего последнего варианта. Спасибо :) ! только я сделал немного по другому "более гибко". Ну и конечно ничего на свете лучше Sin,Cos нету =)

Код:

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Escape)) Application.Quit();
        calls++;

                rot=rot+2.5f;//Random.Range(-5, 5);
                float speed=Time.deltaTime*25;
                float deg2rad=rot*0.0174532925f;
                for(int i = 0; i<cube.Length; i++){
                        cubex[i]+=Mathf.Sin(deg2rad)*speed;       
                        cubey[i]+=Mathf.Cos(deg2rad)*speed;       
                }       
               
                int updates=2000;
                int block=(updates*calls)%cube.Length;
                int end=block+updates;
                if(end>cube.Length)end=cube.Length;
                for(int i = block; i<end; i++){
                        cube[i].transform.position = new Vector3(cubex[i],500,cubey[i]);
                        cube[i].transform.rotation = Quaternion.AngleAxis(rot,Vector3.up);
                }                 
    }

Если взять 6000 кубов и за один Update трансформировать 2000 скорость 90FPS.
Отмечу в каждом Update меняются координаты всех 6000 кубов в первом for, но трансформируются (transform.position/rotation) только 2000. За три кадра 6000.

Тему можно еще развить если обновлять только объекты находящиеся близко к камере или находящиеся в поле зрения камеры. Предполагаю, что первое должно быть проще, а по скорости скорее всего будет небольшая разница.

pax 13.01.2011 14:40

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Ну Вам виднее. Только у вас будет неравномерное перемещение, т.к. 2 обновления по 2000 а одно 1000. Следовательно deltaTime для следующей первой группы в 2000 будет меньше в 2 раза.

PHP код:

float deg2rad=rot*0.0174532925f

это можно так:
PHP код:

float deg2rad=rot*Mathf.Deg2Rad

а еще можно
PHP код:

int end=block+updates;
if(
end>cube.Length)end=cube.Length

заменить на
PHP код:

int endMathf.Clamp(block+updates,0,cube.Length); 


Evgen 13.01.2011 14:53

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Цитата:

Сообщение от .Squid (Сообщение 175469)
Когда в блитце такое делал, какой результат был?
Я так подозреваю, что без правильного кода, который время обращения к памяти сводил бы к минимуму, ты вряд ли существенного прироста производительности добьешься.

Точно не помню но на Blitz около 5000 кубов где-то 40-50FPS и выдавало. Ну Unity то по мощнее будет чем Blitz.

Evgen 13.01.2011 15:01

Ответ: C# Быстрый поворот/перемещение множества объектов
 
Цитата:

Сообщение от pax (Сообщение 175481)
можно так:
PHP код:

float deg2rad=rot*Mathf.Deg2Rad

PHP код:

int endMathf.Clamp(block+updates,0,cube.Length); 


Да можно. Только у меня уже привычка (оставшаяся от Java) обращаться к классам типа Mathf.бла-бла-бла только в случае крайней необходимости. Скорость выражения типа Mathf. практический не уменьшают, но когда дело касается 5-10тыс. объектов могут отнять десяток FPS. Если я не прав поправьте.


Часовой пояс GMT +4, время: 16:02.

vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot