Poor face collision checking

master
Nicole Collings 2020-06-03 14:55:42 -07:00
parent 0c1f0c05a3
commit d4c51d6056
18 changed files with 418 additions and 147 deletions

View File

@ -16,8 +16,8 @@ void main() {
vec3 color = spec.xyz;
if (highlight) {
color *= 1.4;
color += 0.025;
color *= 1.25;
color += 0.05;
}
outColor = color;

View File

@ -22,7 +22,7 @@ App::App() :
void App::update() {
window.update();
controller.update();
blockManager.update(input);
blockManager.update(input, controller);
}
void App::render() {

View File

@ -1,3 +1,3 @@
set(MODELLER_SRC
graph/Renderer.cpp graph/Renderer.h App.cpp App.h graph/Window.cpp graph/Window.h graph/Shader.cpp graph/Shader.h graph/Camera.h graph/Camera.cpp graph/Mesh.inl graph/Mesh.h graph/Vertex.h graph/Texture.h graph/Texture.cpp input/ViewportControl.cpp input/ViewportControl.h input/Input.cpp input/Input.h model/BlockModelManager.cpp model/BlockModelManager.h model/BlockModel.cpp model/BlockModel.h model/BlockFace.cpp model/BlockFace.h)
graph/Renderer.cpp graph/Renderer.h App.cpp App.h graph/Window.cpp graph/Window.h graph/Shader.cpp graph/Shader.h graph/Camera.h graph/Camera.cpp graph/Mesh.h graph/Vertex.h graph/Texture.h graph/Texture.cpp input/ViewportControl.cpp input/ViewportControl.h input/Input.cpp input/Input.h model/BlockModelManager.cpp model/BlockModelManager.h model/BlockModelInstance.cpp model/BlockModelInstance.h model/BlockFace.cpp model/BlockFace.h model/BlockModel.cpp model/BlockModel.h model/EditingBlockModel.cpp model/EditingBlockModel.h input/Ray.h)
add_library(${MAIN_LIB_NAME} ${MODELLER_SRC})

View File

@ -32,7 +32,73 @@ protected:
std::shared_ptr<int> refs = std::make_shared<int>();
};
#include "Mesh.inl"
template <class V>
Mesh<V>::Mesh(const std::vector<V>& vertices, const std::vector<unsigned int>& indices) {
create(vertices, indices);
}
template <class V>
void Mesh<V>::create(const std::vector<V> &vertices, const std::vector<unsigned int> &indices) {
indCount = static_cast<size_t>(indices.size());
createArrays(static_cast<unsigned int>(vertices.size() * sizeof(V)),
static_cast<unsigned int>(indices.size() * sizeof(unsigned int)),
&vertices.front(), &indices.front());
}
template<class V>
void Mesh<V>::finish() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
template <class V>
void Mesh<V>::createArrays(unsigned int vboLength, unsigned int iboLength, const void *verticesPtr, const void *indicesPtr) {
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iboLength, indicesPtr, GL_STATIC_DRAW);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vboLength, verticesPtr, GL_STATIC_DRAW);
}
template <class V>
void Mesh<V>::createVertexAttrib(unsigned int offset, unsigned int size, int type, unsigned int stride, const void* pointer) {
glEnableVertexAttribArray(offset);
if (type == GL_INT) glVertexAttribIPointer(offset, size, type, stride, pointer);
else glVertexAttribPointer(offset, size, type, GL_FALSE, stride, pointer);
}
template <class V>
void Mesh<V>::draw() const {
if (VAO == 0) return;
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glDrawElements(GL_TRIANGLES, indCount, GL_UNSIGNED_INT, nullptr);
}
template <class V>
void Mesh<V>::cleanup() {
if (VAO) glDeleteVertexArrays(1, &VAO);
if (VBO) glDeleteBuffers(1, &VBO);
if (IBO) glDeleteBuffers(1, &IBO);
VAO = 0;
VBO = 0;
IBO = 0;
indCount = 0;
}
template <class V>
Mesh<V>::~Mesh() {
if (refs.use_count() == 1) cleanup();
}
class BlockMesh : public Mesh<BlockVertex> {
public:

View File

@ -1,73 +0,0 @@
//
// Created by aurailus on 2020-05-29.
//
#include "Mesh.h"
template <class V>
Mesh<V>::Mesh(const std::vector<V>& vertices, const std::vector<unsigned int>& indices) {
create(vertices, indices);
}
template <class V>
void Mesh<V>::create(const std::vector<V> &vertices, const std::vector<unsigned int> &indices) {
indCount = static_cast<size_t>(indices.size());
createArrays(static_cast<unsigned int>(vertices.size() * sizeof(V)),
static_cast<unsigned int>(indices.size() * sizeof(unsigned int)),
&vertices.front(), &indices.front());
}
template<class V>
void Mesh<V>::finish() {
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
template <class V>
void Mesh<V>::createArrays(unsigned int vboLength, unsigned int iboLength, const void *verticesPtr, const void *indicesPtr) {
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
glGenBuffers(1, &IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, iboLength, indicesPtr, GL_STATIC_DRAW);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vboLength, verticesPtr, GL_STATIC_DRAW);
}
template <class V>
void Mesh<V>::createVertexAttrib(unsigned int offset, unsigned int size, int type, unsigned int stride, const void* pointer) {
glEnableVertexAttribArray(offset);
if (type == GL_INT) glVertexAttribIPointer(offset, size, type, stride, pointer);
else glVertexAttribPointer(offset, size, type, GL_FALSE, stride, pointer);
}
template <class V>
void Mesh<V>::draw() const {
if (VAO == 0) return;
glBindVertexArray(VAO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO);
glDrawElements(GL_TRIANGLES, indCount, GL_UNSIGNED_INT, nullptr);
}
template <class V>
void Mesh<V>::cleanup() {
if (VAO) glDeleteVertexArrays(1, &VAO);
if (VBO) glDeleteBuffers(1, &VBO);
if (IBO) glDeleteBuffers(1, &IBO);
VAO = 0;
VBO = 0;
IBO = 0;
indCount = 0;
}
template <class V>
Mesh<V>::~Mesh() {
if (refs.use_count() == 1) cleanup();
}

View File

@ -49,10 +49,16 @@ void Input::update() {
}
}
lastMouse = mouse;
double x, y;
glm::ivec2 lastMouse = mouse;
glfwGetCursorPos(window, &x, &y);
mouse = { static_cast<int>(x), static_cast<int>(y) };
delta = mouse - lastMouse;
if (mouseLocked) {
glfwSetCursorPos(window, lock.x, lock.y);
mouse = lock;
}
}
bool Input::keyDown(int key) const {
@ -101,5 +107,12 @@ glm::ivec2 Input::mousePos() const {
}
glm::ivec2 Input::mouseDelta() const {
return mouse - lastMouse;
}
return delta;
}
void Input::setMouseLocked(bool locked) {
if ((this->mouseLocked && locked) || (!this->mouseLocked & !locked)) return;
this->mouseLocked = locked;
this->lock = mouse;
glfwSetInputMode(window, GLFW_CURSOR, locked ? GLFW_CURSOR_HIDDEN : GLFW_CURSOR_NORMAL);
}

