在 OpenGL 4.0 中绘制球体
Posted
技术标签:
【中文标题】在 OpenGL 4.0 中绘制球体【英文标题】:draw sphere in OpenGL 4.0 【发布时间】:2017-03-29 07:56:29 【问题描述】:我的 OpenGL 版本是 4.0。我想通过纬度和经度画一个球体。我用这个方法:
x=ρsinϕcosθ
y=ρsinϕsinθ
z=ρcosϕ
这是我的代码的一部分:
glm::vec3 buffer[1000];
glm::vec3 outer;
buffercount = 1000;
float section = 10.0f;
GLfloat alpha, beta;
int index = 0;
for (alpha = 0.0 ; alpha <= PI; alpha += PI/section)
for (beta = 0.0 ; beta <= 2* PI; beta += PI/section)
outer.x = radius*cos(beta)*sin(alpha);
outer.y = radius*sin(beta)*sin(alpha);
outer.z = radius*cos(alpha);
buffer[index] = outer;
index = index +1;
GLuint sphereVBO, sphereVAO;
glGenVertexArrays(1, &sphereVAO);
glGenBuffers(1,&sphereVBO);
glBindVertexArray(sphereVAO);
glBindBuffer(GL_ARRAY_BUFFER,sphereVBO);
glBufferData(GL_ARRAY_BUFFER,sizeof(glm::vec3) *buffercount ,&buffer[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
...
while (!glfwWindowShouldClose(window))
...
...
for (GLuint i = 0; i < buffercount; i++)
...
...
glm::mat4 model;
model = glm::translate(model, buffer[i]);
GLfloat angle = 10.0f * i;
model = glm::rotate(model, angle, glm::vec3(1.0f, 0.3f, 0.5f));
glUniformMatrix4fv(modelMat, 1, GL_FALSE, glm::value_ptr(model));
glDrawArrays(GL_TRIANGLE_FAN, 0, 900);
glfwSwapBuffers(window);
如果section = 5,表现是这样的:
如果section = 20。表现是这样的:
我认为我的代码中可能存在逻辑问题。我在这个问题上挣扎...
-----更新-----
我编辑了我的代码,它没有任何错误,但我得到了一个空白屏幕。我猜我的顶点着色器出了点问题。我可能会将错误的变量传递给顶点脱落器。请帮我。
gluperspective
在我的 OpenGL 4.1 中已弃用
我切换到:
float aspect=float(4.0f)/float(3.0f);
glm::mat4 projection_matrix = glm::perspective(60.0f/aspect,aspect,0.1f,100.0f);
它表明这个错误:常量表达式的计算结果为 -1,不能缩小到类型 'GLuint'(aka 'unsigned int')
GLuint sphere_vbo[4]=-1,-1,-1,-1;
GLuint sphere_vao[4]=-1,-1,-1,-1;
我不知道如何修改它...我切换到:
GLuint sphere_vbo[4]=1,1,1,1;
GLuint sphere_vao[4]=1,1,1,1;
我把Spektre的代码放在spherer.h
文件里
这是我的 main.cpp 文件的一部分:
...
...
Shader shader("basic.vert", "basic.frag");
sphere_init();
while (!glfwWindowShouldClose(window))
glfwPollEvents();
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
shader.Use();
GLuint MatrixID = glGetUniformLocation(shader.Program, "MVP");
GLfloat radius = 10.0f;
GLfloat camX = sin(glfwGetTime()) * radius;
GLfloat camZ = cos(glfwGetTime()) * radius;
// view matrix
glm::mat4 view;
view = glm::lookAt(glm::vec3(camX, 0.0, camZ), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
glm::mat4 view_matrix = view;
// projection matrix
float aspect=float(4.0f)/float(3.0f);
glm::mat4 projection_matrix = glm::perspective(60.0f/aspect,aspect,0.1f,100.0f);
// model matrix
glm::mat4 model_matrix = glm::mat4(1.0f);// identity
//ModelViewProjection
glm::mat4 model_view_projection = projection_matrix * view_matrix * model_matrix;
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &model_view_projection[0][0]);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-10.0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
sphere_draw();
glFlush();
glfwSwapBuffers(window);
sphere_exit();
glfwTerminate();
return 0;
这是我的顶点着色器文件:
#version 410 core
uniform mat4 MVP;
layout(location = 0) in vec3 vertexPosition_modelspace;
out vec4 vertexColor;
void main()
gl_Position = MVP * vec4(vertexPosition_modelspace,1);
vertexColor = vec4(0, 1, 0, 1.0);
我在我的 shader.h 文件中添加了错误检查功能 get_log
。
...
...
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
checkCompileErrors(vertex, "VERTEX");
get_log(vertex);
...
...
void get_log(GLuint shader)
GLint isCompiled = 0;
GLchar infoLog[1024];
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE)
printf("----error--- \n");
GLint maxLength = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength);
glGetShaderInfoLog(shader, 1024, NULL, infoLog);
std::cout << "| ERROR::::" << &infoLog << "\n| -- ------------------ --------------------------------- -- |" << std::endl;
glDeleteShader(shader); // Don't leak the shader.
else
printf("---no error --- \n");
我测试了片段着色器和顶点着色器,都显示---没有错误---
【问题讨论】:
这看起来是对的,你的观点是正确的。只是你没有画出球体的表面,而是一个圆锥形螺旋线或一组在北极点的圆锥体填充了球体.问题是,buffer
是如何变成网格的?
我非常怀疑您是否可以绘制球形三角形扇形。由于每个三角形都包含北极顶点,因此这仅适用于第一个“环”,而不适用于所有其他“环”。
请查看***.com/q/5988686/3088138 以了解生成球体的 C++ 方式或将您的语言更改为 [C]。另请参阅***.com/a/8044252/3088138,了解GL_TRIANGLE_FAN
如何解释缓冲区数据,从而为您提供所见即所得的信息。
在每一层上使用 TRIANGLE_FAN ...它需要设置索引缓冲区来索引哪些点与三角形相连。执行此操作还有另一种选择:sphere triangulation by subdivision 或 Applying map of the earth texture a Sphere。此外,如果您渲染线框,您会更好地了解发生了什么,因为您不使用灯光和法线 ....
嗨@LutzL,谢谢你的建议。看起来glDrawElemen ts(GL_QUADS..
GL_QUADS 不支持我的 openGL 版本(我的版本是 4.1)。
【参考方案1】:
正如我在 cmets 中提到的,您需要向网格 VAO/VBO 添加索引。不知道为什么GL_QUADS
没有在您的机器上实现,这没有意义,因为它是基本的原语,所以为了使这个易于处理,我只使用GL_TRIANGLES
,这远非理想,但到底是什么......试试这个:
//---------------------------------------------------------------------------
const int na=36; // vertex grid size
const int nb=18;
const int na3=na*3; // line in grid size
const int nn=nb*na3; // whole grid size
GLfloat sphere_pos[nn]; // vertex
GLfloat sphere_nor[nn]; // normal
//GLfloat sphere_col[nn]; // color
GLuint sphere_ix [na*(nb-1)*6]; // indices
GLuint sphere_vbo[4]=-1,-1,-1,-1;
GLuint sphere_vao[4]=-1,-1,-1,-1;
void sphere_init()
// generate the sphere data
GLfloat x,y,z,a,b,da,db,r=3.5;
int ia,ib,ix,iy;
da=2.0*M_PI/GLfloat(na);
db= M_PI/GLfloat(nb-1);
// [Generate sphere point data]
// spherical angles a,b covering whole sphere surface
for (ix=0,b=-0.5*M_PI,ib=0;ib<nb;ib++,b+=db)
for (a=0.0,ia=0;ia<na;ia++,a+=da,ix+=3)
// unit sphere
x=cos(b)*cos(a);
y=cos(b)*sin(a);
z=sin(b);
sphere_pos[ix+0]=x*r;
sphere_pos[ix+1]=y*r;
sphere_pos[ix+2]=z*r;
sphere_nor[ix+0]=x;
sphere_nor[ix+1]=y;
sphere_nor[ix+2]=z;
// [Generate GL_TRIANGLE indices]
for (ix=0,iy=0,ib=1;ib<nb;ib++)
for (ia=1;ia<na;ia++,iy++)
// first half of QUAD
sphere_ix[ix]=iy; ix++;
sphere_ix[ix]=iy+1; ix++;
sphere_ix[ix]=iy+na; ix++;
// second half of QUAD
sphere_ix[ix]=iy+na; ix++;
sphere_ix[ix]=iy+1; ix++;
sphere_ix[ix]=iy+na+1; ix++;
// first half of QUAD
sphere_ix[ix]=iy; ix++;
sphere_ix[ix]=iy+1-na; ix++;
sphere_ix[ix]=iy+na; ix++;
// second half of QUAD
sphere_ix[ix]=iy+na; ix++;
sphere_ix[ix]=iy-na+1; ix++;
sphere_ix[ix]=iy+1; ix++;
iy++;
// [VAO/VBO stuff]
GLuint i;
glGenVertexArrays(4,sphere_vao);
glGenBuffers(4,sphere_vbo);
glBindVertexArray(sphere_vao[0]);
i=0; // vertex
glBindBuffer(GL_ARRAY_BUFFER,sphere_vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sizeof(sphere_pos),sphere_pos,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
i=1; // indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,sphere_vbo[i]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof(sphere_ix),sphere_ix,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,4,GL_UNSIGNED_INT,GL_FALSE,0,0);
i=2; // normal
glBindBuffer(GL_ARRAY_BUFFER,sphere_vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sizeof(sphere_nor),sphere_nor,GL_STATIC_DRAW);
glEnableVertexAttribArray(i);
glVertexAttribPointer(i,3,GL_FLOAT,GL_FALSE,0,0);
/*
i=3; // color
glBindBuffer(GL_ARRAY_BUFFER,sphere_vbo[i]);
glBufferData(GL_ARRAY_BUFFER,sizeof(sphere_col),sphere_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 sphere_exit()
glDeleteVertexArrays(4,sphere_vao);
glDeleteBuffers(4,sphere_vbo);
void sphere_draw()
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glBindVertexArray(sphere_vao[0]);
// glDrawArrays(GL_POINTS,0,sizeof(sphere_pos)/sizeof(GLfloat)); // POINTS ... no indices for debug
glDrawElements(GL_TRIANGLES,sizeof(sphere_ix)/sizeof(GLuint),GL_UNSIGNED_INT,0); // indices (choose just one line not both !!!)
glBindVertexArray(0);
void gl_draw()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float aspect=float(xs)/float(ys);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.0/aspect,aspect,0.1,100.0);
glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0,0.0,-10.0);
glEnable(GL_DEPTH_TEST);
glDisable(GL_TEXTURE_2D);
sphere_draw();
glFlush();
SwapBuffers(hdc);
//---------------------------------------------------------------------------
在创建 OpenGL 上下文并加载扩展程序调用 sphere_init()
之后,在关闭应用调用 sphere_exit()
之前使用很简单(当 OpenGL 上下文仍在运行时)以及当您想要渲染呼叫sphere_draw()
。我用一些设置做了一个gl_draw()
示例,这里是它的预览:
重点是创建覆盖整个球体表面的 2D 点网格(通过球面长,纬度 a,b
角度),然后创建覆盖整个网格的三角形...
【讨论】:
嗨@spektre,我没有任何错误,但我得到了一个空白屏幕。我在我的问题中更新了我的代码,你能帮我看看吗?谢谢。 @Whatlahuhu 我认为这vertexColor = vec4(0, 1, 0, 1.0);
是你的问题尝试vertexColor = vec4(0.0, 1.0, 0.0, 1.0);
因为在GLSL 中禁止从int 自动转换为float,至少在我弄脏的实现中是禁止的。您应该始终检查 GLSL 编译和链接日志,如下所示:How to debug GLSL Fragment shader 特别是查找 glGetShaderInfoLog
用法
我仍然有一个空白屏幕。我正在尝试使用glGetShaderInfoLog
。
@Whatlahuhu 我试过你的顶点,它看起来不错(所以他们一定已经用新的驱动程序改变了自动转换。唯一剩下的是错误的矩阵或片段着色器或 VBO 绑定。确保你的 VBO 与位置绑定到位置0
(与着色器中相同)并尝试在关闭CULL FACE的情况下开始使用单位矩阵。如果渲染应该覆盖整个屏幕然后添加CULL FACE如果渲染添加投影并在相机之前平移矩阵并且仅然后添加其他内容,例如从欧拉角度查看
@Whatlahuhu 试试#version 410 core layout(location = 0) in vec3 vertexPosition_modelspace; out vec4 vertexColor; void main() gl_Position = vec4(vertexPosition_modelspace,1.0); vertexColor = vec4(0, 1, 0, 1.0);
我这边正在渲染,所以要么你遇到片段问题,要么矩阵错误或矩阵顺序......因为我不使用 GLM 我不知道它使用什么顺序.尝试不同的背景颜色,因为默认片段将在不使用旧样式颜色变量时使用黑色以上是关于在 OpenGL 4.0 中绘制球体的主要内容,如果未能解决你的问题,请参考以下文章