2

i try to get a basic OpenGL program working. I created two methods which create a modelview matrix (very rudimental at the moment, it only moves my object on the Z-Axis) and a projection Matrix.

My proplem is, that as far as i understood OpenGL my Projection Matrix should place Vertices with positive Z-Coordinates on the screen and the ones with negative Coordinates behind the screen.

But what i experience is, that i need to move the cube i draw in the negative z-direction if i want it to be shown. Can you explain, why this is? Where am i wrong? Or is there an error in my code?

I Use this function to create my projection matrix:

void Perspective(float *a, float fov, float aspect, float zNear, float zFar)
{
    for(int i = 0; i < 16; i++)
        a[i] = 0.0f;

    float f = 1.0f/float(tan(fov / 2.0f * (M_PI / 180.0f)));

    a[0 + 4 * 0] = f / aspect;
    a[1 + 4 * 1] = f;
    a[2 + 4 * 2] = (zNear + zFar) / (zNear - zFar);
    a[2 + 4 * 3] = 2.0f * zNear *+ zFar / (zNear - zFar);
    a[3 + 4 * 2] = -1.0f;
}

And this one for the Modelview (i pass varying offsets, they swing around 0, and z around -2):

void Modelview(float *mv, float scale, float xOff, float yOff, float zOff)
{
    for(int i = 0; i < 16; i++)
        mv[i] = 0.0f;

    mv[0 + 4 * 0] = scale;
    mv[0 + 4 * 3] = xOff;
    mv[1 + 4 * 1] = scale;
    mv[1 + 4 * 3] = yOff;
    mv[2 + 4 * 2] = scale;
    mv[2 + 4 * 3] = zOff;
    mv[3 + 4 * 3] = 1.0f;
}

The matrices are both passed correctly to opengl, i calculate the vertex position by:

gl_Position = modelview * projection * vertex_position;

Here is the whole code, in case anyone needs it:

main.h

#include <stdio.h>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <algorithm>
#include <GL/glew.h>
#include <GL/glut.h>

#include "util.h"

GLuint positionBufferObject, program;
GLint projectionLoc, modelviewLoc, vertexLoc, colorLoc;
float zNear = 0.1f, zFar = 100.0f;
float projection[16], modelview[16];

const Vertex vertices[] =
{
    Vertex(
                Vector4f(0.25f,  0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 0.0f, 1.0f, 1.0f)),
        Vertex(
                Vector4f(0.25f,  -0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 0.0f, 1.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f,  0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 0.0f, 1.0f, 1.0f)),

        Vertex(
                Vector4f(0.25f,  -0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 0.0f, 1.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f,  -0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 0.0f, 1.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f,  0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 0.0f, 1.0f, 1.0f)),

        Vertex(
                Vector4f(0.25f, 0.25f, -0.25f, 1.0f),
                ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, 0.25f, -0.25f, 1.0f),
                ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)),
        Vertex(
                Vector4f(0.25f, -0.25f, -0.25f, 1.0f),
                ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)),

        Vertex(
                Vector4f(0.25f, -0.25f, -0.25f, 1.0f),
                ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, 0.25f, -0.25f, 1.0f),
                ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, -0.25f, -0.25f, 1.0f),
                ColorRGBA(0.8f, 0.8f, 0.8f, 1.0f)),

        Vertex(
                Vector4f(-0.25f, 0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, -0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, -0.25f, -0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 0.0f, 1.0f)),

        Vertex(
                Vector4f(-0.25f, 0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, -0.25f, -0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, 0.25f, -0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 0.0f, 1.0f)),

        Vertex(
                Vector4f(0.25f,  0.25f, 0.25f, 1.0f),
                ColorRGBA(0.5f, 0.5f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(0.25f, -0.25f, -0.25f, 1.0f),
                ColorRGBA(0.5f, 0.5f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(0.25f, -0.25f, 0.25f, 1.0f),
                ColorRGBA(0.5f, 0.5f, 0.0f, 1.0f)),

        Vertex(
                Vector4f(0.25f, 0.25f, 0.25f, 1.0f),
                ColorRGBA(0.5f, 0.5f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(0.25f, 0.25f, -0.25f, 1.0f),
                ColorRGBA(0.5f, 0.5f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(0.25f, -0.25f, -0.25f, 1.0f),
                ColorRGBA(0.5f, 0.5f, 0.0f, 1.0f)),

        Vertex(
                Vector4f(0.25f, 0.25f, -0.25f, 1.0f),
                ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(0.25f,  0.25f, 0.25f, 1.0f),
                ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, 0.25f, 0.25f, 1.0f),
                ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f)),

        Vertex(
                Vector4f(0.25f, 0.25f, -0.25f, 1.0f),
                ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, 0.25f, 0.25f, 1.0f),
                ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, 0.25f, -0.25f, 1.0f),
                ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f)),

        Vertex(
                Vector4f(0.25f, -0.25f, -0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 1.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, -0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 1.0f, 1.0f)),
        Vertex(
                Vector4f(0.25f, -0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 1.0f, 1.0f)),

        Vertex(
                Vector4f(0.25f, -0.25f, -0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 1.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, -0.25f, -0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 1.0f, 1.0f)),
        Vertex(
                Vector4f(-0.25f, -0.25f, 0.25f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 1.0f, 1.0f)),

        Vertex(
                Vector4f(-1.0f, 0, -1.0f, 1.0f),
                ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(0.0f, 1.0, -1.0f, 1.0f),
                ColorRGBA(0.0f, 1.0f, 0.0f, 1.0f)),
        Vertex(
                Vector4f(1.0f, 0, -1.0f, 1.0f),
                ColorRGBA(0.0f, 0.0f, 1.0f, 1.0f))
};

const float vertexData[] =
{
     0.0f,    0.5f, 0.0f, 1.0f,
     0.5f, -0.366f, 0.0f, 1.0f,
    -0.5f, -0.366f, 0.0f, 1.0f,
     1.0f,    0.0f, 0.0f, 1.0f,
     0.0f,    1.0f, 0.0f, 1.0f,
     0.0f,    0.0f, 1.0f, 1.0f,
};

std::string strVertexShader = "simple.vert";

std::string strFragmentShader = "simple.frag";

void init();

void display();

void resize(int w, int h);

void InitializeProgram();

void InitializeVertexBuffer();

void InitializeGlutCallbacks();

void Perspective(float *a, float fov, float aspect, float zNear, float zFar);

void Modelview(float *mv, float scale, float xOff, float yOff, float zOff);

void ComputePositionOffsets(float &fXOffset, float &fYOffset, float &fZOffset, float &scale);

void PrintMat4(float *mat);

main.cpp

#include "main.h"

int main(int argc, char **argv)
{
    glutInit(&argc, argv);

        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
        glutInitWindowSize(640, 480);
        glutInitWindowPosition(100, 100);
        glutCreateWindow("Test");

        GLenum res = glewInit();
        if(res != GLEW_OK)
        {
                fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res));
                return -1;
        }

        init();

        glutMainLoop();

        return 0;
}

void display()
{
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        float fXOffset = 0.0f, fYOffset = 0.0f, fZOffset = 0.0f, scale = 0.0f;
        ComputePositionOffsets(fXOffset, fYOffset, fZOffset, scale);

        Modelview(modelview, scale, fXOffset, fYOffset, -2.0f + fZOffset);

        glUseProgram(program);

        glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, &projection[0]);
        glUniformMatrix4fv(modelviewLoc, 1, GL_FALSE, &modelview[0]);

        glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);

        glEnableVertexAttribArray(vertexLoc);
        glEnableVertexAttribArray(colorLoc);

        glVertexAttribPointer(vertexLoc, sizeof(Vector4f)/sizeof(float), GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
        glVertexAttribPointer(colorLoc, sizeof(ColorRGBA)/sizeof(float), GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof(Vertex)/2));

        glDrawArrays(GL_TRIANGLES, 0, sizeof(vertices)/sizeof(Vertex));

        glDisableVertexAttribArray(vertexLoc);
        glDisableVertexAttribArray(colorLoc);

        glUseProgram(0);

        glutSwapBuffers();
        glutPostRedisplay();
}

void resize(int w, int h)
{
        glViewport(0, 0, w, h);
        Perspective(projection, 90.0f, float(w)/float(h), zNear, zFar);
        PrintMat4(projection);
}

void InitializeProgram()
{
        std::vector<GLuint> shaderList;

        shaderList.push_back(CreateShader(GL_VERTEX_SHADER, strVertexShader));
        shaderList.push_back(CreateShader(GL_FRAGMENT_SHADER, strFragmentShader));

        program = CreateProgram(shaderList);

        vertexLoc = glGetAttribLocation(program, "vertex_position");
        colorLoc = glGetAttribLocation(program, "vertex_color");

        modelviewLoc = glGetUniformLocation(program, "modelview");
        projectionLoc = glGetUniformLocation(program, "projection");

        std::for_each(shaderList.begin(), shaderList.end(), glDeleteShader);
}

void InitializeVertexBuffer()
{
        glGenBuffers(1, &positionBufferObject);

        glBindBuffer(GL_ARRAY_BUFFER, positionBufferObject);
        glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void InitializeGlutCallbacks()
{
        glutDisplayFunc(display);
        glutReshapeFunc(resize);
}

void init()
{
        InitializeProgram();
        InitializeVertexBuffer();

        InitializeGlutCallbacks();

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

        glEnable(GL_DEPTH_TEST);
}

void Perspective(float *a, float fov, float aspect, float zNear, float zFar)
{
        for(int i = 0; i < 16; i++)
                a[i] = 0.0f;

        float f = 1.0f/float(tan(fov / 2.0f * (M_PI / 180.0f)));

        a[0 + 4 * 0] = f / aspect;
        a[1 + 4 * 1] = f;
        a[2 + 4 * 2] = (zNear + zFar) / (zNear - zFar);
        a[2 + 4 * 3] = 2.0f * zNear *+ zFar / (zNear - zFar);
        a[3 + 4 * 2] = -1.0f;
}

void Modelview(float *mv, float scale, float xOff, float yOff, float zOff)
{
        for(int i = 0; i < 16; i++)
                mv[i] = 0.0f;

        mv[0 + 4 * 0] = scale;
        mv[0 + 4 * 3] = xOff;
        mv[1 + 4 * 1] = scale;
        mv[1 + 4 * 3] = yOff;
        mv[2 + 4 * 2] = scale;
        mv[2 + 4 * 3] = zOff;
        mv[3 + 4 * 3] = 1.0f;
}

void ComputePositionOffsets(float &fXOffset, float &fYOffset, float &fZOffset, float &scale)
{
        float elapsedTime = glutGet(GLUT_ELAPSED_TIME) / 1000.0f;
        float timeScale = 3.14159f * 2.0f;

        float xLoopDuration = 8.0f;
        float yLoopDuration = 3.0f;
        float zLoopDuration = 2.0f;
        float scaleLoopDuration = 10.0f;
        float xLoopProgress = fmodf(elapsedTime, xLoopDuration) / xLoopDuration;
        float yLoopProgress = fmodf(elapsedTime, yLoopDuration) / yLoopDuration;
        float zLoopProgress = fmodf(elapsedTime, zLoopDuration) / zLoopDuration;
        float scaleLoopProgress = fmodf(elapsedTime, scaleLoopDuration) /scaleLoopDuration;

        fXOffset = sinf(xLoopProgress * timeScale) * 0.5f;
        fYOffset = sinf(yLoopProgress * timeScale) * 0.5f;
        fZOffset = sinf(zLoopProgress * timeScale) * 0.5f;
        scale = 1/(1 + sinf(scaleLoopProgress * timeScale) * 0.5f);
}

void PrintMat4(float *mat)
{
        for(int i = 0; i < 4; i++)
        {
                for(int j = 0; j < 4; j++)
                {
                        std::cout << mat[j * 4 + i] << "\t";
                }
                std::cout << std::endl;
        }
        std::cout << std::endl;
}
genpfault
  • 51,148
  • 11
  • 85
  • 139
Horstinator
  • 548
  • 1
  • 5
  • 18
  • 1
    It's possible that your code is correct, and that you just need to modify your `zNear` and `zFar` values. Or, if your eye point is at the origin, try moving it along the +z axis. – Pat Lillis Jul 02 '13 at 14:11
  • 1
    Check out the glm library, it has it (and much more) done already. – Bartek Banachewicz Jul 02 '13 at 14:12
  • 2
    @BartekBanachewicz i will use a library or engine in the future, but i think its important to understand the basics so i try to get them working. – Horstinator Jul 02 '13 at 14:26
  • 1
    @Horstinator nice thinking. GLM is opensource, though, so shall you get stuck, you can read its code. Good luck! – Bartek Banachewicz Jul 02 '13 at 14:31
  • I might be wrong, but shouldn't the vertex shader calculate `gl_Position = proj_matrix * mv_matrix * position;`? Atleast that's how my book does it and it seems logical. First move your vertex (`position`) to world coordinates, then apply the projection matrix. – skiwi Jan 17 '14 at 11:46

3 Answers3

1

A few things:

First, you seem to be setting the "eye" of your projection matrix at [0, 0 -1], pushing your "camera" towards the back of your screen. If this is the case, it's only normal that you have to move your objects beyond that point to have them appear.

The culprit line is (I think, your variable names aren't particularily clear :-/):

a[3 + 4 * 2] = -1.0f;

I'd try and change it to

a[3 + 4 * 2] = 1.0f;

and see if that makes a difference.

Second, depending on what you're rendering, your "camera" might just happen to be inside your mesh. Since you have backface culling enabled, you would see absolutely nothing because all visible faces are culled and moving your model further away would put un-culled faces in view. To see if this is the issue, change the line

glEnable(GL_CULL_FACE);

to

glDisable(GL_CULL_FACE);

and see if your "camera" is inside your mesh.

Third, your mesh might be between your "camera" and your near plane. Trying playing with zNear and see if it makes a difference. zFar is probably correct as your objects appear when you move them away.

EDIT: So I looked into it in more detail and tried to figure out your projection matrix. According to this great explaination of the math behind perspective projections, your projection matrix generation code seems correct to generate a matrix that looks down -Z. Basically, your code works as expected, since OpenGL, by default, uses a right-handed coordinate system.

If you want to be able to offset your objects in +Z because the negative values annoy you, you can create a View matrix that performs a 180 degrees rotation around the Y axis and multiply it with your projection matrix. You'd then get

finalCoordinates = projection * view * model * vertex;

TL;DR: your code works as expected.

anthonyvd
  • 7,329
  • 4
  • 30
  • 51
  • Hi, and thanks for the answer. when i edit the projection matrix to a positive value i dont see anything at all. i tried moving my cube around different values of the Z-axis without any effect. With the original -1 i can see it with negativ Z-offsets and the inside without any offsets. i dont think that my zNear and zFar values are responsible for the behaviour, since they have a very wie range, but i will try changing them, too. – Horstinator Jul 02 '13 at 14:33
  • @Horstinator I added some more info to my answer. Let us know when you get your code working as you want it to :) – anthonyvd Jul 02 '13 at 15:19
  • Okay, the solution where i rotate the object works, but i just removed since i think i can life with the negative z-axis... – Horstinator Jul 03 '13 at 12:02
  • @Horstinator Cool! Good luck on your endeavor :) – anthonyvd Jul 03 '13 at 13:36
  • Thanks =) i managed to get my camera properly working, i think i can proceed to lighning and textures now... – Horstinator Jul 03 '13 at 22:43
  • @Horstinator Good luck :-) don't forget to amrk the most relevant answer to your question as accepted! – anthonyvd Jul 04 '13 at 02:04
0

I didn't check on your code but here's one simple answer: As OpenGL uses a so called right-handed coordinate system, negative z-values indicate the direction "into" the screen whereas a positive z-value means "out of the screen" (ie. use your right hand, point you thumb to the right -> positive x axis. Your first finger points up, right angle to your thumb -> positive y-axis. And last but not least: your middlefinger, right-angled to your first finger and your thump, points towards you -> positive z-axis!)

insaneivan
  • 93
  • 1
  • 7
0

I found this website very useful:

http://www.scratchapixel.com/lessons/3d-advanced-lessons/perspective-and-orthographic-projection-matrix/opengl-perspective-projection-matrix/

It explains the topic you are interested in very well.

user18490
  • 3,546
  • 4
  • 33
  • 52