3
votes

So I've recently been learning some openGL. I've initially been using the SDL library to print images on screen but I figured it would be interested to try and achieve something similar with openGL and thus also being able to apply shaders to my images for neat effects such as lighting effects and night/day cycles and such. What I'm doing right now is simply loading a texture, then applying that texture to a quad with the same size of the texture. This works well.

Now I want to apply some shaders. This is an example of a vertex and fragment shader that I could apply to one of my textured quads:

in vec2 LVertexPos2D; 
void main()
 { 
      gl_Position = vec4( LVertexPos2D.x, LVertexPos2D.y, 0, 1); 
 }

which does nothing, then my fragment shader:

out vec4 LFragment;
void main()
{
LFragment = vec4(1.0, 1.0, 1.0, 1.0);
}

Which obviously just turns the texture I'm applying it on into a white block, which isn't exactly what I want. Somehow I need to retrieve the current texel data so I can modify that instead of simply changing it.

I've read that the function call to texture2D is supposed to return a vec4 of the current pixel data but I haven't gotten this to work. (Having a hard time finding a good explanation of the function inputs and how it works). Furthermore texture2D is supposedly deprecated but I can't get its replacement (texture()) to work either. Any nudges in the right direction would be greatly appreciated!

Edit: I'll throw in some more info on how I'm doing things, this is the function that loads my textures:

texture makeTexture(std::string fileLocation)
{
    texture tempTexture;
    SDL_Surface *mySurface = IMG_Load(fileLocation.c_str());
    if (mySurface == NULL)
    {
        std::cout << "Error in loading image at: " << fileLocation << std::endl;
        return tempTexture;
    }

    GLuint myTexture;
    glGenTextures(1, &myTexture);
    glBindTexture(GL_TEXTURE_2D, myTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mySurface->w, mySurface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, mySurface->pixels);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glBindTexture(GL_TEXTURE_2D, 0);
    SDL_FreeSurface(mySurface);
    tempTexture.texture_id = myTexture;
    tempTexture.h = mySurface->h;
    tempTexture.w = mySurface->w;
    return tempTexture;
}

Where this is my texture struct:

struct texture
{
    int w;
    int h;
    GLuint texture_id;
};

and this function draws any texture to a given x and y coordinate:

void draw(int y, int x, texture &tempTexture)
{
    glBindTexture(GL_TEXTURE_2D, tempTexture.texture_id);
    glBegin(GL_QUADS);
    glTexCoord2f(0, 1);
    glVertex2f(-1 + ((float)(x) / SCREEN_WIDTH) * 2, 1 - ((float)(y + tempTexture.h) / SCREEN_HEIGHT) * 2); //Bottom left
    glTexCoord2f(1, 1);
    glVertex2f(-1 + ((float)(x + tempTexture.w)/SCREEN_WIDTH)*2, 1 - ((float)(y + tempTexture.h) / SCREEN_HEIGHT) * 2); //Bottom right?
    glTexCoord2f(1, 0);
    glVertex2f(-1 + ((float)(x + tempTexture.w) / SCREEN_WIDTH) * 2, 1.0 - ((float)y / SCREEN_HEIGHT) * 2); //top right
    glTexCoord2f(0, 0);
    glVertex2f(-1 + ((float)(x) / SCREEN_WIDTH) * 2, 1.0 - ((float)y / SCREEN_HEIGHT) * 2); //Top left (notification: Coordinates are (x,y), not (y,x).
    glEnd();
    glBindTexture(GL_TEXTURE_2D, 0);
}

then in my main render function I'm now doing:

draw(0, 0, myTexture);
glUseProgram(gProgramID);
glUniform1i(baseImageLoc, myTexture2.texture_id);
draw(100, 100, myTexture2);
glUseProgram(NULL);

where myTexture is just a meadow of grass and myTexture2 is a player character that I want to apply some shading shenanigans to. gPriogramID is a program that has my two aformentioned shaders loaded to it.

1
I might also add that I've seen other people have similar questions (such as gamedev.stackexchange.com/questions/77751/…) but applying that solution just made my texture transparent.user3932479

1 Answers

3
votes

In order to access texture data in a shader you have to do the following:

  • First you need to glBind your texture to a specific texture unit (change active texture unit using glActiveTexture.
  • Pass the texture unit index as a uniform sampler to the shader.
  • Access the texture in the shader like the following.

    // tex holds the value of the texture unit to be used (not the texture) uniform sampler2D tex;

    void main() { vec4 color = texture(tex,texCoord); LFragment = color; }

You also need to pass texCoords to the shader as in vertex attribute.