用C / C ++绘制3D球体

时间:2014-07-31 11:12:29

标签: c graphics voxel

我正在寻找一种算法,可以在小分辨率上绘制漂亮的3D球体。我找到了Bresenham's circle algorithm,但它是用于2D绘图的。我只需要球体边框(我不需要它填充)。我也搜索了问题的解决方案,但我没有找到任何东西。 This文章没有帮助(什么是暴力算法?)。我不能使用任何OpenGL库,我需要vanilla C / C ++解决方案。提前谢谢。

3 个答案:

答案 0 :(得分:5)

如果我做对了你想要渲染球体的所有表面体素

蛮力是O(R^3)。如果您只是从平面投射光线并计算第3个坐标,那么您将获得O(R^2),但为了确保没有 Voxels 缺失,您必须从所有3个平面进行此投影,这是仍然是O(R^2)

看起来像这样:

sphere

关于LED立方体16x16x16模拟。现在算法:

  1. 计算可见边界框

    无需将整个渲染空间渲染为球体,因此居中+/-半径...

  2. 取一个平面(例如XY)

    从边界框内的所有x,y点投射光线,这只是2个循环,并通过球体方程计算光线击中的z坐标:

    (x-x0)^2 + (y-y0)^2 + (z-z0)^2 = R^2
    

    所以

    z=z0 +/- sqrt(R^2 - (x-x0)^2 - (y-y0)^2)
    

    并渲染两个体素。有限尺寸的int sqrt(int x)(如LED立方体/屏幕或体素空间)可以通过 LUT 查找表来完成,以加快速度。

  3. 为所有飞机执行步骤#2(xy,yz,xz

  4. C ++ 中的代码如下所示:

    //---------------------------------------------------------------------------
    //--- LED cube class ver: 1.00 ----------------------------------------------
    //---------------------------------------------------------------------------
    #ifndef _LED_cube_h
    #define _LED_cube_h
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    const int _LED_cube_size=16;
    //---------------------------------------------------------------------------
    class LED_cube
        {
    public:
        int n,map[_LED_cube_size][_LED_cube_size][_LED_cube_size];
    
        LED_cube()              { n=_LED_cube_size; }
        LED_cube(LED_cube& a)   { *this=a; }
        ~LED_cube()             { }
        LED_cube* operator = (const LED_cube *a) { *this=*a; return this; }
        //LED_cube* operator = (const LED_cube &a) { /*...copy...*/ return this; }
        void cls(int col);                                  // clear cube with col 0x00BBGGRR
        void sphere(int x0,int y0,int z0,int r,int col);    // draws sphere surface with col 0x00BBGGRR
        void glDraw();                                      // render cube by OpenGL as 1x1x1 cube at 0,0,0
        };
    //---------------------------------------------------------------------------
    void LED_cube::cls(int col)
        {
        int x,y,z;
        for (x=0;x<n;x++)
         for (y=0;y<n;y++)
          for (z=0;z<n;z++)
           map[x][y][z]=col;
        }
    //---------------------------------------------------------------------------
    void LED_cube::sphere(int x0,int y0,int z0,int r,int col)
        {
        int x,y,z,xa,ya,za,xb,yb,zb,xr,yr,zr,xx,yy,zz,rr=r*r;
        // bounding box
        xa=x0-r; if (xa<0) xa=0; xb=x0+r; if (xb>n) xb=n;
        ya=y0-r; if (ya<0) ya=0; yb=y0+r; if (yb>n) yb=n;
        za=z0-r; if (za<0) za=0; zb=z0+r; if (zb>n) zb=n;
        // project xy plane
        for (x=xa,xr=x-x0,xx=xr*xr;x<xb;x++,xr++,xx=xr*xr)
         for (y=ya,yr=y-y0,yy=yr*yr;y<yb;y++,yr++,yy=yr*yr)
            {
            zz=rr-xx-yy; if (zz<0) continue; zr=sqrt(zz);
            z=z0-zr; if ((z>0)&&(z<n)) map[x][y][z]=col;
            z=z0+zr; if ((z>0)&&(z<n)) map[x][y][z]=col;
            }
        // project xz plane
        for (x=xa,xr=x-x0,xx=xr*xr;x<xb;x++,xr++,xx=xr*xr)
         for (z=za,zr=z-z0,zz=zr*zr;z<zb;z++,zr++,zz=zr*zr)
            {
            yy=rr-xx-zz; if (yy<0) continue; yr=sqrt(yy);
            y=y0-yr; if ((y>0)&&(y<n)) map[x][y][z]=col;
            y=y0+yr; if ((y>0)&&(y<n)) map[x][y][z]=col;
            }
        // project yz plane
        for (y=ya,yr=y-y0,yy=yr*yr;y<yb;y++,yr++,yy=yr*yr)
         for (z=za,zr=z-z0,zz=zr*zr;z<zb;z++,zr++,zz=zr*zr)
            {
            xx=rr-zz-yy; if (xx<0) continue; xr=sqrt(xx);
            x=x0-xr; if ((x>0)&&(x<n)) map[x][y][z]=col;
            x=x0+xr; if ((x>0)&&(x<n)) map[x][y][z]=col;
            }
        }
    //---------------------------------------------------------------------------
    void LED_cube::glDraw()
        {
        #ifdef __gl_h_
        int x,y,z;
        float p[3],dp=1.0/float(n-1);
        glEnable(GL_BLEND);
        glBlendFunc(GL_ONE,GL_ONE);
    
        glPointSize(2.0);
    
        glBegin(GL_POINTS);
    
        for (p[0]=-0.5,x=0;x<n;x++,p[0]+=dp)
         for (p[1]=-0.5,y=0;y<n;y++,p[1]+=dp)
          for (p[2]=-0.5,z=0;z<n;z++,p[2]+=dp)
            {
            glColor4ubv((BYTE*)(&map[x][y][z]));
            glVertex3fv(p);
            }
        glEnd();
        glDisable(GL_BLEND);
        glPointSize(1.0);
        #endif
        }
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    #endif
    //---------------------------------------------------------------------------
    //---------------------------------------------------------------------------
    

    课程用法:

    LED_cube cube;
    cube.cls(0x00202020); // clear space to dark gray color
    int a=cube.n>>1;      // just place sphere to middle and size almost the whole space
    int r=a-3;
    cube.sphere(a,a,a,r,0x00FFFFFF);
    cube.glDraw();        // just for mine visualization you have to rewrite it to your rendering system
    

    如果您只想使用 C ,那么只需将类分解为全局函数和变量,并将 C ++ 运算符x++,--,+=,-=,*=,...转换为 C style x=x+1,...

答案 1 :(得分:-2)

此字段中最常用的库是openGL 这张幻灯片向您展示了如何在IDE上配置库从此处下载文件 http://www.xmission.com/~nate/glut.html 然后把它们放在这条路上 glut32.dll - &gt; C:\ Windows \ System32下 glut32.lib - &gt; C:\ Program Files \ Microsoft Visual Studio .NET \ Vc7 \ PlatformSDK \ lib glut.h - &gt; C:\ Program Files \ Microsoft Visual Studio .NET \ Vc7 \ PlatformSDK \ Include \ gl

opengl-superbible-4th这本教科书令人惊叹,从头开始到高级水平

答案 2 :(得分:-2)

  

我不能使用任何OpenGL库,我需要vanilla C / C ++解决方案。

这是否意味着没有图形库?在这种情况下,非常简单的答案是:你不是。 C和C ++都没有本机图形渲染能力。你需要使用外部库和驱动程序只是为了接触操作系统&#39;帧缓冲和/或图形卡。

但是,对于我的非图形相关解决方案,它取决于:

  

我找到了Bresenham的圆形算法,但是它用于2D绘图。我只需要球体边界。

这是否意味着你字面只需要球体的边界?因为在这种情况下,你应该只使用你已经拥有的2d绘图算法,因为它可以为你提供正确的边界。

如果这意味着你想要球体的各个体素,它会变得更加复杂,并且需要更多的数学运算,并且可能达到软件渲染器刚刚被打入的程度。面对性能,取决于你的球体有多少体素和个别顶点。

我认为你想要得到的是游戏和物理引擎开发人员称之为“边界框”的内容。或&#34;碰撞盒&#34;,有时也称为&#34; hitbox&#34;。所需要的只是绘制一个包围整个球体的立方体(通常是线框)而不是更多(换句话说,你只是绘制一个与球体具有相同宽度,高度和深度的立方体,假设我们是使用XYZ维度。)