Szerkesztő:Szerkesztonev Proba/próbalap
- pragma once
// C++ includes
- include <memory>
- include <random>
// 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_program; // mesh shader ProgramObject m_programSkybox; // skybox shader
VertexArrayObject m_CubeVao; // VAO IndexBuffer m_CubeIndices; // index buffer ArrayBuffer m_CubeVertexBuffer; // VBO VertexArrayObject m_SkyboxVao; IndexBuffer m_SkyboxIndices; ArrayBuffer m_SkyboxPos;
gCamera m_camera;
Texture2D m_woodTexture; Texture2D m_suzanneTexture; TextureCubeMap m_skyboxTexture;
struct Vertex { glm::vec3 p; glm::vec3 n; glm::vec2 t; };
// mesh adatok std::unique_ptr<Mesh> m_mesh;
// a jobb olvashatóság kedvéért void InitShaders(); void InitCube(); void InitSkyBox();
//domborzat VertexArrayObject groundVao; IndexBuffer groundIb; ArrayBuffer groundVbo;
glm::mat4 groundWorld = glm::scale(glm::vec3(20, 0.3f, 20)) * glm::translate(glm::vec3(-0.5f, 0, -0.5f));
void InitGround(); glm::vec3 Ground(float u, float v);
Texture2D grassTexture;
const int N = 20;
//háttérfák VertexArrayObject forestVao; IndexBuffer forestIb; ArrayBuffer forestVbo; Texture2D forestTexture; void InitForest();
//fa std::unique_ptr<Mesh> cylinderMesh;
VertexArrayObject sphereVao; IndexBuffer sphereIb; ArrayBuffer sphereVbo;
glm::vec3 Sphere(float u, float v);
Texture2D barkTexture; Texture2D leavesTexture; void InitTree(); void DrawTree(glm::mat4 world);
struct Tree { int x, y; glm::vec3 pos; float scale = 1.0f; Tree() {} Tree(int x, int y, glm::vec3 pos, float scale) : x(x), y(y), pos(pos), scale(scale) {} }; std::vector<Tree> trees; bool occupied[20][20];
void SimulateTrees(float deltatime); std::default_random_engine rng; glm::vec3 GridPointToWorldPos(int x, int y);
};
//------------------------------------------------------
- include "MyApp.h"
- include <math.h>
- include <vector>
- 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 ); }
glm::vec3 CMyApp::GetCylinderPos(float u, float v)
{
float alpha = -u * 2 * M_PI; float h = v * 3.0; float r = 2.0f; return glm::vec3(cosf(alpha) * r, h, sin(alpha) * r);
} void CMyApp::InitCircle() {
Vertex vert[(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;
vert[i + j * (N + 1)].p = GetCylinderPos(u, v); vert[i + j * (N + 1)].n = glm::normalize(vert[i + j * (N + 1)].p); vert[i + j * (N + 1)].t = glm::vec2(u, v); } circleVbo.BufferData(vert);
std::vector<int> indices; indices.reserve(N * M * 2 * 3);
for (int i = 1; i < N; ++i) { indices.push_back(0 + M * (N + 1)); indices.push_back(i + M * (N + 1)); indices.push_back((i + 1) + M * (N + 1)); } circleIb.BufferData(indices);
circleVao.Init( { {CreateAttribute<0,glm::vec3,0,sizeof(Vertex)>,circleVbo}, {CreateAttribute<1,glm::vec3,sizeof(glm::vec3),sizeof(Vertex)>,circleVbo}, {CreateAttribute<2,glm::vec2,sizeof(glm::vec3) * 2,sizeof(Vertex)>,circleVbo}, }, circleIb ); earthTexture.FromFile("Assets/earth.png");
}
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::InitShaders() { // a shadereket tároló program létrehozása az OpenGL-hez hasonló módon: m_program.AttachShaders({ { GL_VERTEX_SHADER, "myVert.vert"}, { GL_FRAGMENT_SHADER, "myFrag.frag"} });
// attributomok osszerendelese a VAO es shader kozt m_program.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_program.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 } ); }
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(); InitCircle();
// egyéb textúrák betöltése m_woodTexture.FromFile("assets/wood.jpg"); m_suzanneTexture.FromFile("assets/marron.jpg");
// mesh betöltése m_mesh = std::unique_ptr<Mesh>(ObjParser::parse("assets/Suzanne.obj")); m_mesh->initBuffers();
// kamera m_camera.SetProj(glm::radians(60.0f), 640.0f / 480.0f, 0.01f, 1000.0f);
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(); }
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();
// fold
glm::mat4 circleWorld = glm::mat4(1.0f);
circleVao.Bind();
m_program.Use();
m_program.SetTexture("texImage", 0, earthTexture);
m_program.SetUniform("MVP", viewProj * circleWorld);
m_program.SetUniform("world", circleWorld);
m_program.SetUniform("worldIT", glm::inverse(glm::transpose(circleWorld)));
glDrawElements(GL_TRIANGLES, 3 * 2 * (N) * (M), GL_UNSIGNED_INT, nullptr);
//Suzanne
glm::mat4 suzanneWorld = glm::mat4(1.0f);
m_program.Use();
m_program.SetTexture("texImage", 0, m_suzanneTexture);
m_program.SetUniform("MVP", viewProj * suzanneWorld);
m_program.SetUniform("world", suzanneWorld);
m_program.SetUniform("worldIT", glm::inverse(glm::transpose(suzanneWorld)));
//m_mesh->draw();
// kockák //m_program.Use(); nem hívjuk meg újra, hisz ugyanazt a shadert használják m_CubeVao.Bind(); m_program.SetTexture("texImage", 0, m_woodTexture); glm::mat4 cubeWorld;
float time = SDL_GetTicks() / 1000.0f * 2 * float(M_PI) / 10; for (int i = 0; i < 10; ++i) { cubeWorld = glm::rotate(time + 2 * glm::pi<float>() / 10 * i, glm::vec3(0, 1, 0))* glm::translate(glm::vec3(10 + 5 * sin(time), 0, 0))* glm::rotate((i + 1)*time, glm::vec3(0, 1, 0)); m_program.SetUniform("MVP", viewProj * cubeWorld); m_program.SetUniform("world", cubeWorld); m_program.SetUniform("worldIT", glm::inverse(glm::transpose(cubeWorld))); glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr); } m_program.Unuse();
// 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(); }
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); }