1
$\begingroup$

First of all, I am completely new to this so please excuse me if this is a dumb question.

I am following the book Real-Time 3D Rendering with DirectX and HLSL, for now implementing shaders in Nvidia FX Composer.

I have created a Phong-shader (P in the pictures) and a BlinnPhong-shader (BP), and both seem to work mostly correct. (The power-term in the specular calculation in the BP-shader is 2x that of the P-shader, as per recommendation).

BlinnPhong left, Phong right

There is a difference, and that is evident when viewing the reflection from an wider angle, where the reflection is spread around the edge of the sphere. This becomes clear in image 2. You can see that the reflection is being spread around the edge in the phong shader, but the reflection mostly keeps its shape in the BP-shader. I think the P-shader looks better, at least in the case of the sphere.

BP - the reflection keeps the shape, P - the reflection is spread out.

Is this correct behavior, or am I doing something wrong? My theory is that it has something to do with the normals, but I'm not quite sure how.

I have supplied the source code here (nvidia fx composer). The only difference is in the pixel shaders, so I have only included the pixel shader from the BP-shader code.

/////////////////////////////// PHONG SHADER ///////////////////////////////
cbuffer CBufPerFrame
{
    float3 LightDirection : DIRECTION
    <
        string Object = "DirectionalLight0";
        string UIName = "lightDirection";
        string Space = "World";
    > = {0.0, 0.0, -1.0};
    
    float3 CameraPosition : CAMERAPOSITION
    <>;
}

cbuffer CBufPerObj
{
    float4x4 WVP : WORLDVIEWPROJECTION
    <>;
    
    float4x4 World : WORLD
    <>;
    
    float4 SpecularColor : SPECULAR
    <
        string UIName = "Specular Color";
        string UIWidget = "Color";
    > = {1.0, 1.0, 1.0, 1.0};
    
    float SpecularPower : SPECULARPOWER
    <
        string UIName = "Specular Power";
        string UIWidget = "slider";
        float UIMin = 1.0;
        float UIMax = 255.0;
        float UIStep = 1.0;
    > = {25.0};
}

RasterizerState RasterOpt
{
    CullMode = NONE;
};

struct VS_INPUT
{
    float4 ObjPos : POSITION;
    float3 Normal : NORMAL;
};

struct VS_OUTPUT
{
    float4 Pos : SV_Position;
    float3 Normal : NORMAL;
    float3 LightDir : LIGHTDIR;
    float3 ViewDir : VIEWDIR;
};

VS_OUTPUT vertex_shader(VS_INPUT In)
{
    VS_OUTPUT Out = (VS_OUTPUT)0;
    
    Out.Pos = mul(In.ObjPos, WVP);
    Out.Normal = normalize(mul(float4(In.Normal,0), World).xyz);
    Out.LightDir = normalize(-LightDirection);
    
    float3 worldPos = mul(In.ObjPos, World).xyz;
    Out.ViewDir = normalize(CameraPosition - worldPos);
    
    return Out;
}

float4 pixel_shader(VS_OUTPUT In) : SV_Target
{
    float4 Out = (float4)0;
    
    float3 normal = In.Normal;
    float3 lightDir = In.LightDir;
    float3 viewDir = In.ViewDir;
    
    float n_dot_l = dot(lightDir, normal);
    
    float4 texColor = float4(0.0, 0.0, 0.0, 1.0);
        
    float3 specular = (float3)0;
    
    if (n_dot_l > 0)
    {
        float3 reflectionVec = normalize(2 * n_dot_l * normal - lightDir);      
        specular = SpecularColor.rgb * SpecularColor.a * min(pow(saturate(dot(reflectionVec, viewDir)), SpecularPower), texColor.a);
    }
    
    Out.rgb = specular;
    Out.a = 1.0f;
    
    return Out;
}

technique10 phongSpec
{
    pass p0
    {
        SetVertexShader(CompileShader(vs_4_0, vertex_shader()));
        SetGeometryShader(NULL);
        SetPixelShader(CompileShader(ps_4_0, pixel_shader()));
        SetRasterizerState(RasterOpt);
    }
}

//////////////////////////////////////////////////////////////////
////////////////BLINN PHONG PIXEL SHADER//////////////////////////
//////////////////////////////////////////////////////////////////

float4 pixel_shader(VS_OUTPUT In) : SV_Target
{
    float4 Out = (float4)0;
    
    float3 normal = normalize(In.Normal);
    float3 lightDir = normalize(In.LightDir);
    float3 viewDir = normalize(In.ViewDir);
    
    float n_dot_l = dot(lightDir, normal);
    
    float4 texColor = float4(0.0, 0.0, 0.0, 1.0);
        
    float3 specular = (float3)0;
    
    if (n_dot_l > 0)
    {
        float3 halfVec = normalize(lightDir + viewDir);
        specular = SpecularColor.rgb * SpecularColor.a * min(pow(saturate(dot(normal, halfVec)), SpecularPower), texColor.a);
    }
    
    Out.rgb = specular;
    Out.a = 1.0f;
    
    return Out;
}
$\endgroup$
2
  • $\begingroup$ Apparently this is the correct behavior, according to this youtube clip: youtu.be/VrF43BT4Yyc?t=877 $\endgroup$
    – egil87
    May 23, 2023 at 9:26
  • 1
    $\begingroup$ are you sure you haven't labeled them incorrectly, since P is working like BP here. $\endgroup$ May 27, 2023 at 6:50

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.