I have the following code for my HLSL pixel shader. Modified from another post here on GameDev (Link), but I have a few problems with it:

// calculate UV and get texture and normal.
float2 UV = Input.position.xy / Input.ScreenSize.xy;
float4 DiffuseColor = ColorTexture.Sample( SampleType, UV );
float4 NormalColor = NormalTexture.Sample( SampleType, UV );
float4 normal = 2.0f * NormalColor - 1.0f;

// calculate distance.
float3 LightDir = LightPos - Input.position.xyz;
float distance = 1 - length( LightDir ) / LightRadius;

// calculate dot of normal and light direction.
float NdL = max( 0, dot( normal.xyz, LightDir ) );

// get final color.
float4 finalColor = ( DiffuseColor * ambientIntensity ) + DiffuseColor * distance * LightIntensity * LightColor * NdL;

return float4( finalColor.rgb, DiffuseColor.a );

ambientIntensity and LightIntensity are currently 1.0f to simplify things. LightRadius depends on the size of the geometry, but is in pixels. ~80 for testing. DiffuseColor is a texture resulting from applying self-illumination and darkening the base image. NormalColor is the normal map for the image.

This shader needs to run for every light on the screen, which isn't that many.

For my tests I use the images from the blog post here. It's a little old, but it is pretty much what I need to do, which I can't.

Now; I did enough testing to know that all input and cbuffer parameters are valid but the results I get are not what I hoped for.

Here are my problems:

  • Problem 1: My knowledge of math is limited and I don't understand exactly what the dot product does, why it is needed in the light calculation or why the distance is calculated as it is. Is there a resource online that would explain lighting in term of HLSL or at least in a way meant for a programmer and not using big equations meant for a mathematician? If I don't understand the basics, I'm afraid I wont be able to improve and I'll be stuck every time I need to add new features (ie: shadows), but I need to get this things running asap.

  • Problem 2: The results I have are not good. When I move the light around, I can actually see where the geometry cuts off, and it is as if the light does not trail off properly near the edges of the geometry. Are the calculations wrong?

  • Problem 3: I built a 2D shape editor that I use to design the shape of the lighting geometry, but I don't know how to edit the shaders or the geometry's UV to have the custom shapes (fans, circles, etc) shaded properly. The light I render is always shaded as if it was a circle.

I spent the last two weeks working on this and whenever I search on Google, I keep getting pages I have already visited, so I'm quite lost right now. Any suggestions would be highly appreciated.

My game is a tile-based 2D game, thought I would mention that.

  • 1
    \$\begingroup\$ The dot product is equals the cosinus, if and only if the to vectors are normalized (have the length 1). The shading model, you are using, uses the cosinus between normal and lightDir as approximation of the effect that a surface receives more light when facing the light. I don't know, if your normal is normalized, but your lightDir is not. That leads to wrong results \$\endgroup\$
    – Tobias B
    Jan 22 '16 at 9:42
  • \$\begingroup\$ I'm using sample textures from the Full Bore game blog, and I suspect they are normalized, because if I normalize() them, there is zero changes in any pixels. \$\endgroup\$ Jan 23 '16 at 21:38

First Question: The dot product basically tells you how much two vectors are pointing in the same direction. So if a light points directly against the normal of a surface the surface will be brighter than if it points at it in an angled way or away from it.
If you are struggling with getting this to work, I would advise very heavily against trying to implement shadows because that is orders of magnitude more complicated.

Second: In deferred shading you are drawing the lights into a light map. The Light shader takes the information it needs to figure out how each pixel is lit out of the GBuffer and then draws it. So you probably want to use additive blending for them, which you may or may not already do. Your code doesn't show it.
The crucial bit of information here is, that you are drawing the light as a thing and that thing has dimensions. Your light is probably drawn as a quad so it has geometry. None of the pixels outside of that quad will be affected by your light. So you are probably drawing a quad that is too small for the area your light should be affecting.

Third: If you want to shape your light you will have to UV map the quad you are drawing as the light so that the shader can know where in the shape you are.
You can then either map a texture mask to it to shape the light or do some math to make the fade out dependent on the distance from the shapes edge or something.

As a last addition I would recommend that you read up on what deferred shading does and why it is used. You seem to lack some understanding of the rendering pipeline, so reading up on that would probably be a good idea.

Hope you get your rendering subsystem working.

  • \$\begingroup\$ I went and read up more on deferred shading as you suggested and I've managed to get a grasp of what the shader actually does. If I want to have my UV mapped shapes properly shaded, I would have to use a modified shader, right? \$\endgroup\$ Jan 23 '16 at 21:23
  • 1
    \$\begingroup\$ Yes and you need to change the vertex data that you pass into it slightly as well. \$\endgroup\$ Jan 24 '16 at 1:12
  • \$\begingroup\$ I will look into custom geometry when the time comes. I can now render over 200 lights before the frame rate dips, and that's without batching. \$\endgroup\$ Jan 24 '16 at 7:54
  • \$\begingroup\$ Should I be concerned about the instruction slots my shaders use? My most complex is around 23 right now. \$\endgroup\$ Jan 24 '16 at 7:55

Your Answer

