0
votes

After a fairly long Google Session I have enough from it!

I had a python/opengl application with some simple Quad's where I used gluLookAt to move around on the scene. Then I needed just 1 Texture on one of those Quad's, so I obviously use a shader progam for this single Quad now.

Now when I use gluLookAt, the Quad with the Texture doesn't move, what I also can understand.

Now is there any way to somehow get the gluLookAt function to working with the shader program, get the Current Matrix Stack so I can feed the shader programm with it or do I have to rewrite the hole application and reinvent the glulookup function like he did(either in the shader or on the CPU)?

EDIT1: I use:

EDIT2 (My Solution):

Since I opened this thread, some things have changed but with the guideance of you I managed to get a modern & stable solution.

There are 3 Main components which I have to draw. A static Field, some Lines (for better visualisation) and some Movable Quads.

The Field is now written once to a VBO in an Array. (major improvement compared to single drawing commands)

The moveable squares and lines work on the same principle, but they are dynamic and must be reuploaded with each frame.

Foreach type of object I have a vertex + fragment shader program. I'am aware that I could use just one big one but that's not like it's supposed to be.

Each Matrix (Model,View,Projection) Is assigned to a uniform which then are multiplied with the Vertices from the VBO in the vertex shader.

Field Vertex Shader (Example):

#version 330

uniform mat4 uniform_Model;
uniform mat4 uniform_View;
uniform mat4 uniform_Projection;

in vec3 Quad_Color_Attrib;
in vec3 Quad_Size_Attrib;

out vec3 frag_ColorId;

void main()
{
    // Pass the tex coord straight through to the fragment shader
    frag_ColorId = Quad_Color_Attrib;

    // Remember : inverted !
    gl_Position = uniform_Projection * uniform_View * uniform_Model * vec4(Quad_Size_Attrib,1);
}

What I asked for wasn't the right way to do it. (Combining old and new OpenGL) Unfortunatly I can't share the hole code as it is but I here you can find all opengl key codes:

Vertex/Fragment Shader Program Loader:

Link to a gist

Initialize Vertex/Fragment Shader (in this case for the field)

def init_field(self, p_VertexShaderPath, p_FragmentShaderPath, p_FieldList, p_FieldCount):
    # ############### Field Shader ###############

    # Shader Program
    self.m_FieldShader = LoadShaders(p_VertexShaderPath, p_FragmentShaderPath)
    glUseProgram(self.m_FieldShader)

    # VAO
    self.m_FieldVAO = glGenVertexArrays(1)
    glBindVertexArray(self.m_FieldVAO)

    # Field Definition        
    self.m_FieldCount = p_FieldCount
    t_Vertices = []

    for t_FieldNr in p_FieldList:
        x = p_FieldList[t_FieldNr].m_XPos
        y = p_FieldList[t_FieldNr].m_YPos
        cr = p_FieldList[t_FieldNr].m_Color[0]/255
        cg = p_FieldList[t_FieldNr].m_Color[1]/255
        cb = p_FieldList[t_FieldNr].m_Color[2]/255

        t_Vertices.extend([
             x - 0.5,  y + 0.5, 0.0,  cr, cg, cb,   #  0----1
             x + 0.5,  y + 0.5, 0.0,  cr, cg, cb,   #  |    |
             x + 0.5,  y - 0.5, 0.0,  cr, cg, cb,   #  |    |
             x - 0.5,  y - 0.5, 0.0,  0, 0, 0    #  3----2
        ])

    t_FieldVerticesBuffer = numpy.array(t_Vertices, dtype = numpy.float32)

    # VBO
    self.m_FieldVBO = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, self.m_FieldVBO)
    glBufferData(GL_ARRAY_BUFFER, t_FieldVerticesBuffer.nbytes, t_FieldVerticesBuffer, GL_STATIC_DRAW)

    # VBO Size Attrib
    self.m_FieldVerticesAttrib = glGetAttribLocation(self.m_FieldShader, "Quad_Size_Attrib")
    glEnableVertexAttribArray(self.m_FieldVerticesAttrib)
    glVertexAttribPointer(self.m_FieldVerticesAttrib,
                          3, 
                          GL_FLOAT, 
                          GL_FALSE, 
                          ctypes.sizeof(6*GLfloat), 
                          ctypes.c_void_p(0))

    # VBO Color Attrib                      
    self.m_FieldColorAttrib = glGetAttribLocation(self.m_FieldShader, "Quad_Color_Attrib")
    glEnableVertexAttribArray(self.m_FieldColorAttrib)
    glVertexAttribPointer(self.m_FieldColorAttrib,
                          3, 
                          GL_FLOAT, 
                          GL_FALSE, 
                          ctypes.sizeof(6*GLfloat), 
                          ctypes.c_void_p(12))

    # Uniform Locations
    self.m_Field_ModelMat_Uniform = glGetUniformLocation(self.m_FieldShader, 'uniform_Model')
    self.m_Field_ViewMat_Uniform = glGetUniformLocation(self.m_FieldShader, 'uniform_View')
    self.m_Field_ProjectionMat_Uniform = glGetUniformLocation(self.m_FieldShader, 'uniform_Projection')

    # Detach Shader & VAO
    glBindVertexArray(0)  # unbind the VAO
    glUseProgram(0)  # Disable shader

Screen Draw Cycle

This now is just psydo code:

OpenGLEnv.Clear()
OpenGLEnv.SetCamera()
OpenGLEnv.DrawField()
OpenGLEnv.FlipBuffer()

So SetCamera set's the ViewMat and ProjectionMat.

def SetCamera(self, camera, zoom_distance):
    self.m_ViewMat = lookAt(glm.vec3(-camera[0], -camera[1], zoom_distance),  # Camera is at (x,x,x), in World Space
                            glm.vec3(-camera[0], -camera[1], -100),  # and looks at the origin
                            glm.vec3(0, 1, 0)) #  Head is up (set to 0,-1,0 to look upside-down)
    self.m_ProjectionMat = perspective(45, self.m_AspectRatio, 1, 1000.0)

Draw Field Routine

With this Function I will draw the Vertices from the VBO.

def DrawField(self):
    glUseProgram(self.m_FieldShader)       # Use shader

    self.m_ModelMat = glm.mat4(1)  # Reset ModelMat
    # ############################
    # 1. Scale          self.ModelMat = scale(self.ModelMat,glm.vec3(10,10,10))
    # 2. Rotation       self.ModelMat = rotate(self.ModelMat, self.test, glm.vec3(0,1,0))
    # 3. Translate      self.ModelMat = translate(self.ModelMat,glm.vec3(0,0,0))
    ####################################

    glUniformMatrix4fv(self.m_Field_ModelMat_Uniform, 1, GL_FALSE, numpy.squeeze(numpy.asarray(self.m_ModelMat.value)))
    glUniformMatrix4fv(self.m_Field_ViewMat_Uniform, 1, GL_FALSE, numpy.squeeze(numpy.asarray(self.m_ViewMat.value)))
    glUniformMatrix4fv(self.m_Field_ProjectionMat_Uniform, 1, GL_FALSE, numpy.squeeze(numpy.asarray(self.m_ProjectionMat.value)))

    glBindVertexArray(self.m_FieldVAO)
    glBindBuffer(GL_ARRAY_BUFFER, self.m_FieldVBO)

    # Draw Field
    glDrawArrays(GL_QUADS, 0, 4*self.m_FieldCount)

    # Disable shader and unbind VAO
    glBindVertexArray(0)
    glUseProgram(0)

Used Librarys:

1
I suggest using a math library instead of trying to fiddle around with the matrix stack. glm might be a good choice and also provides a lookat function. For the rest of your question: It depends on which version and profile you use. - BDL
Sorry for not mentioning it, I work with Python ^^ Okay you would go with a manual calculation of the Matrices... Thanks for your Advice. - noscript
There is python version of glm also . Please see following link github.com/mackst/glm. It is not as full functional as glm but has functions you need. - Paritosh Kulkarni
Side note: If you must use gluLookAt and friends, I would consider using GLSL 120 + OpenGL 2.1 instead and try to stick to as much of the "modern subset" of it as you can (i.e. using VBOs at least). If you use GLSL 120, then you can use predefined variables like gl_ModelViewMatrix and gl_ProjectionMatrix in your shader instead to access the "fixed function" matrix function stacks. - CodeSurgeon
That being said, I am using python as well and it most certainly isn't impossible per se to create your own uniform matrices to pass into your shaders, just more frustrating. While you "can" pass in raw numpy matrices to the glUniform* commands, you then lose out on these convenience functions. I personally ended up writing my own matrix math classes in cython, but if you need a pure python solution, I would check out pyrr or pyeuclid for python 3d math libraries. - CodeSurgeon

1 Answers

1
votes

You may decide :

  1. You may use OpenGL 2, what makes things much easier and means no shader programming but less efficiency.

  2. If you have to draw at least 1000 triangles or want to add bumpmapping or other special effects, you should maybe consider a shader. That means :

  3. Do not use Python & Pyopengl if you are aiming at high efficiency(own experience)

    • Id suggest you Java and jogl(My configuration currently). Then I could provide you my camera class.
  4. I will maybe also port my camera class to Python, but it depends on the jogl Matrix4 class and so on, but is easy if pyopengl also offers this math helper classes(Matrix4, Quaternion, ...)

EDIT :

Vertex Shader :

#version 330

uniform mat4 uniform_Transformation;
uniform mat4 uniform_Modelview;
uniform mat4 uniform_Projection;

in vec4 attribute_Position;
in vec4 texcoords;

out vec4 texcoords_pass;

void main(void) 
{ 
  texcoords_pass=texcoords;
  vec4 transformedPoint=attribute_Position*uniform_Transformation;
  vec4 toCamera=transformedPoint*uniform_Modelview;
  gl_Position = vec4(toCamera*uniform_Projection);
}

Fragment Shader :

#version 330

uniform sampler2D tex;

in vec2 texcoords_pass;

out vec4 mgl_FragColor;

void main (void)
{ 
  vec4 texture_color =  texture(tex,texcoords_pass);
  if (texture_color.w == 0) {
      discard;
  }
  mgl_FragColor=vec4(texture_color.x,texture_color.y,texture_color.z,1.0f);
}

About the matrices :

  • uniform_Transformation is the Transformation matrix. It is used to rotate, scale, flip, mirror and move your models, in your case quads.

  • uniform_Modelview is the View matrix. It's basically the camera. It defines how the camera is rotated and where it is located.

  • uniform_Projection is the Projection matrix. It's about the perspective projection. Read more about it here : http://www.songho.ca/opengl/gl_projectionmatrix.html

Hope it helps !