Управление увеличением масштаба набора Мандельброта

Я написал простой фрагментный шейдер, который отображает множество Мандельброта. Я делаю это в c и с opengl, используя glsl.

#version 330 core
in vec2 fCoord; //position.x position.y which is -1 to 1 on both axis
uniform int maxIterations;
uniform sampler1D mandiTexture;

out vec4 color;

void main()
{
   vec2 c, z;

    c.x = fCoord.x;
    c.y = fCoord.y;

        int i;
        z = vec2(0.0f, 0.0f);
        for(i=0; i<maxIterations; i++) {
            float x = (z.x * z.x - z.y * z.y) + c.x;
            float y = (z.y * z.x + z.x * z.y) + c.y;

            if((x * x + y * y) > 4.0) break;
            z.x = x;
            z.y = y;
        }

    vec4 tcolor;

    if (i == maxIterations)
    {
       tcolor = vec4(0.0f, 0.0f, 0.0f, 1.0f);
    }
       else
    {
       tcolor = texture(mandiTexture, float(i) / float(maxIterations));
    }
    color =  tcolor;
}

я заметил, что, играя с начальным значением z, я получаю разные результаты, но в основном они выходят за пределы моего квадрата. С z как 0, я получаю этот результат. введите описание изображения здесь

как вы можете видеть, левая сторона набора не отображается на четырехугольнике.

Значение c исходит из вершинного шейдера, поэтому я предполагаю, что оно идет от -1 до 1 по осям x и y и интерполируется между ними.

Мои вопросы:

  • 1) Как я могу центрировать изображение на квадроцикле? Я не совсем уверен в этом.
  • 2) Как я могу сказать увеличить масштаб набора Мандельброта и продолжить, скажем, я хочу увеличить конкретную часть набора?
  • 2B) Допустим, я нажимаю на экран и получаю позицию в НДЦ?
  • 3) Если я установлю свои максимальные итерации выше, набор, похоже, станет действительно неровным, это нормальное поведение?

Я думаю, что если я смогу понять, как увеличить масштаб устройства, я смогу понять, как увеличить конкретную часть, но я не уверен.

редактировать, убедившись, что мой код

main.c

int maxIterations = 70;
int iterAmount = 1;

char* vshad, *fshad;

GLuint verticesBuffer, colorBuffer, vao, texCoordBuffer, indicesBuffer;
GLuint mandiTextureID, sp;

mat4_s vm, pm, opm, tm;
GLint viewMat = -1;
GLint projMat = -1;
GLint modelMat = -1;

GLint mandiTexture = -1;
GLint maxIterLoc = -1;



void initShaders(void)
{

    char* vertexShaderSource = getResource("vert.shad");
    char* fragmentShaderSource = getResource("frag.shad");

    vshad = readFile(vertexShaderSource);
    fshad = readFile(fragmentShaderSource);

    free(vertexShaderSource);
    free(fragmentShaderSource);
}

int run_game()
{
    current_utc_time(&start_time);
    while(game_running)
    {
        current_utc_time(&current_time);
        double frameTime = (diff(start_time,current_time).tv_sec + diff(start_time,current_time).tv_nsec) * .00000001;
        //printf("float time: %0.8f\n",frameTime);
        if ( frameTime > 0.25 )
        {
            frameTime = 0.25;
        }
        current_utc_time(&start_time);
        current_time = start_time;

        accumulator += frameTime;

        while ( accumulator >= dt )
        {
            accumulator -= dt;
            t += dt;
            //printf("fixed update dt: %0.8f\n",dt);
        }
        //render_state = currentState * alpha +  previousState * ( 1.0 - alpha );
        const double alpha = accumulator / dt;
        render();

        if(game_running < 1) { break; }
        while (SDL_PollEvent(&event))
        {
            switch (event.type) {
                case SDL_QUIT:
                    game_running = -1;
                    break;
                case SDL_KEYDOWN:
                    switch (event.key.keysym.sym)
                    {
                        case SDLK_ESCAPE:
                            game_running = -1;
                            break;
                    }
                    break;
            }
        }
    }
    return -1;
}

int main(int argc, char const *argv[]) {
    initShaders();

    mat4_identity(&vm);
    vec3_s eye    = {0, 0, 0};
    vec3_s center = {0, 0, -1};
    vec3_s up     = {0, 1, 0};

    mat4_lookAt(&vm, &eye, &center, &up);

    mat4_identity(&opm);
    mat4_ortho(&opm, 0, 200, 0, 200, 1, 100);

    mat4_identity(&tm);
    mat4_scalex(&tm, &tm, 100, 100, 0);
    mat4_translatex(&tm, &tm, 100.0f, 100.0f, -20);

    SDL_Surface* mandiSurface = loadPNG(getResource("mandi.png"));

    if(!mandiSurface) {
        printf("IMG_Load: %s\n", IMG_GetError());
        // handle error
    }

    GLenum Mode1 = GL_RGB;

    if(4 == mandiSurface->format->BytesPerPixel)
    {
        Mode1 = GL_RGBA;
        printf("mode change");
    }

    sp = getShaderProgram(vshad, fshad);
    r = newRenderable2d();

    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &verticesBuffer);
    glGenBuffers(1, &colorBuffer);
    glGenBuffers(1, &indicesBuffer);
    glGenBuffers(1, &texCoordBuffer);

    glBindVertexArray(vao); //bind vertex array buffer

    glBindBuffer(GL_ARRAY_BUFFER, verticesBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(r->vertices), r->vertices, GL_STATIC_DRAW);

    //bind n setup indices
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(r->indices), r->indices, GL_STATIC_DRAW);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind indices

    //bind n setup colors
    glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(r->colors), r->colors, GL_STATIC_DRAW);
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind colors

    //bind n setup texture coords
    glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(r->texCoords), r->texCoords, GL_STATIC_DRAW);
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(2);
    glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind texture coords

    glBindVertexArray(0); //unbind vertex array buffer

    //mandi 1d texture
    glGenTextures(1, &mandiTextureID);
    glBindTexture(GL_TEXTURE_1D, mandiTextureID);

    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glTexImage1D(GL_TEXTURE_1D, 0, Mode1, mandiSurface->w, 0, Mode1, GL_UNSIGNED_BYTE, mandiSurface->pixels);
    glBindTexture(GL_TEXTURE_1D, 0);
    free(mandiSurface);


    while(run_game() >= 0);
    free(r);
    IMG_Quit();
    SDL_GL_DeleteContext(maincontext);
    SDL_DestroyWindow(window);
    return 0;
}

