c - 在 C/C++ 中绘制 3D 球体

标签 c graphics voxel

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

最佳答案

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

蛮力是O(R^3)。如果您只是从平面投影光线并计算第 3 坐标,那么您会得到 O(R^2) 但要确保没有 Voxels 丢失,您必须做来自所有 3 个平面的投影仍然是 O(R^2)

看起来像这样:

sphere

在 LED 立方体 16x16x16 模拟上。现在的算法:

  1. 计算可见边界框

    不需要只渲染整个渲染空间的球体,所以中心 +/- 半径...

  2. 乘坐一架飞机(例如XY)

    从所有 x,y 点转换光线到边界框内,这只是 2 个 for 循环,并通过球面方程计算光线命中的 z 坐标:

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

    所以

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

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

  3. 对所有平面 (xy,yz,xz) 执行步骤 #2

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 风格 x=x+1,...

关于c - 在 C/C++ 中绘制 3D 球体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25057471/

相关文章:

c - Malloc 指针参数失败

java - 在单独线程中定义的 Paint 函数不绘图(Java)

c++ - 如何将一个 int 数组发送到我的着色器

matlab - matlab中的3D体素显示

c - 如何使 'C' 中的函数转到程序开始

c - 全 1 的最大方阵子矩阵

c++ - 在 QGraphicsView/QGraphicsScene 上用鼠标移动项目

c++ - OpenGL体素引擎慢

c - 需要有关 C 中 lzss 压缩的帮助

最大化 JFrame 期间发生 Java 绘制错误