calculating a sphere in opengl
Asked Answered
S

6

5

I want to calculate all the vertices needed and connect them with lines, so I eventually come up with a sphere. How many ways are there to do it? And also the lines between the vertices, will be straight; how can I make them "curved" I know that I can use glutWireSphere(), but I am interested in actually calculating the vertices. A way that I thought about it, was to put all the vertices manually in an array, but I guess that is not the way it's done.

Selia answered 30/10, 2011 at 18:11 Comment(2)
Be sure to check out the well-known magnificent page by Andreas Kahler, blog.andreaskahler.com/2009/06/…Henriettahenriette
You can draw curved primitives, not by using vertices, but by using an entirely different paradigm: distance functions in a fragment shader. This is strictly non-beginner material, though, so be warned! =)Sesquicarbonate
D
16

Copy and Pasting some code I originally wrote in Creating a 3D sphere in Opengl using Visual C++

class SolidSphere
{
protected
    std::vector<GLfloat> vertices;
    std::vector<GLfloat> normals;
    std::vector<GLfloat> texcoords;
    std::vector<GLushort> indices;

public:
    void SolidSphere(float radius, unsigned int rings, unsigned int sectors)
    {
        float const R = 1./(float)(rings-1);
        float const S = 1./(float)(sectors-1);
        int r, s;

        sphere_vertices.resize(rings * sectors * 3);
        sphere_normals.resize(rings * sectors * 3);
        sphere_texcoords.resize(rings * sectors * 2);
        std::vector<GLfloat>::iterator v = sphere_vertices.begin();
        std::vector<GLfloat>::iterator n = sphere_normals.begin();
        std::vector<GLfloat>::iterator t = sphere_texcoords.begin();
        for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
                float const y = sin( -M_PI_2 + M_PI * r * R );
                float const x = cos(2*M_PI * s * S) * sin( M_PI * r * R );
                float const z = sin(2*M_PI * s * S) * sin( M_PI * r * R );

                *t++ = s*S;
                *t++ = r*R;

                *v++ = x * radius;
                *v++ = y * radius;
                *v++ = z * radius;

                *n++ = x;
                *n++ = y;
                *n++ = z;
        }

        sphere_indices.resize(rings * sectors * 4);
        std:vector<GLushort>::iterator i = sphere_indices.begin();
        for(r = 0; r < rings; r++) for(s = 0; s < sectors; s++) {
                *i++ = r * sectors + s;
                *i++ = r * sectors + (s+1);
                *i++ = (r+1) * sectors + (s+1);
                *i++ = (r+1) * sectors + s;
        }
    }

    void draw(GLfloat x, GLfloat y, GLfloat z)
    {
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
        glTranslatef(x,y,z);

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_NORMAL_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glVertexPointer(3, GL_FLOAT, 0, &sphere_vertices[0]);
        glNormalPointer(GL_FLOAT, 0, &sphere_normals[0]);
        glTexCoordPointer(2, GL_FLOAT, 0, &sphere_texcoords[0]);
        glDrawElements(GL_QUADS, sphere_indices.size()/4, GL_UNSIGNED_SHORT, sphere_indices);
        glPopMatrix();
    }
}

how can I make them "curved"

You can't. All OpenGL primitives are "affine", i.e. planar or straight. Curvature is emulated by drawing short, straight sections with sufficient resolution.

Dissolve answered 30/10, 2011 at 19:12 Comment(3)
The sphere produced by your code is screwed:UVs are wrong and some of the vertices are too.Tried it with triangle strip.Schuh
@MichaelIV: The sphere is not meant to be used with triangle strip.Dissolve
You didn't paste it correctly : the indexing part should stop at sector-1 and rings-1. Your other post is correct though. Actually copy pasting it would have been safer !Plater
A
4

Paul Bourke actually has a nice introduction to sphere generation. And as for curved lines, there is no such thing in OpenGL. You can only make them appear curved by adding more intermediate connected points.

Aguayo answered 30/10, 2011 at 18:21 Comment(0)
N
4

There's more than one way to do this: a) icosphere generation and b)UV sphere generation. There may be more methods to do this. Some googling got me this excellent post on icosphere generation. I couldn't find UV sphere generation method though.

Nephrolith answered 30/10, 2011 at 18:21 Comment(1)
It's true, Kahler's page blog.andreaskahler.com/2009/06/… is an absolute classic - it's brilliant.Henriettahenriette
P
0

datenwolf's answer is great but contains some error. When you use vbo, client states must be disabled after enabled.

Add Three lines to draw code

void draw(GLfloat x, GLfloat y, GLfloat z)
{
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glTranslatef(x,y,z);

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glVertexPointer(3, GL_FLOAT, 0, &sphere_vertices[0]);
    glNormalPointer(GL_FLOAT, 0, &sphere_normals[0]);
    glTexCoordPointer(2, GL_FLOAT, 0, &sphere_texcoords[0]);
    glDrawElements(GL_QUADS, sphere_indices.size()/4, GL_UNSIGNED_SHORT, sphere_indices);

    **glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);**

    glPopMatrix();
}
Priedieu answered 31/7, 2017 at 8:56 Comment(0)
S
0

An iconosphere would do the trick . Still , to make a sphere with it , you will have to subdivide it's triangles.

Screamer answered 1/8, 2017 at 10:9 Comment(0)
P
0

It seems to me there's a great abundance of tutorials on how to make icospheres, but not so much about the method of facet approximation using polar coordinates.

So here's a very slightly edited code sample from the OpenGL Superbible 4th Edition book by Richard S. Wright Jr.

Since it's a very bare bones usage of the fixed-function pipeline (no glDrawElements, etc...) I found it useful for educational purposes.

Stacks are drawn as series of triangle strips. Obviously not the optimal performance, but it works!

// For best results, put this in a display list
// Draw a sphere at the origin
void RenderSphere(const float fRadius, const int iStacks, const int iSlices)
    {
        const auto PI = (float)M_PI;
        const auto PIx2 = (float)(M_PI * 2.0);
    
        GLfloat drho = PI / (GLfloat)iStacks;
        GLfloat dtheta = PIx2 / (GLfloat)iSlices;
        GLfloat ds = 1.0f / (GLfloat)iSlices;
        GLfloat dt = 1.0f / (GLfloat)iStacks;
        GLfloat t = 1.0f;
        GLfloat s = 0.0f;
    
        for (int i = 0; i < iStacks; i++)
        {
            const GLfloat rho = (GLfloat)i * drho;
            const GLfloat srho = (GLfloat)(std::sinf(rho));
            const GLfloat crho = (GLfloat)(std::cosf(rho));
            const GLfloat srhodrho = (GLfloat)(std::sinf(rho + drho));
            const GLfloat crhodrho = (GLfloat)(std::cosf(rho + drho));
    
            // Many sources of OpenGL sphere drawing code uses a triangle fan
            // for the caps of the sphere. This however introduces texturing
            // artifacts at the poles on some OpenGL implementations
            glBegin(GL_TRIANGLE_STRIP);
            s = 0.0f;
            for (int j = 0; j <= iSlices; j++)
            {
                const GLfloat theta = (j == iSlices) ? 0.0f : j * dtheta;
                const GLfloat stheta = (GLfloat)(-std::sinf(theta));
                const GLfloat ctheta = (GLfloat)(std::cosf(theta));
    
                GLfloat x = stheta * srho;
                GLfloat y = ctheta * srho;
                GLfloat z = crho;
    
                glTexCoord2f(s, t);
                glNormal3f(x, y, z);
                glVertex3f(x * fRadius, y * fRadius, z * fRadius);
    
                x = stheta * srhodrho;
                y = ctheta * srhodrho;
                z = crhodrho;
                glTexCoord2f(s, t - dt);
                s += ds;
                glNormal3f(x, y, z);
                glVertex3f(x * fRadius, y * fRadius, z * fRadius);
            }
            glEnd();
    
            t -= dt;
        }
    }

Unfortunately I couldn't find back a link to the original online repository of this source code, it's pretty ancient. Feel free to post if you know where to find it !

Pustule answered 3/8, 2021 at 17:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.