Lights inputs in GLSL shaders

OK, I just checked in support for custom light shader inputs. You can now do something like this (just a hacked-up test shader, don’t take too many lessons from this):

light = PointLight('abc')  # Or Spotlight, or DirectionalLight
light.setColor(...)
light_path = render.attachNewNode(light)
render.setShaderInput("customLight", light_path)
// Custom light shader input, works on all light types except AmbientLight
uniform gl_LightSourceParameters customLight;

uniform struct {
  // Sum of all ambient lights
  vec4 ambient;
} p3d_LightModel;

uniform struct {
  vec4 ambient;
  vec4 diffuse;
  vec3 specular;
  float shininess;
} p3d_Material;

in vec3 vpos;
in vec3 norm;

void main() {
  gl_FragColor = p3d_LightModel.ambient * p3d_Material.ambient;
  vec3 diff = customLight.position.xyz - vpos * customLight.position.w;
  vec3 L = normalize(diff);
  vec3 E = normalize(-vpos);
  vec3 R = normalize(-reflect(L, norm));
  vec4 diffuse = clamp(p3d_Material.diffuse * customLight.diffuse * max(dot(norm, L), 0), 0, 1);
  vec4 specular = vec4(p3d_Material.specular, 1) * customLight.specular * pow(max(dot(R, E), 0), gl_FrontMaterial.shininess);
  float spotEffect = dot(normalize(customLight.spotDirection), -L);
  if (spotEffect > customLight.spotCosCutoff) {
    gl_FragColor += (diffuse + specular) / (customLight.constantAttenuation + customLight.linearAttenuation * length(diff) + customLight.quadraticAttenuation * length(diff) * length(diff));
  }
}

If you don’t want to use the built-in definition of the gl_LightSourceParameters struct you can just define your own:

struct p3d_LightSourceParameters {
  // Ambient is always vec4(0, 0, 0, 1)
  vec4 ambient;
  // light.get_color()
  vec4 diffuse;
  // light.get_specular_color()
  vec4 specular;
  // In case of Spotlight/PointLight, this is the light position in view space, with fourth component 1
  // In case of DirectionalLight, this is actually (-dir) with the fourth component set to 0
  vec4 position;
  // This is the only one that's not actually available
  vec4 halfVector;
  // Etc blah blah same as OpenGL FFP equivalents
  // You can just omit their declaration if you don't need them, they are bound by name
  vec3 spotDirection;
  float spotExponent;
  float spotCutoff;
  float spotCosCutoff;
  float constantAttenuation;
  float linearAttenuation;
  float quadraticAttenuation;
};

uniform p3d_LightSourceParameters customLight;

For compactness, you can just define what you need:

uniform struct {
  vec4 position;
  vec4 diffuse;
} customLight;

Please let me know if this is sufficient for your needs. I can add more attributes if desired. I will be adding p3d_LightSource[i] in the future as a way to access lights that were set via setLight() rather than via setShaderInput().

(The shader input code is a bit messy at the moment, this might go a bit more easily once I start merging in some of the improvements I’ve been working on regarding the shader system, but that’ll have to wait a while.)