View File

@ -25,6 +25,8 @@ public:
glm::ivec2 mousePos() const;
glm::ivec2 mouseDelta() const;
void setMouseLocked(bool locked);
private:
static void keyCallback(GLFWwindow* window, int key, int code, int action, int mode);
static void scrollCallback(GLFWwindow* window, double, double yO);
@ -37,5 +39,7 @@ private:
std::unordered_set<std::shared_ptr<std::function<void(int delta)>>> callbacks;
GLFWwindow* window = nullptr;
glm::ivec2 mouse, lastMouse;
glm::ivec2 mouse, delta, lock;
bool mouseLocked = false;
};

43
src/input/Ray.h Normal file
View File

@ -0,0 +1,43 @@
//
// Created by aurailus on 2020-06-02.
//
#pragma once
#include <glm/glm.hpp>
#include "../graph/Window.h"
#include "../graph/Camera.h"
namespace Ray {
static glm::vec3 worldRayFromCursor(Window &window, Camera &camera) {
return glm::vec3(glm::inverse(camera.getViewMatrix()) *
glm::vec4(glm::vec2(glm::inverse(camera.getProjectionMatrix()) * glm::vec4 {
(2.f * window.getInput().mousePos().x) / window.getSize().x - 1.f,
1.f - (2.f * window.getInput().mousePos().y) / window.getSize().y, -1.f, 1.f }), -1.0, 0.0));
}
static float rayInterceptsRect(std::array<glm::vec3, 4> p, glm::vec3 rayOrigin, glm::vec3 rayDir) {
rayDir = glm::normalize(rayDir);
glm::vec3 v1 = p[1] - p[0];
glm::vec3 v2 = p[3] - p[0];
glm::vec3 n = glm::normalize(glm::cross(v1, v2));
float A = p[0].y * (p[1].z - p[2].z) + p[1].y * (p[2].z - p[0].z) + p[2].y * (p[0].z - p[1].z);
float B = p[0].z * (p[1].x - p[2].x) + p[1].z * (p[2].x - p[0].x) + p[2].z * (p[0].x - p[1].x);
float C = p[0].x * (p[1].y - p[2].y) + p[1].x * (p[2].y - p[0].y) + p[2].x * (p[0].y - p[1].y);
float D = -p[0].x * (p[1].y * p[2].z - p[2].y * p[1].z) - p[1].x * (p[2].y * p[0].z - p[0].y * p[2].z) - p[2].x * (p[0].y * p[1].z - p[1].y * p[0].z);
float t = -(A * rayOrigin.x + B * rayOrigin.y + C * rayOrigin.z + D) / (A * rayDir.x + B * rayDir.y + C * rayDir.z);
if (t < 0) return 0;
glm::vec3 intercepts = rayOrigin + rayDir * t;
v1 = glm::normalize(v1);
glm::vec3 v3 = glm::normalize(p[3] - p[2]);
glm::vec3 v4 = glm::normalize(intercepts - p[0]);
glm::vec3 v5 = glm::normalize(intercepts - p[2]);
if (glm::dot(v1, v4) > 0 && glm::dot(v3, v5) > 0) return t;
return 0;
}
}

View File

@ -16,17 +16,18 @@
ViewportControl::ViewportControl(Input &input, Camera &camera) :
input(input),
camera(camera) {
this->cb = input.addScrollCallback([&](int delta) {
distance -= delta * (distance / 6);
});
this->cb = input.addScrollCallback([&](int delta) { distance = fmin(fmax(distance - delta * (distance / 6), 1.1), 20); });
}
void ViewportControl::update() {
if (input.keyDown(GLFW_MOUSE_BUTTON_LEFT)) {
if (input.keyDown(GLFW_MOUSE_BUTTON_MIDDLE)) {
input.setMouseLocked(true);
yaw += -input.mouseDelta().x * panFactor;
pitch += -input.mouseDelta().y * panFactor;
pitch = fmin(fmax(pitch, -1.5), 1.5);
pitch = fmin(fmax(pitch, -1.55), 1.55);
}
else input.setMouseLocked(false);
glm::vec3 camPos = {
distance * -sinf(yaw) * cosf(pitch),
@ -35,7 +36,7 @@ void ViewportControl::update() {
};
glm::vec3 look = -camPos;
float length = glm::length(look) + 0.00001;
float length = glm::length(look) + 0.000001;
float lookPitch = asin(look.y / length);
float lookYaw = asin(look.z / (cos(asin(look.y / length)) * length));
@ -45,7 +46,11 @@ void ViewportControl::update() {
lookYaw += M_PI;
}
camera.setPos(camPos);
camera.setPos(camPos + focus);
camera.setPitch(lookPitch);
camera.setYaw(lookYaw);
}
void ViewportControl::setViewFocus(glm::vec3 focus) {
this->focus = focus;
}

View File

@ -15,14 +15,16 @@ public:
ViewportControl(Input& input, Camera& camera);
void update();
void setViewFocus(glm::vec3 focus);
private:
Input& input;
Camera& camera;
double panFactor = 0.01;
double panFactor = 0.0075;
double distance = 4;
glm::vec3 focus;
double pitch, yaw;
std::shared_ptr<std::function<void(int delta)>> cb;

View File

@ -1,13 +1,10 @@
//
// Created by aurailus on 2020-05-31.
// Created by aurailus on 2020-06-02.
//
#include <glm/gtc/matrix_transform.hpp>
#include "BlockModel.h"
BlockModel::BlockModel() {
faces = {
BlockFace({ glm::vec3 {-0.5, -0.5, 0.5}, {-0.5, 0.5, 0.5}, {-0.5, 0.5, -0.5}, {-0.5, -0.5, -0.5}},
{ glm::vec2 {0, 0}, {0, 1}, {1, 1}, {1, 0}}),
@ -26,14 +23,6 @@ BlockModel::BlockModel() {
updateMesh();
}
glm::ivec3 BlockModel::getPos() {
return pos;
}
void BlockModel::setPos(glm::vec3 pos) {
this->pos = pos;
}
void BlockModel::updateMesh() {
std::vector<BlockVertex> vertices {};
std::vector<unsigned int> indices {};
@ -59,14 +48,6 @@ void BlockModel::updateMesh() {
mesh.create(vertices, indices);
}
void BlockModel::render(Renderer &renderer) {
glm::mat4 model = glm::mat4(1.0);
model = glm::translate(model, pos);
renderer.setModelMatrix(model);
renderer.sWorld.set(renderer.uHighlight, highlighted);
void BlockModel::render() {
mesh.draw();
}
void BlockModel::setHighlighted(bool highlighted) {
this->highlighted = highlighted;
}

View File

@ -1,28 +1,20 @@
//
// Created by aurailus on 2020-05-31.
// Created by aurailus on 2020-06-02.
//
#pragma once
#include "BlockFace.h"
#include "../graph/Mesh.h"
#include "../graph/Renderer.h"
class BlockModel {
friend class EditingBlockModel;
public:
BlockModel();
glm::ivec3 getPos();
void setPos(glm::vec3 pos);
void updateMesh();
void render(Renderer& renderer);
void setHighlighted(bool highlighted);
void render();
private:
glm::vec3 pos;
bool highlighted = false;
BlockMesh mesh;
std::vector<BlockFace> faces {};
};

View File

@ -0,0 +1,36 @@
//
// Created by aurailus on 2020-05-31.
//
#include <glm/gtc/matrix_transform.hpp>
#include "BlockModelInstance.h"
#include "BlockModel.h"
BlockModelInstance::BlockModelInstance(std::shared_ptr<BlockModel> model) :
model(model) {}
void BlockModelInstance::render(Renderer &renderer) {
glm::mat4 model = glm::mat4(1.0);
model = glm::translate(model, glm::vec3(pos));
renderer.setModelMatrix(model);
renderer.sWorld.set(renderer.uHighlight, highlighted);
this->model->render();
}
glm::ivec3 BlockModelInstance::getPos() {
return pos;
}
void BlockModelInstance::setPos(glm::ivec3 pos) {
this->pos = pos;
}
std::shared_ptr<BlockModel> BlockModelInstance::getModel() {
return model;
}
void BlockModelInstance::setHighlighted(bool highlighted) {
this->highlighted = highlighted;
}

View File

@ -0,0 +1,29 @@
//
// Created by aurailus on 2020-05-31.
//
#pragma once
#include <memory>
#include "../graph/Renderer.h"
class BlockModel;
class BlockModelInstance {
public:
BlockModelInstance(std::shared_ptr<BlockModel> model);
void render(Renderer& renderer);
glm::ivec3 getPos();
void setPos(glm::ivec3 pos);
std::shared_ptr<BlockModel> getModel();
void setHighlighted(bool highlighted);
private:
std::shared_ptr<BlockModel> model;
glm::ivec3 pos;
bool highlighted = false;
};

View File

@ -3,49 +3,85 @@
//
#include <glm/glm.hpp>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "BlockModel.h"
#include "BlockModelManager.h"
#include "EditingBlockModel.h"
#include "../graph/Camera.h"
#include "../graph/Window.h"
#include "../graph/Renderer.h"
#include "../input/ViewportControl.h"
#include "../input/Ray.h"
BlockModelManager::BlockModelManager(Camera* camera, Window* window) :
dirt("../assets/textures/dirt.png"),
camera(camera),
window(window) {
models.emplace_back();
models.emplace_back();
models.emplace_back();
models.emplace_back();
models.emplace_back();
models.emplace_back(std::make_shared<BlockModel>());
models[1].setPos({1, 0, 1});
models[2].setPos({-1, 0, 1});
models[3].setPos({1, 0, -1});
models[4].setPos({-1, 0, -1});
instances.emplace_back(models[0]);
// instances.emplace_back(models[0]);
// instances.emplace_back(models[0]);
// instances.emplace_back(models[0]);
// instances.emplace_back(models[0]);
// instances.emplace_back(models[0]);
// instances.emplace_back(models[0]);
// instances[0].setPos({1, 0, 0});
// instances[1].setPos({-1, 0, 0});
// instances[3].setPos({0, 0, 1});
// instances[4].setPos({0, 0, -1});
// instances[5].setPos({0, 1, 0});
// instances[6].setPos({0, -1, 0});
}
void BlockModelManager::update(Input& input) {
for (auto& model : models) model.setHighlighted(false);
void BlockModelManager::update(Input& input, ViewportControl& viewport) {
for (auto& instance : instances) instance.setHighlighted(false);
glm::vec4 ray_clip = glm::vec4 {
(2.f * input.mousePos().x) / window->getSize().x - 1.f,
1.f - (2.f * input.mousePos().y) / window->getSize().y, -1.f, 1.f };
if (!editingModel) {
glm::vec3 dir = Ray::worldRayFromCursor(*window, *camera);
glm::vec3 ray = camera->getPos();
bool found = false;
float dis = 0.05f;
glm::vec4 ray_eye = glm::inverse(camera->getProjectionMatrix()) * ray_clip;
ray_eye = glm::vec4(ray_eye.x, ray_eye.y, -1.0, 0.0);
while (dis < 20) {
glm::vec3 end = ray + (dir * dis);
glm::ivec3 blockSpace = glm::floor(end + glm::vec3(0.5));
glm::vec3 ray = glm::vec3(glm::inverse(camera->getViewMatrix()) * ray_eye);
ray *= 20;
models[0].setPos(camera->getPos() + glm::vec3(ray));
for (auto& instance : instances) {
if (instance.getPos() == blockSpace) {
instance.setHighlighted(true);
if (input.keyPressed(GLFW_MOUSE_BUTTON_LEFT)) {
viewport.setViewFocus(instance.getPos());
setEditingModel(instance);
}
found = true;
break;
}
}
std::cout << ray.x << ", " << ray.y << ", " << ray.z << std::endl;
if (found) break;
dis += 0.05;
}
}
else editingInstance->update(viewport, *window, *camera);
}
void BlockModelManager::render(Renderer &renderer) {
dirt.use();
for (auto& model : models) model.render(renderer);
for (auto& instance : instances)
if (!editingModel || editingPos != instance.getPos()) instance.render(renderer);
if (editingInstance) editingInstance->render(renderer);
}
void BlockModelManager::setEditingModel(BlockModelInstance& instance) {
editingPos = instance.getPos();
editingModel = instance.getModel();
editingInstance = std::make_shared<EditingBlockModel>(editingPos, editingModel);
}

View File

@ -4,25 +4,35 @@
#pragma once
#include "BlockModel.h"
#include "../graph/Mesh.h"
#include "../graph/Texture.h"
#include "BlockModelInstance.h"
class Input;
class Camera;
class Window;
class Renderer;
class Camera;
class ViewportControl;
class EditingBlockModel;
class BlockModelManager {
public:
BlockModelManager(Camera* camera, Window* window);
void update(Input& input, ViewportControl& viewport);
void render(Renderer& renderer);
void update(Input& input);
void setEditingModel(BlockModelInstance& instance);
std::vector<std::shared_ptr<BlockModel>> models;
std::vector<BlockModelInstance> instances;
private:
Camera* camera;
Window* window;
std::vector<BlockModel> models;
Texture dirt;
std::shared_ptr<BlockModel> editingModel = nullptr;
std::shared_ptr<EditingBlockModel> editingInstance = nullptr;
glm::ivec3 editingPos {};
};

View File

@ -0,0 +1,94 @@
//
// Created by aurailus on 2020-06-02.
//
#include <glm/mat4x4.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "EditingBlockModel.h"
#include "BlockModel.h"
#include "../input/Ray.h"
#include "../graph/Renderer.h"
EditingBlockModel::EditingBlockModel(glm::vec3 pos, std::shared_ptr<BlockModel> model) :
pos(pos),
model(model) {
updateFaces();
}
void EditingBlockModel::update(ViewportControl &viewport, Window &window, Camera &camera) {
glm::vec3 dir = Ray::worldRayFromCursor(window, camera);
glm::vec3 ray = camera.getPos();
// bool found = false;
// float dis = 0.05f;
//
// while (dis < 20) {
// glm::vec3 end = ray + (dir * dis);
// glm::ivec3 blockSpace = glm::floor(end + glm::vec3(0.5));
//
// for (auto& face : model->faces) {
//// if (instance.getPos() == blockSpace) {
//// instance.setHighlighted(true);
//// if (input.keyPressed(GLFW_MOUSE_BUTTON_LEFT)) {
//// viewport.setViewFocus(instance.getPos());
//// setEditingModel(instance);
//// }
//// found = true;
//// break;
//// }
// }
//
// if (found) break;
// dis += 0.05;
// }
std::cout << Ray::rayInterceptsRect(this->model->faces[0].points, ray, dir) << std::endl;
int ind = -1;
float smallestDistance = 1000;
for (int i = 0; i < faces.size(); i++) {
facesHighlighted[i] = false;
float dist = Ray::rayInterceptsRect(this->model->faces[i].points
// {
// this->model->faces[i].points[3],
// this->model->faces[i].points[2],
// this->model->faces[i].points[1],
// this->model->faces[i].points[0]
// }
, ray, dir);
if (dist != 0 && dist < smallestDistance) {
smallestDistance = dist;
ind = i;
}
}
if (ind != -1) facesHighlighted[ind] = true;
}
void EditingBlockModel::render(Renderer &renderer) {
glm::mat4 model = glm::mat4(1.0);
model = glm::translate(model, glm::vec3(pos));
renderer.setModelMatrix(model);
for (int i = 0; i < faces.size(); i++) {
renderer.sWorld.set(renderer.uHighlight, facesHighlighted[i]);
faces[i].draw();
}
}
void EditingBlockModel::updateFaces() {
faces.clear();
facesHighlighted.clear();
for (auto& face : this->model->faces) {
BlockMesh mesh;
mesh.create({
BlockVertex { face.points[0], face.texCoords[0], {} },
BlockVertex { face.points[1], face.texCoords[1], {} },
BlockVertex { face.points[2], face.texCoords[2], {} },
BlockVertex { face.points[3], face.texCoords[3], {} }
}, {0, 1, 2, 2, 3, 0});
faces.push_back(mesh);
facesHighlighted.push_back(false);
}
}

View File

@ -0,0 +1,33 @@
//
// Created by aurailus on 2020-06-02.
//
#pragma once
#include <memory>
#include <vector>
#include "../graph/Mesh.h"
class Window;
class Camera;
class Renderer;
class BlockModel;
class ViewportControl;
class EditingBlockModel {
public:
EditingBlockModel(glm::vec3 pos, std::shared_ptr<BlockModel> model);
void update(ViewportControl &viewport, Window &window, Camera &camera);
void render(Renderer& renderer);
private:
void updateFaces();
glm::vec3 pos;
std::shared_ptr<BlockModel> model;
std::vector<BlockMesh> faces;
std::vector<bool> facesHighlighted;
};