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\$
    – Ocelot
    Jan 8 '20 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\$ Jan 9 '20 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\$ Jan 9 '20 at 1:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.