<p>First of all, I am completely new to this so please excuse me if this is a dumb question.</p>
<p>I am following the book Real-Time 3D Rendering with DirectX and HLSL, for now implementing shaders in Nvidia FX Composer.</p>
<p>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).</p>
<p><a href="https://i.sstatic.net/Kd4Ai.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/Kd4Ai.png" alt="BlinnPhong left, Phong right" /></a></p>
<p>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.</p>
<p><a href="https://i.sstatic.net/lkHQE.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/lkHQE.png" alt="BP - the reflection keeps the shape, P - the reflection is spread out." /></a></p>
<p>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.</p>
<p>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.</p>
<pre><code>/////////////////////////////// PHONG SHADER ///////////////////////////////
cbuffer CBufPerFrame
{
    float3 LightDirection : DIRECTION
    &lt;
        string Object = &quot;DirectionalLight0&quot;;
        string UIName = &quot;lightDirection&quot;;
        string Space = &quot;World&quot;;
    &gt; = {0.0, 0.0, -1.0};
    
    float3 CameraPosition : CAMERAPOSITION
    &lt;&gt;;
}

cbuffer CBufPerObj
{
    float4x4 WVP : WORLDVIEWPROJECTION
    &lt;&gt;;
    
    float4x4 World : WORLD
    &lt;&gt;;
    
    float4 SpecularColor : SPECULAR
    &lt;
        string UIName = &quot;Specular Color&quot;;
        string UIWidget = &quot;Color&quot;;
    &gt; = {1.0, 1.0, 1.0, 1.0};
    
    float SpecularPower : SPECULARPOWER
    &lt;
        string UIName = &quot;Specular Power&quot;;
        string UIWidget = &quot;slider&quot;;
        float UIMin = 1.0;
        float UIMax = 255.0;
        float UIStep = 1.0;
    &gt; = {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 &gt; 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 &gt; 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;
}
</code></pre>

CC BY-SA 4.0
2023-05-23T09:26:50.183Z
Apparently this is the correct behavior, according to this youtube clip:

https://youtu.be/VrF43BT4Yyc?t=877
egil87
CC BY-SA 4.0
2023-05-27T06:50:16.737Z
are you sure you haven't labeled them incorrectly, since P is working like BP here.
gallickgunner
<shader><lighting><hlsl><reflection><pixel-shader>
BlinnPhong sphere edges look worse than Phong. Am I doing it wrong? (code and pictures included)
egil87
# BlinnPhong sphere edges look worse than Phong. Am I doing it wrong? (code and pictures included)

(Asked by: username_0 on 2023-05-22)

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](https://i.sstatic.net/Kd4Ai.png)](https://i.sstatic.net/Kd4Ai.png)

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.](https://i.sstatic.net/lkHQE.png)](https://i.sstatic.net/lkHQE.png)

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;
}

```

**Tags:** shader, lighting, hlsl, reflection, pixel-shader

> **Comments:**
> **username_0**: Apparently this is the correct behavior, according to this youtube clip:  https://youtu.be/VrF43BT4Yyc?t=877  
> **username_1**: are you sure you haven't labeled them incorrectly, since P is working like BP here.  

---

## 0 answers

