3
votes

All right, thankfully you guys I have a little deeper understanding how OpenGL in (almost) the modern work. But there is something I can't figure out.

How can the fragment shader sampling my texture even if I missing it set up correctly? I think somehow the sampler automatically get the texture. But how?

After I commented out the glBindTexture(GL_TEXTURE_2D, 1) the texture still showed up.

*(I'm using GLSL 1.2 because of my Raspberry Pi.)

Vertex shader:

#version 120

attribute vec2 vPosition;
attribute vec2 vTexcoords;

varying vec2 fTexcoords;

void main()
{
    gl_Position = vec4(vPosition.x/1.33, vPosition.y, 0.0, 1.0);
    fTexcoords = vTexcoords;
}

Fragment shader:

#version 120

varying vec2 fTexcoords;
uniform sampler2D textureObj;

void main()
{
    gl_FragColor = texture2D(textureObj, fTexcoords);
}

Code:

from OpenGL.GL import *
from OpenGL.GL.shaders import *

import pygame
from pygame.locals import *
import numpy, time, sys

def getFileContent(file):
    content = open(file, 'r').read()
    return content

def init():
    pygame.init()
    pygame.display.set_mode((640, 480), HWSURFACE | OPENGL | DOUBLEBUF)
    glViewport(0, 0, 640, 480)

    img = pygame.image.load("brick.jpg")
    textureData = pygame.image.tostring(img, "RGB", 1)
    width = img.get_width()
    height = img.get_height()
    #glGenTextures(1)
    #glBindTexture(GL_TEXTURE_2D, 1)
    glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)

    vertices = [-0.5, -0.5,
                -0.5, 0.5,
                0.5, 0.5,
                0.5, -0.5]

    texcoords = [0.0, 0.0,
                 0.0, 1.0,
                 1.0, 1.0,
                 1.0, 0.0]

    vertices = numpy.array(vertices, dtype=numpy.float32)
    texcoords = numpy.array(texcoords, dtype=numpy.float32)

    vertexShader = compileShader(getFileContent("helloTriangle.vert"), GL_VERTEX_SHADER)
    fragmentShader = compileShader(getFileContent("helloTriangle.frag"), GL_FRAGMENT_SHADER)

    global shaderProgram
    shaderProgram = glCreateProgram()
    glAttachShader(shaderProgram, vertexShader)
    glAttachShader(shaderProgram, fragmentShader)
    glLinkProgram(shaderProgram)

    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertices)
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoords)
    glEnableVertexAttribArray(0)
    glEnableVertexAttribArray(1)

    global texLocation
    texLocation = glGetUniformLocation(shaderProgram, "textureObj")

def main():
    init()

    while 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT: sys.exit()

        glClearColor(0.25, 0.25, 0.25, 1)
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

        glUseProgram(shaderProgram)
        #glUniform1i(texLocation, 0)
        glDrawArrays(GL_QUADS, 0, 4)

        pygame.display.flip()

main()
1

1 Answers

3
votes

In glsl uniform variables are default initialized by 0 respectively 0.0. So the value of the texture sampler uniform textureObj is initialized by (texture unit) 0, too.

Further there is the default texture object (0). If you don't create and bind a named texture object, then there is still the default texture object (0), and glTexImage2D specifies the texture image of the default texture object (0).

See OpenGL 4.6 API Compatibility Profile Specification; 8.1 Texture Objects; page 179

Textures in GL are represented by named objects. The name space for texture objects is the unsigned integers, with zero reserved by the GL to represent the default texture object. The default texture object is bound to each of the TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, [...] targets during context initialization.

GLSL - The OpenGL Shading Language 4.6; 4.3.5. Uniform Variables; page 50

The uniform qualifier is used to declare global variables whose values are the same across the entire primitive being processed. All uniform variables are read-only and are initialized externally either at link time or through the API. The link-time initial value is either the value of the variable’s initializer, if present, or 0 if no initializer is present.


By the way, glGenTextures returns a named texture object, which can be bound by glBindTexture. It is not specified that the 1st named texture object, which is generated by glGenTextures, has to be 1. It can be any id (number).

So it has to be:

texID = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texID)

instead of

glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, 1)