[TODO] Added. [Chunk|World] Mouse picking: WIP.

This commit is contained in:
Quentin Bazin 2018-06-13 03:47:20 +02:00
parent 3c76f5ebaa
commit 23630138d4
12 changed files with 324 additions and 30 deletions

0
Notes
View File

60
TODO Normal file
View File

@ -0,0 +1,60 @@
TODO
# Nettoyage
• TODO: Vérifier les utilisations inutiles de pointeurs
• TODO: Nettoyer les vieux headers
• TODO: `Types.hpp` → `IntTypes.hpp`
• TODO: Remplacer les anciennes classes par leur upgrade:
◦ TODO: `ApplicationState` / `ApplicationStateStack`
◦ TODO: `GameClock`
◦ TODO: `Window` (depuis `ZeldaOOL`)
◦ TODO: `Debug` / `Exception` (+ gestion dans le `main()`)
◦ TODO: Input system (Mouse + Keyboard)
• TODO: Découper les gros pâtés en sous-classes
• TODO: Séparer le code client du code serveur
# ToDoList
## Joueur
• TODO: Collisions + Gravité
◦ TODO: Système dentités (réutiliser lECS mais en multi-thread)
• TODO: Ciblage de bloc
◦ TODO: Ajout de bloc
◦ TODO: Suppression de bloc
## Items
• TODO: Créer un système ditems
◦ TODO: Inventaire basique (1 slot)
◦ TODO: Récupération du bloc cassé
• TODO: Faire un vrai drop ditem
• TODO: Ajouter les animations de destruction des blocs
## Monde
• TODO: Cycle jour/nuit
◦ TODO: Dynamic lighting
• TODO: Chargement des chunks multi-thread
## Génération
• TODO: Augmenter la hauteur du terrain
• TODO: Dirt + Grass
• TODO: WATEEEEEEER
• TODO: Arbres
• TODO: Fleurs (emit light at night?)
• TODO: Biomes
• TODO: Génération multi-thread
## Affichage
• TODO: Optimiser au maximum laffichage des chunks
◦ TODO: Faire le max de culling
▸ DONE: Face culling
▸ DONE: Frustum culling
▸ TODO: Occlusion culling
◦ TODO: Face-merging
→ Trouver une solution pour utiliser un texture atlas avec ça

View File

@ -5,13 +5,9 @@
*
* Description:
*
* Version: 1.0
* Created: 14/12/2014 13:45:14
* Revision: none
* Compiler: gcc
*
* Author: Quentin BAZIN, <quent42340@gmail.com>
* Company:
*
* =====================================================================================
*/
@ -23,4 +19,7 @@
#define APP_NAME "KubKraft"
#define DIST_NEAR 0.1f
#define DIST_FAR 1000.0f
#endif // CONFIG_HPP_

View File

@ -5,13 +5,9 @@
*
* Description:
*
* Version: 1.0
* Created: 29/12/2014 04:56:02
* Revision: none
* Compiler: gcc
*
* Author: Quentin BAZIN, <quent42340@gmail.com>
* Company:
*
* =====================================================================================
*/
@ -24,13 +20,17 @@
class Block {
public:
Block(u32 id);
Block(const glm::vec3 &pos, u32 id);
glm::vec4 getTexCoords();
const glm::vec3 &pos() const { return m_pos; }
u32 id() const { return m_id; }
private:
glm::vec3 m_pos;
u32 m_id;
};

View File

