OpenGL:绘制一个立方体

时间:2015-02-25 14:20:24

标签: c++ opengl

我刚开始学习OpenGL,这是我第一个绘制立方体的程序。我在这里迷失了,因为我能够通过在2d中指定矩形的坐标来绘制矩形,但我不能通过指定(x,y,z)格式的坐标来绘制立方体。我在这里缺少什么?

以下是代码:

#include <GL/glew.h>
#include <GL/gl.h>
#include <math.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

// Open an OpenGL window
GLFWwindow* window;

/****Step 1: define vertices in (x, y, z) form****/

// Coordinates to draw a cube
const GLdouble coordinates[8][3] = {
    {-0.5, -0.5, -0.5},
    {0.5, -0.5, -0.5},
    {0.5, -0.5, 0.5},
    {-0.5, -0.5, 0.5},
    {-0.5, 0.5, 0.5},
    {-0.5, 0.5, -0.5},
    {0.5, 0.5, -0.5},
    {0.5, 0.5, 0.5}
};
/************************/


int main( void ) {
    if (!glfwInit()){
        fprintf(stderr, "Failed to initialize GLFW.\n");
        return -1;
    }

    // Create a windowed mode window and its OpenGL context
    window = glfwCreateWindow(700, 500, "Hello World", NULL, NULL);
    if (window == NULL) {
            fprintf(stderr, "glfw failed to create window.\n");
            //glfwTerminate();
            return -1;
            }
    // Make the window's context current
    glfwMakeContextCurrent(window);

    glewInit();
    if (glewInit() != GLEW_OK){
        fprintf(stderr, "Failed to initialize GLEW: %s.\n", glewGetErrorString(glewInit()));
        return -1;
    }
    // 4x anti aliasing
    glfwWindowHint(GLFW_SAMPLES, 4);

    int cube_size = sizeof(coordinates)/sizeof(coordinates[0]);
    /**Step 2: send this cube vertices to OpenGL through a buffer**/
    GLuint vertexBuffer; // Declare vertex buffer
    glGenBuffers(1, &vertexBuffer); // generating 1 buffer, put resulting identifier in this buffer
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, cube_size*12, coordinates, GL_STATIC_DRAW);
    /************************/

    std::cout << sizeof(coordinates)/sizeof(coordinates[0]);

    /**Step 3: Main loop for OpenGL draw the shape**
    /* Main loop */
    do{
        glClearColor(1.0, 0.1, 0.1, .0);
        glClear(GL_COLOR_BUFFER_BIT);

        glEnableVertexAttribArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
        glDrawArrays(GL_LINE_LOOP, 0, cube_size);
        glDisableVertexAttribArray(0);

        // Swap front and back rendering buffers
        glfwSwapBuffers(window);
        //Poll for and process events
        glfwPollEvents();
    } // check if the ESC key was pressed or the window was closed
    while(glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && glfwWindowShouldClose(window) == 0);
    /***********************************************/


    // Close window and terminate GLFW
    glfwDestroyWindow(window);
    glfwTerminate();
    // Exit program
    exit( EXIT_SUCCESS );
}

3 个答案:

答案 0 :(得分:4)

您的程序中存在类型不匹配的情况。在本声明中:

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

你是说OpenGL将你的数据解释为float,但你的坐标点被声明为double。

我建议你在坐标类型声明中将GLdouble更改为GLfloat。

顺便说一句,有了这些点,你就不会得到一个立方体,而只是它的部分草图

答案 1 :(得分:1)

