Lights inputs in GLSL shaders

The GLSL-style name of the matrix you refer to is p3d_ModelViewMatrixInverse, by the way. :slight_smile:. I don’t recommend use of the Cg-style naming - my intent is to be offering all inputs in GLSL-style naming. Not to impose my style preferences, though-- use what you prefer.

Instead of transforming your light position by p3d_ModelViewMatrixInverse and performing the lighting in model space, you could just transform your vertices to view space (with p3d_ModelViewMatrix) and do your lighting there. That’s the OpenGL way. :slight_smile:

To transform normals to view space, you can use p3d_NormalMatrix. Beware that it’s a mat3, not a mat4.

I like to follow the usual style for the API, so I’ll switch to new input names and view space lighting. I saw you added the Color uniform, thanks.

I ported almost all shaders to GLSL, but still have doubt about ambient lights. Couldn’t ambient lights too be passed with setShaderInput, to support handling all lights in the same manner? Something like the attached patch.
ambient.patch (1.08 KB)

Yes, I considered making that change as well, although I didn’t do it because I thought it might just be useless. It makes sense, though, and if it’s useful to you, I’ll apply the patch; but I would like to see logic to the “diffuse” color case so that the diffuse color is forced to zero if it’s an ambient light. This makes the result of calling .diffuse on an ambient light make a bit more sense (ambient lights have no diffuse color, of course). It also keeps it possible to make one light calculation that will work for all light types, in case that property might be useful to someone.

If we’re going to consider AmbientLight a valid light type to pass to setShaderInput, it would also probably be a good idea if calling .position or .halfVector on an ambient light didn’t crash due to the failed cast to LightLensNode, even though the actual values don’t have to make sense (we can just use (0, 0, 0, 0)). The other properties will already do the right thing, I think.

If you could make those changes, that’d be great; otherwise I’ll probably get around to it eventually.

Right, that was a too quick patch :blush: Here is an update. Also in the spot direction there was cast to lens, so zeroed that too.
ambient2.patch (4.33 KB)

Thanks so much! Just pushed it. :slight_smile:

Thank you!

I just checked in a change to p3d_Color handling to git that makes it generally more useful.

Before today, if p3d_Color was used but no vertex color information was present on the model, the values would be undefined (but usually (0, 0, 0, 0)). This means that you could not use the same shader on objects with and without vertex colors, since objects without vertex colors would appear black instead of white.

From now on, p3d_Color respects the ColorAttrib rules that also applied to the fixed-function pipeline: p3d_Color will contain a white color if the vertex colors are absent or if colors are disabled using set_color_off(), and a flat color if one is applied using set_color(), even if vertex colors are present.

You can still declare it as a uniform, of course, if you are sure that the model does not have vertex colors, but declaring it as an attribute should do the right thing in all cases.

If you would like to treat the color column as a generic vertex attribute with no special handling, you should use the name “color” instead of “p3d_Color”, which will bind it without any special handling.

Yeah, that makes sense. I haven’t noticed the earlier behavior, because a color texture was always used as the base color.

But now I also see that I always multiply with uniform p3d_Color input, even when I’m not explicitly calling set_color(). This works as expected, so the default for uniform p3d_Color must be (1, 1, 1, 1). Is it ok to rely on this behavior?

Yes, the default for “uniform vec4 p3d_Color” in absence of a setColor call has been (1, 1, 1, 1) since it was introduced. I made no changes to the p3d_Color uniform.

The default for “in vec4 p3d_Color” (the attribute) in absence of vertex colors was (0, 0, 0, 0) in the past, now it is (1, 1, 1, 1) if no color was set.

If some of your models may have vertex colors, use the p3d_Color attribute, which will now always contain the correct value. If you are not interested in vertex colors but only in flat colors, use the p3d_Color uniform.

Note that textures have nothing to do with this. Color attributes and color textures are independent inputs. Typically the flat/vertex color is used in absence of a diffuse material color and will tint the sampled texture color, or used as a base color for a PBR lighting.

Just checked in support for p3d_LightSource[]. I also added additional light inputs such as “attenuation” (a vec3 form that combines the three attenuation term), shadowMap (a sampler containing the shadow map for the light) and shadowMatrix (to transform coordinates to the texture space of the shadow map).

UPDATE: shadowMatrix has now been deprecated; please use shadowViewMatrix instead to transform from view-space coordinates, which is more efficient.

I can post a sample program if someone requests it.

What happens if vertex colors are present and no flat color has been applied? Shouldn’t the vertex colors show up then? That does not seem to be the case.

Consider the following code sample, which uses a very basic shader:

from panda3d.core import *
from direct.showbase.ShowBase import ShowBase


def create_cube(parent):

    vertex_format = GeomVertexFormat.get_v3n3cp()
    vertex_data = GeomVertexData("cube_data", vertex_format, Geom.UH_static)
    tris = GeomTriangles(Geom.UH_static)

    pos_writer = GeomVertexWriter(vertex_data, "vertex")
    col_writer = GeomVertexWriter(vertex_data, "color")
    normal_writer = GeomVertexWriter(vertex_data, "normal")

    vertex_count = 0

    for direction in (-1, 1):

        for i in range(3):

            normal = VBase3()
            normal[i] = direction
            rgb = [0., 0., 0.]
            rgb[i] = 1.

            if direction == 1:
                rgb[i-1] = 1.

            r, g, b = rgb
            color = (r, g, b, 1.)

            for a, b in ( (-1., -1.), (-1., 1.), (1., 1.), (1., -1.) ):

                pos = VBase3()
                pos[i] = direction
                pos[(i + direction) % 3] = a
                pos[(i + direction * 2) % 3] = b

                pos_writer.add_data3f(pos)
                col_writer.add_data4f(color)
                normal_writer.add_data3f(normal)

            vertex_count += 4

            tris.add_vertices(vertex_count - 2, vertex_count - 3, vertex_count - 4)
            tris.add_vertices(vertex_count - 4, vertex_count - 1, vertex_count - 2)

    geom = Geom(vertex_data)
    geom.add_primitive(tris)
    node = GeomNode("cube_node")
    node.add_geom(geom)
    cube = parent.attach_new_node(node)

    vert_shader = """
        #version 330

        uniform mat4 p3d_ModelViewProjectionMatrix;

        in vec4 p3d_Vertex;
    //    in vec4 color;
        in vec4 p3d_Color;

        out vec4 vertex_color;

        void main()
        {
            gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;
    //        vertex_color = color;
            vertex_color = p3d_Color;
        }
    """

    frag_shader = """
        #version 330

        in vec4 vertex_color;
        out vec4 out_color;

        void main()
        {
            out_color = vertex_color;
        }
    """

    shader = Shader.make(Shader.SL_GLSL, vert_shader, frag_shader)
    cube.set_shader(shader)

    return cube


class MyApp(ShowBase):

    def __init__(self):

        ShowBase.__init__(self)

        create_cube(self.render)

        self.cam.set_pos(-7., -10., 4.)
        self.cam.look_at(0., 0., 0.)


app = MyApp()
app.run()

When I run this, I get a completely white cube, even though no flat color is applied to it and each side has its own vertex color (comment out the call to set_shader to see them).
(If I replace “p3d_Color” with “color”, the vertex colors show up fine, but flat colors are not taken into consideration then, which corresponds to what you stated earlier.)

Is this a bug, or am I missing something?

This was tested with a recent development build, Panda3D-SDK-1.10.0pre-3db8ce2-x64.exe.

You need to call this to enable vertex colours on the model:

cube.set_attrib(ColorAttrib.make_vertex())

That said, there was a bug that prevented it from working, even with that applied. I’ve just checked in a fix for that bug.

Right, I actually forgot about that when putting together the code sample. In my project I call set_color_off, which seems to set that attribute automatically to T_vertex.

Thank you so much, it works great now :slight_smile: !