I am trying to do a probabilistic simulation on a 20X20 grid. The simulation will generate numbers say 2, 3 or 4 and grid location say [5][4]
. I will convert the simulated number to c string and add ".png"
to feed to stb as the name of image file to load as a texture at a certain block. I have been able to create the . Here is the code-
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stb/stb_image.h>
#include <iostream>
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char* fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(0.8f, 0.3f, 0.02f, 1.0f);\n"
"}\n\0";
const GLint CELL_NO = 400; // total number of cells
const GLfloat CELL_DIM = 0.075f; // length and width of each cell
const GLfloat CELL_GAP = 0.025f; // Gap between cells
struct point {
GLfloat x = 0.0f;
GLfloat y = 0.0f;
GLfloat z = 0.0f;
};
typedef struct block {
point vertices[4];
}cell;
GLfloat vertice[400][12] = { 0.0f };
GLuint indices[] = {
0, 1, 2,
2, 3, 0
};
// cell vertex data
void inititialize(cell* C)
{
// corner left top
C[0].vertices[0] = { -0.9875f, 0.9875f };
C[0].vertices[1] = { -0.9875f, 0.9125f };
C[0].vertices[2] = { -0.9125f, 0.9125f };
C[0].vertices[3] = { -0.9125f, 0.9875f };
// corner bottom left
C[380].vertices[0] = { -0.9875f, -0.9125f };
C[380].vertices[1] = { -0.9875f, -0.9875f };
C[380].vertices[2] = { -0.975f, -0.9875f };
C[380].vertices[3] = { -0.975f, -0.9125f };
// left column
for (int i = 1; i < 20; i++)
{
for (short k = 0; k < 4; k++)
{
C[i * 20].vertices[k] = { C[(i - 1) * 20].vertices[k].x, C[(i - 1) * 20].vertices[k].y - CELL_DIM - CELL_GAP };
}
}
// whole grid
for (int i = 0; i < 20; i++)
{
for (int j = 1; j < 20; j++)
{
for (short k = 0; k < 4; k++)
{
C[i * 20 + j].vertices[k] = { C[i * 20 + j - 1].vertices[k].x + CELL_DIM + CELL_GAP, C[i * 20 + j - 1].vertices[k].y };
}
}
}
}
// loading the vertex data to vertice so opengl can read the data
void load_vertices(cell* c)
{
for (unsigned int i = 0; i < 20; i++)
{
for (unsigned int j = 0; j < 20; j++)
{
vertice[i * 20 + j][0] = c[i * 20 + j].vertices[0].x;
vertice[i * 20 + j][1] = c[i * 20 + j].vertices[0].y;
vertice[i * 20 + j][2] = c[i * 20 + j].vertices[0].z;
vertice[i * 20 + j][3] = c[i * 20 + j].vertices[1].x;
vertice[i * 20 + j][4] = c[i * 20 + j].vertices[1].y;
vertice[i * 20 + j][5] = c[i * 20 + j].vertices[1].z;
vertice[i * 20 + j][6] = c[i * 20 + j].vertices[2].x;
vertice[i * 20 + j][7] = c[i * 20 + j].vertices[2].y;
vertice[i * 20 + j][8] = c[i * 20 + j].vertices[2].z;
vertice[i * 20 + j][9] = c[i * 20 + j].vertices[3].x;
vertice[i * 20 + j][10] = c[i * 20 + j].vertices[3].y;
vertice[i * 20 + j][11] = c[i * 20 + j].vertices[3].z;
}
}
}
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
int main()
{
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(800, 800, "Boltzman_distribution", NULL, NULL);
if (window == NULL)
{
std::cout << "Window not Created" << std::endl;
glfwDestroyWindow(window);
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glViewport(0, 0, 800, 800);
cell* c = new cell[400];
inititialize(c);
load_vertices(c);
delete []c;
GLuint vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetProgramInfoLog(vertexShader, 512, NULL, infoLog);
std::cout << "VERTEX SHADER ERROR" << std::endl;
}
GLuint fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetProgramInfoLog(fragmentShader, 512, NULL, infoLog);
std::cout << "FRAGMENT SHADER ERROR" << std::endl;
}
GLuint shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
std::cout << "SHADER PROGRAM ERROR" << std::endl;
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
GLuint VBO[400] = { 0 }, VAO[400] = { 0 }, EBO = { 0 };
glGenVertexArrays(400, VAO);
glGenBuffers(400, &VBO[0]);
glGenBuffers(1, &EBO);
for (us i = 0; i < 400; i++)
{
glBindVertexArray(VAO[i]);
glBindBuffer(GL_ARRAY_BUFFER, VBO[i]);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertice[i]), vertice[i], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0); // Vertex attributes stay the same
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shaderProgram);
for (us i = 0; i < 400; i++)
{
glBindVertexArray(VAO[i]);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(400, VAO);
glDeleteBuffers(400, VBO);
glDeleteProgram(shaderProgram);
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
To load the texture, I will have to change the vertice
array GLfloat vertice[400][20] = { 0.0f };
(colors are not important).
void load_vertices(cell* c)
{
for (unsigned int i = 0; i < 20; i++)
{
for (unsigned int j = 0; j < 20; j++)
{
vertice[i * 20 + j][0] = c[i * 20 + j].vertices[0].x;
vertice[i * 20 + j][1] = c[i * 20 + j].vertices[0].y;
vertice[i * 20 + j][2] = c[i * 20 + j].vertices[0].z;
vertice[i * 20 + j][3] = 0.0f;
vertice[i * 20 + j][4] = 1.0f;
vertice[i * 20 + j][5] = c[i * 20 + j].vertices[1].x;
vertice[i * 20 + j][6] = c[i * 20 + j].vertices[1].y;
vertice[i * 20 + j][7] = c[i * 20 + j].vertices[1].z;
vertice[i * 20 + j][8] = 0.0f;
vertice[i * 20 + j][9] = 0.0f;
vertice[i * 20 + j][10] = c[i * 20 + j].vertices[2].x;
vertice[i * 20 + j][11] = c[i * 20 + j].vertices[2].y;
vertice[i * 20 + j][12] = c[i * 20 + j].vertices[2].z;
vertice[i * 20 + j][13] = 1.0f;
vertice[i * 20 + j][14] = 0.0f;
vertice[i * 20 + j][15] = c[i * 20 + j].vertices[3].x;
vertice[i * 20 + j][16] = c[i * 20 + j].vertices[3].y;
vertice[i * 20 + j][17] = c[i * 20 + j].vertices[3].z;
vertice[i * 20 + j][18] = 1.0f;
vertice[i * 20 + j][19] = 1.0f;
}
}
}
vertex shader will become-
const char* vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec2 aTex;\n"
"out vec3 color;\n"
"out vec2 texCoord;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
" texCoord = aTex;\n"
"}\n\0"
and I can't figure out what fragment shader should be?
Also for texture i will have to generate 3 texture buffer for and specify which texture to load in which block and how to render the whole thing?
I need an example code where say 51th, 100th, 205th block has values 2, 3, 4 respectively and changes to 3, 2, 4 respectively and changes back and forth.
My grid is 20X20. so vertice[50], vertice[99], vertice[204] has the vertex data.
I have searched a lot and found a lot of tutorial for making games in c++ but almost none for scientific visualization.