[GLSL shader question 2]Light data

Hello!
I need to know if it is possible to get light data in shader from all the lights in scene. I need it for GLSL shader. I wanna actually get the closest lights to object(for example, 10 lights, but it must be user defined number) and receive their data(type(SPOT, HEMI, SUN, POINT, maybe also AREA), strenght, color, specular/diffuse(on/off), etc.).
After that I need a voluenteer who can help me scripting up the light calculations(I know point lights, but none other).

I think you can’t get all the data from lamps directly in the shader (unless you pass the data to the shader as uniforms in the shader). But there are already some internal functions (gl_LightSource[0].position is almost supported (not completely right), gl_LightSource[index].diffuse … You have to test which ones are supported)… To get the color from an object, you have to use gl_FrontMaterial.emission (so you have to set emit to a float > 0) because as far I know, gl_FrontMaterial.diffuse is not supported…

It would fit well to use uniforms if they don’t make it slower. It can be empties. I just don’t know how to add uniforms. Especially when we speak about array uniforms.

What I can figure out:


for object in scene.objects:
    if "lampType" in object:
        lampList.append(object)

Here I have all the lamps. I can access their properties, but how do I uniform them?

to pass uniform to the shader, you can take a look here: http://www.blender.org/api/blender_python_api_2_75a_release/bge.types.BL_Shader.html?highlight=setuniform#bge.types.BL_Shader.setUniform1f

But about arrays I don’t know if you can pass an array to the shader. Could you give a concrete example of what you are trying to achieve? A picture?

I’ll do it tomorrow…

Here is some shader code setting up an array of light structs:


struct Light {
    int type;
    int falloff;
    float dist;
    vec3 color;
    vec3 position;
    mat3 orientation;
};

uniform int light_count;
uniform Light lights[16];

And some Python code for passing in data to those uniforms:


import bge
import mathutils

scene = bge.logic.getCurrentScene()
view_mat = bge.logic.getCurrentScene().active_camera.worldTransform.inverted()


lights = [light for light in scene.lights if (1&light.layer)]

for object in scene.objects:
        for mesh in object.meshes:
            for material in mesh.materials:
                shader = material.getShader()
                
                for i, light in enumerate(lights):
                    shader.setUniform1f("lights[%s].dist"%i, light.distance)
                    color = light.color
                    e = light.energy
                    shader.setUniform3f("lights[%s].color"%i, color[0]*e, color[1]*e, color[2]*e)
                    pos = view_mat*mathutils.Vector(light.position)
                    shader.setUniform3f("lights[%s].position"%i, *pos)
                    
                shader.setUniform1i("light_count", i+1)

Not sure if you are still looking for help on this since the last post was a couple of weeks ago, but I figured I might as well post this code since I had it sitting around. Hopefully I grabbed the right code snippets.

OK! However - will this support lamps like hemis and area too? And is it possible to take in spot angle, shape and other of theese per-lamp specific values?

@Kupoman: Thanks for your example! It’s very usefull!

I’ve yet work on shader before but had played around with KX_LightObject

OK! However - will this support lamps like hemis and area too?

Currently the light.type id is either SPOT, SUN or NORMAL(point,hemi,area are ALL inside this, not sure why?:confused:) so you’ll need to id them with property or something

And is it possible to take in spot angle, shape and other of theese per-lamp specific values?

Yes, I think*

OK! Sounds better, but yeah - type should be a property instead of getting actual type…

Someone knows how to get the spotDirection Vector of a light with python?
I know there is LightSource[index].spotDirection and I have a working shader with Lighting that works fine too but I think LightSource[index] is limited to 8 lights and I want to make a optional shader which supports more lights so I must pass the data with python to the shader. No Problem but the only thing I don’t know is how to get the spotDirection vector in python I only know how to get the Light.orientation but in my shader I use vec3 for calculation.

And another question, does anyone have an code example how to calculate hemi light?

Thank you that was what I was looking for. It works fine! :slight_smile:

Now I just need the info how to calculate a hemi light then it almost work like the normal bge material/lighting.
Maybe there is a documentation about the lighting somewhere or something like that?

Okay I run into another issue, because it’s looks like the sun rotation is not used. I’m use the same code that Kupoman shows above but it’s seems like there is something missing when I use gl_LightSource[index].position the sun Rotation is used.

I use something like this to get the Values. I know there is nothing with rotation in this values but why should it, I thought it’s only the sun Position in view space but it seems gl_LightSource[index].position is more than this :


view_mat = cam.worldTransform.inverted()
        pos = view_mat*mathutils.Vector(light.position)
        shader.setUniform3f("lights[%s].position"%i, *pos)

In the shader I use something like this for sunlamps:

       
 if (lights[l].type == 1) // directional light?
        {
            attenuation = 1.0; // no attenuation
            lightDirection = normalize(vec3(lights[l].position));
        } 

The position of value of the fixed function lighting is a little strange for directional (sun) lights. From the OpenGL documentation on glLight:

The position is transformed by the modelview matrix when glLight is called (just as if it were a point), and it is stored in eye coordinates. If the w component of the position is 0, the light is treated as a directional source. Diffuse and specular lighting calculations take the light’s direction, but not its actual position, into account, and attenuation is disabled. Otherwise, diffuse and specular lighting calculations are based on the actual location of the light in eye coordinates, and attenuation is enabled. The initial position is (0, 0, 1, 0); thus, the initial light source is directional, parallel to, and in the direction of the -z axis.

For hemi lights, here is the relevant code straight from Blender’s shader:


void shade_is_hemi(float inp, out float is)
{
    is = 0.5*inp + 0.5;
}

I am pretty sure the input value (inp) is the diffuse lighting term (N dot L).

Okay that is strange…

EDIT: Okay now I hope I’ve got it finally. So for the sun/directional light calculation I use the rotation instead of the Position vector.


lightDirection = normalize(lights[l].spotDirection);

If someone want to know how I get the direction:

        
lightDirection = light.worldOrientation.col[2]
spotDirection = cam.worldOrientation.inverted() * lightDirection.normalized()

For hemi lights, here is the relevant code straight from Blender’s shader:

void shade_is_hemi(float inp, out float is)
{
    is = 0.5*inp + 0.5;
}

I am pretty sure the input value (inp) is the diffuse lighting term (N dot L).

Yes, that should work, I have found a similar code on the internet.

Thanks for your help. :slight_smile: