pythonshaderpyqtgraphpyopengl

PyQtGraph: Custom Shader Not Displaying GLMeshItem


When importing ShaderProgram, VertexShader, and FragmentShader, I cannot get them to display my GLMeshItem.
I connect my shader to my GLMeshItem the way I see online in a very old forum:

gl.shaders.Shaders.append(ShaderProgram('hilight', 
    [   
        VertexShader("""
        uniform mat4 u_mvp;
        attribute vec4 a_position;
        attribute vec3 a_normal;
        attribute vec4 a_color;
        varying vec4 v_color;
        varying vec3 normal;
        void main() {
            // compute here for use in fragment shader
            normal = normalize(gl_NormalMatrix * gl_Normal);
            v_color = a_color;
            gl_Position = u_mvp * a_position;
        }
    """),
    FragmentShader("""
        #ifdef GL_ES
        precision mediump float;
        #endif
        varying vec4 v_color;
        varying vec3 normal;
        void main() {
            vec4 color = v_color;
            color.x = (normal.x + 1.0) * 0.5;
            color.y = (normal.y + 1.0) * 0.5;
            color.z = (normal.z + 1.0) * 0.5;
            gl_FragColor = color;
        }
    """)
    ]))

Then calling


    self.current_plot = gl.GLMeshItem(
        meshdata=mesh_data,
        shader='hilight', # Set shader here
        smooth=True,
        drawFaces=True,
        computeNormals=True
    )

This fails but the same thing with shader='edgeHilight' (a built-in pyqtgraph shader) doesn't. Why? Even when 'hilight' is a carbon copy of 'edgeHilight', there is still no visual.
I made sure it was added to the list of shaders by calling

print("Shader program ID:", self.shader.program()) # Output 6

What's strange is that when I edit GLMeshItem's paint function like this:

def paint(self):
    self.setupGLState()
    
    self.parseMeshData()        
    
    if self.opts['drawFaces']:
        with self.shader():
            # Add debug lines
            print("Position: " + str(glGetAttribLocation(self.shader().program(), 'a_position')))
            print("Normal: " + str(glGetAttribLocation(self.shader().program(), 'a_normal')))
            print("Color: " + str(glGetAttribLocation(self.shader().program(), 'a_color')))
            # Rest of code...

With shader='hilight':

Position: 2
Normal: 0
Color: 1

but when shader='edgeHilight':

Position: -1
Normal: -1
Color: -1

This is counterintuitive since the latter is the shader that works.


Solution

  • Solved on the pyqtgraph GitHub via https://github.com/pyqtgraph/pyqtgraph/discussions/3230#discussioncomment-11976036

    Because I didn't realize that the code I was referencing on GitHub was an unreleased dev version, all of my assumptions about what should work were wrong.

    Essentially, the shader I was trying to use would only work on an unreleased dev version (0.14.0.dev0), not 0.13.7. The fix for my issue was to either change my shader to one that would work with 1.13.7 (by removing the attributes) or to upgrade my pyqtgraph to 0.14.0.dev0.

    I chose to upgrade my pyqtgraph version by running pip install git+https://github.com/pyqtgraph/pyqtgraph/tree/master in cmd.