2

I wrote a simple fragment shader that renders a mandelbrot set. I am doing this in c and with opengl using 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;
}

i've noticed playing around with the initial z value I get some different results but mostly they extend outside of my quad. With z as 0, 0 I get this result. enter image description here

as you can see the left side of the set is not being rendered on the quad.

The c value is coming from the vertex shader so i assume it goes for -1 to 1 on both x and y axis and being interpolated in between.

My questions are:

  • 1) How can I center the image on the quad? I am not really sure of that.
  • 2) How can I say zoom in on some in on the mandelbrot set and a follow up, lets say I want to zoom in on a specific part of the set?
  • 2B) Let's say I click the screen and get the position in NDC?
  • 3) If I set my max iterations higher the set seems to get really jaggy, is that normal behavior?

I think if I can understand how to zoom in on the set I can figure out how to zoom in on a specific part but I am unsure.

edit, making sure that my code is

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;
}

vertex shader

#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);
}

thanks to @samgak I was able to fixed the issues that I was having and now I am adding some shots of the Mandelbrot set.

enter image description here

enter image description here

enter image description here

MD XF
  • 7,860
  • 7
  • 40
  • 71
user1610950
  • 1,837
  • 5
  • 33
  • 49
  • If you have a specific problem with your code, please provide a [mcve]. As-is, the question might be more suitable for code review, but read their FAQs before posting. – too honest for this site Aug 10 '15 at 18:19
  • @Olaf That code is broken, making it off-topic on Code Review. Please, read our FAQs before recommending anything. – Ismael Miguel Aug 10 '15 at 18:21
  • @IsmaelMiguel: Did you even read the last part of my comment? – too honest for this site Aug 10 '15 at 18:23
  • @Olaf Yes. And, as-is, the question is off-topic there. – Ismael Miguel Aug 10 '15 at 18:23
  • @IsmaelMiguel: So OP should notice that when reading the FAQs before posting as I told him. – too honest for this site Aug 10 '15 at 18:24
  • @Olaf You should notice it before recommending anything. Don't make others waste their time. This question perfectly fits here. And yes, I upvoted it. – Ismael Miguel Aug 10 '15 at 18:25
  • @IsmaelMiguel: Without further information, the question is not suitable here either. – too honest for this site Aug 10 '15 at 18:26
  • @Olaf Then downvote or vote to close! As said by the co-foundator: [Don't Migrate Crap](http://meta.stackexchange.com/a/91446) – Ismael Miguel Aug 10 '15 at 18:30
  • @IsmaelMiguel: "Then downvote or vote to close!" Thans a lot for the hint. I'd never had that thought myself. I will not further ask, where I wrote or asked to migrate crap. EOF – too honest for this site Aug 10 '15 at 18:31
  • @user1610950 In your previous question you had two extra uniforms in your fragment shader: vec2 center and float scale, which you seem to have removed. If you put them back you can use them for zooming in on a particular part of the set. – samgak Aug 10 '15 at 23:28
  • @samgak I was using the center and scale values from another shader that I saw online. I couldn't figure out the proper inputs to use for those values so I got rid of them. That's why I am asking this question because if I can understand the concept behind zooming into the set then I won't just be using variables that I don't understand. I removed those values and the fragment shader provided works and produces the output in the image. Actually I will update the question to make it be [Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) – user1610950 Aug 11 '15 at 00:10
  • @Olaf i'm not trying to aggravate you, i read the link posted in the comments and updated the question accordingly. I hope this fixes the issue you were having with my questions. A reply saying yes or no and why not would be appreciated. Along with help sorting out the questions that I ask if all is in order with my question. – user1610950 Aug 11 '15 at 00:30

1 Answers1

3

The c value is coming from the vertex shader so i assume it goes for -1 to 1 on both x and y axis and being interpolated in between.

That's correct.

1) How can I center the image on the quad? I am not really sure of that.

You just need to zoom out by a factor of 1.5 and center it on -0.5. The interesting parts of the Mandelbrot set extend from roughly -2 to 1 on the real axis and -i to i on the imaginary axis:

enter image description here

2) How can I say zoom in on some in on the mandelbrot set and a follow up, lets say I want to zoom in on a specific part of the set? 2B) Let's say I click the screen and get the position in NDC?

Put back the 2 uniforms that you had in your previous version:

uniform vec2 center;
uniform float scale;

Declare variables to hold these values in your C code and set them with glUniform2f and glUniform1f. To center the set the initial values should be -0.5, 0.0 for the center, and 1.5 for the scale (larger values zoom out). Then in your fragment shader, just apply them like this:

c = (fCoord * scale) + center;

To click the screen and zoom in on a particular location, turn the mouse location into a value between -1,-1 and 1,1 based on its position on the screen then apply the above equation to it to find the location you clicked on. Set that as the new center and multiply scale by a value less than 1 to zoom in a given amount.

3) If I set my max iterations higher the set seems to get really jaggy, is that normal behavior?

The screenshot you posted looks ok. It would probably look better if you implemented some kind of multi-sampling in your fragment shader (e.g. calculate several values in a loop and add them together so that each pixel is actually the average of a 2x2 or 4x4 block of pixels etc).

If you zoom in far enough eventually you will run into the limits of the precision of the floating point numbers used by the GPU.

samgak
  • 23,944
  • 4
  • 60
  • 82
  • 1
    thanks for all the help, it worked out great. I will update the question with some shots that I took from a zoomed in position. Doing some more research I found out that the aliasing is from just number precision which I could fix with some fixed point math stuff. – user1610950 Aug 11 '15 at 16:39