float __fastcall ulsqrt(float x) {
return x * ulrsqrt(x);
}
3 Нормализация векторов. Обычно делают неправильно, но сначала код:
//Обычно делают так:
void normaliseNormalise(Vector *v)
{
float L, L_squared, one_over_L;
L_squared = (v->x * v->x) + (v->y * v->y) + (v->z * v->z);
L = sqrt(L_squared);
one_over_L = 1.0 / L;
v->x = v->x * one_over_L;
v->y = v->y * one_over_L;
v->z = v->z * one_over_L;
}
// А можно так:
#define ONE_AS_INTEGER ((DWORD)(0x3F800000))
float __fastcall InvSqrt(const float & x)
{
DWORD tmp = ((ONE_AS_INTEGER << 1) + ONE_AS_INTEGER - *(DWORD*)&x) >> 1;
float y = *(float*)&tmp
return y * (1.47f - 0.47f * x * y * y);
}
void Normalise(Vector *v)
{
float L_squared, one_over_L;
L_squared = (v->x * v->x) + (v->y * v->y) + (v->z * v->z);
one_over_L = InvSqrt(L_squared);
v->x = v->x * one_over_L;
v->y = v->y * one_over_L;
v->z = v->z * one_over_L;
}
По-моему комментарии излишни :).
4 Разворачивание циклов
Обычно циклы разворачиваются. Наша цель максимально эффективно использовать кэш процессора, поэтому слишком глубокого разворачивания не нужно, достаточно повторений в цикле.
Для этого используем макросы, но оставляем возможность переключится на функции и не развернутые циклы для отладки (Отладка развернутых циклов сложна и неинформативна).
Опасайтесь разбухания кода!
Измеряйте производительность кода постоянно, причем желательно вести базу данных, в которой будут указываться не только изменения в коде, но и изменения в производительности. Особенно такие базы полезны при работе с несколькими программистами графического ядра приложения.
Благодатная тема для описания, существует огромное количество способов сделать неправильно и один способ сделать правильно (Это заявление не относится к операционной системе Windows, для нее правильнее другое: Существует огромное количество способов сделать правильно, но они устарели и их лучше не использовать, а самый лучший способ — это как раз тот, в который мы недавно добавили большое количество NOP'ов и он работает как раз так, чтобы чуть-чуть тормозить на средней системе :)).
DirectX 8 и, в частности, Direct3D8 - это безусловно самая лучшая разработка Корпорации (ведь мы уже смело можем ТАК ее называть).
Итак, следуйте следующим указаниям:
1. Не используйте "тяжелые" функции в цикле рендеринга. Всегда функции
ValidateDevice, CreateVB, CreateIB, DestroyVB, Optimize, Clone, CreateStateBlock, AssembleVertexShader
помещайте в загрузку сцены и НИКОГДА в цикл рендеринга приложения. Создание буфера вершин может занять до 100 ms!
2. Использование DrawPrimitiveUP является ошибкой, вызывает задержки в работе процессора и всегда вызывает дополнительное копирование вершин.
3. Не позволяйте художникам контролировать ваш код. Если вам необходимо рисовать по 200+ вершин за проход, то геометрия должна удовлетворять этому требованию. Позволите себе рисовать по 2 вершины за вызов — и вы ТРУП :(.
4. Сортируйте по текстурам и по шейдерам. Если сложно сортировать по обоим параметрам, используйте кэширование. Создаем большую текстуру 4K×4K, в нее копируем текстуры, используемые в сцене, подправляем текстурные координаты геометрии и рисуем большой кусок с одной текстурой сортированный по шейдерам. Либо готовим геометрию таким образом, чтобы это кэширование не требовалось.
5. Стараемся использовать как можно меньшее количество буферов вершин. Смена буфера очень "тяжелая" операция и дорого нам стоит. Поэтому
6. Загружаем модели в сцене в минимальное количество буферов.
7. Используем минимальное количество разновидностей FVF, если возможно — то один общий FVF (Максимального размера).
8. Доступ к буферу асинхронный, поэтому мы можем одновременно рисовать модель из одной части буфера и изменять значения в другой.
9. Всегда считайте данные в видеокарте, как доступные только для записи.
10. Если вам необходимо восстанавливать состояние буфера, храните две копии.
11. Если вы обновляете данные в буфере каждый фрейм, используйте динамические буферы вершин.
12. Старайтесь вместо динамического буфера использовать статический буфер, анимированный шейдером.
13. Разделяйте буфер на потоки, если вам необходимо обновлять только часть информации, и.