Advertisement Jump to content
Sign in to follow this  
Alundra

AreaLight : Rectangle

This topic is 1809 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

Hi all,

I'm working on some area light (forward rendering).

I searched on the net for some documentation and tried with what I found.

Here the actual code :

void Area( in SURFACE_DATA SurfaceData, in AREA_LIGHT Light, inout LIGHTING_RESULTS Result )
{
  float3 ToLightPosition = SurfaceData.Position - Light.Position;
  float DistOnLine = dot( ToLightPosition, Light.Direction );
  float3 PointOnLine = SurfaceData.Position - Light.Direction * DistOnLine;
  float3 FromCenter = PointOnLine - Light.Position;
  float DiagonalX = dot( FromCenter, Light.Right );
  float DiagonalY = dot( FromCenter, Light.Up );
  float NearestX = clamp( DiagonalX, -Light.HalfSize.x, Light.HalfSize.x );
  float NearestY = clamp( DiagonalY, -Light.HalfSize.y, Light.HalfSize.y );
  float3 NearestInside = Light.Position + ( Light.Right*NearestX + Light.Up*NearestY );
  float3 LightDirection = NearestInside - SurfaceData.Position;
  float d = length( LightDirection );
  if( d < Light.EndAttenuation )
  {
    LightDirection /= d;
    float NdotL = max( 0.0f, dot( SurfaceData.Normal, LightDirection ) );
    if( NdotL > 0.0f )
    {
      // Compute the specular factor.
      float SpecFactor = ComputePhongFactor( SurfaceData, LightDirection );
      
      // Compute the attenuation factor.
      float Attenuation = smoothstep( Light.EndAttenuation, Light.StartAttenuation, d );
      
      // Accumulate the light results.
      Result.Diffuse += Light.Intensity * DiffuseColor.rgb * Light.Color * Attenuation;
      Result.Specular += Light.Intensity * SpecularColor.rgb * SpecFactor * Attenuation;
    }
  }
}
I got bad result based on orientation and surely a better way exist for better result.
If someone can explain me what's going wrong and how get better result.
Thanks for the help
 
EDIT : change to if( d < Light.EndAttenuation && DistOnLine > 0.0f ) removes the problem of side but still a prob of rendering.
Edited by Alundra

Share this post


Link to post
Share on other sites
Advertisement

Check that the light sources and models are represented in the same space. Light sources are sometimes represented in camera space.

Output some simple colors to make sure that your constant buffers don't have padding or alignment mismatch between GPU and CPU.

Share this post


Link to post
Share on other sites

I think you need to normalize both the surface normal and the light direction since it looks as if your dot product is returning huge values.

Share this post


Link to post
Share on other sites

LightDirection is already normalized as you can see :

LightDirection /= d;

and the normal has no problem with other lighting type.

The problem looks like an angle who is missing, an idea ?

Share this post


Link to post
Share on other sites

Thanks to have solved this problem !

The actual shader working is now :

void Area( in SURFACE_DATA SurfaceData, in AREA_LIGHT Light, inout LIGHTING_RESULTS Result )
{
  float3 ToLightPosition = SurfaceData.Position - Light.Position;
  float DistOnLine = dot( ToLightPosition, Light.Direction );
  float3 PointOnLine = SurfaceData.Position - Light.Direction * DistOnLine;
  float3 FromCenter = PointOnLine - Light.Position;
  float DiagonalX = dot( FromCenter, Light.Right );
  float DiagonalY = dot( FromCenter, Light.Up );
  float NearestX = clamp( DiagonalX, -Light.HalfSize.x, Light.HalfSize.x );
  float NearestY = clamp( DiagonalY, -Light.HalfSize.y, Light.HalfSize.y );
  float3 NearestInside = Light.Position + ( Light.Right*NearestX + Light.Up*NearestY );
  float3 LightDirection = NearestInside - SurfaceData.Position;
  float d = length( LightDirection );
  if( d < Light.EndAttenuation && DistOnLine > 0.0f )
  {
    LightDirection /= d;
    float NdotL = max( 0.0f, dot( SurfaceData.Normal, LightDirection ) );
    if( NdotL > 0.0f )
    {
      // Compute the specular factor.
      float SpecFactor = ComputePhongFactor( SurfaceData, LightDirection );
      
      // Compute the attenuation factor.
      float Attenuation = smoothstep( Light.EndAttenuation, Light.StartAttenuation, d );
      
      // Accumulate the light results.
      Result.Diffuse += Light.Intensity * DiffuseColor.rgb * Light.Color * NdotL * Attenuation;
      Result.Specular += Light.Intensity * SpecularColor.rgb * SpecFactor * Attenuation;
    }
  }
}

