- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
首先,我知道这个问题听起来好像我没有搜索过,但我搜索了很多。
我为 C# 编写了一个小的 Mandelbrot 绘图代码,它基本上是一个带有 PictureBox 的窗口窗体,我在上面绘制了 Mandelbrot 集。
我的问题是,它太慢了。没有深度缩放它做得很好,四处移动和缩放非常流畅,每张图花费不到一秒钟,但是一旦我开始稍微放大并到达需要更多计算的地方,它就会变得非常慢。
在其他 Mandelbrot 应用程序上,我的计算机在我的应用程序中运行速度慢得多的地方确实做得很好,所以我猜我可以做很多事情来提高速度。
我做了以下事情来优化它:
我没有在位图对象上使用 SetPixel GetPixel 方法,而是使用 LockBits 方法直接写入内存,这样速度更快。
我没有使用复数对象(使用我自己创建的类,而不是内置的类),而是使用 2 个变量 re 和 im 模拟复数。这样做让我减少了乘法运算,因为实部和虚部的平方是在计算过程中多次完成的事情,所以我只是将平方保存在一个变量中并重复使用结果而不需要重新计算它。
我使用 4 个线程绘制 Mandelbrot,每个线程处理图像的不同四分之一,它们都同时工作。据我了解,这意味着我的 CPU 将使用其 4 个核心来绘制图像。
我使用逃逸时间算法,据我所知这是最快的?
这是我在像素之间移动和计算的方式,它被注释掉了,所以我希望它是可以理解的:
//Pixel by pixel loop:
for (int r = rRes; r < wTo; r++)
{
for (int i = iRes; i < hTo; i++)
{
//These calculations are to determine what complex number corresponds to the (r,i) pixel.
double re = (r - (w/2))*step + zeroX ;
double im = (i - (h/2))*step - zeroY;
//Create the Z complex number
double zRe = 0;
double zIm = 0;
//Variables to store the squares of the real and imaginary part.
double multZre = 0;
double multZim = 0;
//Start iterating the with the complex number to determine it's escape time (mandelValue)
int mandelValue = 0;
while (multZre + multZim < 4 && mandelValue < iters)
{
/*The new real part equals re(z)^2 - im(z)^2 + re(c), we store it in a temp variable
tempRe because we still need re(z) in the next calculation
*/
double tempRe = multZre - multZim + re;
/*The new imaginary part is equal to 2*re(z)*im(z) + im(c)
* Instead of multiplying these by 2 I add re(z) to itself and then multiply by im(z), which
* means I just do 1 multiplication instead of 2.
*/
zRe += zRe;
zIm = zRe * zIm + im;
zRe = tempRe; // We can now put the temp value in its place.
// Do the squaring now, they will be used in the next calculation.
multZre = zRe * zRe;
multZim = zIm * zIm;
//Increase the mandelValue by one, because the iteration is now finished.
mandelValue += 1;
}
//After the mandelValue is found, this colors its pixel accordingly (unsafe code, accesses memory directly):
//(Unimportant for my question, I doubt the problem is with this because my code becomes really slow
// as the number of ITERATIONS grow, this only executes more as the number of pixels grow).
Byte* pos = px + (i * str) + (pixelSize * r);
byte col = (byte)((1 - ((double)mandelValue / iters)) * 255);
pos[0] = col;
pos[1] = col;
pos[2] = col;
}
}
我可以做些什么来改善这一点?你在我的代码中发现任何明显的优化问题吗?
现在我知道有两种方法可以改进它:
我需要为数字使用不同的类型,double 的精度有限,我确信有更好的非内置替代类型,它们更快(它们乘法和加法更快)并且具有更高的精度,我只需要有人指出我需要查看的位置并告诉我它是否属实。
我可以将处理转移到 GPU。我不知道该怎么做(也许是 OpenGL?DirectX?就这么简单吗?还是我需要学习很多东西?)。如果有人可以向我发送有关此主题的适当教程的链接,或者告诉我有关它的一般情况,那就太好了。
非常感谢您阅读到这里,希望您能帮助我 :)
最佳答案
如果您决定将处理转移到 GPU,您可以从多个选项中进行选择。由于您使用的是 C#,XNA 将允许您使用 HLSL。 RB Whitaker如果您选择此选项,它有最简单的 XNA 教程。另一个选项是 OpenCL . OpenTK附带一个 julia 集分形的演示程序。这将非常容易修改以显示 mandlebrot 集。参见 here请记住找到源代码附带的 GLSL 着色器。
About the GPU, examples are no help for me because I have absolutely no idea about this topic, how does it even work and what kind of calculations the GPU can do (or how is it even accessed?)
不同的 GPU 软件的工作方式不同......
通常,程序员会使用 HLSL、GLSL 或 OpenCL 等着色器语言为 GPU 编写程序。用 C# 编写的程序将加载着色器代码并对其进行编译,然后使用 API 中的函数向 GPU 发送作业并随后取回结果。
看看FX Composer或者渲染猴子,如果你想使用着色器进行一些练习而不必担心 API。
如果您使用的是 HLSL,则渲染管道如下所示。
顶点着色器负责获取 3D 空间中的点并计算它们在 2D 视野中的位置。 (因为你在 2D 中工作,所以对你来说不是什么大问题)
像素着色器负责在顶点着色器完成后将着色器效果应用于像素。
OpenCL 是另一回事,它面向通用 GPU 计算(即:不仅仅是图形)。它的功能更强大,可用于 GPU、DSP 和构建 super 计算机。
关于c# - 使 C# mandelbrot 绘图更高效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17406474/
我现在在 Mandelbrot 集的 DirectX 11 版本上工作了几天。到目前为止,我所做的是创建一个带有纹理的四边形。我可以使用 Pixel Shader 为点着色,但由于某种原因,Pixel
我在 Javascript 上编写了一个程序,用于创建 mandelbrot 分形,并将其绘制在 html Canvas 中。我的渲染方法是每行迭代,从 0 到 500 像素,然后简单地执行一个循环,
我的类(class)布置了一项作业,要求我编写一个程序来绘制曼德尔布洛特图形。 我们必须基本上让程序绘制结果的位图。 问题是,我的 CalcMBF 函数只输出 2 作为 Mandelbrot 数。 我
我认为问题在于我如何将笛卡尔坐标转换为复数,但我现在知道如何操作了。你能解释一下我应该如何转换吗?这是我尝试过的: double c_Im = (y + (maxIm - minIm)) / heig
我是 C++ 编程的新手,为了改进,我正在尝试制作一个 mandelbrot set consol 应用程序。我已经让它几乎完美地工作:图像生成,我可以放大/缩小,并且非常容易地四处移动。不过,我遇到
我想使用 Java 生成 Mandelbrot 集的 PNG 照片,输出应该可以在 Google 图片搜索中轻松找到。 该集合定义为以下序列: z_n+1 = z_n^2 + c 其中 c 和 z 是
我用 Java 编写了一个 Mandelbrot 集分形,并包含了在一定程度上平移和放大分形的功能。唯一的问题是,当我平移图像并尝试放大时,它看起来好像试图放大中心并平移一点。平移和缩放并不是真正的平
我用 python 编写了 Mandelbrot 集,但它看起来很奇怪,所以我搜索了平滑的颜色。我已经使用对数和线性插值编写了一个平滑的着色函数,但无论我尝试什么,我都无法得到我想要的: self.p
我编写了一个简单的片段着色器来渲染 mandelbrot 集。我正在使用 c 语言和使用 glsl 的 opengl 执行此操作。 #version 330 core in vec2 fCoord;
我正在尝试制作一个程序,通过制作一个 .PPM 文件来生成标准 Mandelbrot 集的图像。该程序没有生成有效的 PPM 文件,我不知道为什么。 这是我的代码: #include #includ
我知道已经回答了很多关于此的问题。然而,我的略有不同。每当我们实现我所理解的平滑着色算法时。 mu = 1 + n + math.log2(math.log2(z)) / math.log2(2)
mandelbrot 集包含 mandelbrot 迭代有界的点,迭代点永远不会“逃逸”。 让我们将边界定义为点,其中迭代点在 N 次迭代后逃逸(逃逸我的意思是与原点的距离变得大于 2)。 是否可以保
我一直在做 Mandelbrot 集并尝试缩放,但缩放模式变得非常麻烦。当我缩放时,它会完美缩放,但图像尺寸会缩小到原始尺寸的一半。下次我再次缩放时,图片尺寸会增加并尝试跳过查看窗口。代码在 c++/
我目前正在编写一个程序来生成非常巨大的(65536x65536 像素及以上)Mandelbrot 图像,并且我想设计一个光谱和着色方案来使它们公平。 wikipedia featured mandel
谁能解释一下扰动是如何描述的in this paper加速渲染 Mandelbrot 集? 我知道如何使用对每个像素执行多次迭代的传统方法来渲染 Mandelbrot 集,但我不太明白那篇论文中描述的
这是我尝试使用 Pygame 模块在 Python 3.5 中编写 Mandelbrot 集。 import math, pygame pygame.init() def mapMandelbrot(
我正在使用 C 编写以下代码。到目前为止,它一直在工作,并且已缩放到正确的级别等,但是我正在努力让颜色按我想要的方式工作。理想情况下,无论颜色如何,我都希望得到这样的结果: 但是我的程序如下所示,目前
我可以生成从 minReal 到 maxReal 以及从 minImaginary 到 maxImaginary 的 Mandelbrot 集的 400x400 图像。所以, makeMandel(m
我正在编写绘制 Mandelbrot 集版本的代码。当它运行时,它接受两个输入 a 和 b,并将其转换为一个复数(例如 complex(a,b))。然后它绘制一个 Mandelbrot 集,其中 z
尝试使用与我在使用 TBB(线程构建块)运行时使用的代码相同的代码(有点)。 我对 OpenCL 没有太多经验,但我认为大部分主要代码是正确的。我相信错误在 .cl文件,它在那里进行数学运算。 这是我
我是一名优秀的程序员,十分优秀!