使用 SDL2 和 OpenGL 编译一个简单的三角形
Using SDL2 and OpenGL to compile a simple triangle
这个问题已在整个互联网上提出,但我尝试的每个代码示例的结果似乎与我个人为使用 OpenGL 和 SDL2 生成简单三角形而进行的所有尝试的结果相同。在切换到不同的窗口 API 之前,我的好奇心不允许我让这种困境变得简单。
至于我要解决的问题,我只是想弄清楚来源是否是我的系统(考虑到我找到的所有代码示例看起来都很相似并且似乎在 2不同的计算机)或者我自己做错了什么。
我的 PC 在 ubuntu 18.04 上有 GTX 1050m 运行 我的驱动程序是 ubuntu ppa 上的官方 nvidia 驱动程序它能够支持 OpenGL 4.6
这是display.h我用于初始化 SDL2 和 Glew 的头文件
#ifndef DISPLAY_H
#define DISPLAY_H
#include<SDL2/SDL.h>
#include<string>
class Display
{
public:
//initializes SDL2 and Glew
Display( int width, int height, const std::string& title );
//Clears the screen and creates a triangle
void Clear();
//Calls SDL_GL_SwapWindow()
void Update();
//Determines whether or not SDL_QUIT Event is called
bool IsClosed();
//Destroys application
virtual ~Display();
protected:
private:
Display( const Display& other )
void operator=( const Display& other );
SDL_Window* m_window;
SDL_GLContext m_glContext;
bool m_isClosed;
};
#endif //DISPLAY_H
这是display.cpp
//Constructor and Destructor container
#include"display.h"
//Glew container
#include<GL/glew.h>
//Standard I[=11=] lib
#include<cstdio>
//Constructor
Display::Display( int width, int height, const std::string& title )
{
//SDL2 initialization and error check
if( SDL_Init( SDL_INIT_VIDEO ) != 0 ){
printf( "Unable to initialize SDL: %s\n", SDL_GetError() );
SDL_ClearError();
}
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_COMPATIBILITY );
//SDL Create window stored in variable m_window
m_window = SDL_CreateWindow( title.c_str(),
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width,
height,
SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE );
// Error checking window
if( !m_window ) {
fprintf( stderr, "Could not create window: %s\n", SDL_GetError() );
return;
}
//Creates OpenGL context
m_glContext = SDL_GL_CreateContext( m_window );
if ( !m_glContext ){
fprintf( stderr, "Couldn't create context: %s\n", SDL_GetError() );
return;
}
//Makes the open window the current context
SDL_GL_MakeCurrent( m_window, m_glContext );
//Checks How OpenGL handled setting
int rs, gs,bs;
SDL_GL_GetAttribute( SDL_GL_RED_SIZE, &rs );
SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, &gs );
SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, &bs );
printf( "Red size: %d, Green size: %d, Blue size: %d\n", rs, gs, bs );
//To be implemented
//glewExperimental = GL_TRUE;
//initialization of glew
GLenum status = glewInit();
if(GLEW_OK != status ){
printf( "GLEW Error: ", glewGetErrorString( status ) );
}
printf( "Status: Using GLEW: %s\n", glewGetString( GLEW_VERSION ) );
}
//Destructer
Display::~Display()
{
//Deletes GL context
SDL_GL_DeleteContext( m_glContext );
//Close and destroy the window
SDL_DestroyWindow( m_window );
//Clean up
SDL_Quit();
}
void Display::Clear()
{
//Clears the screen
glClear( GL_COLOR_BUFFER_BIT );
//Creating a triangle
glBegin( GL_POLYGON );
glColor3f( 1, 0, 0 );
glVertex3f( -0.6, -0.75, 0.5 );
glColor3f( 0, 1, 0 );
glVertex3f( 0.6, -0.75, 0 );
glColor3f( 0, 0, 1 );
glVertex3f( -0, -0.75, 0 );
glEnd();
glFlush();
}
//Closes the window on SDL_QUIT event
bool Display::IsClosed()
{
return m_isClosed;
}
void Display::Update()
{
SDL_GL_SwapWindow( m_window );
SDL_Event e;
while( SDL_PollEvent( &e ) )
{
if( e.type == SDL_QUIT )
m_isClosed = true;
}
}
最后这是我的简单 main.cpp
#include<GL/glew.h>
#include<iostream>
#include"display.h"
int main( int argc, char* argv[] )
{
Display display( 640, 480, "flagShip" );
while( !display.IsClosed() )
{
display.Clear();
display.Update();
}
return 0;
}
方便的 Makefile
CC=g++
OBJS= main.cpp
LINKER_FLAGS= -lSDL2 -lGL -lGLEW
COMPILER_FLAGS= -w -pedantic
OBJ_NAME=flagShip
$(OBJ_NAME):main.o display.o
$(CC) $(COMPILER_FLAGS) -o $(OBJ_NAME) main.o display.o $(LINKER_FLAGS)
main.o:$(OBJS) display.h
$(CC) $(COMPILER_FLAGS) -c $(OBJS)
display.o: display.cpp display.h
$(CC) $(COMPILER_FLAGS) -c display.cpp
拿一张方格纸,画出你的"triangle"的顶点坐标。你注意到什么了吗?
提示1:你画的三角形面积为零
提示 2:查看最后一次 glVertex 调用的 y 值。
您没有使用任何视图矩阵或投影矩阵。这意味着您必须分别在归一化设备 space.
中设置剪辑 space 中三角形的顶点坐标
归一化设备space是一个立方体,左下近坐标为(-1, -1, -1),右上远坐标为(1, 1, 1 ):
x轴到视口的投影,从左到右,y轴的投影从下到上。
由于三角形的所有 y 坐标都相等,因此三角形垂直于视口:
glVertex3f( -0.6, -0.75, 0.5 );
...
glVertex3f( 0.6, -0.75, 0 );
...
glVertex3f( -0, -0.75, 0 );
交换三角形顶点坐标的y和z分量,问题解决:
glVertex3f( -0.6, 0.5, -0.75 );
...
glVertex3f( 0.6, 0.0, -0.75 );
...
glVertex3f( -0.0, 0.0, -0.75 );
预览:
这个问题已在整个互联网上提出,但我尝试的每个代码示例的结果似乎与我个人为使用 OpenGL 和 SDL2 生成简单三角形而进行的所有尝试的结果相同。在切换到不同的窗口 API 之前,我的好奇心不允许我让这种困境变得简单。
至于我要解决的问题,我只是想弄清楚来源是否是我的系统(考虑到我找到的所有代码示例看起来都很相似并且似乎在 2不同的计算机)或者我自己做错了什么。
我的 PC 在 ubuntu 18.04 上有 GTX 1050m 运行 我的驱动程序是 ubuntu ppa 上的官方 nvidia 驱动程序它能够支持 OpenGL 4.6
这是display.h我用于初始化 SDL2 和 Glew 的头文件
#ifndef DISPLAY_H
#define DISPLAY_H
#include<SDL2/SDL.h>
#include<string>
class Display
{
public:
//initializes SDL2 and Glew
Display( int width, int height, const std::string& title );
//Clears the screen and creates a triangle
void Clear();
//Calls SDL_GL_SwapWindow()
void Update();
//Determines whether or not SDL_QUIT Event is called
bool IsClosed();
//Destroys application
virtual ~Display();
protected:
private:
Display( const Display& other )
void operator=( const Display& other );
SDL_Window* m_window;
SDL_GLContext m_glContext;
bool m_isClosed;
};
#endif //DISPLAY_H
这是display.cpp
//Constructor and Destructor container
#include"display.h"
//Glew container
#include<GL/glew.h>
//Standard I[=11=] lib
#include<cstdio>
//Constructor
Display::Display( int width, int height, const std::string& title )
{
//SDL2 initialization and error check
if( SDL_Init( SDL_INIT_VIDEO ) != 0 ){
printf( "Unable to initialize SDL: %s\n", SDL_GetError() );
SDL_ClearError();
}
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK,
SDL_GL_CONTEXT_PROFILE_COMPATIBILITY );
//SDL Create window stored in variable m_window
m_window = SDL_CreateWindow( title.c_str(),
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
width,
height,
SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE );
// Error checking window
if( !m_window ) {
fprintf( stderr, "Could not create window: %s\n", SDL_GetError() );
return;
}
//Creates OpenGL context
m_glContext = SDL_GL_CreateContext( m_window );
if ( !m_glContext ){
fprintf( stderr, "Couldn't create context: %s\n", SDL_GetError() );
return;
}
//Makes the open window the current context
SDL_GL_MakeCurrent( m_window, m_glContext );
//Checks How OpenGL handled setting
int rs, gs,bs;
SDL_GL_GetAttribute( SDL_GL_RED_SIZE, &rs );
SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, &gs );
SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, &bs );
printf( "Red size: %d, Green size: %d, Blue size: %d\n", rs, gs, bs );
//To be implemented
//glewExperimental = GL_TRUE;
//initialization of glew
GLenum status = glewInit();
if(GLEW_OK != status ){
printf( "GLEW Error: ", glewGetErrorString( status ) );
}
printf( "Status: Using GLEW: %s\n", glewGetString( GLEW_VERSION ) );
}
//Destructer
Display::~Display()
{
//Deletes GL context
SDL_GL_DeleteContext( m_glContext );
//Close and destroy the window
SDL_DestroyWindow( m_window );
//Clean up
SDL_Quit();
}
void Display::Clear()
{
//Clears the screen
glClear( GL_COLOR_BUFFER_BIT );
//Creating a triangle
glBegin( GL_POLYGON );
glColor3f( 1, 0, 0 );
glVertex3f( -0.6, -0.75, 0.5 );
glColor3f( 0, 1, 0 );
glVertex3f( 0.6, -0.75, 0 );
glColor3f( 0, 0, 1 );
glVertex3f( -0, -0.75, 0 );
glEnd();
glFlush();
}
//Closes the window on SDL_QUIT event
bool Display::IsClosed()
{
return m_isClosed;
}
void Display::Update()
{
SDL_GL_SwapWindow( m_window );
SDL_Event e;
while( SDL_PollEvent( &e ) )
{
if( e.type == SDL_QUIT )
m_isClosed = true;
}
}
最后这是我的简单 main.cpp
#include<GL/glew.h>
#include<iostream>
#include"display.h"
int main( int argc, char* argv[] )
{
Display display( 640, 480, "flagShip" );
while( !display.IsClosed() )
{
display.Clear();
display.Update();
}
return 0;
}
方便的 Makefile
CC=g++
OBJS= main.cpp
LINKER_FLAGS= -lSDL2 -lGL -lGLEW
COMPILER_FLAGS= -w -pedantic
OBJ_NAME=flagShip
$(OBJ_NAME):main.o display.o
$(CC) $(COMPILER_FLAGS) -o $(OBJ_NAME) main.o display.o $(LINKER_FLAGS)
main.o:$(OBJS) display.h
$(CC) $(COMPILER_FLAGS) -c $(OBJS)
display.o: display.cpp display.h
$(CC) $(COMPILER_FLAGS) -c display.cpp
拿一张方格纸,画出你的"triangle"的顶点坐标。你注意到什么了吗?
提示1:你画的三角形面积为零
提示 2:查看最后一次 glVertex 调用的 y 值。
您没有使用任何视图矩阵或投影矩阵。这意味着您必须分别在归一化设备 space.
中设置剪辑 space 中三角形的顶点坐标归一化设备space是一个立方体,左下近坐标为(-1, -1, -1),右上远坐标为(1, 1, 1 ):
x轴到视口的投影,从左到右,y轴的投影从下到上。
由于三角形的所有 y 坐标都相等,因此三角形垂直于视口:
glVertex3f( -0.6, -0.75, 0.5 );
...
glVertex3f( 0.6, -0.75, 0 );
...
glVertex3f( -0, -0.75, 0 );
交换三角形顶点坐标的y和z分量,问题解决:
glVertex3f( -0.6, 0.5, -0.75 );
...
glVertex3f( 0.6, 0.0, -0.75 );
...
glVertex3f( -0.0, 0.0, -0.75 );
预览: