• Advertisement
Sign in to follow this  

Per-Pixel Point Light

This topic is 1648 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have been having some troubles to get point light to work, I looked into some code samples, but always getting a problem when trying to implement point light.

 

Can someone show me how do I modify my shader to implement point light? 

matrix World;
matrix View;
matrix Projection;

// Point light variables
float4 lightPosition;
float lightRange;
float4 lightDiffuse;
float4 lightAmbient;
float4 lightSpecular;

// Texture
texture colorMapTexture;

sampler2D colorMap = sampler_state
{
    Texture = <colorMapTexture>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

struct PS_INPUT
{
   float4 Pos : SV_POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
};

struct VS_INPUT 
{
   float4 Pos : SV_POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
};

struct VS_OUTPUT 
{
   float4 Pos : SV_POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
};

//-----------------------------------------------------------------------
// Vertex shader function
//-----------------------------------------------------------------------
VS_OUTPUT VS( VS_INPUT IN )
{
    VS_OUTPUT Out;
    Out = (VS_OUTPUT)0;
    Out.Pos = mul (IN.Pos, World);
    Out.Pos = mul (Out.Pos, View);
    Out.Pos = mul (Out.Pos, Projection);
    Out.UV = IN.UV;
    Out.Normal = mul(IN.Normal, (float3x3)World);
    return Out;
}

//-----------------------------------------------------------------------
// Pixel shader function
//-----------------------------------------------------------------------
float4 PS( PS_INPUT IN ) : COLOR
{
     // *** I need to modify this function for point light ***
     return tex2D(colorMap, IN.UV);
}

//-----------------------------------------------------------------------------
// Techniques.
//-----------------------------------------------------------------------------
technique PointLighting
{
    pass
    {
        AlphaBlendEnable = false;
        ZEnable = true;
        VertexShader = compile vs_3_0 VS();
        PixelShader = compile ps_3_0 PS();
    }
}

 

Edited by Medo3337

Share this post


Link to post
Share on other sites
Advertisement
Okay, I have been trying for a while to do basic lighting in shader and here is what I got so far (Point Light):

[attachment=16818:5948.png]

 

So here I have 2 problems:

1. The point light is weird (as shown in the screenshot)

2. When the mesh move away from the point light it get black

 

Shader code:

float4x4 World;
float4x4 View;
float4x4 Projection;

// Point light
float4 lightPosition;
float4 lightDiffuse;
float4 lightAmbient;
float4 lightSpecular;
float lightRange;

// Material
float4 materialDiffuse;
float4 materialAmbient;
float4 materialSpecular;
float materialPower;

float4 globalAmbient;

// Camera position
float eyePos;

// Texture
texture colorMapTexture;

sampler2D colorMap = sampler_state
{
    Texture = <colorMapTexture>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

struct PS_INPUT
{
   float3 Pos : POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
   float3 worldPos : TEXCOORD2;
};

struct VS_INPUT 
{
   float3 Pos : POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
};

struct VS_OUTPUT 
{
   float4 Pos : POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
   float3 worldPos : TEXCOORD2;
};

//-----------------------------------------------------------------------
// Vertex shader function
//-----------------------------------------------------------------------
VS_OUTPUT VS( VS_INPUT IN )
{
    VS_OUTPUT Out;
    Out = (VS_OUTPUT)0;
    float4x4 WVP = mul(World, mul(View, Projection));
    Out.Pos = mul(float4(IN.Pos, 1.0f), WVP);
    Out.UV = IN.UV;
    Out.Normal = mul(IN.Normal, (float3x3)World);
    Out.worldPos = mul(float4(IN.Pos, 1.0f), World).xyz;
    return Out;
}

//-----------------------------------------------------------------------
// Pixel shader function
//-----------------------------------------------------------------------
float4 PS( PS_INPUT IN ) : COLOR
{
     float3 viewDir = eyePos - IN.worldPos;
     float3 lightDir = (lightPosition - IN.worldPos) / lightRange;


    float atten = saturate(1.0f - dot(lightDir, lightDir));


    float3 n = normalize(tex2D(colorMap, IN.UV).rgb * 2.0f - 1.0f);
    float3 l = normalize(lightDir);
    float3 v = normalize(viewDir);
    float3 h = normalize(l + v);
    
    float nDotL = saturate(dot(n, l));
    float nDotH = saturate(dot(n, h));
    float power = (nDotL == 0.0f) ? 0.0f : pow(nDotH, materialPower);


    float4 FinalDiffuse = materialDiffuse * lightDiffuse;
    float4 FinalSpecular = materialSpecular * lightSpecular;


    float4 color = (materialAmbient * (globalAmbient + (atten * lightAmbient))) +
                   (FinalDiffuse * nDotL * atten) + (FinalSpecular * power * atten);
            
    return color * tex2D(colorMap, IN.UV);
}

//-----------------------------------------------------------------------------
// Techniques.
//-----------------------------------------------------------------------------
technique PointLighting
{
    pass
    {
        AlphaBlendEnable = false;
        ZEnable = true;
        VertexShader = compile vs_3_0 VS();
        PixelShader = compile ps_3_0 PS();
    }
}

 

Share this post


Link to post
Share on other sites

The whiteness looks like your specularity is too high (if materialPower is too big) and the darkness is something you should expect from a point light. The brightness decreases with the square of the distance. So it may be the case that it is just falling off too quickly from lightRange being too small.

 

VS_OUTPUT and PS_INPUT are the same thing--use a typedef or just use one of them to avoid mistakes.

Share this post


Link to post
Share on other sites

@menohack: I notice that the whiteness decrease when I give higher materialPower.

 

However, it still doesn't look like specular light, I see just white pixels on the mesh.

 

How do I avoid the darkness? For example, when there is a fire, there should be a point light, however the point light should not make everything black

 

lightRange is not too small, I notice in a direction the falloff decrease smoothly, while in the other direction it decrease not smoothly (like in the screenshot).

 

So, I guess that there is something wrong with the Shader code.

Share this post


Link to post
Share on other sites

I am confused as you are trying to use diffuse map as normal, WTF?

Do following changes and report back if it works as expected:

//float3 n = normalize(tex2D(colorMap, IN.UV).rgb * 2.0f - 1.0f);
float3 n = normalize(IN.Normal);

Share this post


Link to post
Share on other sites

@belfegor: Okay, the problem is partly resolved, the falloff transition is now smooth.

 

But I have two problems:

1. I don't see the speular light anymore

2. The mesh get black when it's far away from the light, how do I make it never black? the mesh should be AFFECTED by the light but never get black

Share this post


Link to post
Share on other sites

By my logic, this:

float4 color = (materialAmbient * (globalAmbient + (atten * lightAmbient))) + ...

should be like this:

// ambients should be added not multiplied or modified by light attenaution
float4 color = (materialAmbient + globalAmbient) + ...

When you fix this above also set some reasonable values for specular color and "materialPower".

Edited by belfegor

Share this post


Link to post
Share on other sites

@belfegor: When I change the line to:

float4 color = (materialAmbient + globalAmbient) + (FinalDiffuse * nDotL * atten) + (FinalSpecular * power * atten);

I don't see the light anymore.

Edited by Medo3337

Share this post


Link to post
Share on other sites


I don't see the light anymore.

This is not descriptive enough.

Give me all your color values that you are sending to shader.

Share this post


Link to post
Share on other sites

@belfegor:

static D3DXHANDLE hTechnique;
hTechnique = pEffect->GetTechniqueByName("PointLighting");
if (FAILED(pEffect->SetTechnique(hTechnique)))
    return;

pEffect->SetMatrix("World", &world);
pEffect->SetMatrix("View", &view);
pEffect->SetMatrix("Projection", &proj);

// Light
float lightDiffuse[4] = {1.0f, 1.0f, 1.0f, 255.0f};
float lightAmbient[4] = {1.0f, 1.0f, 1.0f, 255.0f};
float lightSpecular[4] = {255.0f, 1.0f, 1.0f, 255.0f};
float lightRange = 100.0f;
pEffect->SetValue("lightDiffuse", &lightDiffuse, sizeof(lightDiffuse));
pEffect->SetValue("lightAmbient", &lightAmbient, sizeof(lightAmbient));
pEffect->SetValue("lightSpecular", &lightSpecular, sizeof(lightSpecular));
pEffect->SetValue("lightRange", &lightRange, sizeof(lightRange));


// Material
float materialDiffuse[4] = {1.0f, 1.0f, 1.0f, 255.0f};
float materialAmbient[4] = {1.0f, 1.0f, 1.0f, 255.0f};
float materialSpecular[4] = {1.0f, 1.0f, 1.0f, 1.0f};
float materialPower = 20;
pEffect->SetValue("materialDiffuse", &materialDiffuse, sizeof(materialDiffuse));
pEffect->SetValue("materialAmbient", &materialAmbient, sizeof(materialAmbient));
pEffect->SetValue("materialSpecular", &materialSpecular, sizeof(materialSpecular));
pEffect->SetValue("materialPower", &materialPower, sizeof(materialPower));

float LightPos[4] = {0.0f, 0.0f, -50.1f, 0.0f};
pEffect->SetValue("lightPosition", &LightPos, sizeof(LightPos));
pEffect->SetValue("eyePos", &camera->GetPosition(), sizeof(camera->GetPosition()));

// Texture
pEffect->SetTexture("colorMapTexture", texture);

UINT passes = 0;
HRESULT hr = pEffect->Begin(&passes, 0);
hr = pEffect->BeginPass(0);

model->Render();

pEffect->EndPass();
pEffect->End();

Here is the current shader code as well:

float4x4 World;
float4x4 View;
float4x4 Projection;


// Point light
float4 lightPosition;
float4 lightDiffuse;
float4 lightAmbient;
float4 lightSpecular;
float lightRange;

// Material
float4 materialDiffuse;
float4 materialAmbient;
float4 materialSpecular;
float materialPower;

float4 globalAmbient;

// Camera position
float eyePos;

// Texture
texture colorMapTexture;

sampler2D colorMap = sampler_state
{
    Texture = <colorMapTexture>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

struct PS_INPUT
{
   float3 Pos : POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
   float3 worldPos : TEXCOORD2;
};

struct VS_INPUT 
{
   float3 Pos : POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
};

struct VS_OUTPUT 
{
   float4 Pos : POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
   float3 worldPos : TEXCOORD2;
};

//-----------------------------------------------------------------------
// Vertex shader function
//-----------------------------------------------------------------------
VS_OUTPUT VS( VS_INPUT IN )
{
    VS_OUTPUT Out;
    Out = (VS_OUTPUT)0;
    float4x4 WVP = mul(World, mul(View, Projection));
    Out.Pos = mul(float4(IN.Pos, 1.0f), WVP);
    Out.UV = IN.UV;
    Out.Normal = mul(IN.Normal, (float3x3)World);
    Out.worldPos = mul(float4(IN.Pos, 1.0f), World).xyz;
    return Out;
}

//-----------------------------------------------------------------------
// Pixel shader function
//-----------------------------------------------------------------------
float4 PS( PS_INPUT IN ) : COLOR
{
     float3 viewDir = eyePos - IN.worldPos;
     float3 lightDir = (lightPosition - IN.worldPos) / lightRange;


    float atten = saturate(1.0f - dot(lightDir, lightDir));


    float3 n = normalize(IN.Normal);
    float3 l = normalize(lightDir);
    float3 v = normalize(viewDir);
    float3 h = normalize(l + v);
    
    float nDotL = saturate(dot(n, l));
    float nDotH = saturate(dot(n, h));
    float power = (nDotL == 0.0f) ? 0.0f : pow(nDotH, materialPower);


    float4 FinalDiffuse = materialDiffuse * lightDiffuse;
    float4 FinalSpecular = materialSpecular * lightSpecular;


    // float4 color = (materialAmbient * (globalAmbient + (atten * lightAmbient))) +
    //               (FinalDiffuse * nDotL * atten) + (FinalSpecular * power * atten);
    
    float4 color = (materialAmbient + globalAmbient) + (FinalDiffuse * nDotL * atten) + (FinalSpecular * power * atten);
    return color * tex2D(colorMap, IN.UV);
}

//-----------------------------------------------------------------------------
// Techniques.
//-----------------------------------------------------------------------------
technique PointLighting
{
    pass
    {
        AlphaBlendEnable = false;
        ZEnable = true;
        VertexShader = compile vs_3_0 VS();
        PixelShader = compile ps_3_0 PS();
    }
}

 

Share this post


Link to post
Share on other sites

Color values should be in 0 - 1 range, ambients should be relatively small, so try this:

// Light
float lightDiffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
//float lightAmbient[4] = {0.0f, 0.0f, 0.0f, 1.0f};
float lightSpecular[4] = {1.0f, 1.0f, 1.0f, 1.0f};
float lightRange = 100.0f;
...

// Material
float materialDiffuse[4] = {1.0f, 1.0f, 1.0f, 1.0f};
float materialAmbient[4] = {0.05f, 0.05f, 0.05f, 1.0f};
float materialSpecular[4] = {1.0f, 1.0f, 1.0f, 1.0f};
float materialPower = 8.0f;
...

 

and you are missing "globalAmbient":

float gAmbient[4] = { 0.15f, 0.15f, 0.15f, 1.0f };
pEffect->SetValue("globalAmbient", &gAmbient, sizeof(gAmbient));

Share this post


Link to post
Share on other sites

It should not be completely black, have you enabled dx debug runtime? Check any dx debug messages in output window!

Repost your cpp code and shader.

Edited by belfegor

Share this post


Link to post
Share on other sites

@belfegor: Nothing really in the output window, the shader is working correctly, but the mesh is black all the time.

 

You might want to the check the shader code...

Edited by Medo3337

Share this post


Link to post
Share on other sites

It can't be pure black, should have at least ambient of 0.2 no matter the view and light angles, unless you have done something wrong in cpp code and then it skips shader.

I ask you again have you enbled dx debug runtime and set proper options in dx control panel?

Repost your cpp and shader!

 

I see you have your camera position in shader as single float set it as float3.

Edited by belfegor

Share this post


Link to post
Share on other sites

@belfegor: Now, the mesh is not black, however I see the texture and it's dark and I don't see any light affecting it when it's very close to the light position.

 

Shader:

float4x4 World;
float4x4 View;
float4x4 Projection;

// Point light
float4 lightPosition;
float4 lightDiffuse;
float4 lightAmbient;
float4 lightSpecular;
float lightRange;

// Material
float4 materialDiffuse;
float4 materialAmbient;
float4 materialSpecular;
float materialPower;

float4 globalAmbient;

// Camera position
float3 eyePos;

// Texture
texture colorMapTexture;

sampler2D colorMap = sampler_state
{
    Texture = <colorMapTexture>;
    MagFilter = Linear;
    MinFilter = Anisotropic;
    MipFilter = Linear;
    MaxAnisotropy = 16;
};

struct PS_INPUT
{
   float3 Pos : POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
   float3 worldPos : TEXCOORD2;
};

struct VS_INPUT 
{
   float3 Pos : POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
};

struct VS_OUTPUT 
{
   float4 Pos : POSITION;
   float2 UV : TEXCOORD0;
   float3 Normal : TEXCOORD1;
   float3 worldPos : TEXCOORD2;
};

//-----------------------------------------------------------------------
// Vertex shader function
//-----------------------------------------------------------------------
VS_OUTPUT VS( VS_INPUT IN )
{
    VS_OUTPUT Out;
    Out = (VS_OUTPUT)0;
    float4x4 WVP = mul(World, mul(View, Projection));
    Out.Pos = mul(float4(IN.Pos, 1.0f), WVP);
    Out.UV = IN.UV;
    Out.Normal = mul(IN.Normal, (float3x3)World);
    Out.worldPos = mul(float4(IN.Pos, 1.0f), World).xyz;
    return Out;
}

//-----------------------------------------------------------------------
// Pixel shader function
//-----------------------------------------------------------------------
float4 PS( PS_INPUT IN ) : COLOR
{
    float3 viewDir = eyePos - IN.worldPos;
    float3 lightDir = (lightPosition - IN.worldPos) / lightRange;

    float atten = saturate(1.0f - dot(lightDir, lightDir));


    float3 n = normalize(IN.Normal);
    float3 l = normalize(lightDir);
    float3 v = normalize(viewDir);
    float3 h = normalize(l + v);
    
    float nDotL = saturate(dot(n, l));
    float nDotH = saturate(dot(n, h));
    float power = (nDotL == 0.0f) ? 0.0f : pow(nDotH, materialPower);

    float4 FinalDiffuse = materialDiffuse * lightDiffuse;
    float4 FinalSpecular = materialSpecular * lightSpecular;

    // float4 color = (materialAmbient * (globalAmbient + (atten * lightAmbient))) +
    //             (FinalDiffuse * nDotL * atten) + (FinalSpecular * power * atten);
    
    float4 color = (materialAmbient + globalAmbient) + (FinalDiffuse * nDotL * atten) + (FinalSpecular * power * atten);
    return color * tex2D(colorMap, IN.UV);
}


//-----------------------------------------------------------------------------
// Techniques.
//-----------------------------------------------------------------------------
technique PointLighting
{
    pass
    {
        AlphaBlendEnable = false;
        ZEnable = true;
        VertexShader = compile vs_3_0 VS();
        PixelShader = compile ps_3_0 PS();
    }
}

 

Share this post


Link to post
Share on other sites

I notice that the global ambient color is the only color that affect the mesh, there is no light at all.

 

The weird thing is that the light works perfectly when I change this line:

float3 n = normalize(IN.Normal);

To the old invalid value:

float3 n = normalize(tex2D(colorMap, IN.UV).rgb * 2.0f - 1.0f);

blink.png

 

What's going on?

Edited by Medo3337

Share this post


Link to post
Share on other sites

Output the normals from the pixel shader as colour. Do they look correct?

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement