OpenGL/GLFW显得透明

vir*_*raj 1 c++ opengl 3d graphics glfw

使用opengl和glfw绘制一个简单的立方体时,立方体的面看起来是透明的.这是代码.使用箭头键旋转.我刚刚在我的程序中封装成了一个类.使用Visual C++ Ultimate 2010.

#include "GAME.h"
using namespace std;
GAME::GAME() 
{
    glfwInit();
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING); 
    glEnable(GL_LIGHT0); 
    glEnable(GL_LIGHT1); 
    glEnable(GL_NORMALIZE); 
}
int GAME::execute() 
{
    glfwOpenWindow(640, 320, 16, 16, 16, 16, 16, 16, GLFW_WINDOW);
    glfwSetWindowTitle("Viraj");
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glfwSetKeyCallback(events);
    running = true;
    while(glfwGetWindowParam(GLFW_OPENED))
    {
        glfwPollEvents();
        loop();
        render();
    }
    return 0;
}
void GAME::events(int key, int action)
{
    switch(key)
    {
    case GLFW_KEY_UP:
        glRotatef(10, 1, 0, 0);
        break;
    case GLFW_KEY_DOWN:
        glRotatef(-10, 1, 0, 0);
        break;
    case GLFW_KEY_RIGHT:
        glRotatef(10, 0, 1, 0);
        break;
    case GLFW_KEY_LEFT:
        glRotatef(-10, 0, 1, 0);
        break;
    }
}
int GAME::loop()
{
    return 0;
}
int GAME::render()
{
    int win_width;
    int win_height;
    glfwGetWindowSize(&win_width, &win_height);
    const float win_aspect = (float)win_width / (float)win_height;
    glViewport(0, 0, win_width, win_height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //glOrtho(-win_aspect, win_aspect, -1., 1., -1., 1.);
    gluPerspective(90, win_aspect, 1, 100.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0, 0, 3.0, 0, 0, 0, 0.0, 1.0, 0.0);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING); 
    glEnable(GL_LIGHT0); 
    glEnable(GL_LIGHT1); 
    glEnable(GL_NORMALIZE); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glBegin(GL_QUADS);
    glRotatef(-1, 0, 1, 0);
    glColor3f(0.0f, 0.0f, 0.0f);
    //Front
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 1.0, 0.0);
    glVertex3f(0.0, 1.0, 0.0);

    glColor3f(1.0f, 0.0f, 0.0f);
    //Left
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(1.0, 1.0, 0.0);

    glColor3f(0.0f, 1.0f, 0.0f);
    //Back
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(0.0, 1.0, -1.0);
    glVertex3f(0.0, 0.0, -1.0);

    glColor3f(0.0f, 0.0f, 1.0f);
    //Right
    glVertex3f(0.0, 0.0, -1.0);
    glVertex3f(0.0, 1.0, -1.0);
    glVertex3f(0.0, 1.0, 0.0);
    glVertex3f(0.0, 0.0, 0.0);

    glColor3f(1.0f, 0.0f, 1.0f);
    //Top
    glVertex3f(0.0, 1.0, -0.0);
    glVertex3f(0.0, 1.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(1.0, 1.0, 0.0);

    glColor3f(1.0f, 1.0f, 0.0f);
    //Bottom
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(0.0, 0.0, -1.0);

    glEnd();
    glfwSwapBuffers();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

dat*_*olf 12

很抱歉告诉你,但你的代码在几个层面上被打破了.让我为你分解一下:

#include "GAME.h"
using namespace std;
GAME::GAME() 
{
    glfwInit();
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING); 
    glEnable(GL_LIGHT0); 
    glEnable(GL_LIGHT1); 
    glEnable(GL_NORMALIZE); 
}
Run Code Online (Sandbox Code Playgroud)

这是第一个错误:GLFW是一个C库,需要初始化一次.调用glfwInit()属于main函数,而不是类构造函数.其他函数调用是OpenGL调用,但是它们需要活动的OpenGL上下文.在程序的这一点上,没有OpenGL上下文,所以你所做的所有调用根本没有效果.

int GAME::execute() 
{
    glfwOpenWindow(640, 320, 16, 16, 16, 16, 16, 16, GLFW_WINDOW);
    glfwSetWindowTitle("Viraj");
    glClearColor(1.0, 1.0, 1.0, 1.0);
Run Code Online (Sandbox Code Playgroud)

再一次,GLFW的性质并不适合用作课程的一部分.GLFW中只能有一个窗口,并且只有一个事件循环.这不能很好地映射到类和对象.你当然可以有一个类EventLoop或类似的,但你不会那样使用它.

然后有下一行,我很惊讶它实际编译:

    glfwSetKeyCallback(events);
Run Code Online (Sandbox Code Playgroud)

events如果是类的成员函数GAME,并且除非这是一个静态成员函数,否则不能使用类成员函数作为回调,尤其不能使用不知道类的C库.应该怎么知道事件函数属于哪个实例?C++没有闭包委托的概念,这是必需的(出于这个原因,其他语言也是如此).

    running = true;
    while(glfwGetWindowParam(GLFW_OPENED))
    {
        glfwPollEvents();
        loop();
        render();
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在出现的是一个经典的新手误解:

void GAME::events(int key, int action)
{
    switch(key)
    {
    case GLFW_KEY_UP:
        glRotatef(10, 1, 0, 0);
        break;
    case GLFW_KEY_DOWN:
        glRotatef(-10, 1, 0, 0);
        break;
    case GLFW_KEY_RIGHT:
        glRotatef(10, 0, 1, 0);
        break;
    case GLFW_KEY_LEFT:
        glRotatef(-10, 0, 1, 0);
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

矩阵操作调用只对绘图代码有意义.在这里调用glRotate只会搞乱矩阵堆栈,但每个理智的OpenGL渲染函数都会初始化所有状态,因此在开始时会有一些理智的值.

您希望在事件处理程序中执行的操作是将所有输入累积到变量中,稍后您可以在绘图代码中使用这些变量来设置和控制渲染.

int GAME::loop()
{
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

如果这是为了循环,为什么没有循环?

int GAME::render()
{
    int win_width;
    int win_height;
    glfwGetWindowSize(&win_width, &win_height);
    const float win_aspect = (float)win_width / (float)win_height;
Run Code Online (Sandbox Code Playgroud)

只缺少一个细节:您需要在此处设置视口.没什么大不了:glViewport(0, 0, win_width, win_height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    //glOrtho(-win_aspect, win_aspect, -1., 1., -1., 1.);
    gluPerspective(90, win_aspect, 1, 100.0);
Run Code Online (Sandbox Code Playgroud)

现在这实际上很好!您可以在渲染功能中设置投影矩阵.要走的路,坚持这种模式!

更新然而下一行错了:

    gluLookAt(0, 0, 3.0, 0, 0, 0, 0.0, 1.0, 0.0);
Run Code Online (Sandbox Code Playgroud)

gluLookAt是一个意味着要在modelview矩阵上执行的函数.模型视图矩阵负责将模型放置在世界空间中并将世界与视图对齐,因此转换是model?world, world?view您可以减少临时world步骤的唯一步骤model?view.

    glMatrixMode(GL_MODELVIEW);
Run Code Online (Sandbox Code Playgroud)

在这里你可以打电话glLoadIdentity(); gluLookAt(...);.现在应该变得明显,为什么在事件处理程序中进行矩阵操作毫无意义.

您应该实际设置模型视图矩阵,所有转换都是从头开始完成的.

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Run Code Online (Sandbox Code Playgroud)

glClear设置矩阵,视口等后调用有点不寻常,但没有错.你可以这样离开.

但是,在开始渲染之前,您应该必须设置所需的所有OpenGL状态.记住那些在构造函数中"初始化"OpenGL调用.他们属于这里.

    glBegin(GL_QUADS);

    glColor3f(0.0f, 0.0f, 0.0f);
    //Front
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 1.0, 0.0);
    glVertex3f(0.0, 1.0, 0.0);

    glColor3f(1.0f, 0.0f, 0.0f);
    //Left
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(1.0, 1.0, 0.0);

    glColor3f(0.0f, 1.0f, 0.0f);
    //Back
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(1.0, 1.0, -1.0);
    glVertex3f(0.0, 1.0, -1.0);
    glVertex3f(0.0, 0.0, -1.0);

    glColor3f(0.0f, 0.0f, 1.0f);
    //Right
    glVertex3f(0.0, 0.0, -1.0);
    glVertex3f(0.0, 1.0, -1.0);
    glVertex3f(0.0, 1.0, 0.0);
    glVertex3f(0.0, 0.0, 0.0);

    glColor3f(1.0f, 0.0f, 1.0f);
    //Top
    glVertex3f(0.0, 0.0, -0.0);
    glVertex3f(0.0, 0.0, -1.0);
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(1.0, 0.0, 0.0);

    glColor3f(1.0f, 1.0f, 0.0f);
    //Bottom
    glVertex3f(0.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, 0.0);
    glVertex3f(1.0, 0.0, -1.0);
    glVertex3f(0.0, 0.0, -1.0);

    glEnd();
Run Code Online (Sandbox Code Playgroud)

如果你想要照明,你需要提供法线.但是我不打算glNormal在那里添加大量的调用:立即模式(glBegin,glEnd)已经过时,我强烈建议你学习顶点数组和顶点缓冲区对象.

    glfwSwapBuffers();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

总结:从课堂上获取GLFW电话.GLFW不是面向对象的.只需从main函数中全局使用它.将事件传递给类是有序的,但是您不能使用类成员函数作为GLFW的回调.你需要编写一些辅助函数

extern GAME *pGame;
void eventhandler(int key, int action)
{
    pGame->event(key, action);
}
Run Code Online (Sandbox Code Playgroud)

您还可以让GAME类管理所有实例的静态列表,并提供静态成员函数,该函数将事件传递给列表中的所有实例.或者使用单身(但我认为单身是反模式,应该避免).