OpenGL投影矩阵

时间:2013-07-02 14:01:42

标签: opengl projection-matrix

我试图让一个基本的OpenGL程序正常工作。我创建了两个方法来创建一个模型视图矩阵(此时非常简陋,它只在Z轴上移动我的对象)和一个投影矩阵。

我的问题是,据我所知,OpenGL我的投影矩阵应该在屏幕上放置具有正Z坐标的顶点,并在屏幕后面放置具有负坐标的顶点。

但我经历的是,如果我希望它显示,我需要移动我在负z方向绘制的立方体。你能解释一下,为什么会这样?我哪里错了?或者我的代码中有错误吗?

我使用此功能创建我的投影矩阵:

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;
}

这个用于Modelview(我传递不同的偏移量,它们在0左右摆动,z在-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;
}

矩阵都正确传递给opengl,我通过以下方式计算顶点位置:

gl_Position = modelview * projection * vertex_position;

以下是整个代码,如果有人需要它:

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;
}

3 个答案:

答案 0 :(得分:1)

一些事情:

首先,您似乎将投影矩阵的“眼睛”设置为[0,0 -1],将“相机”推向屏幕背面。如果是这种情况,那么您必须移动对象超出该点才能显示它们是正常的。

罪魁祸首是(我认为,你的变量名不是特别清楚: - /):

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

我会尝试将其更改为

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

看看是否有所作为。

其次,根据您正在渲染的内容,您的“相机”可能恰好位于内部您的网格中。由于您启用了背面剔除,因此您将看不到任何内容,因为所有可见面都被剔除并且将模型移动得更远会将未剔除的面部放入视图中。要查看这是否是问题,请更改行

glEnable(GL_CULL_FACE);

glDisable(GL_CULL_FACE);

并查看你的“相机”是否在你的网格中。

第三,您的网格可能位于“相机”和近平面之间。尝试使用zNear,看看它是否有所作为。当你将它们移开时,zFar可能是正确的。

编辑:所以我更详细地研究了它,并试图弄清楚你的投影矩阵。根据这个great explaination of the math behind perspective projections,您的投影矩阵生成代码似乎是正确的,以生成向下看-Z的矩阵。基本上,您的代码按预期工作,因为默认情况下,OpenGL使用右手坐标系。

如果您希望能够在+ Z中偏移对象,因为负值会让您烦恼,您可以创建一个围绕Y轴旋转180度并将其与投影矩阵相乘的View矩阵。然后你得到

finalCoordinates = projection * view * model * vertex;

TL; DR:您的代码按预期工作。

答案 1 :(得分:0)

我没有检查你的代码,但这里有一个简单的答案:由于OpenGL使用所谓的右手坐标系,负z值表示方向“进入”屏幕,而正z值表示“out”屏幕“(即使用你的右手,拇指指向右边 - >正x轴。你的第一根手指指向上方,与拇指成直角 - >正y轴。最后但并非最不重要:你的中指,直角指向你的第一根手指和你的砰砰声,指向你 - >正z轴!)

答案 2 :(得分:0)