I’m having a lot of trouble getting my per-pixel spotlight shader to work right. I’ve attached the code as well as a video demonstrating the problem. The little floating guy in the video represents the position and orientation of the light. As you can see, the problem is that the circle on the ground from the light is the wrong shape, and actually changes shape when I rotate the camera even though the light is never moved. This only happens when I rotate the camera, not when I simply translate it. I’ve verified that the normals of the ground’s vertices are all [0,1,0] as they should be. The relevant values for the light are:
Ya, I was pretty sure the half vector calculation was wrong, but that just affects the specular highlight and the floor material doesn’t have a specular component anyways, so it doesn’t visually affect the problem I’m having at all. Still, what is the correct way to calculate the half vector?
I think the usual way to calculate the half vector is to normalize the sum of the light direction and the view direction. Both the light direction and view direction should be normalized vectors. Neither depends on the object being rendered, so the half vector can be computed once per frame per light.
When I have a problem I can’t figure out, I try to simplify it as much as possible, until the problem is isolated and becomes apparent. Your code is not trivial; you could simplify it in a way intended to isolate where the problem is occurring. For example, you could replace all the code within the nested “if” statement in the fragment shader, with something really simple such as “fragmentColor *= 1.5;”. By doing that, and observing whether the problem continues or goes away, will let you know where you need to focus your attention. By conducting a number of such tests, you should be able to pretty quickly isolate exactly where the problem occurs.
I did some tests in the fragment shader like you suggested (replacing nested if contents, etc) and the problem still persists. It looks like the problem must be with the vertex shader or with something I’m feeding the vertex shader…
I’m glad you mentioned that because I was passing lightDirection to the fragment shader in world space instead of view space which I have since corrected. My spotlight is still moving around when I move the camera though
The only issue I’m having now is that the lit area isn’t perfectly round when the spotlight is pointed directly at a flat plane. It’s slightly oval shaped…any suggestions on where to look for the cause of that problem?
So I can describe the problem a little better now. The scene I’m using for testing is a large plane centered at the origin consisting of two triangles. When I position the spotlight directly above the center of the plane, the lit area is a perfect circle as expected. If I move the light away from the center of the plane, but still pointing directly down at it, the lit area correctly moves with it, but distorts into an oval. The oval appears to be what the lit area would look like if I had left the light over the origin and tilted it instead of translating it. Does that description make sense?
Yes, that description makes sense. My guess is that it is now an entirely different problem: perspective projection distortion. If you change the field of view to a narrower angle and the distortion goes down, then that is your problem. So, can you reduce your field of view (and compensate by moving the camera position further away, to maintain the same relative sizes of your scene)?
Thanks for helping, but that doesn’t appear to be the problem. The shape of the lit area isn’t affected by changing the camera’s FOV. Here are a couple screenshots. The plane is 1000x1000 centered at the origin. The light is positioned at (0,700,-800) and is oriented to point straight down at the plane (I have verified both of these things in the debugger). As you can see, not only is the lit area elongated, but it’s rotated slightly as well even though the only rotation applied to the light is a single 90 degree rotation to point it straight down.
I’ve run in the exact same problem and found this solution :
You shouldn’t normalize the lightDir vector (the one going from the light to the vertex) in the vertex shader.
I think the explanation is that the lightDir is supposed to be vertPos-lightPos. Now, the fragment will interpolate this direction from the vertices around the fragment. By normalizing before this interpolation, a vertex very far away will have the same “weight” as a close vertex and I guess that is the cause of the problem.