在opengl中计算球体

发布于 2024-12-12 21:19:16 字数 150 浏览 0 评论 0原文

我想计算所需的所有顶点并用线连接它们,所以我最终想出了一个球体。有多少种方法可以做到?顶点之间的线也是直的;我怎样才能使它们“弯曲” 我知道我可以使用 glutWireSphere(),但我对实际计算顶点感兴趣。我想到的一种方法是将所有顶点手动放入一个数组中,但我想这不是它的完成方式。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

饮惑 2024-12-19 21:19:16

复制并粘贴我最初在 使用 Visual C++ 在 Opengl 中创建 3D 球体

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

如何使它们“弯曲”

你不能。所有 OpenGL 图元都是“仿射”的,即平面的或直线的。通过绘制具有足够分辨率的短而直的部分来模拟曲率。

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.

冧九 2024-12-19 21:19:16

有不止一种方法可以做到这一点:a) icosphere 生成和 b)UV 球体生成。可能有更多方法可以做到这一点。一些谷歌搜索让我找到了这篇关于 icosphere 生成的优秀文章。但我找不到 UV 球体生成方法。

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.

风向决定发型 2024-12-19 21:19:16

Paul Bourke 实际上对球体生成有一个很好的介绍。至于曲线,OpenGL中没有这样的东西。您只能通过添加更多中间连接点来使它们看起来弯曲。

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.

一向肩并 2024-12-19 21:19:16

datenwolf 的答案很好,但包含一些错误。
使用 vbo 时,客户端状态必须在启用后禁用。

添加三行绘制代码

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

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();
}
胡渣熟男 2024-12-19 21:19:16

一个圣像圈就能达到目的。
不过,要用它制作一个球体,您必须细分它的三角形。

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

找回味觉 2024-12-19 21:19:16

在我看来,关于如何制作 icosphere 的教程有很多,但关于使用极坐标的面逼近方法的教程却很少。

因此,这里是 Richard S. Wright Jr. 所著的《OpenGL Superbible》第 4 版书中的代码示例,经过稍加编辑。

因为它是固定功能管道的非常简单的使用(没有 glDrawElements 等...),我发现它对于教育很有用目的。

堆栈被绘制为一系列三角形条带。显然不是最佳性能,但它确实有效!

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

不幸的是,我找不到该源代码的原始在线存储库的链接,它非常古老。如果您知道在哪里可以找到它,请随时发帖!

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 !

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文