Specular reflection in HLSL
Asked Answered
M

1

5

I'am trying to understand specular reflection in HLSL and 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;
}

Now I have only diffuse reflection, specular is show only white cube. :( Where can I get an example or tutor about specular reflection?

Marsipobranch answered 29/10, 2014 at 19:53 Comment(0)
O
8

What you are trying to achieve is called the Phong Reflection Model which generates specular highlights by computing the reflection vector between the normal vector and the light direction vector. A dot product is then used to calculate the cosine of the angle between the reflection vector and a vector from the surface to the eye position.

There are a few problems with your Specular shader.

First, your Eye vector is incorrect. It needs to be a vector from the surface to the eye location. Currently, you are using just a position. To accomplish this, you will need to modify your vertex shader to output the world space location of the vertex position. To do this add:

float3 WorldPos : TEXCOORD1;

to your PS_INPUT. Now compute the world space vertex position in your vertex shader:

output.WorldPos = mul( input.Pos, World );

This value will be sent to the pixel shader and interpolated across the pixels so that it gives the world position of the pixel. Using this, you can calculate the view vector V from the pixel to the eye position in your pixel shader. To do that use:

float3 V = normalize( Eye - input.WorldPos );

Now, the reflection vector R is created by reflecting the incoming light direction around the surface normal (not the eye position), and it must be computed for every light in your loop:

float3 R = reflect( normalize( vLightDir[i] ), normalize( input.Norm ) );

Note that in this equation the light vector is pointing from the light to the surface (so don't negate it as described below).

Now you are ready to compute the specular component created by each light using the dot product between R and V:

finalColor += intensity * vLightColor[i] * pow( saturate( dot( R, V ) ), power );

The last problem I see is that you are not computing diffuse properly in your Specular shader. You need to do it just like your Diffuse shader if you want areas not facing the light to be darker. However, instead of using vLightDir[i] directly, you need to negate it so that it points from the surface to the light:

float3 L = -normalize( vLightDir[i].xyz );

A cheaper method than the Phong Reflection Model is called the Blinn-Phong Reflection Model. Instead of using R, it calculates the half vector between V and L using this simple equation:

float3 H = normalize( L + V );

Now instead of using dot( R, V ) when calculating specular, you use:

dot( N, H );
Odelle answered 29/10, 2014 at 21:35 Comment(1)
H needs to be normalized.Forequarter

© 2022 - 2024 — McMap. All rights reserved.