【问题标题】:Mandelbrot Set not displayed曼德布罗集未显示
【发布时间】:2017-10-26 12:20:23
【问题描述】:

使用 C 编程和 OpenGL 的 Mandelbrot 集分形。这是我的代码。它现在只在中心显示一个点。我无法弄清楚我哪里出错了。我很确定我的数学是正确的。也许我的循环有问题?

This picture is what Im trying to get

到目前为止,这是我的代码:

#include <GLUT/glut.h>
#include <math.h>

void init(void);
void display(void);

const int screenWidth = 640;
const int screenHeight = 480;

int main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(screenWidth, screenHeight);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Mandelbrot");

    // glViewport(-320, -320, 320, 320);
    init();
    glutDisplayFunc(display);
    glutMainLoop();
    return 0;
}

void init(void) {
    glMatrixMode(GL_PROJECTION);
    gluOrtho2D(-500.0, screenWidth, -500.0, screenHeight);
    // A = screenWidth / 4.0;
    // B = 0.0;
    // C = D = screenHeight / 2.0;
}

void display(void) {
    GLdouble x, f, y, xtemp, y0, x0, iteration, maxInteration;
    glClearColor(1.0, 1.0, 1.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT);
    glPointSize(1);
    glColor3f(0.0, 0.0, 0.0);

    glEnable(GL_POINT_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    for (y0 = - 1; y0 < 1.1; y0 = y0 + 0.0025) {
        for (x0 = -2.5; x0 < 1.1; x0 = x0 + 0.0025) {
            x = 0;
            y = 0;
            iteration = 0;
            maxInteration = 1000;

            while (((x * x) + (y * y) < (2 * 2)) && iteration < maxInteration) {
                xtemp = (x * x) - (y * y) + x0;
                y = (2 * x * y) + y0;
                x = xtemp;
                iteration = iteration + 1;

                if (y <= 2) {
                    glBegin(GL_POINTS);

                    glVertex2d(x / 750, y / 750);
                    glEnd();
                }
            }
        }
    }    
    glFlush();
}

这是我在修复 cmets 中的建议后更新的代码。它会产生上图。但是,现在我正在尝试在对象周围创建灰色圆圈???我试图通过最后的 else 来做到这一点......有什么想法吗?

#include <GLUT/glut.h>
#include <math.h>

void init(void);
void display(void);


const int screenWidth = 640;
const int screenHeight = 640;
GLdouble A, B, C, D;

int main(int argc, char** argv) {
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
  glutInitWindowSize(screenWidth, screenHeight);
  glutInitWindowPosition(0, 0);
  glutCreateWindow("Mandelbrot");
glViewport(-1, 1, -1, 1);
  init();
  glutDisplayFunc(display);
  glutMainLoop();
  return 0;
}

  void init(void) {
  //glMatrixMode(GL_PROJECTION);
   gluOrtho2D(-3.0, 3.0, -3.0, 3.0);
  A = screenWidth / 4.0;
  B = 0.0;
  C = D = screenHeight / 2.0;
}

void display(void)
{
GLdouble x, f, y, xtemp, y0, x0, iteration, maxInteration;
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glPointSize(1);


glEnable(GL_POINT_SMOOTH);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);



for(y0 = -1; y0< 1.1; y0 = y0 + 0.0025){

for (x0 = -2.5; x0 < 1.1; x0 = x0 + 0.0025) {
    x = 0;
    y = 0;
    iteration = 0;
    maxInteration = 200;

    while(((x*x) + (y*y) <(2*2)) && iteration <maxInteration){
        xtemp = (x*x) - (y*y) + x0;
        y = (2*x*y) +y0;
        x = xtemp;
        iteration = iteration + 1;


        }
    if(iteration >= maxInteration){
        glBegin(GL_POINTS);

        glVertex2d(x0 , y0);
         glColor3f(0.0, 0.0, 0.0);
        glEnd();
    }
    else{
        ????

    }



}
}



glFlush();
  }

【问题讨论】:

  • “很确定”你的数学是正确的?我建议验证一下——打印出每个 glVertex2d 调用的坐标。此外,您的 Ortho 调用是可疑的:您正在尝试设置一个从 x = -500 到 x = 屏幕宽度的窗口。这是一个奇怪的组合。如果你只是在中心得到一个点,我猜顶点调用都发出接近零的值,最终在 [-500,w] 的“中间”
  • 我很好奇,为什么有人会否决这个问题?有时我很难理解 SO,+1:P
  • 您的视口方式太大了;整个 Mandelbrot 集都在 -2-2i 到 2+2i 的范围内。首先将视口坐标设置为 -2,2,-2,2。
  • 迭代数学是正确的,所以正如@JohnBode 建议的那样,中心的一个像素似乎是一个比例问题。
  • 感谢您的帮助。我将其更改为@JohnBode 建议,它仍然只是中心的一个点

标签: c opengl mandelbrot


【解决方案1】:

