使用 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 ); 

预览: