2013-07-02 294 views
2

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

我的看法是,据我了解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; 
} 

而这其中的模型变换(我通过不同的偏移量,他们在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; 
} 

gl_Position = modelview * projection * vertex_position; 

的矩阵都被正确地传递到OpenGL,我通过计算顶点位置这里是整个代码,如果有人需要它:

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

有可能你的代码是正确的,你只需要修改你的'zNear'和'zFar'值。或者,如果您的视点位于原点,请尝试沿+ z轴移动它。 –

+1

检查glm库,它已经完成了(还有更多)。 –

+2

@BartekBanachewicz我将在未来使用库或引擎,但我认为它对于理解基础知识非常重要,所以我尝试让它们工作。 – Horstinator

回答

1

有几件事情:

首先,你似乎是设置投影矩阵的“眼睛”在[0,0-1]处,将“相机”推向屏幕后方。如果是这种情况,那么你必须移动你的物体超过这个点才能让它们出现,这只是正常的。

罪魁祸首线(我想,你的变量名是不明确particularily: - /):

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偏移您的对象,因为负值会让您恼火,您可以创建一个View矩阵,该矩阵围绕Y轴执行180度旋转并将其与您的投影矩阵相乘。您随后可以获得

finalCoordinates = projection * view * model * vertex; 

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

+0

嗨,谢谢你的回答。 当我编辑投影矩阵到正值,我什么也没有看到。我试着围绕Z轴的不同值移动我的立方体,但没有任何效果。 随着原来的-1我可以看到它与负面Z偏移和内部没有任何偏移量。我不认为我的zNear和zFar值对这个行为负责,因为他们有一个非常好的范围,但是我也会尝试改变它们。 – Horstinator

+0

@Horstinator我添加了一些更多的信息给我的答案。让我们知道,当你得到你的代码工作,因为你想它:) –

+0

好吧,我旋转对象的解决方案的作品,但我只是删除,因为我认为我可以与负Z轴生活... – Horstinator

0

我没有检查你的代码,但这里有一个简单的答案:由于OpenGL使用所谓的右手坐标系,所以负z值表示方向“进入”屏幕,而正z值意味着“屏幕外”(即,用你的右手,指着你的拇指向右 - >正X轴。你的第一根手指指向你的拇指的正确角度 - >正的Y轴。最后但并非最不重要的:你middlefinger,直角,以你的第一个手指和你的捶击,点向你 - >正z轴)