现在的位置: 首页 > 综合 > 正文

记录下Directx11中几个易错点_C++和HLSL的变量绑定

2019年04月15日 ⁄ 综合 ⁄ 共 3086字 ⁄ 字号 评论关闭

    最近遇到几个Directx11的bug,有些最后弄懂了,有些没有,记录下避免下次再犯错。

    一个bug是在Directx11推荐用的数学库xnamath,里面的XMCOLOR居然无法和HLSL里面的float4绑定,如果你要用颜色的变量和HLSL的float4绑定,必须得用XMFLOAT4,或者Directx10的数学库里面的D3DXCOLOR都可以。(D3DXVECTOR4没测试过,可能也可以)。

 

    一个bug很弱智,如果不用Effect框架,那么在Vertex shader里面VSSetConstantBuffers绑定了一个constant buffer等,在Pixel shader如果用到,必须用PSSetConstantBuffers再绑定一次。

 

   最后一个是我虽然糊里糊涂debug出来,但却依然最不明白。是C++和HLSL的类里面的变量排列问题。

   如果想在Directx和HLSL里面定义一个同样的结构体

   在HLSL里面:

struct Light
{
 float3 pos;
 float3 dir;
 float4 ambient;
 float4 diffuse;
 float4 spec;
 float3 att;
 float  spotPower;
 float  range;
};

 

在Directx里面你就必须注意float pad1,和floatpad2.

__declspec(align(16)) struct Light
{
 XMFLOAT3 pos;

float pad1;
 XMFLOAT3 dir;

float pad2;
 XMFLOAT4 ambient;
 XMFLOAT4 diffuse;
 XMFLOAT4 spec;
 XMFLOAT3 att;//表示点光源或聚光灯源的距离影响的因子:a0+a1*d+a2*d*d的三个系数a0,a1,a2。
 FLOAT spotPower;//表示在聚光灯源中,偏离的角度对光照的影响因子:max((-LightDir*dir),0)^spotPower
 FLOAT range;//表示光照的范围距离
};

    为什么会有float pad1,float pad2恩?《Intro to d3d10》里面如下解释:

  The preceding effect file has a constant buffer with a
Light
instance. We would like to be able to set this value with one function call. Therefore, in the C++ code we define a structure very similar to the HLSLLight structure:

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).

    但我不明白的是按照它的说法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,这么说我不用float pad1,和float pad2也可以啊。毕竟D3DXVECTOR3 pos和D3DXVECTOR3
dir也会被分在两个4D vector里。但是经试验是不行的,如果没有float pad1,float pad2。变量的绑定就会莫名其妙。

   估计依然是C++和HLSL里面变量绑定的问题。在HLSL定义一个constant buffer,在C++定义一个相应的如下:

  下面这样子是ok是:

  C++:

__declspec(align(16)) struct PerFrameCBuffer
{
 INT gLightType;//光的类型
 XMFLOAT3 gEyePosW;//眼睛在世界坐标系的位置
 Light gLight;//光的结构及变量
};

 

  HLSL:

cbuffer cbPerFrame:register(b0)
{
 int gLightType;//光的类型
 float3 gEyePosW;//眼睛在世界坐标系的位置
 Light gLight;//光的结构及变量
}

   但是把几个变量的顺序换下就不ok了,比如把int gLightType这个变量放到结构体最后面,那么在HLSL中就识别不了了。

下面这样子是不ok是:

C++:

__declspec(align(16)) struct PerFrameCBuffer
{

Light gLight;//光的结构及变量

XMFLOAT3 gEyePosW;//眼睛在世界坐标系的位置

INT gLightType;//光的类型

};

HLSL:

cbuffer cbPerFrame:register(b0)
{

Light gLight;//光的结构及变量

float3 gEyePosW;//眼睛在世界坐标系的位置

int gLightType;//光的类型
}

   换个这样样子后,在HLSL里面就识别不了gLightType这个变量了,但是gLight还是可以识别。(gEyePosW无法确定)

   所以说在用Directx和HLSL里面变量绑定的时候要非常小心啊。

 

 

 

抱歉!评论已关闭.