Szerkesztő:Kisteklak/próbalap
HEADER
#pragma once
// C++ includes
#include <memory>
// GLEW
#include <GL/glew.h>
// SDL
#include <SDL.h>
#include <SDL_opengl.h>
// GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform2.hpp>
#include "includes/gCamera.h"
#include "includes/ProgramObject.h"
#include "includes/BufferObject.h"
#include "includes/VertexArrayObject.h"
#include "includes/TextureObject.h"
// mesh
#include "includes/ObjParser_OGL3.h"
class CMyApp
{
public:
CMyApp();
~CMyApp();
bool Init();
void Clean();
void Update();
void Render();
void KeyboardDown(SDL_KeyboardEvent&);
void KeyboardUp(SDL_KeyboardEvent&);
void MouseMove(SDL_MouseMotionEvent&);
void MouseDown(SDL_MouseButtonEvent&);
void MouseUp(SDL_MouseButtonEvent&);
void MouseWheel(SDL_MouseWheelEvent&);
void Resize(int, int);
protected:
// shaderekhez szükséges változók
ProgramObject m_programGround; // mesh shader
ProgramObject m_programSkybox; // skybox shader
ProgramObject m_program;
VertexArrayObject m_CubeVao; // VAO
IndexBuffer m_CubeIndices; // index buffer
ArrayBuffer m_CubeVertexBuffer; // VBO
VertexArrayObject m_SkyboxVao;
IndexBuffer m_SkyboxIndices;
ArrayBuffer m_SkyboxPos;
VertexArrayObject m_GroundVao; // VAO
IndexBuffer m_GroundIndices; // index buffer
ArrayBuffer m_GroundVertexBuffer; // VBO
VertexArrayObject m_ForestVao; // VAO
IndexBuffer m_ForestIndices; // index buffer
ArrayBuffer m_ForestVertexBuffer; // VBO
VertexArrayObject m_SphereVao; // VAO
IndexBuffer m_SphereIndices; // index buffer
ArrayBuffer m_SphereVertexBuffer; // VBO
gCamera m_camera;
Texture2D m_woodTexture;
Texture2D m_suzanneTexture;
Texture2D m_forestTexture;
Texture2D m_leavesTexture;
Texture2D m_barkTexture;
TextureCubeMap m_skyboxTexture;
int gridRes = 18;
float trees[18][18];
bool disableLine[18];
float initialHeight = 0.05f;
float cutHeight = 1.0f;
float growTime = 10.0f;
int cutTreeCount = 0;
int lastTickCount = 0;
glm::vec3 light_dir = { -1.0f, -1.0f, -1.0f };
glm::vec3 winter_color = { 0.3, 0.6, 0.7 };
glm::vec3 summer_color = { 0.7, 0.7, 0.6 };
float yearTime = 0.0f;
float yearLength = 20.0f;
struct Vertex
{
glm::vec3 p;
glm::vec3 n;
glm::vec2 t;
};
// mesh adatok
std::unique_ptr<Mesh> m_mesh;
std::unique_ptr<Mesh> m_cylinder;
void DrawTree(glm::mat4 viewProj, glm::mat4 world);
// a jobb olvashatóság kedvéért
void InitShaders();
void InitCube();
void InitSkyBox();
void InitGround();
void InitForest();
void InitSphere();
glm::vec3 GetSpherePos(float u, float v);
glm::vec3 GetNorm(float u, float v);
glm::vec2 GetTex(float u, float v);
float height(glm::vec2 pos);
void SpawnTrees();
void DrawGui();
};
-------
MYAPP.CPP
#include "MyApp.h"
#include <math.h>
#include <vector>
#include <cstdlib>
#include <time.h>
#include <array>
#include <list>
#include <tuple>
#include <imgui/imgui.h>
#include "includes/GLUtils.hpp"
CMyApp::CMyApp(void)
{
m_camera.SetView(glm::vec3(5, 5, 5), glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
m_mesh = nullptr;
}
CMyApp::~CMyApp(void)
{
}
void CMyApp::InitCube()
{
//struct Vertex{ glm::vec3 position; glm::vec3 normals; glm::vec2 texture; };
std::vector<Vertex>vertices;
//front
vertices.push_back({ glm::vec3(-0.5, -0.5, +0.5), glm::vec3(0, 0, 1), glm::vec2(0, 0) });
vertices.push_back({ glm::vec3(+0.5, -0.5, +0.5), glm::vec3(0, 0, 1), glm::vec2(1, 0) });
vertices.push_back({ glm::vec3(-0.5, +0.5, +0.5), glm::vec3(0, 0, 1), glm::vec2(0, 1) });
vertices.push_back({ glm::vec3(+0.5, +0.5, +0.5), glm::vec3(0, 0, 1), glm::vec2(1, 1) });
//back
vertices.push_back({ glm::vec3(+0.5, -0.5, -0.5), glm::vec3(0, 0, -1), glm::vec2(0, 0) });
vertices.push_back({ glm::vec3(-0.5, -0.5, -0.5), glm::vec3(0, 0, -1), glm::vec2(1, 0) });
vertices.push_back({ glm::vec3(+0.5, +0.5, -0.5), glm::vec3(0, 0, -1), glm::vec2(0, 1) });
vertices.push_back({ glm::vec3(-0.5, +0.5, -0.5), glm::vec3(0, 0, -1), glm::vec2(1, 1) });
//right
vertices.push_back({ glm::vec3(+0.5, -0.5, +0.5), glm::vec3(1, 0, 0), glm::vec2(0, 0) });
vertices.push_back({ glm::vec3(+0.5, -0.5, -0.5), glm::vec3(1, 0, 0), glm::vec2(1, 0) });
vertices.push_back({ glm::vec3(+0.5, +0.5, +0.5), glm::vec3(1, 0, 0), glm::vec2(0, 1) });
vertices.push_back({ glm::vec3(+0.5, +0.5, -0.5), glm::vec3(1, 0, 0), glm::vec2(1, 1) });
//left
vertices.push_back({ glm::vec3(-0.5, -0.5, -0.5), glm::vec3(-1, 0, 0), glm::vec2(0, 0) });
vertices.push_back({ glm::vec3(-0.5, -0.5, +0.5), glm::vec3(-1, 0, 0), glm::vec2(1, 0) });
vertices.push_back({ glm::vec3(-0.5, +0.5, -0.5), glm::vec3(-1, 0, 0), glm::vec2(0, 1) });
vertices.push_back({ glm::vec3(-0.5, +0.5, +0.5), glm::vec3(-1, 0, 0), glm::vec2(1, 1) });
//top
vertices.push_back({ glm::vec3(-0.5, +0.5, +0.5), glm::vec3(0, 1, 0), glm::vec2(0, 0) });
vertices.push_back({ glm::vec3(+0.5, +0.5, +0.5), glm::vec3(0, 1, 0), glm::vec2(1, 0) });
vertices.push_back({ glm::vec3(-0.5, +0.5, -0.5), glm::vec3(0, 1, 0), glm::vec2(0, 1) });
vertices.push_back({ glm::vec3(+0.5, +0.5, -0.5), glm::vec3(0, 1, 0), glm::vec2(1, 1) });
//bottom
vertices.push_back({ glm::vec3(-0.5, -0.5, -0.5), glm::vec3(0, -1, 0), glm::vec2(0, 0) });
vertices.push_back({ glm::vec3(+0.5, -0.5, -0.5), glm::vec3(0, -1, 0), glm::vec2(1, 0) });
vertices.push_back({ glm::vec3(-0.5, -0.5, +0.5), glm::vec3(0, -1, 0), glm::vec2(0, 1) });
vertices.push_back({ glm::vec3(+0.5, -0.5, +0.5), glm::vec3(0, -1, 0), glm::vec2(1, 1) });
std::vector<int> indices(36);
int index = 0;
for (int i = 0; i < 6 * 4; i += 4)
{
indices[index + 0] = i + 0;
indices[index + 1] = i + 1;
indices[index + 2] = i + 2;
indices[index + 3] = i + 1;
indices[index + 4] = i + 3;
indices[index + 5] = i + 2;
index += 6;
}
//
// geometria definiálása (std::vector<...>) és GPU pufferekbe való feltöltése BufferData-val
//
// vertexek pozíciói:
/*
Az m_CubeVertexBuffer konstruktora már létrehozott egy GPU puffer azonosítót és a most következő BufferData hívás ezt
1. bind-olni fogja GL_ARRAY_BUFFER target-re (hiszen m_CubeVertexBuffer típusa ArrayBuffer) és
2. glBufferData segítségével áttölti a GPU-ra az argumentumban adott tároló értékeit
*/
m_CubeVertexBuffer.BufferData(vertices);
// és a primitíveket alkotó csúcspontok indexei (az előző tömbökből) - triangle list-el való kirajzolásra felkészülve
m_CubeIndices.BufferData(indices);
// geometria VAO-ban való regisztrálása
m_CubeVao.Init(
{
// 0-ás attribútum "lényegében" glm::vec3-ak sorozata és az adatok az m_CubeVertexBuffer GPU pufferben vannak
{ CreateAttribute< 0, // attribútum: 0
glm::vec3, // CPU oldali adattípus amit a 0-ás attribútum meghatározására használtunk <- az eljárás a glm::vec3-ból kikövetkezteti, hogy 3 darab float-ból áll a 0-ás attribútum
0, // offset: az attribútum tároló elejétől vett offset-je, byte-ban
sizeof(Vertex) // stride: a következő csúcspont ezen attribútuma hány byte-ra van az aktuálistól
>, m_CubeVertexBuffer },
{ CreateAttribute<1, glm::vec3, (sizeof(glm::vec3)), sizeof(Vertex)>, m_CubeVertexBuffer },
{ CreateAttribute<2, glm::vec2, (2 * sizeof(glm::vec3)), sizeof(Vertex)>, m_CubeVertexBuffer },
},
m_CubeIndices
);
}
void CMyApp::InitSkyBox()
{
m_SkyboxPos.BufferData(
std::vector<glm::vec3>{
// hátsó lap
glm::vec3(-1, -1, -1),
glm::vec3(1, -1, -1),
glm::vec3(1, 1, -1),
glm::vec3(-1, 1, -1),
// elülső lap
glm::vec3(-1, -1, 1),
glm::vec3(1, -1, 1),
glm::vec3(1, 1, 1),
glm::vec3(-1, 1, 1),
}
);
// és a primitíveket alkotó csúcspontok indexei (az előző tömbökből) - triangle list-el való kirajzolásra felkészülve
m_SkyboxIndices.BufferData(
std::vector<int>{
// hátsó lap
0, 1, 2,
2, 3, 0,
// elülső lap
4, 6, 5,
6, 4, 7,
// bal
0, 3, 4,
4, 3, 7,
// jobb
1, 5, 2,
5, 6, 2,
// alsó
1, 0, 4,
1, 4, 5,
// felső
3, 2, 6,
3, 6, 7,
}
);
// geometria VAO-ban való regisztrálása
m_SkyboxVao.Init(
{
{ CreateAttribute<0, glm::vec3, 0, sizeof(glm::vec3)>, m_SkyboxPos },
}, m_SkyboxIndices
);
// skybox texture
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
m_skyboxTexture.AttachFromFile("assets/xpos.png", false, GL_TEXTURE_CUBE_MAP_POSITIVE_X);
m_skyboxTexture.AttachFromFile("assets/xneg.png", false, GL_TEXTURE_CUBE_MAP_NEGATIVE_X);
m_skyboxTexture.AttachFromFile("assets/ypos.png", false, GL_TEXTURE_CUBE_MAP_POSITIVE_Y);
m_skyboxTexture.AttachFromFile("assets/yneg.png", false, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y);
m_skyboxTexture.AttachFromFile("assets/zpos.png", false, GL_TEXTURE_CUBE_MAP_POSITIVE_Z);
m_skyboxTexture.AttachFromFile("assets/zneg.png", true, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
// a GL_TEXTURE_MAG_FILTER-t és a GL_TEXTURE_MIN_FILTER-t beállítja az AttachFromFile
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
void CMyApp::InitGround()
{
std::vector<Vertex>vertices;
for (int x = 0; x < 20; ++x) {
for (int z = 0; z < 20; ++z) {
float u = x / (float)19;
float v = z / (float)19;
vertices.push_back(
{
glm::vec3(u,0,v),
glm::vec3(0,1,0),
glm::vec2(u,v)
}
);
}
}
std::vector<int> indices;
for (int x = 0; x <= 18; ++x) {
for (int z = 0; z <= 18; ++z) {
indices.push_back(x * 20 + z);
indices.push_back((x+1) * 20 + z+1);
indices.push_back((x+1) * 20 + z);
indices.push_back((x + 1) * 20 + z + 1);
indices.push_back(x * 20 + z);
indices.push_back(x * 20 + z+1);
}
}
m_GroundVertexBuffer.BufferData(vertices);
m_GroundIndices.BufferData(indices);
m_GroundVao.Init(
{
// 0-ás attribútum "lényegében" glm::vec3-ak sorozata és az adatok az m_CubeVertexBuffer GPU pufferben vannak
{ CreateAttribute< 0, // attribútum: 0
glm::vec3, // CPU oldali adattípus amit a 0-ás attribútum meghatározására használtunk <- az eljárás a glm::vec3-ból kikövetkezteti, hogy 3 darab float-ból áll a 0-ás attribútum
0, // offset: az attribútum tároló elejétől vett offset-je, byte-ban
sizeof(Vertex) // stride: a következő csúcspont ezen attribútuma hány byte-ra van az aktuálistól
>, m_GroundVertexBuffer },
{ CreateAttribute<1, glm::vec3, (sizeof(glm::vec3)), sizeof(Vertex)>, m_GroundVertexBuffer },
{ CreateAttribute<2, glm::vec2, (2 * sizeof(glm::vec3)), sizeof(Vertex)>, m_GroundVertexBuffer },
},
m_GroundIndices
);
}
void CMyApp::InitForest()
{
std::vector<Vertex>vertices;
//front
vertices.push_back({ glm::vec3(-0.5, -0.5, +0.5), glm::vec3(0, 0, 1), glm::vec2(0, 0) });
vertices.push_back({ glm::vec3(+0.5, -0.5, +0.5), glm::vec3(0, 0, 1), glm::vec2(1, 0) });
vertices.push_back({ glm::vec3(-0.5, +0.5, +0.5), glm::vec3(0, 0, 1), glm::vec2(0, 1) });
vertices.push_back({ glm::vec3(+0.5, +0.5, +0.5), glm::vec3(0, 0, 1), glm::vec2(1, 1) });
//back
vertices.push_back({ glm::vec3(+0.5, -0.5, -0.5), glm::vec3(0, 0, -1), glm::vec2(0, 0) });
vertices.push_back({ glm::vec3(-0.5, -0.5, -0.5), glm::vec3(0, 0, -1), glm::vec2(1, 0) });
vertices.push_back({ glm::vec3(+0.5, +0.5, -0.5), glm::vec3(0, 0, -1), glm::vec2(0, 1) });
vertices.push_back({ glm::vec3(-0.5, +0.5, -0.5), glm::vec3(0, 0, -1), glm::vec2(1, 1) });
//right
vertices.push_back({ glm::vec3(+0.5, -0.5, +0.5), glm::vec3(1, 0, 0), glm::vec2(0, 0) });
vertices.push_back({ glm::vec3(+0.5, -0.5, -0.5), glm::vec3(1, 0, 0), glm::vec2(1, 0) });
vertices.push_back({ glm::vec3(+0.5, +0.5, +0.5), glm::vec3(1, 0, 0), glm::vec2(0, 1) });
vertices.push_back({ glm::vec3(+0.5, +0.5, -0.5), glm::vec3(1, 0, 0), glm::vec2(1, 1) });
//left
vertices.push_back({ glm::vec3(-0.5, -0.5, -0.5), glm::vec3(-1, 0, 0), glm::vec2(0, 0) });
vertices.push_back({ glm::vec3(-0.5, -0.5, +0.5), glm::vec3(-1, 0, 0), glm::vec2(1, 0) });
vertices.push_back({ glm::vec3(-0.5, +0.5, -0.5), glm::vec3(-1, 0, 0), glm::vec2(0, 1) });
vertices.push_back({ glm::vec3(-0.5, +0.5, +0.5), glm::vec3(-1, 0, 0), glm::vec2(1, 1) });
std::vector<int> indices(24);
int index = 0;
for (int i = 0; i < 4 * 4; i += 4)
{
indices[index + 0] = i + 0;
indices[index + 1] = i + 2;
indices[index + 2] = i + 1;
indices[index + 3] = i + 1;
indices[index + 4] = i + 2;
indices[index + 5] = i + 3;
index += 6;
}
m_ForestVertexBuffer.BufferData(vertices);
// és a primitíveket alkotó csúcspontok indexei (az előző tömbökből) - triangle list-el való kirajzolásra felkészülve
m_ForestIndices.BufferData(indices);
// geometria VAO-ban való regisztrálása
m_ForestVao.Init(
{
// 0-ás attribútum "lényegében" glm::vec3-ak sorozata és az adatok az m_CubeVertexBuffer GPU pufferben vannak
{ CreateAttribute< 0, // attribútum: 0
glm::vec3, // CPU oldali adattípus amit a 0-ás attribútum meghatározására használtunk <- az eljárás a glm::vec3-ból kikövetkezteti, hogy 3 darab float-ból áll a 0-ás attribútum
0, // offset: az attribútum tároló elejétől vett offset-je, byte-ban
sizeof(Vertex) // stride: a következő csúcspont ezen attribútuma hány byte-ra van az aktuálistól
>, m_ForestVertexBuffer },
{ CreateAttribute<1, glm::vec3, (sizeof(glm::vec3)), sizeof(Vertex)>, m_ForestVertexBuffer },
{ CreateAttribute<2, glm::vec2, (2 * sizeof(glm::vec3)), sizeof(Vertex)>, m_ForestVertexBuffer },
},
m_ForestIndices
);
}
glm::vec3 CMyApp::GetSpherePos(float u, float v)
{
// origó középpontú, r sugarú gömb parametrikus alakja: http://hu.wikipedia.org/wiki/G%C3%B6mb#Egyenletek
// figyeljünk: matematikában sokszor a Z tengely mutat felfelé, de nálunk az Y, tehát a legtöbb képlethez képest nálunk
// az Y és Z koordináták felcserélve szerepelnek
u *= float(2 * M_PI);
v *= float(M_PI);
float r = 2;
return glm::vec3(r * sin(v) * cos(u),
r * cos(v),
r * sin(v) * sin(u));
}
//
// egy parametrikus felület (u,v) paraméterértékekhez tartozó normálvektorának
// kiszámítását végző függvény
//
glm::vec3 CMyApp::GetNorm(float u, float v)
{
// Képlettel
u *= float(2 * M_PI);
v *= float(M_PI);
return glm::vec3(sin(v) * cos(u), cos(v), sin(v) * sin(u));
// Numerikusan (nem kell ismerni a képletet, elég a pozícióét)
/*
glm::vec3 du = GetPos(u+0.01, v)-GetPos(u-0.01, v);
glm::vec3 dv = GetPos(u, v+0.01)-GetPos(u, v-0.01);
return glm::normalize(glm::cross(du, dv));*/
}
glm::vec2 CMyApp::GetTex(float u, float v)
{
return glm::vec2(1 - u, 1 - v);
}
void CMyApp::InitSphere()
{
int N = 20;
int M = 20;
// NxM darab négyszöggel közelítjük a parametrikus felületünket => (N+1)x(M+1) pontban kell kiértékelni
std::vector<Vertex> vertices;
vertices.resize((N + 1) * (M + 1));
for (int i = 0; i <= N; ++i)
for (int j = 0; j <= M; ++j)
{
float u = i / (float)N;
float v = j / (float)M;
Vertex tmp;
tmp.p = GetSpherePos(u, v);
tmp.n = GetNorm(u, v);
tmp.t = GetTex(u, v);
vertices[i + j * (N + 1)] = tmp;
}
// indexpuffer adatai: NxM négyszög = 2xNxM háromszög = háromszöglista esetén 3x2xNxM index
//GLushort indices[3 * 2 * (N) * (M)];
std::vector<int> indices;
for (int i = 0; i < N; ++i)
for (int j = 0; j < M; ++j)
{
// minden négyszögre csináljunk kettő háromszöget, amelyek a következő
// (i,j) indexeknél született (u_i, v_i) paraméterértékekhez tartozó
// pontokat kötik össze:
//
// (i,j+1)
// o-----o(i+1,j+1)
// |\ | a = p(u_i, v_i)
// | \ | b = p(u_{i+1}, v_i)
// | \ | c = p(u_i, v_{i+1})
// | \ | d = p(u_{i+1}, v_{i+1})
// | \|
// (i,j) o-----o(i+1, j)
//
// - az (i,j)-hez tartózó 1D-s index a VBO-ban: i+j*(N+1)
// - az (i,j)-hez tartózó 1D-s index az IB-ben: i*6+j*6*(N+1)
// (mert minden négyszöghöz 2db háromszög = 6 index tartozik)
//
indices.push_back((i)+(j) * (N + 1));
indices.push_back((i + 1) + (j) * (N + 1));
indices.push_back((i)+(j + 1) * (N + 1));
indices.push_back((i + 1) + (j) * (N + 1));
indices.push_back((i + 1) + (j + 1) * (N + 1));
indices.push_back((i)+(j + 1) * (N + 1));
}
m_SphereVertexBuffer.BufferData(vertices);
m_SphereIndices.BufferData(indices);
m_SphereVao.Init(
{
// 0-ás attribútum "lényegében" glm::vec3-ak sorozata és az adatok az m_CubeVertexBuffer GPU pufferben vannak
{ CreateAttribute< 0, // attribútum: 0
glm::vec3, // CPU oldali adattípus amit a 0-ás attribútum meghatározására használtunk <- az eljárás a glm::vec3-ból kikövetkezteti, hogy 3 darab float-ból áll a 0-ás attribútum
0, // offset: az attribútum tároló elejétől vett offset-je, byte-ban
sizeof(Vertex) // stride: a következő csúcspont ezen attribútuma hány byte-ra van az aktuálistól
>, m_SphereVertexBuffer },
{ CreateAttribute<1, glm::vec3, (sizeof(glm::vec3)), sizeof(Vertex)>, m_SphereVertexBuffer },
{ CreateAttribute<2, glm::vec2, (2 * sizeof(glm::vec3)), sizeof(Vertex)>, m_SphereVertexBuffer },
},
m_SphereIndices
);
}
void CMyApp::InitShaders()
{
// a shadereket tároló program létrehozása az OpenGL-hez hasonló módon:
m_programGround.AttachShaders({
{ GL_VERTEX_SHADER, "myVert.vert"},
{ GL_FRAGMENT_SHADER, "frag.frag"}
});
// attributomok osszerendelese a VAO es shader kozt
m_programGround.BindAttribLocations({
{ 0, "vs_in_pos" }, // VAO 0-as csatorna menjen a vs_in_pos-ba
{ 1, "vs_in_norm" }, // VAO 1-es csatorna menjen a vs_in_norm-ba
{ 2, "vs_in_tex" }, // VAO 2-es csatorna menjen a vs_in_tex-be
});
m_programGround.LinkProgram();
// shader program rövid létrehozása, egyetlen függvényhívással a fenti három:
m_programSkybox.Init(
{
{ GL_VERTEX_SHADER, "skybox.vert" },
{ GL_FRAGMENT_SHADER, "skybox.frag" }
},
{
{ 0, "vs_in_pos" }, // VAO 0-as csatorna menjen a vs_in_pos-ba
}
);
m_program.Init(
{
{ GL_VERTEX_SHADER, "vert.vert" },
{ GL_FRAGMENT_SHADER, "frag.frag" }
},
{
{ 0, "vs_in_pos" }, // VAO 0-as csatorna menjen a vs_in_pos-ba
{ 1, "vs_in_norm" }, // VAO 1-es csatorna menjen a vs_in_norm-ba
{ 2, "vs_in_tex" },
}
);
}
bool CMyApp::Init()
{
// törlési szín legyen kékes
glClearColor(0.125f, 0.25f, 0.5f, 1.0f);
glEnable(GL_CULL_FACE); // kapcsoljuk be a hatrafele nezo lapok eldobasat
glEnable(GL_DEPTH_TEST); // mélységi teszt bekapcsolása (takarás)
InitShaders();
InitCube();
InitSkyBox();
InitGround();
InitForest();
InitSphere();
// egyéb textúrák betöltése
m_woodTexture.FromFile("assets/wood.jpg");
m_suzanneTexture.FromFile("assets/grass.jpg");
m_forestTexture.FromFile("assets/forest.jpg");
m_leavesTexture.FromFile("assets/leaves.jpg");
m_barkTexture.FromFile("assets/bark.jpg");
// mesh betöltése
m_mesh = std::unique_ptr<Mesh>(ObjParser::parse("assets/Suzanne.obj"));
m_mesh->initBuffers();
m_cylinder = std::unique_ptr<Mesh>(ObjParser::parse("assets/henger.obj"));
m_cylinder->initBuffers();
// kamera
m_camera.SetProj(glm::radians(60.0f), 640.0f / 480.0f, 0.01f, 1000.0f);
srand(time(nullptr));
int count = (rand() % 51) + 50;
for (int i = 0; i < gridRes; ++i) {
for (int j = 0; j < gridRes; ++j) {
trees[i][j] = -1;
}
}
while (count > 0) {
int x = rand() % (gridRes + 1);
int y = rand() % (gridRes + 1);
if (trees[x][y] < 0) {
trees[x][y] = initialHeight;
count--;
}
}
for (int j = 0; j < gridRes; ++j) {
disableLine[j] = false;
}
return true;
}
void CMyApp::Clean()
{
}
void CMyApp::Update()
{
static Uint32 last_time = SDL_GetTicks();
float delta_time = (SDL_GetTicks() - last_time) / 1000.0f;
m_camera.Update(delta_time);
last_time = SDL_GetTicks();
int tickCount = SDL_GetTicks();
if (tickCount / 2000 > lastTickCount / 2000) {
SpawnTrees();
}
float growSpeed = (cutHeight - initialHeight) / growTime;
for (int i = 0; i < gridRes; ++i) {
for (int j = 0; j < gridRes; ++j) {
if (trees[i][j] >= 0) {
trees[i][j] += growSpeed * delta_time;
}
if (trees[i][j] > cutHeight) {
trees[i][j] = -1;
cutTreeCount++;
}
}
}
yearTime += delta_time;
if (yearTime > yearLength) {
yearTime -= yearLength;
}
lastTickCount = SDL_GetTicks();
}
void CMyApp::DrawTree(glm::mat4 viewProj, glm::mat4 world)
{
glm::mat4 worldCylinder = world * glm::translate(glm::vec3(0, 2, 0));
m_program.Use();
m_program.SetTexture("texImage", 0, m_barkTexture);
m_program.SetUniform("MVP", viewProj * worldCylinder);
m_program.SetUniform("world", worldCylinder);
m_program.SetUniform("worldIT", glm::inverse(glm::transpose(worldCylinder)));
m_program.SetUniform("eye_pos", m_camera.GetEye());
m_program.SetUniform("light_dir", light_dir);
m_program.SetUniform("year_progress", yearTime / yearLength);
m_program.SetUniform("winter_color", winter_color);
m_program.SetUniform("summer_color", summer_color);
m_cylinder->draw();
glm::mat4 worldSphere = world * glm::translate(glm::vec3(0, 5, 0)) * glm::scale(glm::vec3(1, 1, 1));
m_program.SetTexture("texImage", 0, m_leavesTexture);
m_program.SetUniform("MVP", viewProj * worldSphere);
m_program.SetUniform("world", worldSphere);
m_program.SetUniform("worldIT", glm::inverse(glm::transpose(worldSphere)));
m_SphereVao.Bind();
glDrawElements(GL_TRIANGLES, 2400, GL_UNSIGNED_INT, nullptr);
}
void CMyApp::Render()
{
// töröljük a frampuffert (GL_COLOR_BUFFER_BIT) és a mélységi Z puffert (GL_DEPTH_BUFFER_BIT)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glm::mat4 viewProj = m_camera.GetViewProj();
//glPolygonMode(GL_FRONT, GL_LINE);
//Ground
glm::mat4 groundWorld = glm::translate(glm::vec3(-10,0,-10)) * glm::scale(glm::vec3(20,1,20));
m_programGround.Use();
m_programGround.SetTexture("texImage", 0, m_suzanneTexture);
m_programGround.SetUniform("MVP", viewProj * groundWorld);
m_programGround.SetUniform("world", groundWorld);
m_programGround.SetUniform("worldIT", glm::inverse(glm::transpose(groundWorld)));
m_programGround.SetUniform("eye_pos", m_camera.GetEye());
m_programGround.SetUniform("light_dir", light_dir);
m_programGround.SetUniform("year_progress", yearTime / yearLength);
m_programGround.SetUniform("winter_color", winter_color);
m_programGround.SetUniform("summer_color", summer_color);
//m_mesh->draw();
m_GroundVao.Bind();
glDrawElements(GL_TRIANGLES, 19 * 19 * 2 * 3, GL_UNSIGNED_INT, nullptr);
glm::mat4 forestWorld = glm::translate(glm::vec3(0, 2.5-0.2, 0)) * glm::scale(glm::vec3(20, 5, 20));
m_program.Use();
m_program.SetTexture("texImage", 0, m_forestTexture);
m_program.SetUniform("MVP", viewProj * forestWorld);
m_program.SetUniform("world", forestWorld);
m_program.SetUniform("worldIT", glm::inverse(glm::transpose(forestWorld)));
m_program.SetUniform("eye_pos", m_camera.GetEye());
m_program.SetUniform("light_dir", light_dir);
m_program.SetUniform("year_progress", yearTime / yearLength);
m_program.SetUniform("winter_color", winter_color);
m_program.SetUniform("summer_color", summer_color);
m_ForestVao.Bind();
//m_SphereVao.Bind();
glDrawElements(GL_TRIANGLES, 24, GL_UNSIGNED_INT, nullptr);
for (int x = 0; x < gridRes; x++) {
for (int y = 0; y < gridRes; y++) {
if (trees[x][y] >= 0) {
glm::vec3 pos(x + 1, height(glm::vec2((x + 1) / 20.0f, (y + 1) / 20.0f)), y + 1);
DrawTree(viewProj, glm::translate(pos + glm::vec3(-10,0,-10)) * glm::scale(glm::vec3(1,1,1)*trees[x][y]));
}
}
}
// skybox
// mentsük el az előző Z-test eredményt, azaz azt a relációt, ami alapján update-eljük a pixelt.
GLint prevDepthFnc;
glGetIntegerv(GL_DEPTH_FUNC, &prevDepthFnc);
// most kisebb-egyenlőt használjunk, mert mindent kitolunk a távoli vágósíkokra
glDepthFunc(GL_LEQUAL);
m_SkyboxVao.Bind();
m_programSkybox.Use();
m_programSkybox.SetUniform("MVP", viewProj * glm::translate( m_camera.GetEye()) );
// cube map textúra beállítása 0-ás mintavételezőre és annak a shaderre beállítása
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, m_skyboxTexture);
glUniform1i(m_programSkybox.GetLocation("skyboxTexture"), 0);
// az előző három sor <=> m_programSkybox.SetCubeTexture("skyboxTexture", 0, m_skyboxTexture);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr);
m_programSkybox.Unuse();
// végül állítsuk vissza
glDepthFunc(prevDepthFnc);
// 1. feladat: készíts egy vertex shader-fragment shader párt, ami tárolt geometria _nélkül_ kirajzol egy tetszőleges pozícióba egy XYZ tengely-hármast,
// ahol az X piros, az Y zöld a Z pedig kék!
//ImGui Testwindow
ImGui::ShowTestWindow();
DrawGui();
}
void CMyApp::KeyboardDown(SDL_KeyboardEvent& key)
{
m_camera.KeyboardDown(key);
}
void CMyApp::KeyboardUp(SDL_KeyboardEvent& key)
{
m_camera.KeyboardUp(key);
}
void CMyApp::MouseMove(SDL_MouseMotionEvent& mouse)
{
m_camera.MouseMove(mouse);
}
void CMyApp::MouseDown(SDL_MouseButtonEvent& mouse)
{
}
void CMyApp::MouseUp(SDL_MouseButtonEvent& mouse)
{
}
void CMyApp::MouseWheel(SDL_MouseWheelEvent& wheel)
{
}
// a két paraméterbe az új ablakméret szélessége (_w) és magassága (_h) található
void CMyApp::Resize(int _w, int _h)
{
glViewport(0, 0, _w, _h );
m_camera.Resize(_w, _h);
}
float CMyApp::height(glm::vec2 pos) {
return sin(pos.x * 3.14 * 2 * 3) * 0.2f;
}
void CMyApp::SpawnTrees()
{
for (int i = 0; i < gridRes; ++i) {
for (int j = 0; j < gridRes; ++j) {
if (trees[i][j] < 0 && !disableLine[i]) {
if (rand() % 100 < 5) {
trees[i][j] = initialHeight;
}
}
}
}
}
void CMyApp::DrawGui()
{
ImGui::Begin("Settings");
ImGui::DragFloat3("ligth dir", &light_dir[0]);
ImGui::InputFloat("grow duration", &growTime);
ImGui::InputFloat("year length", &yearLength);
ImGui::SliderFloat("cut height", &cutHeight, 0.5f, 1.2f);
/*if (ImGui::InputFloat("cut height", &cutHeight)) {
if (cutHeight < 0.5f)
cutHeight = 0.5f;
}*/
std::string text = "# trees cut " + std::to_string(cutTreeCount);
ImGui::Text(text.c_str());
if (ImGui::Button("CUT!")) {
for (int i = 0; i < gridRes; ++i) {
for (int j = 0; j < gridRes; ++j) {
if (trees[i][j] >= 0) {
cutTreeCount++;
trees[i][j] = -1;
}
}
}
}
ImGui::BeginGroup();
//ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom");
ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)0), ImVec2(ImGui::GetWindowWidth() * 0.8f, 100.0f), true);
for (int line = 0; line < gridRes; line++)
{
std::string text = "disable line " + std::to_string(line);
//ImGui::Text(text.c_str());
ImGui::Checkbox(text.c_str(), &disableLine[line]);
}
ImGui::EndChild();
ImGui::EndGroup();
ImGui::ColorEdit3("winter color", &winter_color[0]);
ImGui::ColorEdit3("summer color", &summer_color[0]);
ImGui::End();
}
FRAG.frag
#version 330 core
// pipeline-ból bejövő per-fragment attribútumok
in vec3 vs_out_pos;
in vec3 vs_out_norm;
in vec2 vs_out_tex;
out vec4 fs_out_col;
// irány fényforrás: fény iránya
uniform vec3 light_dir = vec3(-1,-1,-1);
uniform vec3 eye_pos;
// fénytulajdonságok: ambiens, diffúz, ...
uniform vec3 La = vec3(0.4, 0.4, 0.4);
uniform vec3 Ld = vec3(0.6, 0.6, 0.6);
uniform vec3 Ls = vec3(0.6, 0.6, 0.6);
uniform vec3 winter_color = vec3(0.3,0.6,0.7);
uniform vec3 spring_color = vec3(0.5,0.7,0.6);
uniform vec3 summer_color = vec3(0.7,0.7,0.6);
uniform vec3 autumn_color = vec3(0.6,0.4,0.3);
uniform float year_progress = 0; // 0 január eleje, 1 december vége
uniform sampler2D texImage;
void main()
{
vec3 light_col;
if(year_progress < 0.25)
light_col = mix(winter_color, spring_color, year_progress/0.25);
else if(year_progress < 0.5)
light_col = mix(spring_color, summer_color, (year_progress-0.25)/0.25);
else if(year_progress < 0.75)
light_col = mix(summer_color, autumn_color, (year_progress-0.5)/0.25);
else
light_col = mix(autumn_color, winter_color, (year_progress-0.75)/0.25);
vec3 ambient = La;
vec3 normal = normalize(vs_out_norm);
vec3 to_light = normalize(-light_dir);
float cosa = clamp(dot(normal, to_light), 0, 1);
vec3 diffuse = cosa*light_col;
vec3 reflected_dir = reflect(normalize(light_dir), normal);
vec3 to_eye = normalize(eye_pos - vs_out_pos);
float cos2 = pow(clamp(dot(to_eye, reflected_dir), 0, 1), 16);
vec3 specular = light_col * cos2;
fs_out_col = vec4(ambient + diffuse + specular, 1) * texture(texImage, vs_out_tex);
}
MyVert.vert
#version 330 core
// VBO-ból érkező változók
in vec3 vs_in_pos;
in vec3 vs_in_norm;
in vec2 vs_in_tex;
// a pipeline-ban tovább adandó értékek
out vec3 vs_out_pos;
out vec3 vs_out_norm;
out vec2 vs_out_tex;
// shader külső paraméterei
uniform mat4 MVP;
uniform mat4 world;
uniform mat4 worldIT;
float height(vec2 pos) {
return sin(pos.x*3.14*2*3)*0.2;
}
vec3 getPos(vec2 uv) {
return vec3(
uv.x,
height(uv),
uv.y
);
}
void main()
{
vec3 pos = getPos(vs_in_pos.xz);
float eps = 0.01;
//vec3 dx = (height(pos+vec3(eps,0,0)) - height(pos-vec3(eps,0,0)))/(2*eps);
vec3 dx = getPos(vs_in_pos.xz + vec2(eps,0)) - getPos(vs_in_pos.xz - vec2(eps,0));
vec3 dz = getPos(vs_in_pos.xz + vec2(0,eps)) - getPos(vs_in_pos.xz - vec2(0,eps));
vec3 n = normalize(cross(dz,dx));
gl_Position = MVP * vec4( pos, 1 );
vs_out_pos = (world * vec4(pos, 1)).xyz;
vs_out_norm = (worldIT * vec4(n, 0)).xyz;
vs_out_tex = vs_in_tex;
}