0
\$\begingroup\$

My point lights seem to have problems when the camera is far away… is it the depth map? Anyway i'll show you the code

Here is my GBUffer fx :

float4x4 World;
float4x4 View;
float4x4 Projection;
float specularIntensity = 0.8f;
float specularPower = 0.5f;

texture Texture;
sampler diffuseSampler = sampler_state
{
Texture = (Texture);
MAGFILTER = LINEAR;
MINFILTER = LINEAR;
MIPFILTER = LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};

struct VertexShaderInput
{
float4 Position : POSITION0;
float3 Normal : NORMAL0;
float2 TexCoord : TEXCOORD0;
};

struct VertexShaderOutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
float3 Normal : TEXCOORD1;
float2 Depth : TEXCOORD2;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;

float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);

output.TexCoord = input.TexCoord;                            //pass the texture coordinates further
float4 worldNormal = float4(mul(input.Normal, (float3x3)World), 1);
output.Normal = worldNormal;
output.Depth.xy = output.Position.zw;

return output;
}

struct PixelShaderOutput
{
half4 Color : COLOR0;
half4 Normal : COLOR1;
half4 Depth : COlOR2;
};


PixelShaderOutput PixelShaderFunction(VertexShaderOutput input)
{
PixelShaderOutput output;
output.Color = tex2D(diffuseSampler, input.TexCoord);            //output Color
output.Color.a = specularIntensity;                                              //output SpecularIntensity                                           //output SpecularPower
output.Normal.rgb = 0.5f * (normalize(input.Normal) + 1.0f);// normalize(mul(input.Normal, (float3x3)World));
output.Normal.a = specularPower;
float exp = (input.Depth.x / input.Depth.y);
/*float exp2 =  
    log(128 * input.Depth.x + 1) /
    (log(128 * 1000 + 1) * input.Depth.y);
output.Depth = exp2 * 10;*/
output.Depth = exp;
return output;
}

technique Technique1
{
pass Pass1
{
    VertexShader = compile vs_2_0 VertexShaderFunction();
    PixelShader = compile ps_2_0 PixelShaderFunction();
}
}

Here is my PointLight fx

float4x4 World;
float4x4 View;
float4x4 Projection;

//color of the light 
float3 Color; 

//position of the camera, for specular light
float3 cameraPosition; 

//this is used to compute the world-position
float4x4 InvertViewProjection; 

//this is the position of the light
float3 lightPosition;

//how far does this light reach
float lightRadius;

//control the brightness of the light
float lightIntensity = 1.0f;

// diffuse color, and specularIntensity in the alpha channel
texture colorMap; 
// normals, and specularPower in the alpha channel
texture normalMap;
//depth
texture depthMap;

