简体   繁体   中英

Using texture2D on OpenGL 3.3

So I've been fiddling with an old University project done in OpenGL 3.3 (FreeGLUT + GLEW) and I've run into some problems.

Right at the start, I run the program and I'm getting an error compiling the BumpMap Fragment Shader:

#version 330 core    
#define lightCount 10

in vec4 vertPos;
in vec4 eyeModel;

in vec3 normalInterp;

in vec4 ambient;
in vec4 color;
in vec4 spec;
in vec2 texuv;

in vec4 lightPosition[lightCount];

struct LightSource {

        vec4 Position;
        vec4 Direction;

        vec4 Color;

        float CutOff;

        float AmbientIntensity;
        float DiffuseIntensity;
        float SpecularIntensity;

        float ConstantAttenuation;
        float LinearAttenuation;
        float ExponentialAttenuation;

        int lightType;
};

layout(std140) uniform LightSources {

        LightSource lightSource[10];
};

uniform sampler2D diffuse_tex;
uniform sampler2D normal_tex;

out vec4 out_Color;

void main() {
        out_Color = vec4(0);

        for(int i=0; i<lightCount; i++) {

                if(lightSource[i].lightType == 0)
                        continue;

                vec3 NormalMap = texture2D(normal_tex, texuv).rgb;
                vec3 normal = normalize(NormalMap * 2.0 - 1.0); //normalize(normalInterp);

                vec4 LightDirection = vertPos - lightSource[i].Position;
                float Distance = length(LightDirection);
                LightDirection = normalize(LightDirection);

                vec4 ambientColor = ambient * lightSource[i].Color * lightSource[i].AmbientIntensity;
                vec4 diffuseColor  =  vec4(0, 0, 0, 0);
                vec4 dColor = texture2D(diffuse_tex, texuv);
                vec4 specularColor = vec4(0, 0, 0, 0);

                float DiffuseFactor = dot(normal, vec3(-LightDirection));

                if (DiffuseFactor > 0) {

                        diffuseColor = dColor * lightSource[i].Color * lightSource[i].DiffuseIntensity * DiffuseFactor;

                        vec3 VertexToEye = normalize(vec3(eyeModel - vertPos));
                        vec3 LightReflect = normalize(reflect(vec3(LightDirection), normal));

                        float SpecularFactor = dot(VertexToEye, LightReflect);

                        SpecularFactor = pow(SpecularFactor, 255);
                        if(SpecularFactor > 0.0){
                        //SpecularFactor = pow( max(SpecularFactor,0.0), 255);
                                specularColor = spec * lightSource[i].Color * lightSource[i].SpecularIntensity * SpecularFactor;
                        }
                }

                out_Color += ambientColor + diffuseColor + specularColor;
        }
}

ERROR: 0:55: 'function' : is removed in Forward Compatible context texture2D
ERROR: 0:55: 'texture2D' : no matching overloaded function found (using implicit conversion)

So I looked the problem up and even though I thought it was weird I was getting this problem on a project I knew had been in working condition, I switched the texture2D call for a texture call and now the shader compiles, but I get a different error, where creating the buffer object for the first object in the scene:

//Consts defined here for readability
#define VERTICES 0
#define COLORS 1
#define NORMALS 2
#define TEXUVS 3
#define AMBIENTS 4
#define TANGENTS 5
#define SPECULARS 6
#define SPECULARS_CONSTANTS 7
#define NOISE_SCALE 8

void BufferObject::createBufferObject() {

    glGenVertexArrays(1, &_vertexArrayObjectID);
    glBindVertexArray(_vertexArrayObjectID);

    glGenBuffers(1, &_vertexBufferObjectID);

    glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferObjectID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*_vertexCount, _vertices, GL_STATIC_DRAW);

    glEnableVertexAttribArray(VERTICES);
    glVertexAttribPointer(VERTICES, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);

    glEnableVertexAttribArray(COLORS);
    glVertexAttribPointer(COLORS, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)sizeof(_vertices[0].XYZW));

    glEnableVertexAttribArray(NORMALS);
    glVertexAttribPointer(NORMALS, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)));

    glEnableVertexAttribArray(TEXUVS);
    glVertexAttribPointer(TEXUVS, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)+sizeof(_vertices[0].NORMAL)));

    glEnableVertexAttribArray(AMBIENTS);
    glVertexAttribPointer(AMBIENTS, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)+sizeof(_vertices[0].NORMAL)+sizeof(_vertices[0].TEXUV)));

    glEnableVertexAttribArray(TANGENTS);
    glVertexAttribPointer(TANGENTS, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)+sizeof(_vertices[0].NORMAL)+sizeof(_vertices[0].TEXUV)+sizeof(_vertices[0].AMBIENT)));

    glEnableVertexAttribArray(SPECULARS);
    glVertexAttribPointer(SPECULARS, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)+sizeof(_vertices[0].NORMAL)+sizeof(_vertices[0].TEXUV)+sizeof(_vertices[0].AMBIENT)+sizeof(_vertices[0].TANGENT)));

    glEnableVertexAttribArray(SPECULARS_CONSTANTS);
    glVertexAttribPointer(SPECULARS_CONSTANTS, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*)(sizeof(_vertices[0].XYZW)+sizeof(_vertices[0].RGBA)+sizeof(_vertices[0].NORMAL)+sizeof(_vertices[0].TEXUV)+sizeof(_vertices[0].AMBIENT)+sizeof(_vertices[0].TANGENT)+sizeof(_vertices[0].SPECULAR)));

    glBindVertexArray(0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    glDisableVertexAttribArray(VERTICES);
    glDisableVertexAttribArray(COLORS);
    glDisableVertexAttribArray(NORMALS);
    glDisableVertexAttribArray(TEXUVS);
    glDisableVertexAttribArray(AMBIENTS);
    glDisableVertexAttribArray(TANGENTS);
    glDisableVertexAttribArray(SPECULARS);
    glDisableVertexAttribArray(SPECULARS_CONSTANTS);

    Utility::checkOpenGLError("ERROR: Buffer Object creation failed.");
}

OpenGL ERROR [Invalid Operation] = 1282

And that's all the info I'm getting. I've moved the checkOpenGLError around and figured out the line glDisableVertexAttribArray(VERTICES) is giving the error. After a bit more of digging I found out that you're not supposed to set glBindVertexArray(0) (at least before you glDisableVertexAttribArray , from what I remember we set those flags to 0 so we wouldn't accidentally affect anything we didn't want)

At this point the error moves to where we're drawing one of the scene objects. At this point I've hit a bit of a wall and don't where to go to next. I guess my question is whether there is a configuration when running the project that needs to be set, or whether just running this on a more recent graphics card could account for the different behaviour. As a final note, this is running on windows off of Visual Studio 10 (or 15, switched to 10 when reverted all changes and didn't retarget the solution) in widnows, the program configurations are as follows:

//GLUT Init
glutInit(&argc, argv);

glutInitContextVersion(3, 3);
glutInitContextFlags(GLUT_FORWARD_COMPATIBLE);
glutInitContextProfile(GLUT_CORE_PROFILE);

glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE,GLUT_ACTION_GLUTMAINLOOP_RETURNS);

glutInitWindowSize(windowWidth, windowHeight);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);

windowHandle = glutCreateWindow(CAPTION);

//GLEW Init
glewExperimental = GL_TRUE;

GLenum result = glewInit(); 

//GLUT Init
std::cerr << "CONTEXT: OpenGL v" << glGetString(GL_VERSION) << std::endl;

glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glDepthMask(GL_TRUE);
glDepthRange(0.0,1.0);
glClearDepth(1.0);

glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glFrontFace(GL_CCW);

with the context above being:

CONTEXT: OpenGL v3.3.0 - Build 22.20.16.4749

Let me know if any aditional information is required, I didn't want to add any more unnecessary clutter and the project is too big to just paste it all here...

In your shader you are using glsl version 330 core, which means texture2D() is deprecated and you should use texture() instead.

As for your INVALID OPERATION error, the problem is that you unbound the vao with glBindVertexArray(0); and then called glDisableVertexAttribArray(VERTICES); which operates on the currently bound vao. You should move glBindVertexArray(0); under these calls.

First let me refer to the specification, OpenGL 4.6 API Core Profile Specification; 10.3.1 Vertex Array Objects; page 347 :

