Порядок хранения элементов матриц для вершинных шейдеров
Автор: Andrey
У многих начинающих разработчиков бывают ошибки при рендеринге, когда либо на экране ничего нет, либо всё выглядит совсем неверно. Это может быть связано с тем, что матрицы трансформации в шейдер попадают с неверным порядком хранения столбцов и строк в памяти.
К примеру, если в проекте используются матрицы из D3DX библиотеки, то для использования в ID3DXEffect/ID3D10Effect/ID3D11Effect достаточно написать такой порядок умножения в шейдере:
float4 pos = mul(in.position, worldViewProj);
где D3DXMATRIX worldViewProj = world * view * projection;
Аналогично, такой подход будет работать для Cg.
В случае использования IDirect3DVertexShader9/ID3D10VertexShader/ID3D11VertexShader, нужно транспонировать матрицы перед отправкой в шейдер, либо поменять порядок умножения в коде:
D3DXMATRIX worldViewProj = projection * view * world;
или в шейдере:
float4 pos = mul(worldViewProj, in.position);
Либо использовать в функциях D3DXCompileShader* (Direct3D9) флаг компиляции D3DXSHADER_PACKMATRIX_ROWMAJOR,
для функций D3DX10CompileFrom*/D3DX11CompileFrom* (Direct3D10/Direct3D11) флаг компияции D3DCOMPILE_PACK_MATRIX_ROW_MAJOR.
Следует учесть, что порядок умножения влияет на набор инструкций в шейдере и производительность. В результате будет либо 4 инструкции dp4 идущее подряд, либо mad/mul
В первом случае перемножение будет выполняться быстрее.
При написании своих классов для работы с матрицами следует учесть эти особенности.
25 июня 2012 (Обновление: 6 авг 2012)