sampler colorSampler = sampler_state
{
Texture = (colorMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = LINEAR;
MinFilter = LINEAR;
Mipfilter = LINEAR;
};
sampler depthSampler = sampler_state
{
Texture = (depthMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = POINT;
MinFilter = POINT;
Mipfilter = POINT;
};
sampler normalSampler = sampler_state
{
Texture = (normalMap);
AddressU = CLAMP;
AddressV = CLAMP;
MagFilter = POINT;
MinFilter = POINT;
Mipfilter = POINT;
};


struct VertexShaderInput
{
float3 Position : POSITION0;
};

struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 ScreenPosition : TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
//processing geometry coordinates
float4 worldPosition = mul(float4(input.Position,1), World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.ScreenPosition = output.Position;
return output;
}

float2 halfPixel;
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
//obtain screen position
input.ScreenPosition.xy /= input.ScreenPosition.w;

//obtain textureCoordinates corresponding to the current pixel
//the screen coordinates are in [-1,1]*[1,-1]
//the texture coordinates need to be in [0,1]*[0,1]
float2 texCoord = 0.5f *(float2(input.ScreenPosition.x,-input.ScreenPosition.y) + 1);
//allign texels to pixels
texCoord -=halfPixel;

//get normal data from the normalMap
float4 normalData = tex2D(normalSampler,texCoord);
//tranform normal back into [-1,1] range
float3 normal = 2.0f * normalData.xyz - 1.0f;
//get specular power
float specularPower = normalData.a * 255;
//get specular intensity from the colorMap
float specularIntensity = tex2D(colorSampler, texCoord).a;

//read depth
float depthVal = tex2D(depthSampler,texCoord).r;

//compute screen-space position
float4 position;
position.xy = input.ScreenPosition.xy;
position.z = depthVal;
position.w = 1.0f;
//transform to world space
position = mul(position, InvertViewProjection);
position /= position.w;

//surface-to-light vector
float3 lightVector = (lightPosition - position);

//compute attenuation based on distance - linear attenuation
float attenuation = saturate(1.0f - max(0, length(lightVector)) / (lightRadius));

//normalize light vector
lightVector = normalize(lightVector); 

//compute diffuse light
float NdL = max(0, dot(normal, lightVector));
float3 diffuseLight = NdL * Color.rgb;

//reflection vector
float3 reflectionVector = normalize(reflect(-lightVector, normal));
//camera-to-surface vector
float3 directionToCamera = normalize(cameraPosition - position);
//compute specular light
float specularLight = specularIntensity * 
    pow(saturate(dot(reflectionVector, -directionToCamera)), specularPower);

//take into account attenuation and lightIntensity.
return attenuation * lightIntensity * float4(diffuseLight.rgb, specularLight);
}

technique Technique1
{
pass Pass1
{
    VertexShader = compile vs_2_0 VertexShaderFunction();
    PixelShader = compile ps_2_0 PixelShaderFunction();
}
}

Here's how i'm setting it up:

colorRT = new RenderTarget2D(
            Device,
            Graphics.PreferredBackBufferWidth,
            Graphics.PreferredBackBufferHeight,
            false,
            SurfaceFormat.Color,
            DepthFormat.Depth24Stencil8);
        normalRT = new RenderTarget2D(
            Device,
            Graphics.PreferredBackBufferWidth,
            Graphics.PreferredBackBufferHeight,
            false,
            SurfaceFormat.Color,
            DepthFormat.Depth24Stencil8);
        depthRT = new RenderTarget2D(
            Device,
            Graphics.PreferredBackBufferWidth,
            Graphics.PreferredBackBufferHeight,
            false,
            SurfaceFormat.Single,
            DepthFormat.Depth24Stencil8);
        lightRT = new RenderTarget2D(
            Device,
            Graphics.PreferredBackBufferWidth,
            Graphics.PreferredBackBufferHeight,
            false,
            SurfaceFormat.Color,
            DepthFormat.Depth24Stencil8);
halfPixel = new Microsoft.Xna.Framework.
                        Vector2(0.5f / (float)Graphics.PreferredBackBufferWidth,
                                0.5f / (float)Graphics.PreferredBackBufferHeight);


    private void DrawPointLight(ICamera camera, PointLight pointLight, Matrix projection)
    {
        //set the G-Buffer parameters
        pointLightEffect.Parameters["colorMap"].
            SetValue(colorRT);
        pointLightEffect.Parameters["normalMap"].
            SetValue(normalRT);
        pointLightEffect.Parameters["depthMap"].
            SetValue(depthRT);
        //compute the light world matrix
        //scale according to light radius, and translate it to light position
        Matrix sphereWorldMatrix = Matrix.CreateScale(pointLight.Radius) *
            Matrix.CreateTranslation(pointLight.GameObject.Transform.Position);
        pointLightEffect.Parameters["World"].
            SetValue(sphereWorldMatrix);
        pointLightEffect.Parameters["View"].
            SetValue(GameWindow.Singleton.Effect.View);
        pointLightEffect.Parameters["Projection"].
            SetValue(projection);
        //light position
        pointLightEffect.Parameters["lightPosition"].
            SetValue(pointLight.GameObject.Transform.Position);
        //set the color, radius and Intensity
        pointLightEffect.Parameters["Color"].
            SetValue(
                new Vector3(
                    pointLight.Color.R, 
                    pointLight.Color.G, 
                    pointLight.Color.B));
        pointLightEffect.Parameters["lightRadius"].
            SetValue(pointLight.Radius / 2);
        pointLightEffect.Parameters["lightIntensity"].
            SetValue(pointLight.Intensity);
        //parameters for specular computations
        pointLightEffect.Parameters["cameraPosition"].
            SetValue(camera.Transform.Position);
        pointLightEffect.Parameters["InvertViewProjection"].
             SetValue(
                Matrix.Invert(
                    GameWindow.Singleton.Effect.View *
                    GameWindow.Singleton.Effect.Projection));
        //size of a halfpixel, for texture coordinates alignment
        pointLightEffect.Parameters["halfPixel"].
            SetValue(halfPixel);

        //calculate the distance between the camera and light center
        float cameraToCenter = 
            Vector3.Distance(
                camera.Transform.Position, 
                pointLight.GameObject.Transform.Position);
        //if we are inside the light volume, draw the sphere's inside face
        if (cameraToCenter < pointLight.Radius)
            Device.RasterizerState =
                RasterizerState.CullClockwise;
        else
            Device.RasterizerState =
                RasterizerState.CullCounterClockwise;

        pointLightEffect.Techniques[0].Passes[0].Apply();
        foreach (ModelMesh mesh in sphereModel.Meshes)
        {
            foreach (ModelMeshPart meshPart in mesh.MeshParts)
            {
                Device.SetVertexBuffer(meshPart.VertexBuffer);
                Device.Indices = meshPart.IndexBuffer;
                Device.DrawIndexedPrimitives(
                    PrimitiveType.TriangleList,
                    meshPart.VertexOffset,
                    meshPart.StartIndex,
                    meshPart.PrimitiveCount);
            }
        }

        Device.RasterizerState =
                RasterizerState.CullCounterClockwise;
    }

This is how it looks when the camera is near :

enter image description here

This is how it looks when the camera is far away :

enter image description here

in the seconds image The light gets "spotty" as the camera gos furhter away from it.

How can I solve this? Is there an error in my code?

\$\endgroup\$
3
  • \$\begingroup\$ Seems to be yet another depth precision problem. Look it up. \$\endgroup\$ Commented Jan 8, 2020 at 18:15
  • \$\begingroup\$ Thank you for the comment…. I've looked it up and i'm now using these formaulas depth_value = log(C * z + 1) / log(C * Far + 1) ---------------------------------------------------------- z = (exp(depth_value * log(C * far+1)) - 1) / C But are they correct? \$\endgroup\$ Commented Jan 9, 2020 at 1:08
  • \$\begingroup\$ if I use C = 1 I have the same behaviour…. If I use c= 128. the z gets wrong values \$\endgroup\$ Commented Jan 9, 2020 at 1:16

0

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.