HLSL中的镜面反射

3 c++ directx graphics hlsl directx-11

我试图了解HLSL和DirectX11中的镜面反射

cbuffer ConstantBuffer : register( b0 )
{
    matrix World;           // ??????? ????
    matrix View;            // ??????? ????
    matrix Projection;      // ??????? ????????
    float4 vLightDir[3];    // Dir of light
    float4 vLightColor[3];  // color of light
    float4 vOutputColor;    // Active color
    //float3 Eye;
}

struct VS_INPUT                 // ???????? ?????? ?????????? ???????
{
    float4 Pos : POSITION;      // ??????? ?? X, Y, Z
    float3 Norm : NORMAL;       // ??????? ?? X, Y, Z
};

struct PS_INPUT                 // ???????? ?????? ??????????? ???????
{
    float4 Pos : SV_POSITION;   // ??????? ??????? ? ???????? (????????)
    float3 Norm : TEXCOORD0;    // ????????????? ??????? ??????? ?? tu, tv
};


PS_INPUT VS( VS_INPUT input )
{
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = mul( input.Pos, World );
    output.Pos = mul( output.Pos, View );
    output.Pos = mul( output.Pos, Projection );
    output.Norm = mul( input.Norm, World );

    return output;
}


float4 Diffuse( PS_INPUT input) : SV_Target
{
    float4 diffuse = float4(1.0, 1.0, 1.0, 1.0);
    float4 finalColor = diffuse *0.1;

    // Adding all light colours
    for(int i=0; i<3; i++)
    {
        finalColor += saturate( dot( (float3)vLightDir[i], input.Norm) * vLightColor[i] );
    }
    finalColor.a = 1;
    return finalColor;
}

float4 Specular(PS_INPUT input) : SV_Target
{   
    float4 diffuse = float4(1.0, 0.0, 0.0, 1.0);
    float4 finalColor = diffuse *0.1;
    float3 Eye = float3(0.0f, 4.0f, -20.0f);
    float4 intensity = 0.1;
    float power = 4;

    float3 R = reflect(-normalize(Eye), input.Norm);
    for (int i = 0; i < 3; i++)
    {
        finalColor += saturate(intensity * vLightColor[i] * pow(dot(R, Eye), power));
    }   
    return finalColor;
}


float4 PSSolid( PS_INPUT input) : SV_Target
{
    return vOutputColor;
}
Run Code Online (Sandbox Code Playgroud)

现在我只有漫反射,镜面反射只显示白色立方体.:(我在哪里可以得到关于镜面反射的例子或导师?

meg*_*dan 6

你想要实现的是Phong反射模型,它通过计算法向量和光方向向量之间的反射向量来产生镜面反射高光.然后使用点积来计算反射矢量和从表面到眼睛位置的矢量之间的角度的余弦.

Specular着色器存在一些问题.

首先,你的Eye矢量不正确.它需要是从表面到眼睛位置的矢量.目前,您只使用一个职位.要做到这一点,你需要修改你的顶点着色器输出世界空间中的位置的顶点位置.为此,请添加:

float3 WorldPos : TEXCOORD1;
Run Code Online (Sandbox Code Playgroud)

到你的PS_INPUT.现在计算顶点着色器中的世界空间顶点位置:

output.WorldPos = mul( input.Pos, World );
Run Code Online (Sandbox Code Playgroud)

该值将被发送到像素着色器并在像素上插值,以便它给出像素的世界位置.使用此功能,您可以计算像素着色器中像素到眼睛位置的视图矢量V. 要做到这一点:

float3 V = normalize( Eye - input.WorldPos );
Run Code Online (Sandbox Code Playgroud)

现在,反射矢量R是通过反射表面法线(不是眼睛位置)周围的入射光方向而创建的,并且必须针对循环中的每个光线计算:

float3 R = reflect( normalize( vLightDir[i] ), normalize( input.Norm ) );
Run Code Online (Sandbox Code Playgroud)

请注意,在此等式中,光矢量指向光线到表面(因此不要如下所述否定它).

现在,您已准备好使用RV之间的点积计算每个灯光创建的镜面反射分量:

finalColor += intensity * vLightColor[i] * pow( saturate( dot( R, V ) ), power );
Run Code Online (Sandbox Code Playgroud)

我看到的最后一个问题是你没有在Specular着色器中正确计算漫反射.Diffuse如果您希望不面向光线的区域更暗,则需要像着色器一样进行.但是,不是vLightDir[i]直接使用,而是需要否定它,使其从表面指向光:

float3 L = -normalize( vLightDir[i].xyz );
Run Code Online (Sandbox Code Playgroud)

Phong反射模型更便宜的方法称为Blinn-Phong反射模型.而不是使用R,它使用这个简单的等式计算VL之间的半矢量:

float3 H = normalize( L + V );
Run Code Online (Sandbox Code Playgroud)

现在,不要dot( R, V )在计算高光时使用,而是使用:

dot( N, H );
Run Code Online (Sandbox Code Playgroud)