c++ - 如何确定 Mandelbrot 集缩放的良好中心

标签 c++ math graphics cuda

我刚写完一个 cuda 程序,它可以渲染 Mandelbrot 集的图像。我设置它的方式是,您将创建图像的函数传递给一个比例,该比例是每单位像素以及复平面中图像中心的 x 和 y 坐标。我想从许多帧创建一个深度缩放电影,我需要我的程序能够自动确定一个中心,在那里将发生“有趣”的事情(而不是放大一个区域,它只会是一种颜色)。我应该如何选择要放大的坐标。

如果有人感兴趣,这是我的代码。

#include <iostream>
#include <thrust/complex.h>
#include <cuda.h>
#include <cassert>
#include <cstdio>
#include <algorithm>

typedef double real;

inline void cuda_error(cudaError_t code, const char* lbl)
{
    if(code != cudaSuccess)
    {
        std::cerr << lbl << " : " << cudaGetErrorString(code) << std::endl;
        exit(1);
    }
}

__global__ void mandelbrot_kernel(unsigned char* pix, real cx, real cy, real pix_scale, size_t w, size_t h, int iters)
{
    cy = -cy;
    real sx = cx - (w * pix_scale) / 2;
    real sy = cy - (w * pix_scale) / 2;

    size_t x = (size_t)blockIdx.x * blockDim.x + threadIdx.x;
    size_t y = (size_t)blockIdx.y * blockDim.y + threadIdx.y;
    if(x >= w || y >= h)
        return;

    thrust::complex<real> c(sx + pix_scale * x, sy + pix_scale * y);
    thrust::complex<real> z(0, 0);
    int i = 0;
    for(; i < iters && thrust::abs(z) < 2; ++i)
        z = z * z + c;

    real scale = 255.0 / (real)iters;
    size_t q = 3 * (w * y + x);
    pix[q] = i * scale;
    pix[q + 1] = 255 * sinf(z.imag());
    pix[q + 2] = 255 * sinf(z.real());
}

void shade_mandelbrot(unsigned char* pix, real* devs, real cx, real cy, real pix_scale, int w, int h, int iters)
{
    dim3 blockDim(16, 16);
    dim3 gridDim((w + 15) / 16, (h + 15) / 16);
    mandelbrot_kernel<<<gridDim, blockDim>>>(pix, cx, cy, pix_scale, w, h, iters);
}

void ppm_write(FILE* f, unsigned char* pix, int w, int h)
{
    assert(fprintf(f, "P6 %d %d 255\n", w, h) > 0);
    size_t sz = 3 * (size_t)w * (size_t)h;
    assert(fwrite(pix, 1, sz, f) == sz);
}

int main()
{
    int dim = 2000;
    int w = dim;
    int h = dim;
    int imgs = 200;
    int iters = 1024;

    real cx = -0.7463, cy = 0.1102;
    cuda_error(cudaSetDevice(0), "Set Device");
    unsigned char* pix_buffers[2];
    real* dev_buffers[2];

    cuda_error(cudaHostAlloc(pix_buffers, 3 * sizeof(unsigned char) * w * h, 0), "Host Alloc 1");
    cuda_error(cudaHostAlloc(pix_buffers + 1, 3 * sizeof(unsigned char) * w * h, 0), "Host Alloc 2");

    real scale = 8.0 / w;
    shade_mandelbrot(pix_buffers[0], dev_buffers[0], cx, cy, scale, w, h, iters);
    for(int i = 0; i < imgs; i++)
    {
        cuda_error(cudaDeviceSynchronize(), "Sync");

        std::cout << scale << std::endl;
        if(i < (imgs - 1))
            shade_mandelbrot(pix_buffers[(i + 1) % 2], dev_buffers[(i + 1) % 2], cx, cy, scale *= 0.97, w, h, 255);
        char fn[100];
        sprintf(fn, "/media/chase/3161D67803D8C5BE/Mandelbroght/image%06d.ppm", i);
        puts(fn);
        FILE* f = fopen(fn, "w");
        assert(f);

        ppm_write(f, pix_buffers[i % 2], w, h);
        fclose(f);
    }


    cuda_error(cudaFreeHost(pix_buffers[0]), "Host Free 1");
    cuda_error(cudaFreeHost(pix_buffers[1]), "Host Free 2");
    return 0;
}

最佳答案

退出内循环时具有高迭代次数(但不等于iters)的点将呈现有趣的行为,因为它们接近设定的边界。您可以随机选择点,通过算法运行它并使用计数最高的点作为中心。如果你随机选择几个点,你可能会更快地得到结果,取迭代次数最高的点,在它周围生成几个点,看看你是否得到更高的迭代次数,然后用这些点中最好的点重复。

关于c++ - 如何确定 Mandelbrot 集缩放的良好中心,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32027864/

相关文章:

c# - 确保奖池不会奖励并列的参与者少于得分较差的参与者

algorithm - 地球地球上多边形中的点

java - 绘制多个移动图形

java - 不确定为什么这个图形屏幕没有更新

java - Android——在 OnDrawFrame 方法之外将 GLSurfaceView.Renderer 置于 sleep 状态(如 Thread.sleep(20))

c++ - Win32 事件与信号量

c++ - 转到文件中的特定行并阅读它

c++ - const_string 库问题

c++ - 如何声明基于平台的C++变量类型?

javascript - PaperJS - 如何沿路径移动并沿路径旋转