OpenGL:绘制立方体
OpenGL: drawing a cube
我刚开始学习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 );
}
您的相机似乎位于框内,因此脸部被剔除。尝试将盒子推到更远的 z 位置。
您的程序类型不匹配。在此声明中:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
您要让 OpenGL 将您的数据解释为浮点数,但您的坐标点被声明为双精度。
我建议您在坐标类型声明处将 GLdouble 更改为 GLfloat。
顺便说一句,有了这些点你不会得到立方体,而只会得到它的部分草图
除了其他的答案...嗯还有更多选项哪里错了
错矩阵
你必须实际看着物体,所以你需要将相机的 Z 轴指向物体(+Z 或 -Z ... 取决于使用的投影)。如果你使用透视那么你的对象必须在 <Znear,Zfar>
范围内
你传递了8点魔方
这还不够,因为立方体有 6 条边,每条边有 4 条线……以这种方式传递的分数要多一些。如果你有一个像样的 OpenGL 驱动程序那么你可以使用索引(元素数组)但是你应该只使用 GLuint
和 Quads
作为元素数组......因为一些 gfx 驱动程序在奇数点基元和不同数据类型方面存在问题(尤其是过去的 ATI...)。如果你有 nVidia 那么你应该没问题,但为了避免以后出现兼容性问题 ...
还有点东西enabled/disabled
启用的纹理通常全部绘制为黑色,如果网格不正确或相机在里面,剔除面可以跳过...还要检查 glDepthFunc
和查看 Z 方向(或尝试禁用 GL_DEPTH_TEST
)
着色器
您正在使用 VBO/VAO 但您的代码中从来没有着色器。如果您不想使用着色器,那么对于 nVidia 兼容硬件,请使用 default layout locations (但这是肮脏的不兼容技巧,不应该用于 public 应用程序...)。请改用 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 window 分辨率
modelview
正在计时器中旋转以使立方体动画...
znear=0.1
, zfar=100.0
, FOV角度为60度
- 立方体在焦点之前 10 个单位,因此在
znear
相机投影平面之前 9.9 个单位
- 立方体大小为 2 个单位 (+/-1.0),因此它适合在平截头体内...
绘制调用是这样的:
glDisable(GL_CULL_FACE);
glDisable(GL_TEXTURE_2D);
vao_draw();
[注释]
在示例中,面没有严格的多边形缠绕,所以不要启用 CULL_FACE
!!!此外,由于我的 GL 引擎遗留问题,纹理禁用是必要的(在我的应用程序中)... 这只是脏的没有着色器的示例 所以我使用了 nVidia 的默认布局positions 所以在不同的 HW 上你也需要着色器......见 bullet #4
我刚开始学习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 );
}
您的相机似乎位于框内,因此脸部被剔除。尝试将盒子推到更远的 z 位置。
您的程序类型不匹配。在此声明中:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
您要让 OpenGL 将您的数据解释为浮点数,但您的坐标点被声明为双精度。
我建议您在坐标类型声明处将 GLdouble 更改为 GLfloat。
顺便说一句,有了这些点你不会得到立方体,而只会得到它的部分草图
除了其他的答案...嗯还有更多选项哪里错了
错矩阵
你必须实际看着物体,所以你需要将相机的 Z 轴指向物体(+Z 或 -Z ... 取决于使用的投影)。如果你使用透视那么你的对象必须在
<Znear,Zfar>
范围内你传递了8点魔方
这还不够,因为立方体有 6 条边,每条边有 4 条线……以这种方式传递的分数要多一些。如果你有一个像样的 OpenGL 驱动程序那么你可以使用索引(元素数组)但是你应该只使用
GLuint
和Quads
作为元素数组......因为一些 gfx 驱动程序在奇数点基元和不同数据类型方面存在问题(尤其是过去的 ATI...)。如果你有 nVidia 那么你应该没问题,但为了避免以后出现兼容性问题 ...还有点东西enabled/disabled
启用的纹理通常全部绘制为黑色,如果网格不正确或相机在里面,剔除面可以跳过...还要检查
glDepthFunc
和查看 Z 方向(或尝试禁用GL_DEPTH_TEST
)着色器
您正在使用 VBO/VAO 但您的代码中从来没有着色器。如果您不想使用着色器,那么对于 nVidia 兼容硬件,请使用 default layout locations (但这是肮脏的不兼容技巧,不应该用于 public 应用程序...)。请改用
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 window 分辨率modelview
正在计时器中旋转以使立方体动画...znear=0.1
,zfar=100.0
, FOV角度为60度- 立方体在焦点之前 10 个单位,因此在
znear
相机投影平面之前 9.9 个单位 - 立方体大小为 2 个单位 (+/-1.0),因此它适合在平截头体内...
绘制调用是这样的:
glDisable(GL_CULL_FACE);
glDisable(GL_TEXTURE_2D);
vao_draw();
[注释]
在示例中,面没有严格的多边形缠绕,所以不要启用 CULL_FACE
!!!此外,由于我的 GL 引擎遗留问题,纹理禁用是必要的(在我的应用程序中)... 这只是脏的没有着色器的示例 所以我使用了 nVidia 的默认布局positions 所以在不同的 HW 上你也需要着色器......见 bullet #4