简体   繁体   中英

Texture data not being used in fragment shader - OpenGL

I'm practicing textures in OpenGL, applying a simple texture defined as white colors onto a quad. The code compiles and runs fine, but the color of the quad is simply black and not white as I have specified.

I think it is because my fragment shader does not do the right kind of sampling, it's like the data it returns from the texture function is all zero, thus the texture of the quad becomes black. The reason I suspect so is because when I run the program, I can make a clear color of white and move one of the vertices on the quad a bit as to see the background (since it usually fills the entire surface). I can then clearly see the white background there, with the black quad on top. So some output color is produced from the fragment shader, it's just the wrong one, since the small pixel array I provided is only white color. The problem is I don't know exactly why it would produce wrong results from the code I have. I'm attempting to follow along in a book, which use or less the same code. I've also tried looking it up on different tutorials but they all seem to use the same approach, so I am stuck.

[EDIT]

I have tracked down some of the problem. Doing some error tracking using glGetError(), I figured out that this line of my code:

glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4);

returns error code 1282, (Invalid Operation), due to the second parameter level being 0. If I set this to 1 the error dissapears. The problem then becomes this line:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_R, GL_FLOAT, myTexture);

Which returns the same error, though does not get fixed by changing the level parameter.

This is the fragment and vertex shader I use:

Fragment Shader

// FRAGMENT SHADER
#version 330

uniform sampler2D tex;

in vec2 vs_tex_coord;

layout (location = 0) out vec4 outputColor;

void main(void)
{
    outputColor = texture(tex, vs_tex_coord);
}

Vertex Shader

// VERTEX SHADER
#version 330

layout(location = 0) in vec4 position;
layout(location = 1) in vec2 in_tex_coord;

uniform vec2 offset;

out vec2 vs_tex_coord;

void main(void)
{
    vec4 finalOffset = vec4(offset.x, offset.y, 0.0, 0.0);
    gl_Position = position + finalOffset;
    vs_tex_coord = in_tex_coord;
}

The code I use for texture object generation and storage is pretty simple:

glGenTextures(1, &textureHandle);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureHandle);

glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4);

const GLubyte myTexture[] = {0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                             0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                             0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF,
                             0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,   0xFF, 0xFF, 0xFF,    0xFF, 0xFF, 0xFF};

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGB, GL_UNSIGNED_BYTE, myTexture);

myTexture simply contains the 4x4 texture in an internal format of RGB with each component having 4 bits. I've set them all to white.

Then I simply generate a default sampler like so:

glGenSamplers(1, &mySampler);

glBindSampler(0, mySampler);

And finally I render:

glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);

glUseProgram(theProgram);

GLuint samplerLoc = glGetUniformLocation(theProgram, "tex");

if (samplerLoc == -1)
    printf("Location name could not be found...\n");

glUniform1i(samplerLoc, 0);

glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);

glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);

glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(16 * sizeof(float)));

glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

The array which I upload to a VBO is:

const float vertexPositions[] =
{
    // Vertex position
    -0.8f, -1.0f, 0.0f, 1.0f,
     1.0f, -1.0f, 0.0f, 1.0f,
     1.0f,  1.0f, 0.0f, 1.0f,
    -1.0f,  1.0f, 0.0f, 1.0f,

    // Texture coordinates
    0.0f, 0.0f,
    1.0f, 0.0f,
    1.0f, 1.0f,
    0.0f, 1.0f
};

Is it because I am using the sampler objects incorrectly? Do I need to set some sort of settings on them before I can get it to work correctly? Do I miss some intermediate step?

For anyone interested, the visual result is this: 在此输入图像描述

You can see the white cleared background, with me having purposefully moved one of the vertex positions a bit so you can see the black quad against the white background.

Alright, so after some bug tracking I finally found the problem! :) For anyone who gets into this problem in the future, here's the (very simple... doh!) solution.

First of all, this line right here:

glTexStorage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4);

Returned an OpenGL error of 1281 (Invalid Operation), is because the second parameter levels has to be at the very least 1, to store enough memory for the base image no matter if you want to use mipmaps or not (which I thought should be 0). So changing it from 0 to 1 fixed it.

Secondly, this line:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_R, GL_FLOAT, myTexture);

Had a problem at the format parameter, where it says GL_R in the above snippet. This was just plain wrong. Looking at the official documention for the function, it states this about it:

format Specifies the format of the pixel data. The following symbolic values are accepted: GL_RED, GL_RG, GL_RGB, GL_BGR, GL_RGBA, GL_BGRA, GL_DEPTH_COMPONENT, and GL_STENCIL_INDEX.

The type I previous specified in glTextStorage2D uses GL_RGB8, which has a base internal format of GL_RGB, this the correct version is:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGB, GL_UNSIGNED_BYTE, myTexture);

Fixing these two issues caused the textured result to show up :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM