我刚刚学习了透视投影,发现在openGl中应用它有点令人困惑。
考虑一个简单的正方形
在使用透视投影之前,我只需要定义它在[-1,1]空间中顶点的坐标,对于{0.0f,0.0f,0.0.f,1.0f,1.0f,1.0f}的输入,正方形将占据窗口的第一象限
从我的代码中考虑以下部分:
设置矩阵:
glm::mat4 mvp(1.0);
mvp*=glm::perspective(45.0f,1.0f,0.01f,100.0f);
制服:
loc = glGetUniformLocation(program.getHandle(),"mvp");
glUniformMatrix4fv(loc,1,GL_FALSE,glm::value_ptr(mvp));
顶点着色器:
#version 330
in vec2 pos;
uniform mat4 mvp;
void main()
{
gl_Position = mvp*vec4(pos,0.0f,1.0f);
}
但是,结果是一个空白屏幕
我需要在这里应用哪些额外的转换
此外,顶点数据应该在哪个坐标中?
这是完整的代码:
#include "program.h"
#include <GL/glew.h>
#include <SFML/Window.hpp>
#include <stdexcept>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/core/type.hpp>
void GlewInit()
{
GLenum err = glewInit();
if (GLEW_OK != err)
{
std::cerr<<"Error: "<<glewGetErrorString(err)<<std::endl;
throw(std::runtime_error("GLEW_INIT Failure."));
}
}
int main()
{
sf::Window win(sf::VideoMode(400,400),"Manasij");
GlewInit();
float vertexdata[]={0.0f,0.0f,0.0f,1.0f,1.0f,1.0f,1.0f,0.0f};
GLubyte indexdata[]={0,1,2,3};
float colordata[]={0.3f,0.0f,0.5f,1.0f};
mm::Program program
(
{
mm::Shader(GL_VERTEX_SHADER,"vshader.vert"),
mm::Shader(GL_FRAGMENT_SHADER,"fshader.frag")
}
);
glm::mat4 mvp(1.0);
mvp*=glm::perspective(45.0f,1.0f,0.01f,100.0f);
GLuint vao,vbo,ibo;
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
glGenBuffers(1,&vbo);
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glBufferData(GL_ARRAY_BUFFER,8*sizeof(GLfloat),vertexdata,GL_STATIC_DRAW);
glGenBuffers(1,&ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,4*sizeof(GLubyte),indexdata,GL_STATIC_DRAW);
glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,0,0);
glEnableVertexAttribArray(0);
glBindAttribLocation(program.getHandle(),0,"pos");
glUseProgram(program.getHandle());
auto loc = glGetUniformLocation(program.getHandle(),"col");
glUniform4fv(loc,1,colordata);
loc = glGetUniformLocation(program.getHandle(),"mvp");
glUniformMatrix4fv(loc,1,GL_FALSE,glm::value_ptr(mvp));
glUseProgram(0);
glClearColor(1.0f,1.0f,1.0f,1.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
while(win.isOpen())
{
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program.getHandle());
// glDrawArrays(GL_QUADS,0,4);
glDrawElements(GL_QUADS,4,GL_UNSIGNED_BYTE,nullptr);
glUseProgram(0);
win.display();
sf::Event eve;
while(win.pollEvent(eve))
if(eve.type==sf::Event::Closed)
win.close();
}
return 0;
}
但是,结果是一个空白屏幕。我需要在这里应用哪些额外的转换?
您可以看到glm::perspective
调用的最后两个参数,它们定义了近剪辑距离和远剪辑距离。您的正方形位于Z=0处,并且在没有进一步变换的情况下,因此会脱离观察体积。解决方案:在-Z方向上移动seqare几个单位。
注意以下对近值和远值的限制:
-
abs(远)>abs(近)>0
-
sgn(近)=sgn(远)
如果sgn(near)=sgn(far)=-还必须交换深度范围的符号,或者将深度测试功能更改为GL_LESS。
由于深度缓冲区的分辨率不是线性分布的,而是以1/z的方式
- abs(近)应该尽可能大
- 腹肌(远)应该尽可能小
也许这个网站可以帮助你,它解释了OpenGL:中投影矩阵的设置
http://www.songho.ca/opengl/gl_projectionmatrix.html