从一开始(有点):几个月来,我一直在使用固定功能管道、弃用的 OpenGL 功能,如 gluLookAt 和 glTranslate。在意识到我这样做之后,我现在正尝试从翻译开始更正我的代码。我有一个橙色三角形,工作正常。当我实现模型矩阵时,我能够按照我想要的方式移动我的三角形(大部分)。
重点:现在我正在尝试创建 View 矩阵和投影矩阵。我还没有开始投影矩阵。当我将 View 矩阵添加到我的顶点着色器时,我再也看不到我的三角形了。我真的不确定为什么。
我的顶点着色器:
#version 150 core
in vec2 position;
uniform mat4 model;
uniform mat4 view;
void main()
{
gl_Position=view*model*vec4(position, 0.0, 1.0);
}
我的 C++ 代码部分:
glm::mat4 model=glm::mat4(1.f);
model=glm::translate(model,glm::vec3(0.5f,0.7f,0.f));
model=glm::scale(model,glm::vec3(1.f));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"model"),1,GL_FALSE,glm::value_ptr(model));
glm::mat4 view=glm::lookAt(glm::vec3(-1,-1,-1),glm::vec3(0,0,0),glm::vec3(0,0,1));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"view"),1,GL_FALSE,glm::value_ptr(view));
bool runOnce=true;
while(!glfwWindowShouldClose(window)){ //While glfw window is not closed yet
glClearColor(0.1f,0.1f,0.1f,1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//Clear buffers to preset values (Clears the screen each time)
glDrawArrays(GL_TRIANGLES,0,3);//Draw array with _,_,x vertices
if(runOnce){
model=glm::rotate(model,glm::radians(1200.f),glm::vec3(0.f,0.f,1.f));
view=glm::lookAt(
glm::vec3(0.0f, 0.f, 0.f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f)
);
}
runOnce=false;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"model"),1,GL_FALSE,glm::value_ptr(model));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"view"),1,GL_FALSE,glm::value_ptr(view));
glfwSwapBuffers(window);//Swaps buffers (vertex data that is loaded to the screen by the gpu)
glfwPollEvents();//glfwPollEvents, processes only those events (like keypresses) that have already been received and then returns immediately
}
如果我需要添加更多信息,我很乐意这样做。添加投影矩阵并没有解决问题。
我的整个 C++ 代码:
//Load functions from usr/include/
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <vector>
//Main function
int main() {
std::ios_base::sync_with_stdio(false);//Disables the synchronization between the C and C++ standard streams (though mixing C- and C++ style I/O will be a challenge)
std::cin.tie(NULL);//Unties cin from cout for faster cin and cout functions (this does mean that they are off sync but if you are not using cin than it doesnt matter)
if(!glfwInit()) {
//Initialization failed
fprintf(stderr,"Failed to initialize GLFW\n");//Initialization error
return -1;//A -1 returned to the main function indicates a unsuccessful run
}
//Window hints change the way the window works (like settings)
glfwWindowHint(GLFW_SAMPLES,4);//4x antialiasing
//"Major" and "minor" are two components of a single version number, separated by a dot.
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR,3);//Version 3...
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR,3);//.3
//glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT,GL_TRUE);//To make MacOS happy; should not be needed
glfwWindowHint(GLFW_OPENGL_PROFILE,GLFW_OPENGL_CORE_PROFILE);//We don't want the old OpenGL
const GLFWvidmode*mode=glfwGetVideoMode(glfwGetPrimaryMonitor());//Constant (not-changable) GLFWvideomode (variable type) is named "mode", is set to the primary monitor
glfwWindowHint(GLFW_RED_BITS,mode->redBits);
glfwWindowHint(GLFW_GREEN_BITS,mode->greenBits);
glfwWindowHint(GLFW_BLUE_BITS,mode->blueBits);
glfwWindowHint(GLFW_REFRESH_RATE,mode->refreshRate);
GLFWwindow*window=glfwCreateWindow(mode->width,mode->height,"My Title",glfwGetPrimaryMonitor(),NULL);//Create window that is the size of "mode" (constant primary monitor), named "", on the primary monitor
if(window==NULL) { //If glfw window does not exist
fprintf(stderr,"Failed to open GLFW window. If you have an Intel GPU, they are not 3.3 compatible.\n");
glfwTerminate();//End glfw processes
return -1;
}
glfwMakeContextCurrent(window);//Initialize GLEW
glewExperimental=true;//Needed in core profile
if(glewInit()!=GLEW_OK) { //If glew is not okay
fprintf(stderr,"Failed to initialize GLEW\n");
return -1;
}
glViewport(0,0,mode->width,mode->height);
glEnable(GL_DEPTH_TEST);
static const GLfloat g_vertex_buffer_data[]= { //Creates static (only runs once) constant (not-changable) array for VBO data
-1.0f,-1.0f,0.0f, // triangle 1 : begin
-1.0f,-1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, // triangle 1 : end
};
GLuint vao;//Declares variable vbo, GLuint (opengl's unsigned interger)
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
//Upload this vertex data to the graphics card
GLuint vbo;//Declares variable vbo, GLuint (opengl's unsigned interger)
glGenBuffers(1,&vbo);//Generate 1 buffer
glBindBuffer(GL_ARRAY_BUFFER,vbo);//To upload the actual data to the graphics card you first have to make it the active object
glBufferData(GL_ARRAY_BUFFER,sizeof(g_vertex_buffer_data),g_vertex_buffer_data,GL_STATIC_DRAW);//Now that our VBO is active we can copy the vertex data to it
const char*vertexSource=R"glsl(
#version 150 core
in vec2 position;
uniform mat4 model;
uniform mat4 view;
unifrom mat4 project;
void main()
{
gl_Position=project*view*model*vec4(position, 0.0, 1.0);
}
)glsl";
GLuint vertexShader=glCreateShader(GL_VERTEX_SHADER);//Creates shader object
glShaderSource(vertexShader,1,&vertexSource,NULL);//Loads data to shader object
glCompileShader(vertexShader);//Compiles shader object
//Vertex compile error message
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
const char* fragmentSource=R"glsl(
#version 150 core
out vec4 outColor;
void main()
{
outColor = vec4(1.0, 0.5, 0.0, 1.0);
}
)glsl";
//The fragment shader is compiled in exactly the same way
GLuint fragmentShader=glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader,1,&fragmentSource,NULL);
glCompileShader(fragmentShader);
//Fragment compile error message
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if(!success)
{
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
//Combines shaders into one program
GLuint shaderProgram=glCreateProgram();//Create shader program
//Attatch vertex shader and fragment shader to new shader program
glAttachShader(shaderProgram,vertexShader);
glAttachShader(shaderProgram,fragmentShader);
glLinkProgram(shaderProgram);//Links shader program
//Shader program linking error message
GLint linked;
int InfoLogLength;
glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 0) {
std::vector<char> ProgramErrorMessage(InfoLogLength+1);
glGetProgramInfoLog(shaderProgram, InfoLogLength, NULL, &ProgramErrorMessage[0]);
printf("%s\n", &ProgramErrorMessage[0]);
}
//To actually start using the shaders in the program, you just have to call:
glUseProgram(shaderProgram);
//You first need to retrieve a reference to the position input in the vertex shader
GLint posAttrib=glGetAttribLocation(shaderProgram,"position");
glVertexAttribPointer(posAttrib,2,GL_FLOAT,GL_FALSE,0,0);//Specify how the data for that input is retrieved from the array
glEnableVertexAttribArray(posAttrib);
glm::mat4 model=glm::mat4(1.f);
model=glm::translate(model,glm::vec3(0.5f,0.7f,0.f));
model=glm::scale(model,glm::vec3(1.f));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"model"),1,GL_FALSE,glm::value_ptr(model));
glm::mat4 view;//=glm::lookAt(glm::vec3(-1,-1,-1),glm::vec3(0,0,0),glm::vec3(0,0,1));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"view"),1,GL_FALSE,glm::value_ptr(view));
glm::mat4 project = glm::ortho( -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 10.0f );
int prj_loc = glGetUniformLocation(shaderProgram,"project");
glUniformMatrix4fv(prj_loc ,1,GL_FALSE,glm::value_ptr(project));
bool runOnce=true;
while(!glfwWindowShouldClose(window)){ //While glfw window is not closed yet
glClearColor(0.1f,0.1f,0.1f,1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//Clear buffers to preset values (Clears the screen each time)
glDrawArrays(GL_TRIANGLES,0,3);//Draw array with _,_,x vertices
if(runOnce){
model=glm::rotate(model,glm::radians(1200.f),glm::vec3(0.f,0.f,1.f));
view=glm::lookAt(
glm::vec3(0.0f, 0.f, 0.f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 0.0f, 1.0f)
);
}
runOnce=false;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"model"),1,GL_FALSE,glm::value_ptr(model));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"view"),1,GL_FALSE,glm::value_ptr(view));
glfwSwapBuffers(window);//Swaps buffers (vertex data that is loaded to the screen by the gpu)
glfwPollEvents();//glfwPollEvents, processes only those events (like keypresses) that have already been received and then returns immediately
}
glfwTerminate();
return 0;//A 0 returned to the main function indicates a successful run
}
我不确定它是否有帮助,但我在 chromebook 上使用 xfce4 Crouton。
最佳答案
When I add the view matrix to my vertex shader, I cannot see my triangle anymore. I am really not sure why.
您不使用投影矩阵。这意味着剪辑空间等于规范化的设备空间。 NDC 在 [-1, 1] 范围内(对于 x、y 和 z)。所有在 NDC 之外的几何图形都被裁剪。
这会导致您的三角形被远平面剪裁。请注意,由于您没有设置投影矩阵,近平面和远平面分别为 -1 和 1,因为归一化设备空间在 [-1, 1] 范围内。
要解决您的问题,请将投影矩阵添加到顶点着色器:
#version 150 core
in vec2 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 project;
void main()
{
gl_Position = project* view * model * vec4(position, 0.0, 1.0);
}
并设置一个带有自适应远平面的正交投影:
glm::mat4 project = glm::ortho( -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 10.0f );
int prj_loc = glGetUniformLocation(shaderProgram, "project");
glUniformMatrix4fv(prj_loc, 1, GL_FALSE, glm::value_ptr(project));
当然你也可以使用透视投影,就像这样:
glm::mat4 project = glm::perspective( glm::radians(90.0f), 1.0f, 0.1f, 10.0f );
进一步注意, View 矩阵的第二个定义将不起作用,因为眼睛位置和中心位置相等。改成
if(runOnce){
view=glm::lookAt(
glm::vec3(0.0f, 0.0f, 1.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f)
);
}
请注意,由于您的三角形是在 xy 平面中绘制的,因此眼睛位置应该具有 z 分量,因为如果视线在 xy 平面中,那么三角形的投影将只是一条无限细的线。
这意味着您的程序必须看起来像这样:
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model,glm::vec3(0.5f,0.7f,0.f));
model = glm::scale(model,glm::vec3(1.f));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"model"),1,GL_FALSE,glm::value_ptr(model));
glm::mat4 view = glm::lookAt(glm::vec3(-1,-1,-1),glm::vec3(0,0,0),glm::vec3(0,0,1));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"view"),1,GL_FALSE,glm::value_ptr(view));
glm::mat4 project = glm::ortho( -1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 10.0f );
int prj_loc = glGetUniformLocation(shaderProgram,"project");
glUniformMatrix4fv(prj_loc,1,GL_FALSE,glm::value_ptr(project));
bool runOnce=true;
while(!glfwWindowShouldClose(window)){
glClearColor(0.1f,0.1f,0.1f,1.0f);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_TRIANGLES,0,3);
if(runOnce){
model=glm::rotate(model,glm::radians(1200.f),glm::vec3(0.f,0.f,1.f));
view=glm::lookAt(
glm::vec3(0.0f, 0.0f, 1.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f)
);
}
runOnce=false;
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"model"),1,GL_FALSE,glm::value_ptr(model));
glUniformMatrix4fv(glGetUniformLocation(shaderProgram,"view"),1,GL_FALSE,glm::value_ptr(view));
glfwSwapBuffers(window);
glfwPollEvents();
}
还有很多其他问题:
三角形的 2 个坐标相等。改成
static const GLfloat g_vertex_buffer_data[]= {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
你的顶点坐标由 3 个分量组成,所以它必须是:
glVertexAttribPointer(
posAttrib,
3, // <-------- 3 instead of 2
GL_FLOAT,GL_FALSE,0,0);
在顶点着色器中有一个拼写错误,它必须是 uniform
而不是 unifrom
:
uniform mat4 project;
关于c++ - 如何在现代 Opengl 中添加 View 矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49468877/