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

if section = 5, the performance is like this:

enter image description here

if section = 20. the performance is like this:

enter image description here

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 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); 

It shows that this error: constant expression evaluates to -1 which cannot be narrowed to type 'GLuint'(aka '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};

I put Spektre's code in spherer.h file

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

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

Whatlahuhu
  • 19
  • 2
  • 8
  • 1
    This looks about right, your points are correct.It is only that you do not draw the surface of the sphere but a conic spiral or a collection of cones with point at the north pole that fills the sphere. The question is, how is `buffer` transformed into a mesh? – Lutz Lehmann Mar 29 '17 at 08:01
  • I highly doubt that you can draw a sphere shaped triangle fan. Since every triangle will contain the north-pole vertex, this will only work for the first "ring" but not for all others. – BDL Mar 29 '17 at 08:48
  • Please check http://stackoverflow.com/q/5988686/3088138 for a C++ way to generate the sphere or change your language to [C]. See also http://stackoverflow.com/a/8044252/3088138 for an explanation on how `GL_TRIANGLE_FAN` interprets the buffer data, giving you exactly what you see. – Lutz Lehmann Mar 29 '17 at 08:52
  • Use TRIANGLE_FAN on each layer ... it will require to set up indices buffer to index which points are connected with triangles. Thre are also another option to do this see: [sphere triangulation by subdivision](http://stackoverflow.com/a/29139125/2521214) or [Applying map of the earth texture a Sphere](http://stackoverflow.com/a/31804515/2521214). Also if you render wireframe you would better see what is happening since you do not use light and normals .... – Spektre Mar 29 '17 at 12:03
  • 1
    Hi @LutzL, thank you for your suggestion. Looks like `glDrawElemen ts(GL_QUADS..` the **GL_QUADS** isn't supported my openGL version(my version is 4.1). – Whatlahuhu Mar 30 '17 at 06:53
  • Hi @Spektre, thank you for your suggestion and explanation. Some of functions such as glBegin are deprecated. I feel so sad and frustrated – Whatlahuhu Mar 30 '17 at 07:15
  • @Whatlahuhu does not matter if you are using VBO or glVertex calls the points and their order are the same ... the difference is in the speed (VBO are faster) – Spektre Mar 30 '17 at 07:20
  • You can subdivide each quad into two triangles. In the long format, `GL_TRIANGLES`, this gives 6 vertices or 6 indices per quad instead of the 4 previously. I think you can also chain the triangles horizontally and vertically using `GL_TRIANGLE_STRIP` for even faster performance. Use the variant with index arrays, they are almost certainly more memory efficient than the versions with repeating vertices. – Lutz Lehmann Mar 30 '17 at 08:24
  • @Whatlahuhu the default value does not matter much as OpenGL will overwrite the values with its own valid IDs ... but maybe I would feel safer with `0` instead of `1` as `0` is default target ... my compilers allows `-1` loading to unsigned variables as it produces `0xFFFFFF...FFFF` pattern which is the biggest possible number for that variable. btw if you got some additional info is a good idea to also comment users with notifivation so they see you added something. – Spektre Mar 31 '17 at 06:30
  • @ Spektre I also tried GLuint sphere_vbo[4]={0,0,0,0};...., but I still got blank screen. I use xcode on mac to compile the code. – Whatlahuhu Mar 31 '17 at 06:35

1 Answers1

3

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);
    }
//---------------------------------------------------------------------------

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:

preview

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

Spektre
  • 49,595
  • 11
  • 110
  • 380
  • Hi @spektre, I don't have any error, but I got a blank screen. I updated my code in my question, Could you help me look at it? Thank you. – Whatlahuhu Mar 31 '17 at 06:33
  • @Whatlahuhu I think this `vertexColor = vec4(0, 1, 0, 1.0);` is your problem try `vertexColor = vec4(0.0, 1.0, 0.0, 1.0);` as auto cast from int to float is forbidden in GLSL at least in implementations I got my hands dirty with. You should always check GLSL compilation and link logs like this: [How to debug GLSL Fragment shader](http://stackoverflow.com/a/31716794/2521214) especially look for `glGetShaderInfoLog` usage – Spektre Mar 31 '17 at 06:39
  • I still got a blank screen. I am trying to use `glGetShaderInfoLog`. – Whatlahuhu Mar 31 '17 at 06:43
  • @Whatlahuhu I tried your vertex and it looks OK (so they must have changed the auto cast with new drivers. The only thing left is wrong matrices or fragment shader or VBO binding. make sure your VBO with positions is binded to location `0` (the same as in shader) and try unit matrices for start with CULL FACE turned off. that should cover whole screen if rendering then add CULL FACE if rendering add projection and translate your matrix before camera and only then add other stuff like view from euler angles – Spektre Mar 31 '17 at 06:47
  • @Whatlahuhu try `#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); }` O my side it is rendering so either you got problem with fragment or wrong matrices or matrix order ... as I do not use GLM I have no clue what order it uses. Try different background color as default fragment will use black color when not old style Color variables used – Spektre Mar 31 '17 at 06:51
  • I think that the `location = 0` is correct, I wanna pass `sphere_pos ` this vertex buffer object. It is located in `i=0`. I have not idea how to revise my code.. – Whatlahuhu Mar 31 '17 at 09:35
  • @Whatlahuhu have you tried different background color yet ? `glClearColor` ... But it makes no sense that is not rendering when before with your old code it was ... did you use the same radius and position of the sphere? so it is not outside camera view. Do `glGeterror` throw anything wrong ,... what gfx card you got if Intel it might be just wrong datatype for indices even ATI/AMD has some bugs in that sometimes .... – Spektre Mar 31 '17 at 10:37
  • @Whatlahuhu also try `glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST);` if ti make a difference – Spektre Mar 31 '17 at 10:43
  • Hi, @Spektre I tried black as my background, but it still doesn't show anything. I also put these in the end of sphere_draw()`glDisable(GL_CULL_FACE); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST);` , it still doesn't work. – Whatlahuhu Mar 31 '17 at 11:09
  • Hi @Spektre I will try `glGeterror` and `glGetShaderInfoLog ` later. I am in America, it is night time. I need to sleep for a while. Thank you for your help. – Whatlahuhu Mar 31 '17 at 11:18
  • @Whatlahuhu try NOT BLACK background ... because if fragment or lighting is wrong then the render is black so you would see at least silhouette. and know what is wrong. if nothing renders then you got wrong matrix math or VBO bindings or depth or camera settings – Spektre Mar 31 '17 at 11:44
  • Hi @Spektre, I tried other color as my background color, it still the same. I tried `glGeterror `, it returns `1282` I use this code to determine it `while ((err = glGetError()) != GL_NO_ERROR) { std::cout << " failed: " << err << std::endl; }` Because `gluErrorString` is deprecated in OSX 10.9, I only can show like this `glGeterror() `. Compare to other correct code, my other correct code doesn't show any number this while loop. I guess I have error in my code. – Whatlahuhu Apr 01 '17 at 00:17
  • Hi @Spektre, I added glGetShaderInfoLog in my shader file(I posted this code in my question ). It showed no error in vertex and fragment shader . – Whatlahuhu Apr 01 '17 at 03:23
  • @Whatlahuhu in `gl.h` there is set of `#define` for return values of glGeterror and `1282dec = 502hex` so `#define GL_INVALID_OPERATION 0x0502` is the meaning try find out which operation did the error . so place `glGeterror` in few places and where it throws error there place more `glGeterror` between it and previos call until you locate the glCall that is wrong. ` – Spektre Apr 01 '17 at 08:05
  • @Whatlahuhu but error present does not necessarily means that that is your problem. – Spektre Apr 01 '17 at 08:08
  • Hi, @ Spektre, I tried `glGeterror` in few places, and revised code a little bit. There is no error now. I got one single line in performance with `glPolygonMode` this function. ( in this link http://imgur.com/a/GKtl5). If I don't use `glPolygonMode`, I get a blank screen. – Whatlahuhu Apr 02 '17 at 00:37
  • @Whatlahuhu and if you use it (and with which mode) then render is OK? that is odd. Also what happens if you use `glDrawArrays` instead of `glDrawElements` (I have it remmed) if that renders dots per each vertex then you got problem with your gfx driver. I had few problems with bad GL drivers in past.... I am not familiar with OSX gfx drivers but on windows ATI is useless, AMD have problem if the indices are not in specific integer format or app contains memory leaks and Intel drivers looks OK but are crappy and do not support basic things correctly (like render to texture). – Spektre Apr 02 '17 at 07:52
  • @Whatlahuhu Try to return to your original rendering code and incrementaly add my code to it to see where it stops working that should indicate what is the problem ... most likely platform specific as on my machines my code works from start ... – Spektre Apr 02 '17 at 07:53
  • it can works with `glDrawArrays`. The performance is in this link (https://vimeo.com/211161409). I am using Intel drivers and xcode in OSX. I think that I might need to revise the indices buffer. – Whatlahuhu Apr 02 '17 at 08:37
  • @Whatlahuhu oh let me guess Intel HD graphics .... try to google for VBO/VAO indices errors workarounds I bet it is a driver bug related and yo uneed to process things a bit differently to make it work .... Intel has the worst GL implementation from branches on the market I usually use OpenGL 1.0 legacy stuf for such cards as the new stuff usually do not work as expected or not at all ... – Spektre Apr 02 '17 at 11:04
  • @ Spektre, thank you for your help. You help me a lot. I use OpenGL 4.1 on mac code. There are many challenges in debugging and writing code. I have learned old version of OpenGL. There are a little bit different between old version and new version and on OSX and Windows. I learned a lot from you, @BDL and @ LutzL. – Whatlahuhu Apr 03 '17 at 09:04