Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 5 of 5

Thread: Is it possible to draw 2D fractals in Modern Opengl ? (Primitive based)

  1. #1
    Junior Member Newbie
    Join Date
    Feb 2018
    Posts
    17

    Unhappy Is it possible to draw 2D fractals in Modern Opengl ? (Primitive based)

    Well i've got a problem while making my Fractal graphics engine.
    Which is made entirely on Modern OpenGL because this engine has to fit from simplest of 2D fractals to the most complex 3D fractals in Real-Time.
    The problem is that in Old graphics pipeline there would be
    Code :
    glBegin(x,y),glEnd()
    .With these commands i could repeat them recursively.
    But in New Pipeline there is only array,shader and vbo based drawing with
    Code :
     glDrawArray
    .
    How can i recurse or even iterate array coordinates to "infinity" ?
    For now i am trying to implement 2D Fractal Tree.
    Next objects would be Sierpinski Triangle,Fern,Koch snowflake.
    2D Objects in Modern engine would be shown in Orthographic projection and 3D Objects would be in Perspective projection.
    And all of them use Fragment and Vertex shaders.For color managment and interpolation.

    There is old code of my Fractal Tree made with old graphics Pipeline.

    Code :
    #include<iostream>
    #include<cmath>
    #include <GL/GLUT.h>
     
    #ifndef M_PI
    #define M_PI 3.14159265358979323846
    #endif
     
    double rtd=M_PI/180; //RADTODEG
    // cosine
    // cos atsako uz x
    // sin atsako uz y
     
     
    void sakosr(float px1,float py1,float px2,float py2,int kamp,int n,double mult){
    	glBegin(GL_LINE_LOOP); // Linijų tipas
    	glVertex2f(px2,py2);
    	float px3=(px2-px1)*mult;
    	float py3=(py2-py1)*mult;
    	GLfloat px3r=px3*cos(kamp*rtd)+py3*sin(kamp*rtd)+px2;
    	GLfloat py3r=-px3*sin(kamp*rtd)+py3*cos(kamp*rtd)+py2;
    	glVertex2f(px3r,py3r);
    	glVertex2f(px2,py2);
    	GLfloat px3l=px3*cos(-kamp*rtd)+py3*sin(-kamp*rtd)+px2;
    	GLfloat py3l=-px3*sin(-kamp*rtd)+py3*cos(-kamp*rtd)+py2;
    	glVertex2f(px3l,py3l);
    	px1=px2;
    	py1=py2;
    	px2=px3r;
    	py2=py3r;
    	glEnd();
    	if(n>0){
    		sakosr(px1,py1,px2,py2,kamp,n-1,mult);
    		px2=px3l;
    		py2=py3l;
    		sakosr(px1,py1,px2,py2,kamp,n-1,mult);
    	}
    }

  2. #2
    Intern Contributor
    Join Date
    Apr 2016
    Location
    Berlin / Germany
    Posts
    61
    With glTransformfeedbackvaryings, that are shader-varyings (like i.e. gl_vertex).

    I've just lerned it myself with help of this forum, so i take the time to anwer you. Mybe this helps a bit:

    On my system, there was a flag to be set before ibitializing OpenGL. Since i init with:
    Code :
        glewExperimental= TRUE;        // needed for glew version under 1.3  -  before glewInit()                 
        GLenum err      = glewInit();                                                                
        if (GLEW_OK    != err) {    wxMessageBox("FATAL ERROR:\n"+wxString(glewGetErrorString(err)));           exit(0);    }
    ...glTransformfeedbackvaryings doesn't crash my program anyomre.



    You don't need a fragment-shader (you want to retrieve / calculate) vertices. Call glDisgardrastarizer(GL_TRUE); in order to do this.

    On my systen (there were some discussions about this point), a fragement-shader has to be used anyway to prevent the shader-compiler to remove varyings that are not used.


    The basic method for iterating one(!) array is this:
    - use i.e. "in float tff_in[8];" and "out float tff_out[8];" in your vertex-shader.
    - compile it and attach it to the program
    - call glTransformfeedbackvaryings("tff_out");
    - call glDiscardrastarizer(GL_TRUE); - might also be done later, i think
    (-attach maybe fragment-shader - on my system no result without "in float tff_out[8];\nout vec4 color;\nvoid main(){\ncolor[0]=tff_out[0];\n};")
    - link program

    After this, you have to think about the input, which is as simple as tricky. The point is that you have (in my example) an array eight floats named "tff_in".
    What yo'll have to do is to apply at first the existence on an input named "tff_in" and after this a pointer to each of the array-items. Here is my code doing this:
    Code :
        GLint tffInput          = glGetAttribLocation (curPRG, (char*)list[3]);             CheckGL("glGetAttribLocation");  
        if   (tffInput < 0)       return;
     
        for  (int i = 0; i < numAttribs; i++) {   
            glEnableVertexAttribArray (tffInput + i);                                       CheckGL("glEnableVertexAttribArray"); 
            glVertexAttribPointer     (tffInput + i, 1, GL_FLOAT, GL_FALSE, byteStride, (GLvoid*) (i * sizeof(GLfloat)) );     CheckGL("glVertexAttribPointer"); 
        }

    This was preparation. Now i to do someting like this:
    Code :
    void clsVAO::Refeed () {                                                                CheckGL("Errors left in cue");
     
    // Create destination
        GLuint dst;
        glGenBuffers            (1, &dst);
        glBindBuffer            (GL_ARRAY_BUFFER, dst);
        glBufferData            (GL_ARRAY_BUFFER, bufBytes, NULL, GL_STATIC_DRAW);          CheckGL("TBO-Creation");  
     
    // PROCESS:                                                                         
        glEnable                (GL_RASTERIZER_DISCARD);                                    CheckGL("glEnable(GL_RASTERIZER_DISCARD)"); 
        glBindBufferBase        (GL_TRANSFORM_FEEDBACK_BUFFER, 0, dst);                     CheckGL("glBindBufferBase"); 
     
        glBeginTransformFeedback(GL_POINTS);                                                CheckGL("glBeginTransformFeedback");              
            glDrawArrays        (GL_POINTS, 0, NumV);                                       CheckGL("glDrawArrays"); 
        glEndTransformFeedback  ();                                                         CheckGL("glEndTransformFeedback"); 
     
        glFlush                 ();                                                         CheckGL("glFlush"); 
     
    // Swap    
        GLuint tmp = VBO;       VBO = dst; 
        glDeleteBuffers         (1,  &tmp);
     
    // Clear
        glBindBuffer            (GL_ARRAY_BUFFER, 0);
        glDisable               (GL_RASTERIZER_DISCARD);                                    CheckGL("glEnable(GL_RASTERIZER_DISCARD)"); 
        glUseProgram            (0);        
    }


    What results is an vertex-array-feedback. So, each of the inputs aof your fractal (like x,y,r,i with Mandebrodt), can be iterated by the shader-program doing someting with the incoming values and write the result to output in the same order (tff_in[3]->tff_out[3]).


    Also you may look here: https://open.gl/feedback, which is short and helped a lot...




    This was a path a to the start first steps, but it's in the end simple. But note: Evrything that is not copy-pasted is wrote out of my head (just lerned some days ago). So no guaraty, for anything.

    Best,
    Frank




    PS. Good idea. I'll progam a Mandebrodt-vertex-shader now - just for testing, what i leaned the last days...
    Last edited by art-ganseforth; 10-09-2018 at 04:15 PM.

  3. #3
    Junior Member Newbie
    Join Date
    Feb 2018
    Posts
    17

    Thank you for reply but

    Quote Originally Posted by art-ganseforth View Post
    With glTransformfeedbackvaryings, that are shader-varyings (like i.e. gl_vertex).

    I've just lerned it myself with help of this forum, so i take the time to anwer you. Mybe this helps a bit:

    On my system, there was a flag to be set before ibitializing OpenGL. Since i init with:
    Code :
        glewExperimental= TRUE;        // needed for glew version under 1.3  -  before glewInit()                 
        GLenum err      = glewInit();                                                                
        if (GLEW_OK    != err) {    wxMessageBox("FATAL ERROR:\n"+wxString(glewGetErrorString(err)));           exit(0);    }
    ...glTransformfeedbackvaryings doesn't crash my program anyomre.



    You don't need a fragment-shader (you want to retrieve / calculate) vertices. Call glDisgardrastarizer(GL_TRUE); in order to do this.

    On my systen (there were some discussions about this point), a fragement-shader has to be used anyway to prevent the shader-compiler to remove varyings that are not used.


    The basic method for iterating one(!) array is this:
    - use i.e. "in float tff_in[8];" and "out float tff_out[8];" in your vertex-shader.
    - compile it and attach it to the program
    - call glTransformfeedbackvaryings("tff_out");
    - call glDiscardrastarizer(GL_TRUE); - might also be done later, i think
    (-attach maybe fragment-shader - on my system no result without "in float tff_out[8];\nout vec4 color;\nvoid main(){\ncolor[0]=tff_out[0];\n};")
    - link program

    After this, you have to think about the input, which is as simple as tricky. The point is that you have (in my example) an array eight floats named "tff_in".
    What yo'll have to do is to apply at first the existence on an input named "tff_in" and after this a pointer to each of the array-items. Here is my code doing this:
    Code :
        GLint tffInput          = glGetAttribLocation (curPRG, (char*)list[3]);             CheckGL("glGetAttribLocation");  
        if   (tffInput < 0)       return;
     
        for  (int i = 0; i < numAttribs; i++) {   
            glEnableVertexAttribArray (tffInput + i);                                       CheckGL("glEnableVertexAttribArray"); 
            glVertexAttribPointer     (tffInput + i, 1, GL_FLOAT, GL_FALSE, byteStride, (GLvoid*) (i * sizeof(GLfloat)) );     CheckGL("glVertexAttribPointer"); 
        }

    This was preparation. Now i to do someting like this:
    Code :
    void clsVAO::Refeed () {                                                                CheckGL("Errors left in cue");
     
    // Create destination
        GLuint dst;
        glGenBuffers            (1, &dst);
        glBindBuffer            (GL_ARRAY_BUFFER, dst);
        glBufferData            (GL_ARRAY_BUFFER, bufBytes, NULL, GL_STATIC_DRAW);          CheckGL("TBO-Creation");  
     
    // PROCESS:                                                                         
        glEnable                (GL_RASTERIZER_DISCARD);                                    CheckGL("glEnable(GL_RASTERIZER_DISCARD)"); 
        glBindBufferBase        (GL_TRANSFORM_FEEDBACK_BUFFER, 0, dst);                     CheckGL("glBindBufferBase"); 
     
        glBeginTransformFeedback(GL_POINTS);                                                CheckGL("glBeginTransformFeedback");              
            glDrawArrays        (GL_POINTS, 0, NumV);                                       CheckGL("glDrawArrays"); 
        glEndTransformFeedback  ();                                                         CheckGL("glEndTransformFeedback"); 
     
        glFlush                 ();                                                         CheckGL("glFlush"); 
     
    // Swap    
        GLuint tmp = VBO;       VBO = dst; 
        glDeleteBuffers         (1,  &tmp);
     
    // Clear
        glBindBuffer            (GL_ARRAY_BUFFER, 0);
        glDisable               (GL_RASTERIZER_DISCARD);                                    CheckGL("glEnable(GL_RASTERIZER_DISCARD)"); 
        glUseProgram            (0);        
    }


    What results is an vertex-array-feedback. So, each of the inputs aof your fractal (like x,y,r,i with Mandebrodt), can be iterated by the shader-program doing someting with the incoming values and write the result to output in the same order (tff_in[3]->tff_out[3]).


    Also you may look here: https://open.gl/feedback, which is short and helped a lot...




    This was a path a to the start first steps, but it's in the end simple. But note: Evrything that is not copy-pasted is wrote out of my head (just lerned some days ago). So no guaraty, for anything.

    Best,
    Frank




    PS. Good idea. I'll progam a Mandebrodt-vertex-shader now - just for testing, what i leaned the last days...
    Hi Frank thanks for quick reply but your code is viable only for iterative fractals (Mandelbrot .etc)
    The problem is that I want to draw recursive fractals like fractal tree fern...

  4. #4
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,955
    Quote Originally Posted by StabberKnight906 View Post
    How can i recurse or even iterate array coordinates to "infinity" ?
    For now i am trying to implement 2D Fractal Tree.
    Multiple passes with transform feedback. Start with a set of vertex arrays containing a single identity matrix. Each pass uses instanced rendering to generate N copies of the data, each copy transformed by a different matrix. After k passes, you'll have N^k matrices. Use a separate pass for rendering.

    Optionally use a geometry shader to discard matrices whose determinant is below a given threshold, so the leaf nodes have roughly constant size rather than constant depth in the tree. In this case, the vertex arrays should contain each matrix' determinant in addition to the matrix, and compute determinants as |A*B|=|A|*|B|.

  5. #5
    Junior Member Newbie
    Join Date
    Feb 2018
    Posts
    17
    GClements thank you for reply im going to try out your method of transform feedback to have n branches on the fractal tree.

    It would be good if you (Or Somebody) could give me extensive transform feedback example or even geometry shader one to analyze, because this is the first time i'm using this method.
    And yes I'm still a newbie in OpenGL even more so in Modern OpenGL

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •