glsl python. Replacing gl_LightSource[0].position?

So if I have a shader that uses gl_LightSource[0].position, I am getting the position of the latest created lightobject.

What if I want to replace this expression with a known object? For example, the object with the name “Sun”.

This is what it looks like at the moment


from bge import logic as g

cont = g.getCurrentController()
own = cont.owner

...

void main() 
{
    LightVec = vec3(ModelMatrix*(gl_ModelViewMatrixInverse*gl_LightSource[0].position));

...

I guess it would have to look something like this, but it doesn’t work :frowning:


from bge import logic as g
from bge import render as r
from mathutils import Vector
import bgl

cont = g.getCurrentController()
own = cont.owner
scene = g.getCurrentScene()
sun = scene.objects['Sun']

...

void main() 
{
    LightVec = vec3(ModelMatrix*(gl_ModelViewMatrixInverse*<b>sun.worldPosition</b>));

...

You can pass in custom GLSL “uniform” data into the shaders. You just define the uniform and do “setUniform” on your shader object.

Something like:



vertexShaderText = """

uniform vec3 sunPos;

void main() 
{
    LightVec = vec3(ModelMatrix*(gl_ModelViewMatrixInverse*<b>sunPos</b>));
...

"""

Then your python code controls ‘sunPos’ by doing:


shader.setUniform3f("sunPos", x, y, z)

The downside is that each that shares the material will draw with a ‘sunPos’ that was set by the last object called in Python. That’s because the game loop goes “Execute python controllers -> update physics -> render”.

Isn’t it also necessary to define sunPos?

Something like


sunPos = sun.worldOrientation * Vector((0,0,1))
or
sunPos = sun.worldPosition

I still do not understand how to give the LightVec the same info from the object “Sun” as the gl_LightSource[0].position.

In the second part of his example he demonstrates that you must set this value with the x, y and z components of the position.

For example;


shader.setUniform3f("sunPos", *sun.worldPosition[:])

Ah, yes. I was assuming that you would do something like this:



import bge

scene = bge.logic.getCurrentScene()
sunObj = scene.objects['sun']

# Then you have to find your object that needs the sun's position, and access its shader to do:
shader.setUniform3f("sunPos", sunObj.worldPosition.x, sunObj.worldPosition.y, sunObj.worldPosition.z)


What I have now is:


from bge import logic as g
from bge import render as r
from mathutils import Vector
import bgl

cont = g.getCurrentController()
own = cont.owner
scene = g.getCurrentScene()
sun = scene.objects['Sun']


VertexShader = """

varying vec3 LightVec;
uniform vec3 sunPos;

...

void main() {

    LightVec = vec3(ModelMatrix*(gl_ModelViewMatrixInverse*sunPos));

...

"""

mesh = own.meshes[0]
if 'shader' not in own:
    for mat in mesh.materials:
        own['shader'] = mat.getShader()
        if own['shader'] != None:        
            if not own['shader'].isValid():
                own['shader'].setSource(VertexShader, FragmentShader, 1)
shader.setUniform3f("sunPos", sun.worldPosition.x, sun.worldPosition.y, sun.worldPosition.z)

But this does not work… I seem to be missing something :frowning:

Of course I have the rest of the shader defined, and is working if you replace sunPos with gl_LightSource[0].position in the LightVec definition.

Edit, I guess the last line could also be:

own['shader'].setUniform3f('sunPos', sun.worldPosition.x, sun.worldPosition.y, sun.worldPosition.z)

The problem was that gl_LightSource[i].position has four coordinates, xyzw, so the solution was became the following:


from bge import logic as g
from bge import render as r
from mathutils import Vector
import bgl

cont = g.getCurrentController()
own = cont.owner
scene = g.getCurrentScene()
sun = scene.objects['Sun']
sunPos = sun.worldOrientation * Vector((1,1,1))

VertexShader = """

uniform vec3 sunPos;
uniform vec4 sunApos;

...

void main() {
             
    sunApos = vec4(sunPos,1);
    LightVec = vec3(sunApos);

...



I thought that you could combine shader output togheter with normal bge materials in the node editor, but that does not seem to be the case (it does work for sharing video textures across materials).

I thought since this is actually a shader for daylight ilumination, it might be another idea to actually control brightness and color of a normal bge light, with python, and to my surprise it does work. So no need for a daylight shader, I will work on a python controlled bge sun with color changes and extinction when rising and setting.

Here is a short test, this might not make any sense to you, but try to play with these values and you see that you can control a light with python, and make changes in realtime. Attach this in GameLogic as Python to a light. Always as pulse 0.



from bge import logic as g


scene = g.getCurrentScene()
lamp = scene.objects['Point']
sunat = scene.objects['Sun']


cont = g.getCurrentController()
own = cont.owner

lamp.energy = 0+1*(sunat.worldPosition.z/5000)
lamp.distance = 500
lamp.color = (1,1+1*(sunat.worldPosition.z/5000),1)