feat: added phong and basic shaders, updated mesh format

This commit is contained in:
Daniel Ledda
2023-01-10 03:54:24 +01:00
parent 93dadfbf4b
commit 658b5d693a
10 changed files with 384 additions and 116 deletions

View File

@@ -7,6 +7,7 @@
#include <string>
#include <algorithm>
#include <vector>
#include <optional>
#include "glad/glad.h"
#include <GLFW/glfw3.h>
@@ -20,9 +21,27 @@
#include "gfx/Texture.h"
#include "gfx/Mesh.h"
#include "gfx/Shader.h"
#include "gfx/Color.h"
#include "VoxelSpace.h"
#include "SomaSolve.h"
struct Entity;
struct Polycube;
struct SceneGraphNode;
auto new_entity() -> int;
auto get_entity(int id) -> Entity*;
auto get_scene_graph_node(int id) -> SceneGraphNode*;
auto new_graph_node() -> int;
auto print_mat(glm::mat4* matrix) -> void {
auto mat = *matrix;
std::cout << mat[0][0] << mat[0][1] << mat[0][2] << mat[0][3] << std::endl;
std::cout << mat[1][0] << mat[1][1] << mat[1][2] << mat[1][3] << std::endl;
std::cout << mat[2][0] << mat[2][1] << mat[2][2] << mat[2][3] << std::endl;
std::cout << mat[3][0] << mat[3][1] << mat[3][2] << mat[3][3] << std::endl;
std::cout << std::endl;
}
struct Camera {
glm::mat4 view;
glm::mat4 proj;
@@ -33,7 +52,7 @@ struct Camera {
auto init(float aspect_ratio = 800.0f / 600.0f) -> void {
view = glm::mat4();
proj = glm::perspective(glm::radians(45.0f), aspect_ratio, 0.1f, 100.0f);
pos = glm::vec3(0.0f, 5.0f, 0.0f);
pos = glm::vec3(0.0f);
up = glm::vec3(0.0f, 1.0f, 0.0f);
}
@@ -47,51 +66,90 @@ struct Camera {
}
};
struct GlobalAppState {
int current_polycube;
int last_polycube_visible;
Shader* active_shader;
std::vector<Polycube> polycubes;
};
GlobalAppState app_state;
struct WindowDims {
unsigned int width;
unsigned int height;
};
struct TrsSpecs {
struct Entity {
Mesh* mesh;
Texture* tex;
bool visible;
int scene_graph_node;
};
struct SceneGraphNode {
glm::mat4 local;
glm::mat4 world;
glm::vec3 translation;
glm::quat rotation;
glm::vec3 scale;
std::vector<int> children;
std::optional<int> entity;
auto reset() -> void {
scale = glm::vec3(1.0f, 1.0f, 1.0f);
translation = glm::vec3(0.0f, 0.0f, 0.0f);
rotation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f);
}
};
struct Entity {
glm::mat4 local;
glm::mat4 world;
TrsSpecs trs;
Mesh* mesh;
Texture* tex;
auto init() -> void {
trs.reset();
reset();
local = glm::mat4(1.0f);
world = local;
}
auto update_model_mat() -> void {
local = glm::mat4(1.0f);
auto update_local() -> void {
local = glm::scale(
glm::translate(
local,
trs.translation
) * glm::toMat4(trs.rotation),
trs.scale
glm::mat4(1.0f),
translation
) * glm::toMat4(rotation),
scale
);
world = local;
}
};
struct Polycube {
std::vector<Entity*>* entities;
uint8_t color;
int graph_node;
glm::vec3 color;
auto show() -> void {
auto node = get_scene_graph_node(graph_node);
for (auto &child : node->children) {
auto node = get_scene_graph_node(child);
if (node->entity) {
get_entity(*node->entity)->visible = true;
}
}
}
auto hide() -> void {
auto node = get_scene_graph_node(graph_node);
for (auto &child : node->children) {
auto node = get_scene_graph_node(child);
if (node->entity) {
get_entity(*node->entity)->visible = false;
}
}
}
auto get_centre() -> glm::vec3 {
auto centre = glm::vec3(0.0f);
for (auto &child : get_scene_graph_node(graph_node)->children) {
centre += get_scene_graph_node(child)->translation;
}
centre /= get_scene_graph_node(graph_node)->children.size();
return centre;
}
};
struct Frame {
@@ -111,20 +169,6 @@ auto framebuffer_size_callback(GLFWwindow* window, int width, int height) -> voi
glViewport(0, 0, width, height);
}
auto process_input(GLFWwindow *window) -> void {
static auto wireframe = false;
static auto last_frame_state_press = false;
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
} else if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS && !last_frame_state_press) {
glPolygonMode(GL_FRONT_AND_BACK, !wireframe ? GL_LINE : GL_FILL);
wireframe = !wireframe;
last_frame_state_press = true;
} else if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_RELEASE) {
last_frame_state_press = false;
}
}
auto init_window_and_gl(WindowDims* window_dims) -> GLFWwindow* {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
@@ -153,67 +197,113 @@ auto gl_update_viewport(WindowDims* window_dims, Frame* frame) -> void {
glViewport(frame->x, window_dims->height - frame->y - frame->height, frame->width, frame->height);
}
auto rotate_cam_around_centre(Camera* cam, int radius) -> void {
cam->pos.x = sin(glfwGetTime()) * radius;
cam->pos.z = cos(glfwGetTime()) * radius;
cam->look_at(0.0f, 0.0f, 0.0f);
}
auto active_shader = Shader{};
auto cube_mesh = Mesh{};
auto wall_tex = Texture{};
auto entities = std::vector<Entity>();
auto scene_graph_nodes = std::vector<SceneGraphNode>();
auto process_input(GLFWwindow *window) -> void {
static auto wireframe = false;
static auto last_frame_state_press_enter = false;
static auto last_frame_state_press = false;
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS && !last_frame_state_press) {
glPolygonMode(GL_FRONT_AND_BACK, !wireframe ? GL_LINE : GL_FILL);
wireframe = !wireframe;
last_frame_state_press = true;
} else if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_RELEASE) {
last_frame_state_press = false;
}
if (glfwGetKey(window, GLFW_KEY_ENTER) == GLFW_PRESS && !last_frame_state_press_enter) {
if (app_state.current_polycube == 6) {
app_state.current_polycube = 0;
} else {
app_state.current_polycube += 1;
}
last_frame_state_press_enter = true;
} else if (glfwGetKey(window, GLFW_KEY_ENTER) == GLFW_RELEASE) {
last_frame_state_press_enter = false;
}
}
auto new_entity() -> int {
entities.emplace_back();
scene_graph_nodes.emplace_back();
entities.back().scene_graph_node = scene_graph_nodes.size();
scene_graph_nodes.back().entity = entities.size();
return entities.size();
}
auto get_entity(int id) -> Entity* {
return &entities[id - 1];
}
auto get_scene_graph_node(int id) -> SceneGraphNode* {
return &scene_graph_nodes[id - 1];
}
auto new_graph_node() -> int {
scene_graph_nodes.emplace_back();
return scene_graph_nodes.size();
}
auto draw_entity(Entity* entity) -> void {
auto modelUniformLoc = glGetUniformLocation(active_shader.prog_id, "model");
glUniformMatrix4fv(modelUniformLoc, 1, GL_FALSE, glm::value_ptr(entity->world));
auto modelUniformLoc = glGetUniformLocation(app_state.active_shader->prog_id, "model");
glUniformMatrix4fv(modelUniformLoc, 1, GL_FALSE, glm::value_ptr(get_scene_graph_node(entity->scene_graph_node)->world));
glBindTexture(GL_TEXTURE_2D, entity->tex->tex_id);
glBindVertexArray(entity->mesh->vao);
glDrawElements(GL_TRIANGLES, entity->mesh->num_indices, GL_UNSIGNED_INT, 0);
glDrawArrays(GL_TRIANGLES, 0, entity->mesh->num_indices);
//glDrawElements(GL_TRIANGLES, entity->mesh->num_indices, GL_UNSIGNED_INT, 0);
}
auto use_default_shader(Camera* cam) -> void {
glUseProgram(active_shader.prog_id);
auto viewUniformLoc = glGetUniformLocation(active_shader.prog_id, "view");
auto projectionUniformLoc = glGetUniformLocation(active_shader.prog_id, "projection");
glUniformMatrix4fv(projectionUniformLoc, 1, GL_FALSE, glm::value_ptr(cam->proj));
glUniformMatrix4fv(viewUniformLoc, 1, GL_FALSE, glm::value_ptr(cam->view));
}
auto print_mat(glm::mat4* matrix) -> void {
auto mat = *matrix;
std::cout << mat[0][0] << mat[0][1] << mat[0][2] << mat[0][3] << std::endl;
std::cout << mat[1][0] << mat[1][1] << mat[1][2] << mat[1][3] << std::endl;
std::cout << mat[2][0] << mat[2][1] << mat[2][2] << mat[2][3] << std::endl;
std::cout << mat[3][0] << mat[3][1] << mat[3][2] << mat[3][3] << std::endl;
std::cout << std::endl;
}
auto create_polycube_from_repr(Voxel::Space* repr) -> std::vector<Entity*> {
auto result = std::vector<Entity*>(Voxel::size(repr->space));
auto create_polycube_from_repr(Voxel::Space* repr) -> Polycube {
auto polycube_id = new_graph_node();
get_scene_graph_node(polycube_id)->init();
for (int x = 0; x < repr->dim_x; x++) {
for (int y = 0; y < repr->dim_y; y++) {
for (int z = 0; z < repr->dim_z; z++) {
if (Voxel::filledAt(repr, x, y, z)) {
entities.push_back({
.mesh=&cube_mesh,
.tex=&wall_tex,
});
auto polycube_segment = &entities.back();
polycube_segment->init();
polycube_segment->trs.translation = glm::vec3(
-((repr->dim_z - 1)/2) + z,
((repr->dim_x - 1)/2) - x,
-((repr->dim_y - 1)/2) + y
auto polycube_segment = get_entity(new_entity());
polycube_segment->mesh=&cube_mesh,
polycube_segment->tex=&wall_tex;
auto graph_node = get_scene_graph_node(polycube_segment->scene_graph_node);
graph_node->init();
graph_node->translation = glm::vec3(
-((repr->dim_z - 1)/2.0f) + z,
((repr->dim_x - 1)/2.0f) - x,
-((repr->dim_y - 1)/2.0f) + y
);
result.push_back(polycube_segment);
graph_node->update_local();
get_scene_graph_node(polycube_id)->children.push_back(polycube_segment->scene_graph_node);
}
}
}
}
auto result = Polycube{
.graph_node=polycube_id,
.color=glm::vec3(1.0f),
};
return result;
}
auto recalculate_scene_graph(SceneGraphNode* top) -> void {
if (top->children.size() == 0) {
return;
}
for (auto &node_id : top->children) {
auto graph_node = get_scene_graph_node(node_id);
graph_node->update_local();
graph_node->world = top->world * graph_node->local;
recalculate_scene_graph(graph_node);
}
}
auto main() -> int {
auto window_dims = WindowDims{ 800, 600 };
auto window = init_window_and_gl(&window_dims);
@@ -221,6 +311,20 @@ auto main() -> int {
return -1;
}
app_state = GlobalAppState{
.current_polycube=0,
.last_polycube_visible=6,
.active_shader=nullptr,
.polycubes={},
};
auto phong_shader = Shader{};
phong_shader.init("../assets/shaders/phong-solid.vertex.glsl", "../assets/shaders/phong-solid.fragment.glsl");
app_state.active_shader = &phong_shader;
cube_mesh.init("../assets/models/c000000.obj");
wall_tex.init("../assets/textures/brick-wall.jpg");
auto little_frame = Frame{ .width=80, .height=60, .x=20, .y=20 };
auto big_frame = Frame{ .width=800, .height=600, .x=0, .y=0 };
auto main_cam = Camera{};
@@ -229,37 +333,62 @@ auto main() -> int {
big_frame.init(&main_cam);
auto frames = std::vector{ &big_frame, &little_frame };
active_shader.init("../assets/shaders/basic.vertex.glsl", "../assets/shaders/basic.fragment.glsl");
auto root_node = SceneGraphNode{};
root_node.init();
cube_mesh.init("../assets/models/c000000.obj");
wall_tex.init("../assets/textures/brick-wall.jpg");
auto voxel_space = Voxel::Space{
.space=SomaSolve::STD_SOMA[0],
.dim_x=3,
.dim_y=3,
.dim_z=3
};
Voxel::cullEmptySpace(&voxel_space);
auto polycube1 = create_polycube_from_repr(&voxel_space);
for (auto &entity : entities) {
entity.update_model_mat();
for (int i = 0; i < SomaSolve::STD_SOMA.size(); i++) {
auto voxel_space = Voxel::Space{ SomaSolve::STD_SOMA[i], 3, 3, 3 };
Voxel::cullEmptySpace(&voxel_space);
auto polycube = create_polycube_from_repr(&voxel_space);
polycube.color = Color::color_from_index(i);
app_state.polycubes.push_back(polycube);
root_node.children.push_back(app_state.polycubes.back().graph_node);
}
while (!glfwWindowShouldClose(window)) {
process_input(window);
rotate_cam_around_centre(big_frame.cam, 10.0f);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
main_cam.pos = glm::vec3(4.0f, 4.0f, 4.0f);
main_cam.look_at(0.0f, 0.0f, 0.0f);
auto light_pos = glm::vec3(6.0f);
glUseProgram(app_state.active_shader->prog_id);
auto view_loc = glGetUniformLocation(app_state.active_shader->prog_id, "view");
auto proj_loc = glGetUniformLocation(app_state.active_shader->prog_id, "projection");
auto light_pos_loc = glGetUniformLocation(app_state.active_shader->prog_id, "light_pos");
glUniform3fv(light_pos_loc, 1, glm::value_ptr(light_pos));
glUniformMatrix4fv(proj_loc, 1, GL_FALSE, glm::value_ptr(main_cam.proj));
glUniformMatrix4fv(view_loc, 1, GL_FALSE, glm::value_ptr(main_cam.view));
auto last_frame = glfwGetTime();
auto time_delta = 1.0f/60.0f;
while (!glfwWindowShouldClose(window)) {
time_delta = glfwGetTime() - last_frame;
process_input(window);
if (app_state.last_polycube_visible != app_state.current_polycube) {
app_state.polycubes[app_state.last_polycube_visible].hide();
app_state.polycubes[app_state.current_polycube].show();
app_state.last_polycube_visible = app_state.current_polycube;
}
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
use_default_shader(big_frame.cam);
gl_update_viewport(&window_dims, &big_frame);
auto current_polycube = &app_state.polycubes[app_state.current_polycube];
get_scene_graph_node(current_polycube->graph_node)->rotation = glm::quat(glm::vec3(0, glfwGetTime() / 2, 0));
glBindVertexArray(cube_mesh.vao);
//glBindTexture(GL_TEXTURE_2D, entity.tex->tex_id);
recalculate_scene_graph(&root_node);
auto model_uniform_loc = glGetUniformLocation(app_state.active_shader->prog_id, "model");
auto solid_color_loc = glGetUniformLocation(app_state.active_shader->prog_id, "solid_color");
glUniform3fv(solid_color_loc, 1, glm::value_ptr(current_polycube->color));
for (auto &entity : entities) {
entity.update_model_mat();
auto scale = glm::mat4(1.0f);
entity.world = glm::scale(glm::mat4(1.0f), glm::vec3(1.0f) * abs((float)sin(glfwGetTime()))) * entity.world;
draw_entity(&entity);
if (entity.visible) {
glUniformMatrix4fv(model_uniform_loc, 1, GL_FALSE, glm::value_ptr(get_scene_graph_node(entity.scene_graph_node)->world));
glDrawArrays(GL_TRIANGLES, 0, entity.mesh->num_indices);
//glDrawElements(GL_TRIANGLES, entity->mesh->num_indices, GL_UNSIGNED_INT, 0);
}
}
glfwSwapBuffers(window);