Hi there.
I have been trying to implement 2D fractal tree to my engine which runs on modern opengl for the past month and without any success at all.
I have asked some questions regarding the issues which i am having and tried to implement given answers to my program and still could not make a working prototype.
To begin with i have the most trouble with iterating the tree.
The problem is that my fractal is actually an object which has different variables that define the fractal which is
Fractal_Tree tree1(depth, branchangle, point1, point2, multiplier,branchcount);
So from previous question i have been suggested to use transform feedback in which shaders are an necessity.
Consequently i got another problem which is that i use orthographic projection space vertex shader to have a manageable “2D” space that is also in another shader program which is called the WorldShader but also i am striving for program to manage and render various fractal objects so the question is how it is possible to connect two different shader programs while having modularity ?
In addition i also got confused which shaders should i be using for calculating and iterating new branching point coordinates in my transform feedback, because it seems like the geometry shader is the best choice for the shader but the problem is that i have 2 points which in fact make trunk of the tree and geometry shader aplies to all points.
So there are some formulas which i have to apply to have a fractal tree
take into consideration that each value here have the x and y axis.
midbranch = (point1 - point2) * multiplier;
//bangle is abbreviation for branch angle
rightbranch.x=midbranch.x * cos(bangle * (M_PI / 180)) + midbranch.y * sin(bangle *(M_PI / 180)) + point2.x;
leftbranch.x=midbranch.x * cos(-bangle * (M_PI / 180)) + midbranch.y * sin(-bangle *(M_PI / 180)) + point2.x;
rightbranch.y = -midbranch.x * sin(bangle * (M_PI / 180)) + midbranch.y * cos(bangle *(M_PI / 180)) + point2.y;
leftbranch.y = -midbranch.x * sin(-angle * (M_PI / 180)) + midbranch.y * cos(-bangle *(M_PI / 180)) + point2.y;
So there’s some source code:
main.cpp
#include "Window/Core/Window.h"
#include "Shaders/ShaderUtil/ShaderProgram.hpp"
#include "Shaders/ShaderUtil/addshader.h"
#include "Drawing//TREE/Fractal_Tree.h"
#include "Maths/Math.hpp"
float CAMangle = (CAMangle = 0) * M_PI / 180;
extern "C" {
_declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
}
int id;
long double CAMx = 0, CAMy = 0, CAMz = 1;
long double zoom = 1;
int width = 800;
int height = 640;
glm::vec2 point1;
glm::vec2 point2;
int bangle = 90;
GLint objectID;
int main()
{
Window Window(width, height, "FRTI ENGINE", NULL); // Width,Height,,Title,MonitorState
glClearColor(1.0, 1.0, 1.0, 1.0); // Clear color rgba
point1.x = 0.0;
point1.y = 0.0;
point2.x = 0.0;
point2.y = 2;
//ShaderReadBasic ReadShaders("Source/Shaders/Files/Vertex/Basic.vert","Source/Shaders/Files/Fragment/Basic.frag");//reading of .vert ,geom,.frag files.
//ReadShaders.enable(); //enabling shaders
// main shader loader
ShaderLoader vertexmain(GL_VERTEX_SHADER);
vertexmain.fileloader("Source/Shaders/Files/Vertex/main.vert");
vertexmain.compile();
ShaderLoader fragmentmain(GL_FRAGMENT_SHADER);
fragmentmain.fileloader("Source/Shaders/Files/Fragment/main.frag");
fragmentmain.compile();
ShaderProgram WorldShader;
WorldShader.attachShader(vertexmain);
WorldShader.attachShader(fragmentmain);
WorldShader.linkProgram();
WorldShader.addUniform("pro_matrix");
WorldShader.addUniform("model_matrix");
WorldShader.addUniform("view_matrix");
WorldShader.addUniform("scale_matrix");
WorldShader.addUniform("OutColor");
//ReadShaders.addShader("geometry", "Source/Drawing/TREE/TREE.geom");
glm::mat4 ortho = glm::ortho(-16.0*(width / height), 16.0*(width / height), -16.0, 16.0);
float multiplier = 0.5;
int depth = 5;
while (!Window.closed())
{
Fractal_Tree tree1(depth, bangle, point1, point2, multiplier,4);
Window.clear();
WorldShader.use();
//Camera
glUniformMatrix4fv(WorldShader.uniform("pro_matrix"), 1, GL_FALSE, glm::value_ptr(ortho));
glUniformMatrix4fv(WorldShader.uniform("model_matrix"), 1, GL_FALSE, glm::value_ptr(glm::translate(glm::mat4(1.0), glm::vec3(CAMx, CAMy, CAMz))));
glUniformMatrix4fv(WorldShader.uniform("view_matrix"), 1, GL_FALSE, glm::value_ptr(glm::rotate(glm::mat4(1.0),CAMangle,glm::vec3(0,0,1))));
glUniformMatrix4fv(WorldShader.uniform("scale_matrix"), 1, GL_FALSE, glm::value_ptr(glm::scale(glm::mat4(1.0), glm::vec3(zoom, zoom, 1))));
//ReadShaders.setUniforMat4f("pro_matrix", ortho);
//ReadShaders.setUniforMat4f("model_matrix", glm::translate(glm::mat4(1.0), glm::vec3(CAMx, CAMy,CAMz)));
//ReadShaders.setUniforMat4f("view_matrix", glm::rotate(glm::mat4(1.0), CAMangle, glm::vec3(0, 0,1)));
//ReadShaders.setUniforMat4f("scale_matrix", glm::scale(glm::mat4(1.0), glm::vec3(zoom,zoom,1)));
// Coloring
double timeValue = glfwGetTime();
double greenValue = cos(timeValue) / 2.0 + 0.5;
glUniform4f(WorldShader.uniform("OutColor"), 0.0,greenValue,0.0,1.0);
//ReadShaders.setUniform4f("OutColor", glm::vec4(0.0,greenValue,0.0,1.0));
//input.
if (Window.KeyPressed(GLFW_KEY_Q))
{
CAMangle += 0.1;
}
if (Window.KeyPressed(GLFW_KEY_E))
{
CAMangle -= 0.1;
}
if (Window.KeyPressed(GLFW_KEY_W))
{
CAMy -= 0.5/zoom;
if (Window.KeyPressed(GLFW_KEY_LEFT_SHIFT))
{
CAMy -= 1.0 / zoom;
}
}
if (Window.KeyPressed(GLFW_KEY_S))
{
CAMy += 0.5 / zoom;
if (Window.KeyPressed(GLFW_KEY_LEFT_SHIFT))
{
CAMy += 1.0 / zoom;
}
}
if (Window.KeyPressed(GLFW_KEY_A))
{
CAMx += 0.5/zoom;
if (Window.KeyPressed(GLFW_KEY_LEFT_SHIFT))
{
CAMx += 1.0 / zoom;
}
}
if (Window.KeyPressed(GLFW_KEY_D))
{
CAMx -= 0.5/zoom;
if (Window.KeyPressed(GLFW_KEY_LEFT_SHIFT))
{
CAMx -= 1.0 / zoom;
}
}
if (Window.KeyPressed(GLFW_KEY_P))
{
zoom += 0.01*zoom;
if (zoom >= DBL_MAX)
{
zoom = DBL_MAX;
}
}
if (Window.KeyPressed(GLFW_KEY_O))
{
zoom -= 0.01*zoom;
if (zoom < 0)
{
zoom = 0;
}
}
if (Window.KeyPressed(GLFW_KEY_ESCAPE))
{
glfwTerminate();
return false;
}
//if (Window.KeyPressed(GLFW_KEY_F11))
if (Window.KeyPressed(GLFW_KEY_M))
{
bangle++;
}
//drawing
tree1.DrawTree();
WorldShader.disable();
Window.update();
}
return 0;
}
Fractal_Tree.h
#pragma once
#ifndef FRACTALTREE_H
#define FRACTALTREE_H
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "../../Shaders/ShaderUtil/ShaderProgram.hpp"
#include "../../Maths/Math.hpp"
class Fractal_Tree
{
private:
double b_angle;
double b_mult;
ShaderProgram TreeShader;
int b_depth;
glm::vec2 stemstart;
glm::vec2 stemend;
public:
Fractal_Tree(int n, int angle, glm::vec2 p1, glm::vec2 p2, double mult,int branchcount);
~Fractal_Tree();
void DrawTree();
};
#endif
Fractal_Tree.cpp
#include "Fractal_Tree.h"
//ShaderProgram TreeShader;
//Tree Definition
Fractal_Tree::Fractal_Tree(int n, int angle, glm::vec2 p1, glm::vec2 p2, double mult,int branchcount)
{
b_angle = angle;
b_depth = n;
b_mult = mult;
stemstart.x = p1.x;
stemstart.y = p1.y;
stemend.x = p2.x;
stemend.y = p2.y;
}
Fractal_Tree::~Fractal_Tree()
{
}
void Fractal_Tree::DrawTree()
{
unsigned long long int sumofpoints = pow(2, b_depth + 1) - 1;
glm::vec2 midbranch;
midbranch.x = (stemend.x - stemstart.x)* b_mult;
midbranch.y = (stemend.y - stemstart.y)* b_mult;
//test
double x3r = midbranch.x * cos(b_angle * (M_PI / 180)) + midbranch.y * sin(b_angle *(M_PI / 180)) + stemend.x;
double y3r = -midbranch.x * sin(b_angle * (M_PI / 180)) + midbranch.y * cos(b_angle *(M_PI / 180)) + stemend.y;
double x3l = midbranch.x * cos(-b_angle * (M_PI / 180)) + midbranch.y * sin(-b_angle * (M_PI / 180)) + stemend.x;
double y3l = -midbranch.x * sin(-b_angle * (M_PI / 180)) + midbranch.y * cos(-b_angle * (M_PI / 180)) + stemend.y;
//stem coords
GLdouble stem[] =
{
stemstart.x,stemstart.y,0,
stemend.x,stemend.y,0,
};
GLuint root_VBO;
glGenBuffers(1, &root_VBO);
glBindBuffer(GL_ARRAY_BUFFER, root_VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(stem), &stem, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
glDrawArrays(GL_LINE_STRIP, 0, 2);
/* GLfloat test[] =
{
3,3,0,
6,6,0,
};
GLuint test_VBO;
glGenBuffers(1, &test_VBO);
glBindBuffer(GL_ARRAY_BUFFER, test_VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(test), &test, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(0);
glBindVertexArray(0);
glDrawArrays(GL_LINES, 0, 4);
*/
//glGenTransformFeedbacks(1, &branch_tff);
//lBindTransformFeedback(GL_TRANSFORM_FEEDBACK, branch_tff);
//glBeginTransformFeedback(GL_LINES);
//glDrawArrays(GL_LINE_STRIP,false,b_depth);
//glEndTransformFeedback();
//glFlush();
}
Take into consideration that branchcount is experimental value and can be discarded if needed.
The questions are:
1.Is it possible to have multiple shader programs ?
2.Which shader should i use to calculate coordinates of the new branch points?
The problems which i am facing are:
1.Unability to render fractal.
2.Confusion between which type of shader should i use for this particular task.
3.Lack of experience with modern openGL
And also i would like to ask how can i implement transform feedback in my code ?