The name space for vertex array objects is the unsigned integers, with zero reserved by the GL .
...
A vertex array object is created by binding a name returned by GenVertexArray with the command

 void BindVertexArray( uint array ); 

array is the vertex array object name. The resulting vertex array object is a new state vector, comprising all the state and with the same initial values listed in tables 23.3 and 23.4.
BindVertexArray may also be used to bind an existing vertex array object. If the bind is successful no change is made to the state of the bound vertex array object, and any previous binding is broken.

Tables 23.3, Vertex Array Object State
VERTEX_ATTRIB_ARRAY_ENABLED , VERTEX_ATTRIB_ARRAY_SIZE , VERTEX_ATTRIB_ARRAY_STRIDE , VERTEX_ATTRIB_ARRAY_TYPE , VERTEX_ATTRIB_ARRAY_NORMALIZED , VERTEX_ATTRIB_ARRAY_INTEGER , VERTEX_ATTRIB_ARRAY_LONG , VERTEX_ATTRIB_ARRAY_DIVISOR , VERTEX_ATTRIB_ARRAY_POINTER

Table 23.4, Vertex Array Object State
ELEMENT_ARRAY_BUFFER_BINDING , VERTEX_ATTRIB_ARRAY_BUFFER_BINDING , VERTEX_ATTRIB_BINDING , VERTEX_ATTRIB_RELATIVE_OFFSET , VERTEX_BINDING_OFFSET , VERTEX_BINDING_STRIDE , VERTEX_BINDING_DIVISOR , VERTEX_BINDING_BUFFER .

This means that a Vertex Array Object collects all the information which is necessary to draw an object. In the vertex array object is stored the information about the location of the vertex attributes and the format. Further the vertex array object "knows" whether an attribute is enabled or disabled.

If you do

glBindVertexArray(0);

glDisableVertexAttribArray( .... );

this causes an INVALID_OPERATION error, when you use a core profile OpenGL context , because then the vertex array object 0 is not a valid vertex array object. If you would use a compatibility profile context this would not cause an error, because then the vertex array object 0 is the default vertex array object and is valid.

If you do

glBindVertexArray(_vertexArrayObjectID);

glEnableVertexAttribArray( ..... );
glVertexAttribPointer( ..... );

glDisableVertexAttribArray( ..... );

glBindVertexArray(0);

then the draw call will fail. You have made the effort to define all the arrays of generic vertex attributes data and to enable them all correctly, but right after doing that you disable them again. So in the vertex array object is stored the "disabled" state for all the attributes.

The correct procedure to define a vertex array object is:

  • Generate the vertex buffers, and creates and initializes the buffer object's data store (this step can be done after creating and binding the vertex array object, too):
glGenBuffers(1, &_vertexBufferObjectID);

glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferObjectID);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*_vertexCount, _vertices, GL_STATIC_DRAW);
  • Generate and bind the vertex array object:
glGenVertexArrays(1, &_vertexArrayObjectID);
glBindVertexArray(_vertexArrayObjectID);
  • Define and enable the arrays of generic vertex attributes data (this has to be done after binding the vertex array object):
glBindBuffer(GL_ARRAY_BUFFER, _vertexBufferObjectID);
glEnableVertexAttribArray(VERTICES);
glVertexAttribPointer(VERTICES, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);

....

glBindBuffer(GL_ARRAY_BUFFER, 0);
  • If you would use an element buffer ( GL_ELEMENT_ARRAY_BUFFER ), then you would have to specify it now, because the name of (reference to) the element buffer object is stored in the vertex array object, and this has to be currently bound, when the element buffer object gets bound.
glGenBuffers(1, &ibo);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, ..... );
  • Finally you can do glBindVertexArray(0) . But there is no reason to do that. It is sufficient to bind a new vertex array object, before you specify a new mesh, or to bind the proper vertex array object before you draw a mesh.

Further there is no need for glDisableVertexAttribArray , as long you don't want to change the vertex array object specification. The state "enabled" is stored in the vertex array object an kept there. If you bind a new vertex array object, the then the object and so all its states become current.

Now drawing is simple:

 glBindVertexArray(_vertexArrayObjectID);
 glDrawArrays( .... );

Again there is no need of glBindVertexArray(0) , after the draw call (especially in core mode).

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