用 C/C++ 绘制 3D 球体 [英] Drawing 3D sphere in C/C++
问题描述
我正在寻找一种算法,可以在小分辨率下绘制漂亮的 3D 球体.我找到了 Bresenham 的圆算法,但它用于 2D 绘图.我只需要球体边界(我不需要填充它).我也用谷歌搜索了这个问题的解决方案,但我没有找到任何东西.这篇文章没有帮助(什么是蛮力算法?).我不能使用任何 OpenGL 库,我需要普通的 C/C++ 解决方案.提前致谢.
I am looking for an algorithm which can draw a nice looking 3D sphere on small resolution. I found Bresenham's circle algorithm but it's for 2D drawing. I just need spheres borders (I don't need it filled). I also googled for a solution of the problem but I didn't find anything. This article doesn't help (what is the brute force algorithm?). I can't use any OpenGL libraries, I need vanilla C/C++ solution. Thank you in advance.
推荐答案
如果我猜对了,你想渲染球体的所有表面体素
if I get it right you want to render all surface Voxels of sphere
蛮力是O(R^3)
.如果您只是从平面投影光线并计算第 3 个坐标,那么您会得到 O(R^2)
但要确保没有 Voxels 丢失,您必须这样做这个来自所有 3 个平面的投影仍然是 O(R^2)
The brute force is O(R^3)
. If you just project rays from plane and compute the 3-th coordinate then you get O(R^2)
but to make sure that no Voxels are missing you have to do this projection from all 3 planes which is still O(R^2)
看起来像这样:
关于 LED 立方体 16x16x16
模拟.现在算法:
on LED cube 16x16x16
simulation. Now the algorithm:
计算可见边界框
无需仅渲染整个渲染空间,因此中心 +/- 半径...
no need to render whole rendering space just the sphere so center +/- radius...
乘坐一架飞机(例如XY)
从边界框内的所有 x,y
点投射光线,它只有 2 个 for 循环,并通过球体方程计算光线击中的 z
坐标:
Cast rays from all x,y
points inside bounding box which is just 2 for loops and compute the z
coordinates where the ray hits via sphere equation:
(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 查找表完成以加快速度.
and render the two voxels. The int sqrt(int x)
for limited size (like LED Cube/Screen or Voxel space) can be done via LUT lookup table to speed things up.
对所有平面 (xy,yz,xz
) 执行第 2 步
do the step #2 for all planes (xy,yz,xz
)
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,...
If you want to use C only then decompose class to just global functions and variables and translate C++ operators x++,--,+=,-=,*=,...
to C style x=x+1,...
这篇关于用 C/C++ 绘制 3D 球体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!