struct Light
{
Light()
{
ZeroMemory(this, sizeof(Light));
}
D3DXVECTOR3 pos;
float pad1; // not used
D3DXVECTOR3 dir;
float pad2; // not used
D3DXCOLOR ambient;
D3DXCOLOR diffuse;
D3DXCOLOR specular;
D3DXVECTOR3 att;
float spotPow;
float range;
};
The issue with the “pad” variables is to make the C++ structure match the HLSL structure. In the HLSL, structure padding occurs so that elements are packed into 4D vectors, with the restriction that a single element cannot be split across two 4D vectors. Consider the following example:
struct S
{
float3 pos;
float3 dir;
};
If we have to pack the data into 4D vectors, you might think it is done like this:
vector 1: (pos.x, pos.y, pos.z, dir.x)
vector 2: (dir.y, dir.z, empty, empty)
However, this splits the element dir across two 4D vectors, which is not allowed — an element is not allowed to straddle a 4D vector boundary. Therefore, it has to be packed like this:
vector 1: (pos.x, pos.y, pos.z, empty)
vector 2: (dir.x, dir.y, dir.z, empty)
Thus, the “pad” variables in our C++ structure are able to correspond to those empty slots in the padded HLSL structure (since C++ does not follow the same packing rules as HLSL).
个人感觉with the restriction that a single element cannot be split across two 4D vectors这段的描述是不对的,至少是有歧义。经过几次测试,加之请教了一个大牛,基本确定的是:HLSL的结构体struct其实并不管你是一个变量还是几个变量,它就是按照一次放满一个float4的内存长度,多少变量都往一个float4里面塞,塞满了再接着塞下一个float4。
所以就要小心面对float3,float2这样的变量,因为前面有变量的关系已经不能再塞到一个float4里面了,那么就要小心。要放几个填充变量,使得float2,float3能够在新的一个float4里面重新开始放置。比如下面的例子:
struct S
{
float3 pos;
float3 normal;
}
应该写为
struct S
{
float3 pos;
float pad1;
float3 normal;
float pad2;
}
一个师兄介绍最好采用下面的方式:
struct S
{
Float4 pos;
Float4 normal;
}
当然如果不想packing也可以,比如下面:
vector a: (pos.x, pos.y, pos.z, dir.x)
vector b: (dir.y, dir.z, empty, empty)存放的话,在hlsl你得float3 aa=a.xyz;float3 bb=float3(a.w,b.x,b.y)
另外如果不想packing。根据大牛的介绍:hlsl编译的时候开了优化选项和不开packing也不一样,就是可以让hlsl不packing,比如在d3d9里面得用Id3DXEffect::setRawValue传递进去,这个偶自己就没有测试过,很少使用Effect框架。