0
votes

I have successfully created a VAO which produces a triangle which can then be rotated with the mouse (with help from shaders).

My problem comes when I try to draw something else using the standard 'glBegin()' and 'glEnd()' functions. It draws successfully, but now, when I try to rotate the triangle the new drawing also rotates.

I know the problem is somehow fixed using the glUseProgram() function, but I'm not entirely sure why or where it should be added.

Here is my code (I've added it all but the main area of focus should be the display() and init() functions:

#include <GL/glew/glew.h>
#include <GL/freeglut.h>
#include <CoreStructures\CoreStructures.h>
#include <iostream>
#include "texture_loader.h"
#include "shader_setup.h"


using namespace std;
using namespace CoreStructures;


float theta = 0.0f;

bool mDown = false;
int mouse_x, mouse_y;


GLuint myShaderProgram;

GLuint locT; // location of "T" uniform variable in myShaderProgram
GLuint locR; // location of "R" uniform variable in myShaderProgram

GLuint sunPosVBO, sunColourVBO, sunIndicesVBO, sunVAO;

// Packed vertex arrays for the star object

// 1) Position Array - Store vertices as (x,y) pairs
static GLfloat sunVertices [] = {

    -0.1f, 0.7f,
    0.1f, 0.7f,
    0.0f, 0.55f
};

// 2) Colour Array - Store RGB values as unsigned bytes
static GLubyte sunColors [] = {

    255, 0, 0, 255,
    255, 255, 0, 255,
    0, 255, 0, 255
};

// 4) Index Array - Store indices to star vertices - this determines the order the vertices are to be processed
static GLubyte sunVertexIndices [] = {0, 1, 2};



void setupSunVAO(void) {

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

    // copy star vertex position data to VBO
    glGenBuffers(1, &sunPosVBO);
    glBindBuffer(GL_ARRAY_BUFFER, sunPosVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(sunVertices), sunVertices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)0);

    // copy star vertex colour data to VBO
    glGenBuffers(1, &sunColourVBO);
    glBindBuffer(GL_ARRAY_BUFFER, sunColourVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(sunColors), sunColors, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, 0, (const GLvoid*)0);

    // enable position, colour buffer inputs
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);

    // setup star vertex index array
    glGenBuffers(1, &sunIndicesVBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sunIndicesVBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(sunVertexIndices), sunVertexIndices, GL_STATIC_DRAW);


    glBindVertexArray(0);
}


void report_version(void) {

    int majorVersion, minorVersion;

    glGetIntegerv(GL_MAJOR_VERSION, &majorVersion);
    glGetIntegerv(GL_MINOR_VERSION, &minorVersion);

    cout << "OpenGL version " << majorVersion << "." << minorVersion << "\n\n";
}


void init(void) {

    // initialise glew library
    GLenum err = glewInit();

    // ensure glew was initialised successfully before proceeding
    if (err==GLEW_OK)
        cout << "GLEW initialised okay\n";
    else
        cout << "GLEW could not be initialised\n";

    report_version();

    glClearColor(0.0, 0.0, 0.0, 0.0);


    //
    // setup "sun" VBO and VAO object
    //
    setupSunVAO();


    //
    // load shader program
    //
    myShaderProgram = setupShaders(string("Resources\\Shaders\\basic_vertex_shader.txt"), string("Resources\\Shaders\\basic_fragment_shader.txt"));

    // get the index / location of the uniform variables "T" and "R" in shader program "myShaderProgram"
    locT = glGetUniformLocation(myShaderProgram, "T");
    locR = glGetUniformLocation(myShaderProgram, "R");

    // "plug-in" shader into GPU pipeline
    glUseProgram(myShaderProgram); // we're in the driving seat!!!!!  Our shaders now intercept and process our vertices as part of the GPU rendering pipeline (as shown in the lecture notes)
}


// Example rendering functions - draw objects in local, or modelling coordinates

void drawSun(void) {

    glBindVertexArray(sunVAO);
    glDrawElements(GL_TRIANGLE_STRIP, 3, GL_UNSIGNED_BYTE, (GLvoid*)0);
}


void drawShape()
{
    glColor3f(0.0f, 0.6f, 0.2f);
    glBegin(GL_POLYGON);

    glVertex2f(-1.0f, -1.0f);   //  Left
    glVertex2f(-1.0f, -0.1f);


    glVertex2f(-0.9f, -0.05f);
    glVertex2f(-0.55f, -0.045f);
    glVertex2f(-0.49f, -0.06f);
    glVertex2f(-0.4f, -0.055f);
    glVertex2f(-0.2f, -0.052f);

    glVertex2f(0.0f, -0.02f);   //  Middle

    glVertex2f(0.3f, -0.085f);
    glVertex2f(0.5f, -0.08f);
    glVertex2f(0.8f, -0.088f);

    glVertex2f(1.0f, -0.1f);
    glVertex2f(1.0f, -1.0f);    //  Right

    glEnd();
}

//
//
void drawScene()
{
    drawSun();

    drawShape();
}