除了其他答案之外......还有更多选择可能出错

  1. 错误的矩阵

    您必须实际查看对象,因此您需要将摄像机的Z轴指向对象(+ Z或-Z ...取决于使用的投影)。如果您使用透视图,那么您的对象必须位于<Znear,Zfar>范围

  2. 您正在传递8个多维数据集

    这还不够,因为立方体有6个边,每个边有4条线...这样就可以通过更多的点。如果你有一个不错的 OpenGL 驱动程序,那么你可以使用索引(元素数组),但是你应该只使用GLuintQuads作为元素数组...因为一些gfx驱动程序有奇点基元和不同数据类型的问题(特别是 ATI 过去......)。如果你有 nVidia 那么你应该没事,但以后要避免以后的兼容性问题......

  3. 启用/停用某些内容

    启用的纹理通常全部用黑色绘制,如果网格不正确或相机在里面,则可以跳过剔除的脸...同时检查glDepthFunc并查看Z方向(或尝试禁用GL_DEPTH_TEST

  4. <强>着色

    您正在使用 VBO / VAO ,但代码中没有任何着色器。如果您不想使用着色器,那么对于 nVidia 兼容的硬件使用default layout locations (但这是不兼容的技巧,不应该用于公共应用...)。使用glVertexPointer,glColorPointer,...代替或编写简单着色器,模拟您需要支持的固定功能。

  5. 我的C ++示例:

    //------------------------------------------------------------------------------
    //--- Open GL VAO example ------------------------------------------------------
    //------------------------------------------------------------------------------
    #ifndef _OpenGL_VAO_example_h
    #define _OpenGL_VAO_example_h
    //------------------------------------------------------------------------------
    GLuint vbo[4]={-1,-1,-1,-1};
    GLuint vao[4]={-1,-1,-1,-1};
    const GLfloat vao_pos[]=
        {
    //  x    y    z
        -1.0,-1.0,-1.0,
        +1.0,-1.0,-1.0,
        +1.0,+1.0,-1.0,
        -1.0,+1.0,-1.0,
        -1.0,-1.0,+1.0,
        +1.0,-1.0,+1.0,
        +1.0,+1.0,+1.0,
        -1.0,+1.0,+1.0,
        };
    
    const GLfloat vao_col[]=
        {
    //  r   g   b
        0.0,0.0,0.0,
        1.0,0.0,0.0,
        1.0,1.0,0.0,
        0.0,1.0,0.0,
        0.0,0.0,1.0,
        1.0,0.0,1.0,
        1.0,1.0,1.0,
        0.0,1.0,1.0,
        };
    
    const GLuint vao_ix[]=
        {
        0,1,2,3,
        4,5,6,7,
        0,1,5,4,
        1,2,6,5,
        2,3,7,6,
        3,0,4,7,
        };
    //---------------------------------------------------------------------------
    void vao_init()
        {
        GLuint i;
        glGenVertexArrays(4,vao);
        glGenBuffers(4,vbo);
        glBindVertexArray(vao[0]);
        i=0; // vertex
        glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vao_pos),vao_pos,GL_STATIC_DRAW);
        glEnableVertexAttribArray(i);
        glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
        i=1; // indices
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,vbo[i]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(vao_ix),vao_ix,GL_STATIC_DRAW);
        glEnableVertexAttribArray(i);
        glVertexAttribPointer(i,4,GL_UNSIGNED_INT,GL_FALSE,0,0);
        i=2; // normal
        i=3; // color
        glBindBuffer(GL_ARRAY_BUFFER,vbo[i]);
        glBufferData(GL_ARRAY_BUFFER,sizeof(vao_col),vao_col,GL_STATIC_DRAW);
        glEnableVertexAttribArray(i);
        glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
    
        glBindVertexArray(0);
        glBindBuffer(GL_ARRAY_BUFFER,0);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);
    //  glDisableVertexAttribArray(2);
        glDisableVertexAttribArray(3);
        }
    //---------------------------------------------------------------------------
    void vao_exit()
        {
        glDeleteVertexArrays(4,vao);
        glDeleteBuffers(4,vbo);
        }
    //---------------------------------------------------------------------------
    void vao_draw()
        {
        glBindVertexArray(vao[0]);
    //  glDrawArrays(GL_LINE_LOOP,0,8);                 // lines ... no indices
        glDrawElements(GL_QUADS,24,GL_UNSIGNED_INT,0);  // indices (choose just one line not both !!!)
        glBindVertexArray(0);
        }
    //------------------------------------------------------------------------------
    #endif
    //------------------------------------------------------------------------------
    //--- end. ---------------------------------------------------------------------
    //------------------------------------------------------------------------------
    

    这就是它的样子:

    example

    • 左侧涂有glDrawArrays
    • 右侧涂有glDrawElements
    • 在GL初始化(包括扩展名)之后调用vao_init()
    • 在GL销毁之前致电vao_exit()
    • 在绘制循环中调用vao_draw()

    矿井矩阵是这样的:

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60,float(scr.xs)/float(scr.ys),0.1,100.0);
    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0,0.0,-10.0);
    

    其中:

    • scr.xs,scr.ys是GL窗口分辨率
    • modelview正在计时器中旋转以设置立方体动画......
    • znear=0.1zfar=100.0 FOV 角度为60度
    • 立方体在焦点之前是10个单位,因此在znear相机投影平面之前是9.9个单位
    • 立方体大小是2个单位(+/- 1.0)所以它适合在frustrum ...

    绘制电话是这样的:

    glDisable(GL_CULL_FACE);
    glDisable(GL_TEXTURE_2D);
    vao_draw();
    

    <强> [注释]

    在示例中,面没有严格的多边形缠绕,因此不要启用CULL_FACE!还有纹理禁用是必要的(在我的应用程序中)由于我的GL引擎的剩余... 这只是脏的没有着色器现在的例子所以我使用 nVidia的默认布局位置所以在不同的硬件上你还需要着色器...参见项目符号#4

答案 2 :(得分:0)

您的相机似乎位于包装盒内,因此面部会被剔除。尝试将盒子推到更远的z位置。