void render()
{
    glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    glUseProgram(sp);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_1D, mandiTextureID);//mandiTexture
    mandiTexture = getUniformLocation(sp, "mandiTexture");
    glUniform1i(mandiTexture, 0);


    glBindVertexArray(verticesBuffer);
    viewMat = getUniformLocation(sp, "viewMat");
    modelMat = getUniformLocation(sp, "modelMat");
    projMat = getUniformLocation(sp, "projMat");

    maxIterLoc = getUniformLocation(sp, "maxIterations");

    glUniformMatrix4fv(viewMat, 1, GL_FALSE, vm.m);
    glUniformMatrix4fv(projMat, 1, GL_FALSE, opm.m);
    glUniformMatrix4fv(modelMat, 1, GL_FALSE, tm.m);

    glUniform1i(maxIterLoc, maxIterations);

    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);

    SDL_GL_SwapWindow(window);
}

int init_sdl(int width, int height, char* title, double fps)
{

if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
  {
    SDL_Log("sdl failed to init");
    SDL_Quit();
    return -1;
  }

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);


  window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
  if(window == NULL)
  {
    SDL_Log("sdl failed to create window");
    SDL_Quit();
    return -1;
  }

  maincontext = SDL_GL_CreateContext(window);
  if(maincontext == NULL)
  {
    SDL_Log("sdl failed to create opengl context");
    SDL_Quit();
    return -1;
  }
    glEnable(GL_CULL_FACE);
    glCullFace(GL_BACK);
    SDL_GL_SetSwapInterval(1);


  return 1;
}

вершинный шейдер

#version 330 core

layout (location = 0) in vec3 position;
layout (location = 1) in vec3 icolor;
layout (location = 2) in vec2 vTexCoord;

uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projMat;

out vec4 fcolor;
out vec2 fTexCoord;
out vec2 fCoord;

void main()
{
    gl_Position =  projMat * viewMat * modelMat * vec4(position, 1.0);

    fCoord = vec2(position);
    fTexCoord = vTexCoord;
    fcolor = vec4(icolor, 1.0f);
}

Благодаря @samgak я смог решить проблемы, которые у меня были, и теперь я добавляю несколько снимков из набора Мандельброта.

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

1 ответ

Решение

Значение c исходит из вершинного шейдера, поэтому я предполагаю, что оно идет от -1 до 1 по осям x и y и интерполируется между ними.

Правильно.

1) Как я могу центрировать изображение на квадроцикле? Я не совсем уверен в этом.

Вам просто нужно уменьшить масштаб в 1,5 раза и отцентрировать его на -0,5. Интересные части множества Мандельброта простираются примерно от -2 до 1 на действительной оси и от -i до i на воображаемой оси:

2) Как я могу сказать увеличить некоторые из набора Мандельброта и продолжить, скажем, я хочу увеличить конкретную часть набора? 2B) Допустим, я нажимаю на экран и получаю позицию в НДЦ?

Верните 2 формы, которые были у вас в предыдущей версии:

uniform vec2 center;
uniform float scale;

Объявите переменные для хранения этих значений в вашем коде C и установите их с помощью glUniform2f а также glUniform1f, Для центрирования набора начальные значения должны быть -0,5, 0,0 для центра и 1,5 для шкалы (большие значения уменьшаются). Затем в своем фрагментном шейдере просто примените их следующим образом:

c = (fCoord * scale) + center;

Чтобы щелкнуть по экрану и увеличить конкретное местоположение, поверните местоположение мыши в значение от -1,-1 до 1,1 в зависимости от его положения на экране, затем примените к нему приведенное выше уравнение, чтобы найти местоположение, на котором вы щелкнули, Установите это как новый центр и умножьте масштаб на значение меньше 1, чтобы увеличить заданную величину.

3) Если я установлю свои максимальные итерации выше, набор, похоже, станет действительно неровным, это нормальное поведение?

Скриншот, который вы разместили, выглядит нормально. Вероятно, это выглядело бы лучше, если бы вы реализовали некоторую мультисэмплирование в своем фрагментном шейдере (например, вычислите несколько значений в цикле и сложите их вместе, чтобы каждый пиксель фактически представлял собой среднее значение для блока пикселей 2x2 или 4x4 и т. Д.).

Если вы увеличите масштаб в конце концов, вы попадете в пределы точности чисел с плавающей запятой, используемых графическим процессором.

Другие вопросы по тегам