Browse Source

kd tree building, line rendering

Kajetan Johannes Hammerle 3 years ago
parent
commit
70595d44b3

+ 12 - 0
client/Game.cpp

@@ -32,6 +32,11 @@ pointIndex(0), moveSpeed(0.125f), movedLength(0.0f), mode(Mode::AUTO) {
         cameraPoints.add({v, q, 0.0f});
     }
     updateDistances();
+
+    lines.add(Vector3(0, 0, 0), Vector3(0, 0, 50));
+    lines.add(Vector3(0, 0, 0), Vector3(0, 50, 0));
+    lines.add(Vector3(0, 0, 50), Vector3(0, 50, 0));
+    lines.build();
 }
 
 void Game::tick() {
@@ -159,6 +164,13 @@ void Game::renderWorld(float lag, Renderer& renderer) const {
     worldRenderer.render(lag, renderer);
 }
 
+void Game::renderWorldLines(float lag, Renderer& renderer) const {
+    (void) lag;
+    renderer.translateTo(0.0f, 0.0f, 0.0f);
+    renderer.update();
+    lines.draw();
+}
+
 void Game::renderTextOverlay(float lag, Renderer& renderer, FontRenderer& fr) const {
     (void) lag;
     renderer.scale(2.0f).update();

+ 5 - 0
client/Game.h

@@ -11,6 +11,8 @@
 #include "common/world/World.h"
 #include "common/block/BlockRegistry.h"
 #include "rendering/renderer/WorldRenderer.h"
+#include "common/utils/KDTree.h"
+#include "client/rendering/Lines.h"
 
 class Game final {
 public:
@@ -18,6 +20,7 @@ public:
 
     void tick();
     void renderWorld(float lag, Renderer& renderer) const;
+    void renderWorldLines(float lag, Renderer& renderer) const;
     void renderTextOverlay(float lag, Renderer& renderer, FontRenderer& fr) const;
 
     bool isRunning() const;
@@ -61,6 +64,8 @@ private:
     };
     
     Mode mode;
+    KDTree kdTree;
+    Lines lines;
 };
 
 #endif

+ 9 - 1
client/rendering/Engine.cpp

@@ -8,7 +8,7 @@
 #include "client/math/Plane.h"
 
 Engine::Engine(Shaders& shaders, Framebuffers& fb, const WindowSize& size, RenderSettings& renderSettings) :
-shaders(shaders), framebuffers(fb), size(size), renderSettings(renderSettings), frustum(60.0f, 0.1f, 80.0f) {
+shaders(shaders), framebuffers(fb), size(size), renderSettings(renderSettings), frustum(60.0f, 0.1f, 1000.0f) {
     rectangle.add(Triangle(
             Vertex(Vector3(-1, -1, 0), Vector2(0, 0)),
             Vertex(Vector3(1, 1, 0), Vector2(1, 1)),
@@ -70,6 +70,14 @@ void Engine::renderWorld(float lag, const Game& game) {
     shaders.world.setFloat("zbias", renderSettings.testBias);
     Renderer renderer(shaders.world, model, worldView);
     game.renderWorld(lag, renderer);
+
+    shaders.worldLines.use();
+    shaders.worldLines.setMatrix("proj", worldProj.getValues());
+    shaders.worldLines.setMatrix("view", worldView.getValues());
+    model.clear();
+    shaders.worldLines.setMatrix("model", model.get().getValues());
+    Renderer lineRenderer(shaders.worldLines, model, worldView);
+    game.renderWorldLines(lag, lineRenderer);
 }
 
 void Engine::renderSSAO() {

+ 25 - 0
client/rendering/Lines.cpp

@@ -0,0 +1,25 @@
+#include "client/rendering/Lines.h"
+
+Lines::Lines() {
+    vertexBuffer.bind();
+    vertexBuffer.setFloatAttribute(0, 3, 0, 3);
+}
+
+void Lines::add(const Vector3& a, const Vector3& b) {
+    buffer.add(a);
+    buffer.add(b);
+}
+
+void Lines::clear() {
+    buffer.clear();
+}
+
+void Lines::build() {
+    vertexBuffer.bindBuffer();
+    vertexBuffer.setData(sizeof (Vector3) * buffer.getLength(), buffer.getData());
+}
+
+void Lines::draw() const {
+    vertexBuffer.bindArray();
+    vertexBuffer.drawLines(buffer.getLength());
+}

+ 23 - 0
client/rendering/Lines.h

@@ -0,0 +1,23 @@
+#ifndef LINES_H
+#define LINES_H
+
+#include "client/rendering/wrapper/VertexBuffer.h"
+#include "common/utils/List.h"
+#include "client/rendering/Triangle.h"
+
+class Lines final {
+public:
+    Lines();
+
+    void add(const Vector3& a, const Vector3& b);
+
+    void clear();
+    void build();
+    void draw() const;
+
+private:
+    VertexBuffer vertexBuffer;
+    List<Vector3, 20000> buffer;
+};
+
+#endif

+ 2 - 1
client/rendering/Shaders.cpp

@@ -2,6 +2,7 @@
 
 Shaders::Shaders() :
 world("resources/shader/worldVertex.vs", "resources/shader/worldFragment.fs"),
+worldLines("resources/shader/lineVertex.vs", "resources/shader/lineFragment.fs"),
 ssao("resources/shader/ssaoVertex.vs", "resources/shader/ssaoFragment.fs"),
 ssaoBlur("resources/shader/ssaoBlurVertex.vs", "resources/shader/ssaoBlurFragment.fs"),
 shadow("resources/shader/worldShadowVertex.vs", "resources/shader/worldShadowFragment.fs"),
@@ -11,6 +12,6 @@ antialias("resources/shader/antialiasVertex.vs", "resources/shader/antialiasFrag
 }
 
 bool Shaders::hasError() const {
-    return world.hasError() || ssao.hasError() || ssaoBlur.hasError() || shadow.hasError() || postWorld.hasError() ||
+    return world.hasError() || worldLines.hasError() || ssao.hasError() || ssaoBlur.hasError() || shadow.hasError() || postWorld.hasError() ||
             text.hasError() || antialias.hasError();
 }

+ 1 - 0
client/rendering/Shaders.h

@@ -8,6 +8,7 @@ struct Shaders final {
     bool hasError() const;
 
     Shader world;
+    Shader worldLines;
     Shader ssao;
     Shader ssaoBlur;
     Shader shadow;

+ 4 - 0
client/rendering/wrapper/VertexBuffer.cpp

@@ -35,3 +35,7 @@ void VertexBuffer::bind() const {
 void VertexBuffer::draw(uint vertices) const {
     glDrawArrays(GL_TRIANGLES, 0, vertices);
 }
+
+void VertexBuffer::drawLines(uint vertices) const {
+    glDrawArrays(GL_LINES, 0, vertices);
+}

+ 1 - 0
client/rendering/wrapper/VertexBuffer.h

@@ -22,6 +22,7 @@ public:
     void bind() const;
     
     void draw(uint vertices) const;
+    void drawLines(uint vertices) const;
 
 private:
     GLuint vertexArray;

+ 125 - 2
common/utils/KDTree.cpp

@@ -1,4 +1,127 @@
-#include "KDTree.h"
+#include <algorithm>
+
+#include "common/utils/KDTree.h"
+
+KDTree::Triangle::Triangle(const Vector3& a, const Vector3& b, const Vector3& c) {
+    v[0] = a;
+    v[1] = b;
+    v[2] = c;
+    mid = (a + b + c) * (1.0f / 3.0f);
+}
+
+const Array<Vector3, 3>& KDTree::Triangle::data() const {
+    return v;
+}
+
+const Vector3& KDTree::Triangle::operator[](int index) const {
+    return v[index];
+}
+
+const Vector3& KDTree::Triangle::getMid() const {
+    return mid;
+}
+
+KDTree::Node::Node() : splitDim(0), splitValue(0.0f), lessEqual(nullptr), greater(nullptr) {
+}
 
 KDTree::KDTree() {
-}
+}
+
+KDTree::~KDTree() {
+    clean(&root);
+}
+
+void KDTree::clean(Node* n) {
+    if(n->lessEqual != nullptr) {
+        clean(n->lessEqual);
+    }
+    if(n->greater != nullptr) {
+        clean(n->greater);
+    }
+    delete n->lessEqual;
+    delete n->greater;
+}
+
+void KDTree::build(std::vector<KDTree::Triangle>& data) {
+    build(&root, data);
+}
+
+float KDTree::median(std::vector<KDTree::Triangle>& data, int dim) const {
+    auto compare = [dim](const Triangle& a, const Triangle & b) {
+        return a.getMid()[dim] < b.getMid()[dim];
+    };
+    size_t length = data.size();
+    if((length & 1) == 0) {
+        std::nth_element(data.begin(), data.begin() + (length / 2 - 1), data.end(), compare);
+        float tmp = data[length / 2 - 1].getMid()[dim];
+        std::nth_element(data.begin(), data.begin() + (length / 2), data.end(), compare);
+        return (tmp + data[length / 2].getMid()[dim]) / 2;
+    }
+    std::nth_element(data.begin(), data.begin() + (length / 2), data.end(), compare);
+    return data[length / 2].getMid()[dim];
+}
+
+void KDTree::build(Node* n, std::vector<KDTree::Triangle>& data) {
+    if(data.size() == 0) {
+        return;
+    } else if(data.size() == 1) {
+        n->data.push_back(data[0]);
+        return;
+    }
+    // find min and max coordinates
+    Vector3 min = data[0][0];
+    Vector3 max = data[0][0];
+    for(const Triangle& t : data) {
+        for(const Vector3& v : t.data()) {
+            min.set(std::min(min[0], v[0]), std::min(min[1], v[1]), std::min(min[2], v[2]));
+            max.set(std::max(max[0], v[0]), std::max(max[1], v[1]), std::max(max[2], v[2]));
+        }
+    }
+    // find biggest span and its dimension
+    int splitDim = 0;
+    float maxSpan = max[0] - min[0];
+    for(int i = 1; i < 3; i++) {
+        float span = max[i] - min[i];
+        if(span > maxSpan) {
+            splitDim = i;
+            maxSpan = span;
+        }
+    }
+    // assign data to node
+    n->splitDim = splitDim;
+    n->splitValue = median(data, splitDim);
+    // storage for split data
+    std::vector<KDTree::Triangle> lessEqualData;
+    std::vector<KDTree::Triangle> greaterData;
+    // actually split the data
+    for(const Triangle& t : data) {
+        // count points on each split side
+        int lessEqualCounter = 0;
+        int greaterCount = 0;
+        for(const Vector3& v : t.data()) {
+            if(v[n->splitDim] <= n->splitValue) {
+                lessEqualCounter++;
+            } else {
+                greaterCount++;
+            }
+        }
+        // put the data in the correct container
+        if(lessEqualCounter == 3) {
+            lessEqualData.push_back(t);
+        } else if(greaterCount == 3) {
+            greaterData.push_back(t);
+        } else {
+            n->data.push_back(t);
+        }
+    }
+    // recursive calls
+    if(lessEqualData.size() > 0) {
+        n->lessEqual = new Node();
+        build(n->lessEqual, lessEqualData);
+    }
+    if(greaterData.size() > 0) {
+        n->greater = new Node();
+        build(n->greater, greaterData);
+    }
+}
+

+ 38 - 1
common/utils/KDTree.h

@@ -1,11 +1,48 @@
 #ifndef KDTREE_H
 #define KDTREE_H
 
+#include <vector>
+#include "common/utils/Array.h"
 #include "common/math/Vector.h"
 
-class KDTree final {
+struct KDTree final {
+
+    class Triangle {
+        Array<Vector3, 3> v;
+        Vector3 mid;
+    public:
+        Triangle(const Vector3& a, const Vector3& b, const Vector3& c);
+        const Array<Vector3, 3>& data() const;
+        const Vector3& operator[](int index) const;
+        const Vector3& getMid() const;
+    };
+
+private:
+
+    struct Node {
+        std::vector<Triangle> data;
+        int splitDim;
+        float splitValue;
+        Node* lessEqual;
+        Node* greater;
+        Node();
+    };
+
+    Node root;
+
 public:
     KDTree();
+    ~KDTree();
+    KDTree(const KDTree& other) = delete;
+    KDTree(KDTree&& other) = delete;
+    KDTree& operator=(const KDTree& other) = delete;
+    KDTree& operator=(KDTree&& other) = delete;
+
+    void build(std::vector<KDTree::Triangle>& data);
+private:
+    void clean(Node* n);
+    float median(std::vector<KDTree::Triangle>& data, int dim) const;
+    void build(Node* n, std::vector<KDTree::Triangle>& data);
 };
 
 #endif

+ 2 - 2
meson.build

@@ -2,11 +2,11 @@ project('cubes plus plus', 'cpp')
 
 # 'common/world/Chunk.cpp', 'common/world/World.cpp', 'common/utils/Face.cpp'
 
-sourcesCommon = ['common/network/Packet.cpp', 'common/block/BlockBuilder.cpp', 'common/block/Block.cpp', 'common/block/BlockRegistry.cpp', 'common/utils/HashedString.cpp', 'common/utils/String.cpp', 'common/utils/SplitString.cpp', 'common/utils/Random.cpp', 'common/world/World.cpp', 'common/math/Vector.cpp']
+sourcesCommon = ['common/network/Packet.cpp', 'common/block/BlockBuilder.cpp', 'common/block/Block.cpp', 'common/block/BlockRegistry.cpp', 'common/utils/HashedString.cpp', 'common/utils/String.cpp', 'common/utils/SplitString.cpp', 'common/utils/Random.cpp', 'common/world/World.cpp', 'common/math/Vector.cpp', 'common/utils/KDTree.cpp']
 
 sourcesServer = ['server/Main.cpp', 'server/network/Server.cpp', 'server/network/Client.cpp', 'server/GameServer.cpp', 'server/commands/ServerCommands.cpp', 'server/commands/CommandManager.cpp', 'server/commands/ConsoleEditor.cpp', 'server/Clock.cpp']
 
-sourcesClient = ['client/Main.cpp', 'client/rendering/WindowSize.cpp', 'client/math/Frustum.cpp', 'client/rendering/Framebuffers.cpp', 'client/rendering/wrapper/GLFWWrapper.cpp', 'client/rendering/wrapper/Window.cpp', 'client/rendering/Engine.cpp', 'client/input/Keys.cpp', 'client/rendering/wrapper/Shader.cpp', 'client/rendering/Shaders.cpp', 'client/utils/Utils.cpp', 'client/rendering/Mesh.cpp', 'client/math/Matrix.cpp', 'client/math/MatrixStack.cpp', 'client/math/Quaternion.cpp', 'client/math/Plane.cpp', 'client/Game.cpp', 'client/input/MouseButtons.cpp', 'client/rendering/FileTexture.cpp', 'client/rendering/FontRenderer.cpp', 'client/rendering/wrapper/Framebuffer.cpp', 'client/rendering/NoiseTexture.cpp', 'client/utils/Clock.cpp', 'client/input/Control.cpp', 'client/rendering/RenderSettings.cpp', 'client/rendering/wrapper/VertexBuffer.cpp', 'client/rendering/wrapper/StreamBuffer.cpp', 'client/rendering/wrapper/Texture.cpp', 'client/utils/PNGReader.cpp', 'client/rendering/wrapper/GLWrapper.cpp', 'client/rendering/Renderer.cpp', 'client/rendering/renderer/WorldRenderer.cpp', 'client/rendering/NormalTexture.cpp', 'client/rendering/Vertex.cpp', 'client/rendering/Triangle.cpp']
+sourcesClient = ['client/Main.cpp', 'client/rendering/WindowSize.cpp', 'client/math/Frustum.cpp', 'client/rendering/Framebuffers.cpp', 'client/rendering/wrapper/GLFWWrapper.cpp', 'client/rendering/wrapper/Window.cpp', 'client/rendering/Engine.cpp', 'client/input/Keys.cpp', 'client/rendering/wrapper/Shader.cpp', 'client/rendering/Shaders.cpp', 'client/utils/Utils.cpp', 'client/rendering/Mesh.cpp', 'client/math/Matrix.cpp', 'client/math/MatrixStack.cpp', 'client/math/Quaternion.cpp', 'client/math/Plane.cpp', 'client/Game.cpp', 'client/input/MouseButtons.cpp', 'client/rendering/FileTexture.cpp', 'client/rendering/FontRenderer.cpp', 'client/rendering/wrapper/Framebuffer.cpp', 'client/rendering/NoiseTexture.cpp', 'client/utils/Clock.cpp', 'client/input/Control.cpp', 'client/rendering/RenderSettings.cpp', 'client/rendering/wrapper/VertexBuffer.cpp', 'client/rendering/wrapper/StreamBuffer.cpp', 'client/rendering/wrapper/Texture.cpp', 'client/utils/PNGReader.cpp', 'client/rendering/wrapper/GLWrapper.cpp', 'client/rendering/Renderer.cpp', 'client/rendering/renderer/WorldRenderer.cpp', 'client/rendering/NormalTexture.cpp', 'client/rendering/Vertex.cpp', 'client/rendering/Triangle.cpp', 'client/rendering/Lines.cpp']
 
 sourcesTest = ['tests/Main.cpp', 'common/utils/String.cpp', 'common/utils/SplitString.cpp', 'common/utils/HashedString.cpp', 'common/utils/Random.cpp']
 

+ 15 - 0
resources/shader/lineFragment.fs

@@ -0,0 +1,15 @@
+#version 430
+
+layout (location = 0) out vec3 worldPosition;
+layout (location = 1) out vec3 worldNormal;
+layout (location = 2) out vec4 worldColor;
+layout (location = 3) out float worldShadow;
+
+in vec3 varPosition;
+
+void main(void) {
+    worldPosition = varPosition;
+    worldNormal = vec3(0.0, 0.0, 1.0);
+    worldColor = vec4(1.0, 1.0, 1.0, 1.0);
+    worldShadow = 1.0;
+}

+ 15 - 0
resources/shader/lineVertex.vs

@@ -0,0 +1,15 @@
+#version 430
+
+layout (location = 0) in vec3 position;
+
+uniform mat4 proj;
+uniform mat4 view;
+uniform mat4 model;
+
+out vec3 varPosition;
+
+void main(void) { 
+    vec4 worldPos = view * model * vec4(position, 1.0);
+    varPosition = worldPos.xyz;
+    gl_Position = proj * worldPos;
+}