void display(void) {

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Setup translation matrix and store in T.  Pass this over the the shader with the function glUniformMatrix4fv
    GUMatrix4 T = GUMatrix4::translationMatrix(0.01f, 0.01f, 0.0f);
    glUniformMatrix4fv(locT, 1, GL_FALSE, (GLfloat*)&T);

    // Setup rotation matrix and store in R.  Pass this over the the shader with the function glUniformMatrix4fv
    GUMatrix4 R = GUMatrix4::rotationMatrix(0.0f, 0.0f, theta);
    glUniformMatrix4fv(locR, 1, GL_FALSE, (GLfloat*)&R);

    // Draw the scene (the above transformations will be applied to each vertex in the vertex shader)
    drawScene();

    glutSwapBuffers();
}


void mouseButtonDown(int button_id, int state, int x, int y) {

    if (button_id==GLUT_LEFT_BUTTON) {

        if (state==GLUT_DOWN) {

            mouse_x = x;
            mouse_y = y;

            mDown = true;

        } else if (state == GLUT_UP) {

            mDown = false;
        }
    }
}


void mouseMove(int x, int y) {

    if (mDown) {

        int dx = x - mouse_x;
        int dy = y - mouse_y;

        float delta_theta = (float)dy * (3.142f * 0.01f);
        theta += delta_theta;

        mouse_x = x;
        mouse_y = y;

        glutPostRedisplay();
    }
}



void keyDown(unsigned char key, int x, int y) {

    if (key=='r') {

        theta = 0.0f;
        glutPostRedisplay();
    }
}


int main(int argc, char **argv) {

    glutInit(&argc, argv);
    initCOM();

    glutInitContextVersion(3, 3);
    glutInitContextProfile (GLUT_COMPATIBILITY_PROFILE);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE);

    glutInitWindowSize(800, 800);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Combining Transforms");

    glutDisplayFunc(display);
    glutKeyboardFunc(keyDown);
    glutMouseFunc(mouseButtonDown);
    glutMotionFunc(mouseMove);

    init();

    glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
    glutMainLoop();

    shutdownCOM();

    return 0;
}

EDIT I have an array of x,y vertices and am trying to draw them alongside the above code. For some reason this seems to take vertex data from the sunVAO.

Is there some kind of cache that needs to be cleared? I've searched google and I can't seem to find anyone else who has conflicting VAO and vertex arrays.

(Also, I have checked my code and the vertex data supplied in the array of vertices is correct, they're just not displayed correctly.)

Code:

static GLfloat bottomMarkerVertices[] = {
    -0.045f, -0.75f,
    0.045f, -0.75f,
    -0.07f, -1.0f,
    0.07f, -1.0f
};

glVertexPointer(2, GL_FLOAT, 0, bottomMarkerVertices);

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

note: vertex arrays have been enabled.

2
IMO, if you already have VAOs down, don't bother with immediate mode rendering (glBegin and friends). They have been depreciated and removed in OpenGL 3, and with good reason (they are very inefficient). - Colonel Thirty Two
First of all, if you're already using VAO, why (excuse me) the frickin' hell do you still use immediate mode? Furthermore, if you don't want stuff to be transformed by a vertex shader, just use a program with a pass-through VS. - thokra
Sadly, I don't have the option not to mix them. - Adam Carter
@AdamCarter: So there's already existing code that you can't refactor? - thokra
@thokra I can change code, but I need to combine the immediate rendering mode with a VAO - Adam Carter

2 Answers

0
votes

The two elements of your scene move together because they are both using the same transformation matrices, specificed by these lines:

// Setup translation matrix and store in T.  Pass this over the the shader with the   function glUniformMatrix4fv
GUMatrix4 T = GUMatrix4::translationMatrix(0.01f, 0.01f, 0.0f);
glUniformMatrix4fv(locT, 1, GL_FALSE, (GLfloat*)&T);

// Setup rotation matrix and store in R.  Pass this over the the shader with the function glUniformMatrix4fv
GUMatrix4 R = GUMatrix4::rotationMatrix(0.0f, 0.0f, theta);
glUniformMatrix4fv(locR, 1, GL_FALSE, (GLfloat*)&R);

If you want drawShape() not to move with the mouse, you need to reset locR with a fixed theta value before you call it.

drawSun();

GUMatrix4 R = GUMatrix4::rotationMatrix(0.0f, 0.0f, 0.0f);
glUniformMatrix4fv(locR, 1, GL_FALSE, (GLfloat*)&R);

drawShape();
0
votes

Assuming you're defining your coordinates in normalized device space (suggested by the apparent absence of a projection matrix), the rendering loop needs to look a little like this:

void drawScene()
{
    //update shader parameters for the sun shader if necessary
    drawSun();

    glUseProgram(0);
    // at this point, the PROJECTION and MODELVIEW matrices are both the identity
    // so the shape is expected to be in NDCs and is not to be transformed
    // at all
    drawShape();                      
    glUseProgram(progForSun);
}

Note that I don't advise to mix legacy and modern OpenGL like that. The results of vertex processing triggered by drawShape() are only defined because you're using a compatibility profile context.