我在寻找一种算法,可以借鉴小分辨率一个很好看的3D球体。 我发现布氏圈算法,但它是2D绘图。 我只需要球边界(我并不需要它填补)。 我也用Google搜索这个问题的解决方案,但我没有发现任何东西。 该文章没有帮助(什么是蛮力算法?)。 我不能使用任何OpenGL库,我需要香草C / C ++溶液。 先感谢您。
Answer 1:
如果我得到它的权利要渲染领域的所有表面体素
蛮力是O(R^3)
如果你只是项目从平面的光线和计算的3个坐标然后你O(R^2)
但以确保没有体素缺少你所要做的所有3架飞机这一预测仍然是O(R^2)
它看起来像这样:
在LED立方体16x16x16
模拟。 现在的算法:
计算可见边框
无需渲染整个渲染空间只是球体所以中心+/-半径...
取一个平面(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)
并呈现两个体素 。 的
int sqrt(int x)
为有限的尺寸(如LED立方/屏幕或体元空间)可以通过LUT查找表来完成,以加快速度。做第2步的所有平面(
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,...
Answer 2:
基于链路上,它看起来就像你更感兴趣的体素算法领域 ,而不是图形本身; 说,像这个页面有助于。 你不想一球,但只是表面。
中点圆算法可以用来绘制的3D体素球体:考虑球体作为切片的堆叠,并且每个切片包含一个圆。
在实践中,您可以使用两个嵌套中点圈,外界定内一个半径。 (虽然幼稚算法上的彼此将有可能离开孔在顶部的体素画圆,中点圆算法利用对称性,并且如果正确地实施,不应发生这样的孔)。
您在串联六个建盖,像雕刻立方体成球形。 由于在每个帽表面斜率总是小于1,在帽去向外将至多变化分别由1坐标,所以空穴不能发生。
这种方法的问题是复杂:每次计算点可能会影响多达48个素细胞。 (在每个帽,每个点八分圆内计算,并因此影响了八个单元。有六个帽,和6×8 = 48)。
我提出一个不同的方法。
在 为中心A -radius球体的表面的方程,是
- 0)2 - - 0)2 = 2
与整数coordinater,栅格点很少完全球体表面上,允许的值的范围:
- 0)2 - -
其中RR MIN和MAX RR是常数; 具体地,最小和最大距离的平方到球体中心。
我建议使用一倍坐标一般情况下。 这样就可以选择球的中心是否在坐标(暗示奇数直径)为中心,或两个相邻cordinates之间的中心(意味着甚至直径)。
如果你有一个SIZE
× SIZE
× SIZE
体素的网格(路灯,积木,等等),然后
int sphere_surface(const char x, const char y, const char z, const char size, const int rrmin, const int rrmax) { const int center = size - (size & 1); /* Size rounded down to even integer */ const int dx = center - x - x, dy = center - y - y, dz = center - z - z; /* Doubled coordinates */ const int rr = dx*dx + dy*dy + dz*dz; /* Distance squared */ return (rrmin <= rr) && (rr <= rrmax); }
返回1,如果点( x
, y
, z
)是立方体中心的球的表面区域内。 (在技术上,它返回如果从该点到中心的距离size
尺度的立方体内sqrt(rrmin)/2
和sqrt(rrmax)/2
以下。)
的“正确”的价值观rrmin
和rrmax
是高度依赖于上下文的。 rrmax
通常是附近某处size*size
(请记住,该函数使用了一倍坐标),与rrmin
稍差。
举例来说,如果你有一个3×3×3格,你只需要在每个面的六个中心细胞对满足条件; 可以做到这一点与size=3
, rrmin=1
, rrmax=4
:
如果你有一个4×4×4网格,要在每个面上四个中心细胞以满足条件(因此总共64个细胞的24都被认为是球体表面上); 你可以做到这一点与size=4
, rrmin=11
, rrmax=11
:
随着5×5×5格,我们得到的上述算法的有趣的副作用。
size=5
, rrmin=8
, rrmax=16
产生非常“角”球,几乎在一个角落一个立方体站立:
size=5
, rrmin=12
, rrmax=20
得到我喜欢的近似球形:
size=5
, rrmin=16
, rrmax=24
产生一个圆形立方体(每个面对一个3×3平):
显然,使用rrmin=0
包括所有内的细胞,同样,得到一球代替球体的只是表面的。
随着电网规模的增大,各大小球的更多的变种,你可以代表。
上述功能是微控制器特别有用,因为你可以在每个点只需通过你的格子循环,更新状态,如你所愿。 此外,大多数微控制器的内存紧张,但具有非常快(单时钟)加法,减法和乘法指令。 (虽然具有32位结果的16×16位乘法通常需要两个或更多的指令。)
一个典型的微控制器不具备ROM /闪存能力储存足够有趣的体素的模式,只有少数具有通过SPI SD卡DMA能力(所以你也可以加载从microSD卡素模式“帧”),但像上述功能可以产生有趣的形状与投入少 - 你可以插值特别投入。
上述功能也可以适用于近似antialising(通过比较rr
到rrmin
和rrmax
),在情况下,你的体素不只是二元的,但例如PWM控制的LED。
由于可视化,通常就有点困难,这里是我用来生成上述图像小巧的黑客工具。 它的SVG图像输出到标准输出,以及ASCII切片标准错误,当给出时size
, rrmin
和rrmax
作为命令行参数。
#include <stdlib.h> #include <string.h> #include <stdio.h> #define BORDER 2 #define XC(x,y,z) ((x)*16 + (y)*12) #define YC(x,y,z) ((x)*6 - (y)*8 - (z)*17) static int xt = 0; static int yt = 0; static void fcube(FILE *out, const int x, const int y, const int z, const int fill) { const int xc = xt + XC(x,y,z); const int yc = yt + YC(x,y,z); fprintf(out, "<path d=\"M%d,%dl16,6,12,-8,0,-17,-16,-6,-12,8z\" fill=\"#%06x\" stroke=\"#000\" />\n", xc, yc, fill & 0xFFFFFF); fprintf(out, "<path d=\"M%d,%dl16,6,12,-8m-12,8l0,17\" fill=\"none\" stroke=\"#000\" />\n", xc, yc-17); } static unsigned long rrmin = 0UL; static unsigned long rrmax = 0UL; static int center = 0; static int surface(const int x, const int y, const int z) { /* Doubled coordinates: */ const long dx = 2*x - center, dy = 2*y - center, dz = 2*z - center; const unsigned long rr = dx*dx + dy*dy + dz*dz; return (rrmin <= rr) && (rr <= rrmax); } int main(int argc, char *argv[]) { int width, height; int size, x, y, z; char dummy; if (argc != 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) { fprintf(stderr, "\n"); fprintf(stderr, "Usage: %s SIZE RRMIN RRMAX\n", argv[0]); fprintf(stderr, "Where\n"); fprintf(stderr, " SIZE is the size of the voxel cube\n"); fprintf(stderr, " RRMIN is the minimum distance squared, and\n"); fprintf(stderr, " RRMAX is the maximum distance squared,\n"); fprintf(stderr, " using doubled coordinates.\n"); fprintf(stderr, "\n"); fprintf(stderr, "Examples:\n"); fprintf(stderr, " %s 3 1 4\n", argv[0]); fprintf(stderr, " %s 4 11 11\n", argv[0]); fprintf(stderr, " %s 5 8 16\n", argv[0]); fprintf(stderr, " %s 5 12 20\n", argv[0]); fprintf(stderr, " %s 5 16 24\n", argv[0]); fprintf(stderr, "\n"); return EXIT_FAILURE; } if (sscanf(argv[1], " %d %c", &size, &dummy) != 1 || size < 3) { fprintf(stderr, "%s: Invalid size.\n", argv[1]); return EXIT_FAILURE; } if (sscanf(argv[2], " %lu %c", &rrmin, &dummy) != 1) { fprintf(stderr, "%s: Invalid rrmin.\n", argv[2]); return EXIT_FAILURE; } if (sscanf(argv[3], " %lu %c", &rrmax, &dummy) != 1 || rrmax < rrmin) { fprintf(stderr, "%s: Invalid rrmax.\n", argv[3]); return EXIT_FAILURE; } /* Calculate coordinate range. */ { int xmin = XC(0,0,0); int ymin = YC(0,0,0); int xmax = XC(0,0,0); int ymax = YC(0,0,0); for (z = 0; z <= size; z++) for (y = 0; y <= size; y++) for (x = 0; x <= size; x++) { const int xc = XC(x,y,z); const int yc = YC(x,y,z); if (xc < xmin) xmin = xc; if (xc > xmax) xmax = xc; if (yc < ymin) ymin = yc; if (yc > ymax) ymax = yc; } xt = BORDER - xmin; width = xmax - xmin + 2*BORDER; yt = BORDER - ymin; height = ymax - ymin + 2*BORDER; } center = size - 1; /* SVG preamble. */ printf("<?xml version=\"1.0\"?>\n"); printf("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 %d %d\">\n", width, height); printf("<path d=\"M%d,%dL%d,%d,%d,%d,%d,%d,%d,%d,%d,%dz\" fill=\"#f7f7f7\" stroke=\"#666666\"/>\n", xt+XC( 0, 0, 0), yt+YC( 0, 0, 0), xt+XC(size, 0, 0), yt+YC(size, 0, 0), xt+XC(size,size, 0), yt+YC(size,size, 0), xt+XC(size,size,size), yt+YC(size,size,size), xt+XC(0, size,size), yt+YC( 0,size,size), xt+XC(0, 0,size), yt+YC( 0, 0,size)); printf("<path d=\"M%d,%dL%d,%d,%d,%dM%d,%dL%d,%d\" fill=\"none\" stroke=\"#666666\"/>\n", xt+XC( 0, 0, 0), yt+YC( 0, 0, 0), xt+XC( 0,size, 0), yt+YC( 0,size, 0), xt+XC(size,size, 0), yt+YC(size,size, 0), xt+XC( 0,size, 0), yt+YC( 0,size, 0), xt+XC( 0,size,size), yt+YC( 0,size,size)); for (z = 0; z < size; z++) for (y = size - 1; y >= 0; y--) for (x = 0; x < size; x++) if (surface(x,y,z)) fcube(stdout, x, y, z, 0x00CCFF); printf("</svg>\n"); for (z=0; z < size; z++) { for (y = 0; y < size; y++) { for (x = 0; x < size; x++) fputc(surface(x,y,z) ? 'X' : '.', stderr); fputs(" ", stderr); for (x = 0; x < size; x++) fputc(surface(x,z,y) ? 'X' : '.', stderr); fputs(" ", stderr); for (x = 0; x < size; x++) fputc(surface(y,z,x) ? 'X' : '.', stderr); fputc('\n', stderr); } fputc('\n', stderr); } return EXIT_SUCCESS; }
我没有刻意去巧妙的输出; 你可以很容易地选择如不同颜色的每个面,也许添加阴影的背景架,等等。
上面这两幅画用该程序创建,然后转换为使用GIMP PNG,但我建议您使用浏览器在本地查看生成的文件。
有问题吗?
Answer 3:
在这个领域中最常用的库OpenGL和这张幻灯片展示你如何配置你的IDE图书馆从这里下载的文件http://www.xmission.com/~nate/glut.html然后把他们在这个路径要将glut32.dll - > C:\ Windows \ System32下glut32.lib - > C:\ Program Files文件\微软的Visual Studio .NET \ VC7 \ PlatformSDK \ lib中glut.h - > C:\ Program Files文件\微软的Visual Studio .NET \ VC7 \ PlatformSDK \包含\ GL
OpenGL的OpenGL超级3-4此教科书惊人的一个从头开始的先进水平
Answer 4:
我不能使用任何OpenGL库,我需要香草C / C ++溶液。
这是否意味着根本没有图形库? 在这种情况下,很简单的答案是:你不知道。 无论ç也不是C ++有原生图形渲染别的技能。 你需要使用一个外部库和驱动器只是在与OS”帧缓冲和/或图形卡取得联系。
但是,对于我的非图形相关的解决方案,这取决于:
我发现布氏圈算法,但它是2D绘图。 我只需要球的边界。
这是否意味着你从字面上只需要在球体的边界? 因为在这种情况下,你应该只使用2D绘图算法你已经拥有的,因为它给你的边界,然后有。
如果这意味着你要球的个体素,这是一个有点复杂,它是将需要多一点的数学,并可能到软件渲染器只是要在脸上得到拳打在性能方面的程度,这取决于你的球有多少体素和各个顶点了。
我想你要得到的是什么游戏和物理引擎开发商所说的“边界框”或“碰撞盒”,有时也被称为只是“击中格”。 所有这一切需要的是拉丝包围球,仅此而已的全部(换句话说立方体(通常线框),你只画一个立方体相同的宽度,高度和深度的领域,假设我们正在使用的XYZ尺寸)。