首先,这里有一些关于您的代码的建议:

  • 在处理复数或向量时,我建议您使用适当的快速数学库,这样您就可以避免使用单个组件进行操作,那里有非常快速的 cpu 数学库可以使用 SIMD 指令,您的代码将变为更具可读性
  • 绘制曼德布罗的方式确实是个坏主意。我的意思是,是的,如果您只想转储简单的图像并学习基础知识,那也没关系,但仅此而已。不要使用 GL_POINTS 并尝试直接渲染/更新纹理,或者更好的是,使用片段着色器 + glsl(推荐方式),这样即使您使用非优化数学,您的 mandelbrot 也会非常快速地渲染。
  • 坐标系,如果您仍然坚持按照您的方式使用 GL_POINTS,我将直接使用窗口坐标并从该空间转到 mandelbrot 数学域,即:[0,0,w,h] [-1,-1,1,1]

这是我的意思的一个小例子:

#include <GL/glut.h>
#include <math.h>
#include <stdio.h>

const int screen_width = 640;
const int screen_height = 480;
float c[4];
float z[4];

float clamp(float x, float vmin, float vmax) {
    if (x < vmin) {
        return vmin;
    } else if (x > vmax) {
        return vmax;
    }

    return x;
}

void dc_add(float *a, float *b, float *res) {
    res[0] = a[0] + b[0];
    res[1] = a[1] + b[1];
    res[2] = a[2] + b[2];
    res[3] = a[3] + b[3];
}

void dc_mul(float *a, float *b, float *res) {
    res[0] = a[0] * b[0] - a[1] * b[1];
    res[1] = a[0] * b[1] + a[1] * b[0];
    res[2] = a[0] * b[2] + a[2] * b[0] - a[1] * b[3] - a[3] * b[1];
    res[3] = a[0] * b[3] + a[3] * b[0] + a[2] * b[1] + a[1] * b[2];
}

void dc_sqr(float *a, float *res) {
    res[0] = a[0] * a[0] - a[1] * a[1];
    res[1] = 2.0f * a[0] * a[1];
    res[2] = 2.0f * (a[0] * a[2] - a[1] * a[3]);
    res[3] = 2.0f * (a[0] * a[3] + a[1] * a[2]);
}

float dot(float x, float y) { return x * x + y * y; }

void init(void) {
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0, screen_width, 0, screen_height);
}

void display(void) {
    glClear(GL_COLOR_BUFFER_BIT);
    glPointSize(1);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    for (int y = 0; y < screen_height; y++) {
        for (int x = 0; x < screen_width; x++) {
            float px = -1.0f + 2.0f * (float)x / (float)screen_width;
            float py = -1.0f + 2.0f * (float)y / (float)screen_height;
            px *= (float)screen_width / (float)screen_height;

            float tz = 0.5f;
            float zo = powf(1.2f, 1.2f);

            float m2 = 0.0f;
            float co = 0.0f;
            float temp[4];
            c[0] = px * zo; c[1] = py * zo; c[2] = 1.0; c[3] = 0.0;
            z[0] = 0.0f; z[1] = 0.0f; z[2] = 0.0f; z[3] = 0.0f;

            for (int i = 0; i < 256; i++) {
                if (m2 > 1024.0f) continue;

                dc_sqr(z, temp);
                dc_add(temp, c, z);
                m2 = dot(z[0], z[1]);
                co += 1.0f;
            }

            float d = 0.0f;
            if (co < 256.0f) {
                d = sqrtf((dot(z[0], z[1]) / dot(z[2], z[3]))) *
                    logf(dot(z[0], z[1]));
            }

            d = clamp(4.0f * d / zo, 0.0f, 1.0f);
            d = powf(d, 0.25f);
            glColor3f(d, d, d);
            glBegin(GL_POINTS);
            glVertex2d(x, y);
            glEnd();
        }
    }

    glFlush();
    glutSwapBuffers();
}

int main(int argc, char **argv) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
    glutInitWindowSize(screen_width, screen_height);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Mandelbrot");
    init();
    glutDisplayFunc(display);
    glutIdleFunc(display);
    glutMainLoop();

    return 0;
}

这是输出:

上述例子的数学是基于thisshadertoy。

上面的代码效率低下而且速度很慢,但它的主要目的是向你证明你永远不应该编写正确的 mandelbrot。

编码愉快。

【讨论】:

  • 好的,谢谢您的提示。我以skr1986.wordpress.com/2012/11/12/… 为例
  • 使用 float 将不允许对 Mandelbrot 集进行太多放大 :(
  • @chqrlie 确实,double 更好...此外,如果使用着色器,您也会受到“highp”范围的限制。
【解决方案2】:

您的代码中有一个简单的问题:您使用除法而不是乘法来计算像素坐标:将glVertex2d(x / 750, y / 750); 更改为

glVertex2d(x * 750, y * 750);

但是,这不是计算 Mandelbrot 集的正确方法。您应该计算平方模块超过 4.0 的迭代次数,然后将 (x0 * 300, y0 * 300) 处的像素颜色设置为该数字作为调色板条目或灰度级。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-03
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多