@ -32,9 +32,11 @@ class Chunk : public NonCopyable {
void draw(Shader &shader);
void addBlock(u32 id);
Block *getBlock(s8 x, s8 y, s8 z);
void addBlock(const glm::vec3 &pos, u32 id);
void setBlock(const glm::vec3 &pos, u32 id);
u32 getCoordID(u8 x, u8 y, u8 z, u8 i, u8 j, u8 coordinate);
u32 getVertexID(u8 x, u8 y, u8 z, u8 i, u8 j, u8 coordinate);
@ -46,10 +48,13 @@ class Chunk : public NonCopyable {
s32 y() const { return m_y; }
s32 z() const { return m_z; }
const std::vector<std::unique_ptr<Block>> &data() const { return m_data; }
Chunk *left() const { return m_surroundingChunks[0]; }
Chunk *right() const { return m_surroundingChunks[1]; }
Chunk *front() const { return m_surroundingChunks[2]; }
Chunk *back() const { return m_surroundingChunks[3]; }
Chunk *getSurroundingChunk(u8 i) { return (i > 3) ? nullptr : m_surroundingChunks[i]; }
static const u8 width = 16;
static const u8 height = 32;

View File

@ -19,6 +19,8 @@
#include "Chunk.hpp"
#include "TerrainGenerator.hpp"
class Camera;
class World {
public:
World();
@ -27,9 +29,20 @@ class World {
Chunk *getChunk(s32 x, s32 z);
void addSelectedBlock() { if(!selectedChunk || !selectedBlock) return; selectedChunk->setBlock(selectedBlock->pos(), 1); selectedChunk->update(); }
void removeSelectedBlock() { if(!selectedChunk || !selectedBlock) return; selectedChunk->setBlock(selectedBlock->pos(), 0); selectedChunk->update(); }
bool intersectionLinePlane(const glm::vec3 &normal, const glm::vec3 &planePoint, const glm::vec3 &lineOrigPoint, const glm::vec3 &directionVector, float *distance);
bool intersectionLineCube(int cubeX, int cubeY, int cubeZ, const glm::vec3 &lineOrigPoint, const glm::vec3 &directionVector, float *distance, s8 *face);
void testCubes(Camera &camera);
// Render distance in chunks
static const u16 renderDistance = 8;
// FIXME: MOVE THIS QUICKLY
static Block *selectedBlock;
static Chunk *selectedChunk;
private:
s32 m_width;
s32 m_depth;

View File

@ -35,14 +35,14 @@ int main(int, char *[]) {
std::cerr << "Fatal error " << e.what() << std::endl;
return 1;
}
catch(const std::exception &e) {
std::cerr << "Exception caught: " << e.what() << std::endl;
return 1;
}
catch(...) {
std::cerr << "Fatal error: Unknown error." << std::endl;
return 1;
}
// catch(const std::exception &e) {
// std::cerr << "Exception caught: " << e.what() << std::endl;
// return 1;
// }
// catch(...) {
// std::cerr << "Fatal error: Unknown error." << std::endl;
// return 1;
// }
return 0;
}

View File

@ -14,7 +14,10 @@
#define GLM_FORCE_RADIANS
#include <glm/gtc/matrix_transform.hpp>
#include "OpenGL.hpp"
#include "Config.hpp"
#include "Mouse.hpp"
#include "GameState.hpp"
GameState::GameState() : m_camera(Camera::getInstance()) {
@ -30,7 +33,8 @@ GameState::GameState() : m_camera(Camera::getInstance()) {
Shader::bind(&m_shader);
m_projectionMatrix = glm::perspective(45.0f, (float)SCREEN_WIDTH / SCREEN_HEIGHT, 0.1f, 1000.0f);
// m_projectionMatrix = glm::perspective(45.0f, (float)SCREEN_WIDTH / SCREEN_HEIGHT, DIST_NEAR, DIST_FAR);
m_projectionMatrix = glm::perspective(45.0f, (float)SCREEN_WIDTH / SCREEN_HEIGHT, DIST_NEAR, DIST_FAR);
m_viewMatrix = m_camera.update();
m_shader.setUniform("u_projectionMatrix", m_projectionMatrix);
@ -42,6 +46,12 @@ GameState::GameState() : m_camera(Camera::getInstance()) {
void GameState::update() {
m_viewMatrix = m_camera.processInputs();
// glm::vec3 start = glm::unProject(glm::vec3(Mouse::getX(), Mouse::getY(), 0.0), m_viewMatrix, m_projectionMatrix, glm::ivec4(0.0, 0.0, SCREEN_WIDTH, SCREEN_HEIGHT));
// glm::vec3 end = glm::unProject(glm::vec3(Mouse::getX(), Mouse::getY(), 1.0), m_viewMatrix, m_projectionMatrix, glm::ivec4(0.0, 0.0, SCREEN_WIDTH, SCREEN_HEIGHT));
m_world.testCubes(m_camera);
// m_world.removeSelectedBlock();
}
void GameState::draw() {

View File

@ -5,19 +5,15 @@
*
* Description:
*
* Version: 1.0
* Created: 29/12/2014 04:56:17
* Revision: none
* Compiler: gcc
*
* Author: Quentin BAZIN, <quent42340@gmail.com>
* Company:
* Author: Quentin Bazin, <quent42340@gmail.com>
*
* =====================================================================================
*/
#include "Block.hpp"
Block::Block(u32 id) {
Block::Block(const glm::vec3 &pos, u32 id) : m_pos(pos) {
m_id = id;
}
@ -31,6 +27,6 @@ glm::vec4 Block::getTexCoords() {
return glm::vec4(textureX,
textureY,
textureX + 16.0f / textureWidth,
textureY + 16.0f / textureHeight);
textureY + 16.0f / textureHeight);
}

View File

@ -211,6 +211,61 @@ void Chunk::update() {
VertexBuffer::bind(nullptr);
}
class Ray {
public:
Ray(const glm::vec3 &orig, const glm::vec3 &dir) : orig(orig), dir(dir)
{
invdir.x = 1 / dir.x;
invdir.y = 1 / dir.y;
invdir.z = 1 / dir.z;
sign[0] = (invdir.x < 0);
sign[1] = (invdir.y < 0);
sign[2] = (invdir.z < 0);
}
glm::vec3 orig, dir; // ray orig and dir
glm::vec3 invdir;
int sign[3];
};
class AxisAlignedBB {
public:
AxisAlignedBB(const glm::vec3 &vmin, const glm::vec3 &vmax)
{
bounds[0] = vmin;
bounds[1] = vmax;
}
glm::vec3 bounds[2];
bool intersect(const Ray &r) const
{
float tmin, tmax, tymin, tymax, tzmin, tzmax;
tmin = (bounds[r.sign[0]].x - r.orig.x) * r.invdir.x;
tmax = (bounds[1-r.sign[0]].x - r.orig.x) * r.invdir.x;
tymin = (bounds[r.sign[1]].y - r.orig.y) * r.invdir.y;
tymax = (bounds[1-r.sign[1]].y - r.orig.y) * r.invdir.y;
if ((tmin > tymax) || (tymin > tmax))
return false;
if (tymin > tmin)
tmin = tymin;
if (tymax < tmax)
tmax = tymax;
tzmin = (bounds[r.sign[2]].z - r.orig.z) * r.invdir.z;
tzmax = (bounds[1-r.sign[2]].z - r.orig.z) * r.invdir.z;
if ((tmin > tzmax) || (tzmin > tmax))
return false;
if (tzmin > tmin)
tmin = tzmin;
if (tzmax < tmax)
tmax = tzmax;
return true;
}
};
void Chunk::draw(Shader &shader) {
if(m_isChanged) update();
@ -243,8 +298,17 @@ void Chunk::draw(Shader &shader) {
VertexBuffer::bind(nullptr);
}
void Chunk::addBlock(u32 id) {
m_data.push_back(std::unique_ptr<Block>(new Block(id)));
void Chunk::addBlock(const glm::vec3 &pos, u32 id) {
m_data.push_back(std::unique_ptr<Block>(new Block(pos, id)));
}
void Chunk::setBlock(const glm::vec3 &pos, u32 id) {
glm::vec3 localPos = pos;
localPos.x -= m_x * width;
localPos.y -= m_y * height;
localPos.z -= m_z * depth;
m_data.at(localPos.y + localPos.x * height + localPos.z * height * width).reset(new Block(pos, id));
}
Block *Chunk::getBlock(s8 x, s8 y, s8 z) {

View File

@ -14,8 +14,13 @@
#define GLM_FORCE_RADIANS
#include <glm/gtc/matrix_transform.hpp>
#include "Camera.hpp"
#include "Config.hpp"
#include "World.hpp"
Block *World::selectedBlock = nullptr;
Chunk *World::selectedChunk = nullptr;
World::World() {
m_width = 100;
m_depth = 100;
@ -113,3 +118,145 @@ Chunk *World::getChunk(s32 x, s32 z) {
return m_chunks.at(x + z * m_width).get();
}
// FIXME: Move to a math module
bool World::intersectionLinePlane(const glm::vec3 &normal, const glm::vec3 &planePoint, const glm::vec3 &lineOrigPoint, const glm::vec3 &directionVector, float *distance) {
float p1 = directionVector.x * normal.x + directionVector.y * normal.y + directionVector.z * normal.z; // First point to be tested
if(p1 == 0) return false; // Degenerate case
glm::vec3 u = glm::vec3(planePoint.x - lineOrigPoint.x,
planePoint.y - lineOrigPoint.y,
planePoint.z - lineOrigPoint.z);
float p2 = u.x * normal.x + u.y * normal.y + u.z * normal.z; // Second point to be tested
float k = p2 / p1;
if((k < 0) || (k > 5)) return false;
// Intersection point
glm::vec3 i = glm::vec3(lineOrigPoint.x + k * directionVector.x,
lineOrigPoint.y + k * directionVector.y,
lineOrigPoint.z + k * directionVector.z);
glm::vec3 v = glm::vec3(i.x - planePoint.x,
i.y - planePoint.y,
i.z - planePoint.z);
float size = 0.5;
if(v.x >= -size && v.x <= size && v.y >= -size && v.y <= size && v.z >= -size && v.z <= size) {
if(distance != nullptr) *distance = k;
return true;
} else {
return false;
}
}
// Front right = 0 | Front left = 1
// Back right = 2 | Back left = 3
// Top = 4 | Bottom = 5
// FIXME: Move to a math module
bool World::intersectionLineCube(int cubeX, int cubeY, int cubeZ, const glm::vec3 &lineOrigPoint, const glm::vec3 &directionVector, float *distance, s8 *face) {
glm::vec3 planePoint[6] = {
glm::vec3(cubeX + 0.5, cubeY + 1, cubeZ + 0.5), // back
glm::vec3(cubeX + 1, cubeY + 0.5, cubeZ + 0.5), // right
glm::vec3(cubeX, cubeY + 0.5, cubeZ + 0.5), // left
glm::vec3(cubeX + 0.5, cubeY, cubeZ + 0.5), // front
glm::vec3(cubeX + 0.5, cubeY + 0.5, cubeZ + 1), // top
glm::vec3(cubeX + 0.5, cubeY + 0.5, cubeZ) // bottom
};
glm::vec3 normal[6] = {
glm::vec3(0, 1, 0), // back
glm::vec3(1, 0, 0), // right
glm::vec3(-1, 0, 0), // left
glm::vec3(0, -1, 0), // front
glm::vec3(0, 0, 1), // top
glm::vec3(0, 0, -1) // bottom
};
float shortestDistance = DIST_FAR;
float dist = DIST_FAR + 1.0;
int nearestFace = -1;
for (int i = 0; i < 6; i++) {
bool result = intersectionLinePlane(normal[i], planePoint[i], lineOrigPoint, directionVector, &dist);
if (result && (dist < shortestDistance)) {
shortestDistance = dist;
nearestFace = i;
}
}
if (nearestFace < 0) {
return false;
} else {
if (distance != nullptr) *distance = shortestDistance;
if (face != nullptr) *face = nearestFace;
return true;
}
}
#include <unordered_map>
#include <unistd.h>
// FIXME: MOVE THIS FUNCTION
void World::testCubes(Camera &camera) {
glm::vec3 linePoint = glm::vec3(camera.x(),
camera.y(),
camera.z());
glm::vec3 directionVector = glm::vec3(camera.pointTargetedX() - camera.x(),
camera.pointTargetedY() - camera.y(),
camera.pointTargetedZ() - camera.z());
Chunk *currentChunk = getChunk(camera.x() / Chunk::width, camera.z() / Chunk::depth);
float distance = DIST_FAR;
Block *block = nullptr;
int face = -1;
Chunk *chunk = nullptr;
const std::vector<std::unique_ptr<Block>> *blocks = nullptr;
for(unsigned short i = 0 ; i < 9 ; i++) {
if(i == 8) blocks = &currentChunk->data();
else if(i < 8) {
if(currentChunk->getSurroundingChunk(i) == nullptr) continue;
blocks = &currentChunk->getSurroundingChunk(i)->data();
}
for(auto &it : *blocks) {
if(it->pos().z < linePoint.z - 10 || it->pos().z > linePoint.z + 10) continue;
if(it->pos().y < linePoint.y - 10 || it->pos().y > linePoint.y + 10) continue;
if(it->pos().x < linePoint.x - 10 || it->pos().x > linePoint.x + 10) continue;
// it->setSelected(false, -1);
float d = -1;
s8 f = -1;
bool result = intersectionLineCube(it->pos().x, it->pos().y, it->pos().z, linePoint, directionVector, &d, &f);
if(result && (d < distance) && (d < 5)) {
distance = d;
block = it.get();
face = f;
if(i == 8) chunk = currentChunk;
else if(i < 8) chunk = currentChunk->getSurroundingChunk(i);
write(1, result ? "y" : "n", 1);
}
}
}
if(block != nullptr) {
selectedBlock = block;
// block->setSelected(true, face);
} else {
// selectedCube->setSelected(false, -1);
}
if(chunk != nullptr) {
selectedChunk = chunk;
} else {
selectedChunk = nullptr;
}
}

View File

@ -26,9 +26,9 @@ void TerrainGenerator::generate(Chunk &chunk) {
for(u8 y = 0 ; y < Chunk::height ; y++) {
if(y + chunk.y() * Chunk::height < h) {
chunk.addBlock(1);
chunk.addBlock(glm::vec3{x + chunk.x() * Chunk::width, y + chunk.y() * Chunk::height, z + chunk.z() * Chunk::depth}, 1);
} else {
chunk.addBlock(0);
chunk.addBlock(glm::vec3{x + chunk.x() * Chunk::width, y + chunk.y() * Chunk::height, z + chunk.z() * Chunk::depth}, 0);
}
}
}