在OpenGL 4.0中绘制球体 [英] draw sphere in OpenGL 4.0

查看:69
本文介绍了在OpenGL 4.0中绘制球体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的OpenGL版本是4.0.我想通过纬度和经度来画一个球.我使用这种方法:

my OpenGL version is 4.0. I would like to draw a sphere through latitude and longitude. I use this method:

x=ρsinϕcosθ
y=ρsinϕsinθ
z=ρcosϕ

这是我的代码的一部分:

This is a part of my code:

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,则性能如下:

if section = 5, the performance is like this:

如果section = 20,则性能如下:

if section = 20. the performance is like this:

我认为我的代码中可能存在逻辑问题.我在这个问题上挣扎...

I think that I might have logic problem in my code. I am struggle in this problem...

-----更新-----

-----update-----

我编辑了代码,没有任何错误,但是屏幕空白.我猜我的顶点着色器出了点问题.我可能会将错误的变量传递给顶点剪切.请帮我.

I edited my code, It doesn't have any error, but I got a blank screen. I guess that something wrong in my vertex shader. I might pass wrong variables to vertex sheder. Please help me.

gluperspective 在我的OpenGL 4.1中已弃用我切换到:

gluperspective is deprecated in my OpenGL 4.1 I switch to :

float aspect=float(4.0f)/float(3.0f);
glm::mat4 projection_matrix =  glm::perspective(60.0f/aspect,aspect,0.1f,100.0f); 

表明此错误:常量表达式的计算结果为-1,无法将其缩小为类型'GLuint'(又名'unsigned int')

GLuint sphere_vbo[4]={-1,-1,-1,-1};
GLuint sphere_vao[4]={-1,-1,-1,-1};

我不确定如何修改它...我切换到:

I'm not sure how to revise it...I switch to:

GLuint sphere_vbo[4]={1,1,1,1};
GLuint sphere_vao[4]={1,1,1,1};

我将Spektre的代码放入了 spherer.h 文件

I put Spektre's code in spherer.h file

这是我的main.cpp文件的一部分:

This is a part of my main.cpp file:

...
...
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;
} 

这是我的顶点着色器文件:

This is my vertex shader file:

#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 .

I added error-check function get_log in my shader.h file.

...
...
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");
    }

}

我同时测试了片段着色器和顶点着色器,它们都显示---没有错误---

I tested both fragment shader and vertex shader, it both showed ---no error---

推荐答案

正如我在评论中所提到的,您需要向网格 VAO/VBO 中添加索引.不确定为什么 GL_QUADS 没有在您的机器上实现,因为它是基本原语,所以没有意义,因此为了便于处理,我只使用了 GL_TRIANGLES ,这远非理想,到底该怎么做...尝试:

As I mentioned in the comments you need to add indices to your mesh VAO/VBO. Not sure why GL_QUADS is not implemented on your machine that makes no sense as it is basic primitive so to make this easy to handle I use only GL_TRIANGLES which is far from ideal but what to heck ... Try this:

//---------------------------------------------------------------------------
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_exit()之前调用加载<扩展> sphere_init()时,用法很简单(而> OpenGL 上下文仍在运行),并且要渲染时,请调用 sphere_draw().我制作了一个 gl_draw()示例,并进行了一些设置,并在此处进行了预览:

Usage is simple after OpenGL context is created and extensions loaded call sphere_init() before closing app call sphere_exit() (while OpenGL context is still running) and when you want to render call sphere_draw(). I make an gl_draw() example with some settings and here the preview of it:

关键点是创建覆盖球体整个表面的点的 2D 网格(通过球面长,纬度 a,b 角),然后创建覆盖整个网格的三角形...

The point is to create 2D grid of points covering whole surface of sphere (via spherical long,lat a,b angles) and then just create triangles covering whole grid...

这篇关于在OpenGL 4.0中绘制球体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