If you have any idea to have better result, it's open on the discussion.

I think the attenuation needs a better physical calcule.

Share this post


Link to post
Share on other sites

 

Thanks to have solved this problem !

The actual shader working is now :

void Area( in SURFACE_DATA SurfaceData, in AREA_LIGHT Light, inout LIGHTING_RESULTS Result )
{
  float3 ToLightPosition = SurfaceData.Position - Light.Position;
  float DistOnLine = dot( ToLightPosition, Light.Direction );
  float3 PointOnLine = SurfaceData.Position - Light.Direction * DistOnLine;
  float3 FromCenter = PointOnLine - Light.Position;
  float DiagonalX = dot( FromCenter, Light.Right );
  float DiagonalY = dot( FromCenter, Light.Up );
  float NearestX = clamp( DiagonalX, -Light.HalfSize.x, Light.HalfSize.x );
  float NearestY = clamp( DiagonalY, -Light.HalfSize.y, Light.HalfSize.y );
  float3 NearestInside = Light.Position + ( Light.Right*NearestX + Light.Up*NearestY );
  float3 LightDirection = NearestInside - SurfaceData.Position;
  float d = length( LightDirection );
  if( d < Light.EndAttenuation && DistOnLine > 0.0f )
  {
    LightDirection /= d;
    float NdotL = max( 0.0f, dot( SurfaceData.Normal, LightDirection ) );
    if( NdotL > 0.0f )
    {
      // Compute the specular factor.
      float SpecFactor = ComputePhongFactor( SurfaceData, LightDirection );
      
      // Compute the attenuation factor.
      float Attenuation = smoothstep( Light.EndAttenuation, Light.StartAttenuation, d );
      
      // Accumulate the light results.
      Result.Diffuse += Light.Intensity * DiffuseColor.rgb * Light.Color * NdotL * Attenuation;
      Result.Specular += Light.Intensity * SpecularColor.rgb * SpecFactor * Attenuation;
    }
  }
}

If you have any idea to have better result, it's open on the discussion.

I think the attenuation needs a better physical calcule.

 

 

I would put the product of (Light.Intensity * (NdotL * Attenuation)) in a new vector.

 

My engine use a quadratic function to approximate division of square distance without giving an infinite size to it's culling bounds.

https://code.google.com/p/david-piuvas-graphics-engine/source/browse/trunk/Engine/Core_ShaderCompiling.h

Edited by Dawoodoz

Share this post


Link to post
Share on other sites
My engine use a quadratic function to approximate division of square distance without giving an infinite size to it's culling bounds.

 

You can have a look at :
You can have a look on this paper page 12-13 :
http://www.unrealengine.com/files/downloads/2013SiggraphPresentationsNotes.pdf
It's the new attenuation in unreal engine 4.

float Factor = clamp(1.0f - pow(d / Light.EndAttenuation, 4.0f), 0.0f, 1.0f);
float Attenuation = (Factor * Factor) / ((d * d) + 1.0f);

Maybe you already tried this function ?

What do you think of it ?

Share this post


Link to post
Share on other sites

 

My engine use a quadratic function to approximate division of square distance without giving an infinite size to it's culling bounds.

 

You can have a look at :
You can have a look on this paper page 12-13 :
http://www.unrealengine.com/files/downloads/2013SiggraphPresentationsNotes.pdf
It's the new attenuation in unreal engine 4.

float Factor = clamp(1.0f - pow(d / Light.EndAttenuation, 4.0f), 0.0f, 1.0f);
float Attenuation = (Factor * Factor) / ((d * d) + 1.0f);

Maybe you already tried this function ?

What do you think of it ?

 

 

Seems a bit expensive for today's hardware.

Share this post


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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!