0
\$\begingroup\$

I'm hoping someone can help me debug this wacky implementation of a Spotlight done in Java LWJGL that I found online. Basically, I found the bug, but I cannot figure out how to fix it so that the math makes sense.

The bug is that the code takes an angle and converts it radians and takes the cosine TWICE before passing it to an Open GL fragment shader. The value that the shader gets for the spotlight's cutoff angle is like 0.99991065.

The first part of the bug appears in this class on lines 93-94: https://github.com/lwjglgamedev/lwjglbook/blob/master/chapter12/c12-p2/src/main/java/org/lwjglb/game/DummyGame.java

    float cutoff = (float) Math.cos(Math.toRadians(140));
    SpotLight spotLight = new SpotLight(pointLight, coneDir, cutoff);

The value being passed to with "cutoff" is -0.76604444. So that's the cosine of 140 degrees in radians... so far I'm ok.

The second part of the bug is in the constructor of the Spotlight class itself: https://github.com/lwjglgamedev/lwjglbook/blob/master/chapter12/c12-p2/src/main/java/org/lwjglb/engine/graph/SpotLight.java

public SpotLight(PointLight pointLight, Vector3f coneDirection, float cutOffAngle) {
    this.pointLight = pointLight;
    this.coneDirection = coneDirection;
    setCutOffAngle(cutOffAngle);
}

Combined with its setCutOffAngle method:

public void setCutOff(float cutOff) {
    this.cutOff = cutOff;
}

public final void setCutOffAngle(float cutOffAngle) {
    this.setCutOff((float)Math.cos(Math.toRadians(cutOffAngle)));
}

Do you see the wackiness I'm talking about??? It's treating the radian angle like degrees, converting it to radians again, and then setting the actual cutoff value to the cosine of that! That value is like 0.99991065 and that is what is passed to the fragment shader's code.

This is the code in the actual fragment shader that uses the resulting value(line 112): https://github.com/lwjglgamedev/lwjglbook/blob/master/chapter12/c12-p2/src/main/resources/shaders/fragment.fs

vec4 calcSpotLight(SpotLight light, vec3 position, vec3 normal)
{
  vec3 light_direction = light.pl.position - position;
  vec3 to_light_dir  = normalize(light_direction);
  vec3 from_light_dir  = -to_light_dir;
  float spot_alfa = dot(from_light_dir, normalize(light.conedir));

  vec4 colour = vec4(0, 0, 0, 0);

  if ( spot_alfa > light.cutoff ) 
  {
      colour = calcPointLight(light.pl, position, normal);
      colour *= (1.0 - (1.0 - spot_alfa)/(1.0 - light.cutoff));
  }
  return colour;    
}

So I understand the concept of the Spotlight and it's cutoff angle, but I'm not good at math or linear algebra. I'm hoping to learn how to use dot products and normalization from good examples. But this has got me totally confused. Yes, I can jury rig it to work by making my degree angle run through this bizarre double cosine(toRadians()) logic, but I'd rather do the math correctly...

Can anyone tell me how to fix this? This particular repository has been dormant for a couple years but it is still my top google search result and many people have recommended it online.

I really appreciate any expert help.

edit: maybe "bug" isn't the right word for this. But I consider it a bug if the implementation intends for you to pass it an angle in degrees, but actually requires you to pass the value in radians...

\$\endgroup\$

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.