geometry - 有没有更有效的方法来纹理圆?
问题描述
我正在尝试创建一个随机生成的“行星”(圆圈),并且我希望水、土地和树叶的区域由柏林噪声或类似的东西决定。目前我有这个(psudo)代码:
for (int radius = 0; radius < circleRadius; radius++) {
for (float theta = 0; theta < TWO_PI; theta += 0.1) {
float x = radius * cosine(theta);
float y = radius * sine(theta);
int colour = whateverFunctionIMake(x, y);
setPixel(x, y, colour);
}
}
这不仅不起作用(由于精度问题,圆圈中有“间隙”),而且速度非常慢。即使我通过将增量更改为 0.01 来提高分辨率,它仍然缺少像素并且更慢(我在使用 Java 的平庸计算机上获得 10fps(我知道不是最好的)并且增量为 0.01。这当然是不可接受的游戏)。
我怎样才能在计算成本低得多的情况下获得类似的结果?
提前致谢。
解决方案
为什么不使用:
(x-x0)^2 + (y-y0)^2 <= r^2
很简单:
int x0=?,y0=?,r=?; // your planet position and size
int x,y,xx,rr,col;
for (rr=r*r,x=-r;x<=r;x++)
for (xx=x*x,y=-r;y<=r;y++)
if (xx+(y*y)<=rr)
{
col = whateverFunctionIMake(x, y);
setPixel(x0+x, y0+y, col);
}
全部在整数上,没有浮动或慢速操作,没有间隙......不要忘记使用 randseed 进行着色功能......
[Edit1] 还有一些东西
现在,如果您想要速度而不是需要直接像素访问(在大多数平台上,Pixels、SetPixel、PutPixels 等都很慢。因为它们执行很多东西,例如范围检查、颜色转换等......)如果您有直接像素访问或渲染到您自己的数组/图像中,无论您需要添加屏幕剪辑(因此您不需要检查每个像素上的像素是否在屏幕内)以避免访问冲突,如果您的圆圈与屏幕重叠。
如评论中所述,您可以使用先前的值摆脱x*x
and y*y
inside 循环(因为两者x,y
都只是递增)。有关它的更多信息,请参见:
数学是这样的:
(x+1)^2 = (x+1)*(x+1) = x^2 + 2x + 1
因此,xx = x*x
我们不只是xx+=x+x+1
为尚未增加x
或xx+=x+x-1
如果x
已经增加。
当把所有东西放在一起时,我得到了这个:
void circle(int x,int y,int r,DWORD c)
{
// my Pixel access
int **Pixels=Main->pyx; // Pixels[y][x]
int xs=Main->xs; // resolution
int ys=Main->ys;
// circle
int sx,sy,sx0,sx1,sy0,sy1; // [screen]
int cx,cy,cx0, cy0 ; // [circle]
int rr=r*r,cxx,cyy,cxx0,cyy0; // [circle^2]
// BBOX + screen clip
sx0=x-r; if (sx0>=xs) return; if (sx0< 0) sx0=0;
sy0=y-r; if (sy0>=ys) return; if (sy0< 0) sy0=0;
sx1=x+r; if (sx1< 0) return; if (sx1>=xs) sx1=xs-1;
sy1=y+r; if (sy1< 0) return; if (sy1>=ys) sy1=ys-1;
cx0=sx0-x; cxx0=cx0*cx0;
cy0=sy0-y; cyy0=cy0*cy0;
// render
for (cxx=cxx0,cx=cx0,sx=sx0;sx<=sx1;sx++,cxx+=cx,cx++,cxx+=cx)
for (cyy=cyy0,cy=cy0,sy=sy0;sy<=sy1;sy++,cyy+=cy,cy++,cyy+=cy)
if (cxx+cyy<=rr)
Pixels[sy][sx]=c;
}
这会在我的设置中渲染一个带半径的圆512 px
( AMD ~35ms
A8-5500 23.5 Mpx/s
3.2GHz Win7 64 位单线程 VCL/GDI 32 位应用程序,由 BDS2006 C++ 编码)。只需更改对您使用的样式/api的直接像素访问...
[编辑2]
要测量 x86/x64 上的速度,您可以RDTSC
在此处使用 asm 指令一些我很久以前使用的古老 C++ 代码(在没有本机 64 位内容的 32 位环境中):
double _rdtsc()
{
LARGE_INTEGER x; // unsigned 64bit integer variable from windows.h I think
DWORD l,h; // standard unsigned 32 bit variables
asm {
rdtsc
mov l,eax
mov h,edx
}
x.LowPart=l;
x.HighPart=h;
return double(x.QuadPart);
}
它返回您的 CPU 自上电以来经过的时钟。请注意,您应该考虑溢出,因为在快速机器上,32 位计数器会在几秒钟内溢出。此外,每个内核都有单独的计数器,因此将关联设置为单个 CPU。在测量之前的变速时钟上,通过一些计算加热 CPU 并转换为时间,只需除以 CPU 时钟频率。要获得它,只需这样做:
t0=_rdtsc()
sleep(250);
t1=_rdtsc();
fcpu = (t1-t0)*4;
和测量:
t0=_rdtsc()
mesured stuff
t1=_rdtsc();
time = (t1-t0)/fcpu
如果t1<t0
您溢出并且您需要将常数添加到结果或再次测量。此外,测量过程必须少于溢出周期。为了提高精度忽略操作系统粒度。有关更多信息,请参阅:
推荐阅读
- python - 如何在 Kivy 中从 python 代码更改屏幕
- javascript - 意外的令牌“导出”
- functional-programming - 将包括列表在内的多个参数传递给函数
- python - 如何仅使用numpy python中的矩阵运算(无for循环)计算两个矩阵之间的欧几里得距离?
- swiftui - SwiftUI 请求将 App 更新到最新版本
- reactjs - React/Leaflet-side-by-side 错误:地图容器已经初始化。#35
- python - 如何使用 mysql 根据 django 中的整数字段将 x 个月添加到日期
- jquery - 带有自定义分页的无限循环滑动器
- vue.js - 如何在 vue 组件之外使用 vuesax $vs.notify
- java - 我无法通过应用程序将文件从 Aix 服务器 SFTP 到 Windows 服务器