【问题标题】:OpenGL: drawing a cubeOpenGL:绘制一个立方体
【发布时间】:2015-02-25 14:20:23
【问题描述】:

我刚开始学习 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 );
}

【问题讨论】:

  • 问题出在哪里?哪一行?
  • 请注意,调用 glfwWindowHint() 不会影响打开的窗口,它们只会影响随后调用 glfwCreateWindow() 的窗口。见:glfw.org/docs/latest/…
  • 实际渲染的是什么?在什么操作系统上使用什么 gfx 硬件?您是否尝试过将透明颜色从黑色更改为其他颜色? (如果启用了没有纹理绑定的纹理,结果颜色通常为黑色)您是否将对象和相机移动到 Z 轴的两侧? (透视矩阵通常在负 Z 轴上查看)

标签: c++ opengl


【解决方案1】:

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

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

您是说 OpenGL 将您的数据解释为浮点数,但您的坐标点被声明为双精度。

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

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

【讨论】:

  • 我认为因为 Z 方向指向屏幕,所以我只能看到一个正方形。但是在我从 glfloat 更改为 gldouble 之后,上面的代码也没有绘制正方形。你能解释一下为什么会这样吗?
  • 因为这里:glBufferData(GL_ARRAY_BUFFER, cube_size*12, coordinates, GL_STATIC_DRAW); 您假设 12 是 3*4,其中 4 是类型的长度。通过 sizeof(coordinates) 更改 cube_size*12 它将起作用
【解决方案2】:

除了其他答案......好吧,还有更多选择是什么问题

  1. 错误的矩阵

    您必须实际查看对象,因此您需要将相机的 Z 轴指向对象(+Z 或 -Z ... 取决于所使用的投影)。如果您使用透视,那么您的对象必须在 &lt;Znear,Zfar&gt; 范围内

  2. 你正在通过 8 个立方体点

    这还不够,因为立方体有 6 个面,每个面有 4 条线……以这种方式通过的点要多一点。如果你有一个不错的 OpenGL 驱动程序,那么你可以使用索引(元素数组),但你应该只使用 GLuintQuads 元素数组......因为一些 gfx 驱动程序有奇怪的问题点原语和不同的数据类型(尤其是过去的ATI...)。如果你有 nVidia 那么你应该没问题,但为了避免以后出现兼容性问题......

  3. 某些东西被启用/禁用

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

  4. 着色器

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

我的 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. ---------------------------------------------------------------------
//------------------------------------------------------------------------------

看起来是这样的:

  • 左侧涂有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.0FOV角度为60度
  • 立方体在焦点之前 10 个单位,所以在znear 相机投影平面之前 9.9 个单位
  • 立方体大小为 2 个单位 (+/-1.0),因此它可以放入截锥体...

Draw 调用是这样的:

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

[备注]

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

【讨论】:

  • 非常感谢!!这给了我一个很好的解释!
【解决方案3】:

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

【讨论】:

  • 你能给我更多的细节吗?我正在使用 GL_PROJECTION 但我不认为我在正确的轨道上,因为我没有看到任何变化......对不起,我很新......
  • 默认禁用剔除进程
  • 我认为他的意思是“剪辑”
猜你喜欢
  • 2020-09-16
  • 1970-01-01
  • 2020-04-15
  • 1970-01-01
  • 1970-01-01
  • 2014-07-25
  • 1970-01-01
  • 2013-05-27
  • 1970-01-01
相关资源
最近更新 更多