From 7b592a9506e9978c72e46214aaf66b8d2898bef0 Mon Sep 17 00:00:00 2001
From: Tobias Frisch <tfrisch@uni-koblenz.de>
Date: Tue, 6 Jul 2021 14:56:05 +0200
Subject: [PATCH] [#56] Fixed graph dependency error and added basic graph
 optimization

Signed-off-by: Tobias Frisch <tfrisch@uni-koblenz.de>
---
 .../include/vkcv/material/Material.hpp        |   2 +
 .../material/src/vkcv/material/Material.cpp   |   4 +
 modules/scene/include/vkcv/scene/Mesh.hpp     |   8 +-
 modules/scene/include/vkcv/scene/MeshPart.hpp |   8 +-
 modules/scene/include/vkcv/scene/Node.hpp     |  19 +-
 modules/scene/include/vkcv/scene/Scene.hpp    |  16 +-
 modules/scene/src/vkcv/scene/Mesh.cpp         |  32 ++--
 modules/scene/src/vkcv/scene/MeshPart.cpp     | 171 ++----------------
 modules/scene/src/vkcv/scene/Node.cpp         | 134 +++++++++++---
 modules/scene/src/vkcv/scene/Scene.cpp        | 163 ++++++++++++++++-
 10 files changed, 334 insertions(+), 223 deletions(-)

diff --git a/modules/material/include/vkcv/material/Material.hpp b/modules/material/include/vkcv/material/Material.hpp
index a3b97823..9b54d998 100644
--- a/modules/material/include/vkcv/material/Material.hpp
+++ b/modules/material/include/vkcv/material/Material.hpp
@@ -41,6 +41,8 @@ namespace vkcv::material {
 		[[nodiscard]]
 		const DescriptorSetHandle& getDescriptorSet() const;
 		
+		explicit operator bool() const;
+		
 		bool operator!() const;
 		
 		static const std::vector<DescriptorBinding>& getDescriptorBindings(MaterialType type);
diff --git a/modules/material/src/vkcv/material/Material.cpp b/modules/material/src/vkcv/material/Material.cpp
index aaf2e130..409db0b9 100644
--- a/modules/material/src/vkcv/material/Material.cpp
+++ b/modules/material/src/vkcv/material/Material.cpp
@@ -15,6 +15,10 @@ namespace vkcv::material {
 		return m_DescriptorSet;
 	}
 	
+	Material::operator bool() const {
+		return (m_Type != MaterialType::UNKNOWN);
+	}
+	
 	bool Material::operator!() const {
 		return (m_Type == MaterialType::UNKNOWN);
 	}
diff --git a/modules/scene/include/vkcv/scene/Mesh.hpp b/modules/scene/include/vkcv/scene/Mesh.hpp
index 2d0a6bec..899e5e0c 100644
--- a/modules/scene/include/vkcv/scene/Mesh.hpp
+++ b/modules/scene/include/vkcv/scene/Mesh.hpp
@@ -14,13 +14,13 @@ namespace vkcv::scene {
 		friend class Node;
 		
 	private:
-		Scene* m_scene;
+		Scene& m_scene;
 		std::vector<MeshPart> m_parts;
 		std::vector<DrawcallInfo> m_drawcalls;
 		glm::mat4 m_transform;
 		Bounds m_bounds;
 		
-		explicit Mesh(Scene* scene);
+		explicit Mesh(Scene& scene);
 		
 		void load(const asset::Scene& scene,
 				  const asset::Mesh& mesh);
@@ -35,8 +35,8 @@ namespace vkcv::scene {
 	public:
 		~Mesh();
 		
-		Mesh(const Mesh& other);
-		Mesh(Mesh&& other) noexcept;
+		Mesh(const Mesh& other) = default;
+		Mesh(Mesh&& other) = default;
 		
 		Mesh& operator=(const Mesh& other);
 		Mesh& operator=(Mesh&& other) noexcept;
diff --git a/modules/scene/include/vkcv/scene/MeshPart.hpp b/modules/scene/include/vkcv/scene/MeshPart.hpp
index 4b64d1d0..027c6f20 100644
--- a/modules/scene/include/vkcv/scene/MeshPart.hpp
+++ b/modules/scene/include/vkcv/scene/MeshPart.hpp
@@ -17,7 +17,7 @@ namespace vkcv::scene {
 		friend class Mesh;
 	
 	private:
-		Scene* m_scene;
+		Scene& m_scene;
 		BufferHandle m_vertices;
 		std::vector<VertexBufferBinding> m_vertexBindings;
 		BufferHandle m_indices;
@@ -25,7 +25,7 @@ namespace vkcv::scene {
 		Bounds m_bounds;
 		size_t m_materialIndex;
 		
-		explicit MeshPart(Scene* scene);
+		explicit MeshPart(Scene& scene);
 		
 		void load(const asset::Scene& scene,
 				  const asset::VertexGroup& vertexGroup,
@@ -34,8 +34,8 @@ namespace vkcv::scene {
 	public:
 		~MeshPart();
 		
-		MeshPart(const MeshPart& other);
-		MeshPart(MeshPart&& other) noexcept;
+		MeshPart(const MeshPart& other) = default;
+		MeshPart(MeshPart&& other) = default;
 		
 		MeshPart& operator=(const MeshPart& other);
 		MeshPart& operator=(MeshPart&& other) noexcept;
diff --git a/modules/scene/include/vkcv/scene/Node.hpp b/modules/scene/include/vkcv/scene/Node.hpp
index 0323fa31..0772172d 100644
--- a/modules/scene/include/vkcv/scene/Node.hpp
+++ b/modules/scene/include/vkcv/scene/Node.hpp
@@ -15,13 +15,15 @@ namespace vkcv::scene {
 		friend class Scene;
 		
 	private:
-		Scene* m_scene;
+		Scene& m_scene;
 		
 		std::vector<Mesh> m_meshes;
 		std::vector<Node> m_nodes;
 		Bounds m_bounds;
 		
-		explicit Node(Scene* scene);
+		explicit Node(Scene& scene);
+		
+		void addMesh(const Mesh& mesh);
 		
 		void loadMesh(const asset::Scene& asset_scene, const asset::Mesh& asset_mesh);
 		
@@ -29,16 +31,23 @@ namespace vkcv::scene {
 							 std::vector<glm::mat4>& matrices,
 							 std::vector<DrawcallInfo>& drawcalls);
 		
+		void splitMeshesToSubNodes(size_t maxMeshesPerNode);
+		
 		[[nodiscard]]
 		size_t getDrawcallCount() const;
 		
-		Node& addNode();
+		size_t addNode();
+		
+		Node& getNode(size_t index);
+		
+		[[nodiscard]]
+		const Node& getNode(size_t index) const;
 	
 	public:
 		~Node();
 		
-		Node(const Node& other);
-		Node(Node&& other) noexcept;
+		Node(const Node& other) = default;
+		Node(Node&& other) = default;
 		
 		Node& operator=(const Node& other);
 		Node& operator=(Node&& other) noexcept;
diff --git a/modules/scene/include/vkcv/scene/Scene.hpp b/modules/scene/include/vkcv/scene/Scene.hpp
index eb14e99f..d9104ab4 100644
--- a/modules/scene/include/vkcv/scene/Scene.hpp
+++ b/modules/scene/include/vkcv/scene/Scene.hpp
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <filesystem>
+#include <mutex>
 
 #include <vkcv/Core.hpp>
 #include <vkcv/camera/Camera.hpp>
@@ -26,6 +27,19 @@ namespace vkcv::scene {
 		
 		explicit Scene(Core* core);
 		
+		size_t addNode();
+		
+		Node& getNode(size_t index);
+		
+		const Node& getNode(size_t index) const;
+		
+		void increaseMaterialUsage(size_t index);
+		
+		void decreaseMaterialUsage(size_t index);
+		
+		void loadMaterial(size_t index, const asset::Scene& scene,
+						  const asset::Material& material);
+		
 	public:
 		~Scene();
 		
@@ -35,8 +49,6 @@ namespace vkcv::scene {
 		Scene& operator=(const Scene& other);
 		Scene& operator=(Scene&& other) noexcept;
 		
-		Node& addNode();
-		
 		size_t getMaterialCount() const;
 		
 		[[nodiscard]]
diff --git a/modules/scene/src/vkcv/scene/Mesh.cpp b/modules/scene/src/vkcv/scene/Mesh.cpp
index 683e660c..ff93029e 100644
--- a/modules/scene/src/vkcv/scene/Mesh.cpp
+++ b/modules/scene/src/vkcv/scene/Mesh.cpp
@@ -5,7 +5,7 @@
 
 namespace vkcv::scene {
 	
-	Mesh::Mesh(Scene* scene) :
+	Mesh::Mesh(Scene& scene) :
 	m_scene(scene) {}
 	
 	static glm::mat4 arrayTo4x4Matrix(const std::array<float,16>& array){
@@ -56,27 +56,17 @@ namespace vkcv::scene {
 		m_parts.clear();
 	}
 	
-	Mesh::Mesh(const Mesh &other) :
-	m_scene(other.m_scene),
-	m_parts(other.m_parts),
-	m_drawcalls(other.m_drawcalls),
-	m_transform(other.m_transform),
-	m_bounds(other.m_bounds) {}
-	
-	Mesh::Mesh(Mesh &&other) noexcept :
-	m_scene(other.m_scene),
-	m_parts(other.m_parts),
-	m_drawcalls(other.m_drawcalls),
-	m_transform(other.m_transform),
-	m_bounds(other.m_bounds) {}
-	
 	Mesh &Mesh::operator=(const Mesh &other) {
 		if (&other == this) {
 			return *this;
 		}
 		
-		m_scene = other.m_scene;
-		m_parts = std::vector<MeshPart>(other.m_parts);
+		m_parts.resize(other.m_parts.size(), MeshPart(m_scene));
+		
+		for (size_t i = 0; i < m_parts.size(); i++) {
+			m_parts[i] = other.m_parts[i];
+		}
+		
 		m_drawcalls = std::vector<DrawcallInfo>(other.m_drawcalls);
 		m_transform = other.m_transform;
 		m_bounds = other.m_bounds;
@@ -85,8 +75,12 @@ namespace vkcv::scene {
 	}
 	
 	Mesh &Mesh::operator=(Mesh &&other) noexcept {
-		m_scene = other.m_scene;
-		m_parts = std::move(other.m_parts);
+		m_parts.resize(other.m_parts.size(), MeshPart(m_scene));
+		
+		for (size_t i = 0; i < m_parts.size(); i++) {
+			m_parts[i] = std::move(other.m_parts[i]);
+		}
+		
 		m_drawcalls = std::move(other.m_drawcalls);
 		m_transform = other.m_transform;
 		m_bounds = other.m_bounds;
diff --git a/modules/scene/src/vkcv/scene/MeshPart.cpp b/modules/scene/src/vkcv/scene/MeshPart.cpp
index acaa14e0..4bed429a 100644
--- a/modules/scene/src/vkcv/scene/MeshPart.cpp
+++ b/modules/scene/src/vkcv/scene/MeshPart.cpp
@@ -4,116 +4,19 @@
 
 namespace vkcv::scene {
 	
-	MeshPart::MeshPart(Scene* scene) :
-			m_scene(scene),
-			m_vertices(),
-			m_vertexBindings(),
-			m_indices(),
-			m_indexCount(0),
-			m_bounds(),
-			m_materialIndex(std::numeric_limits<size_t>::max()) {}
-	
-	static void loadImage(Core& core, const asset::Scene& asset_scene,
-				   const asset::Texture& asset_texture,
-				   const vk::Format& format,
-				   ImageHandle& image, SamplerHandle& sampler) {
-		asset::Sampler* asset_sampler = nullptr;
-		
-		if ((asset_texture.sampler >= 0) && (asset_texture.sampler < asset_scene.samplers.size())) {
-			//asset_sampler = &(asset_scene.samplers[asset_texture.sampler]); // TODO
-		}
-		
-		Image img = core.createImage(format, asset_texture.w, asset_texture.h);
-		img.fill(asset_texture.data.data());
-		image = img.getHandle();
-		
-		if (asset_sampler) {
-			//sampler = core.createSampler(asset_sampler) // TODO
-		} else {
-			sampler = core.createSampler(
-					vkcv::SamplerFilterType::LINEAR,
-					vkcv::SamplerFilterType::LINEAR,
-					vkcv::SamplerMipmapMode::LINEAR,
-					vkcv::SamplerAddressMode::REPEAT
-			);
-		}
-	}
-	
-	static material::Material loadMaterial(Core& core, const asset::Scene& scene,
-									const asset::Material& material) {
-		ImageHandle diffuseImg;
-		SamplerHandle diffuseSmp;
-		
-		if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) {
-			loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb,
-					  diffuseImg,diffuseSmp);
-		}
-		
-		ImageHandle normalImg;
-		SamplerHandle normalSmp;
-		
-		if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) {
-			loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb,
-					  diffuseImg,diffuseSmp);
-		}
-		
-		ImageHandle metalRoughImg;
-		SamplerHandle metalRoughSmp;
-		
-		if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) {
-			loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb,
-					  diffuseImg,diffuseSmp);
-		}
-		
-		ImageHandle occlusionImg;
-		SamplerHandle occlusionSmp;
-		
-		if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) {
-			loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb,
-					  diffuseImg,diffuseSmp);
-		}
-		
-		ImageHandle emissionImg;
-		SamplerHandle emissionSmp;
-		
-		if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) {
-			loadImage(core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb,
-					  diffuseImg,diffuseSmp);
-		}
-		
-		const float colorFactors [4] = {
-				material.baseColorFactor.r,
-				material.baseColorFactor.g,
-				material.baseColorFactor.b,
-				material.baseColorFactor.a
-		};
-		
-		const float emissionFactors[4] = {
-				material.emissiveFactor.r,
-				material.emissiveFactor.g,
-				material.emissiveFactor.b
-		};
-		
-		return material::Material::createPBR(
-				core,
-				diffuseImg, diffuseSmp,
-				normalImg, normalSmp,
-				metalRoughImg, metalRoughSmp,
-				occlusionImg, occlusionSmp,
-				emissionImg, emissionSmp,
-				colorFactors,
-				material.normalScale,
-				material.metallicFactor,
-				material.roughnessFactor,
-				material.occlusionStrength,
-				emissionFactors
-		);
-	}
+	MeshPart::MeshPart(Scene& scene) :
+	m_scene(scene),
+	m_vertices(),
+	m_vertexBindings(),
+	m_indices(),
+	m_indexCount(0),
+	m_bounds(),
+	m_materialIndex(std::numeric_limits<size_t>::max()) {}
 	
 	void MeshPart::load(const asset::Scene& scene,
 						const asset::VertexGroup &vertexGroup,
 						std::vector<DrawcallInfo>& drawcalls) {
-		Core& core = *(m_scene->m_core);
+		Core& core = *(m_scene.m_core);
 		
 		auto vertexBuffer = core.createBuffer<uint8_t>(
 				BufferType::VERTEX, vertexGroup.vertexBuffer.data.size()
@@ -156,11 +59,11 @@ namespace vkcv::scene {
 			(vertexGroup.materialIndex < scene.materials.size())) {
 			m_materialIndex = vertexGroup.materialIndex;
 			
-			auto& material = m_scene->m_materials[m_materialIndex];
-			
-			if (0 == material.m_usages++) {
-				material.m_data = loadMaterial(core, scene, scene.materials[vertexGroup.materialIndex]);
+			if (!getMaterial()) {
+				m_scene.loadMaterial(m_materialIndex, scene, scene.materials[vertexGroup.materialIndex]);
 			}
+			
+			m_scene.increaseMaterialUsage(m_materialIndex);
 		} else {
 			m_materialIndex = std::numeric_limits<size_t>::max();
 		}
@@ -177,39 +80,7 @@ namespace vkcv::scene {
 	}
 	
 	MeshPart::~MeshPart() {
-		if ((m_scene->m_core) && (m_materialIndex < m_scene->m_materials.size())) {
-			auto& material = m_scene->m_materials[m_materialIndex];
-			
-			if (material.m_usages > 0) {
-				material.m_usages--;
-			}
-		}
-	}
-	
-	MeshPart::MeshPart(const MeshPart &other) :
-	m_scene(other.m_scene),
-	m_vertices(other.m_vertices),
-	m_vertexBindings(other.m_vertexBindings),
-	m_indices(other.m_indices),
-	m_indexCount(other.m_indexCount),
-	m_bounds(other.m_bounds),
-	m_materialIndex(other.m_materialIndex) {
-		if (m_materialIndex < std::numeric_limits<size_t>::max()) {
-			auto& material = m_scene->m_materials[m_materialIndex];
-			
-			material.m_usages++;
-		}
-	}
-	
-	MeshPart::MeshPart(MeshPart &&other) noexcept :
-	m_scene(other.m_scene),
-	m_vertices(other.m_vertices),
-	m_vertexBindings(other.m_vertexBindings),
-	m_indices(other.m_indices),
-	m_indexCount(other.m_indexCount),
-	m_bounds(other.m_bounds),
-	m_materialIndex(other.m_materialIndex) {
-		other.m_materialIndex = std::numeric_limits<size_t>::max();
+		m_scene.decreaseMaterialUsage(m_materialIndex);
 	}
 	
 	MeshPart &MeshPart::operator=(const MeshPart &other) {
@@ -217,7 +88,6 @@ namespace vkcv::scene {
 			return *this;
 		}
 		
-		m_scene = other.m_scene;
 		m_vertices = other.m_vertices;
 		m_vertexBindings = other.m_vertexBindings;
 		m_indices = other.m_indices;
@@ -229,7 +99,6 @@ namespace vkcv::scene {
 	}
 	
 	MeshPart &MeshPart::operator=(MeshPart &&other) noexcept {
-		m_scene = other.m_scene;
 		m_vertices = other.m_vertices;
 		m_vertexBindings = other.m_vertexBindings;
 		m_indices = other.m_indices;
@@ -243,18 +112,12 @@ namespace vkcv::scene {
 	}
 	
 	const material::Material & MeshPart::getMaterial() const {
-		static material::Material noMaterial;
-		
-		if (m_materialIndex < m_scene->m_materials.size()) {
-			return m_scene->m_materials[m_materialIndex].m_data;
-		} else {
-			return noMaterial;
-		}
+		return m_scene.getMaterial(m_materialIndex);
 	}
 	
 	MeshPart::operator bool() const {
 		return (
-				(m_materialIndex < m_scene->m_materials.size()) &&
+				(getMaterial()) &&
 				(m_vertices) &&
 				(m_indices)
 		);
@@ -262,7 +125,7 @@ namespace vkcv::scene {
 	
 	bool MeshPart::operator!() const {
 		return (
-				(m_materialIndex >= m_scene->m_materials.size()) ||
+				(!getMaterial()) ||
 				(!m_vertices) ||
 				(!m_indices)
 		);
diff --git a/modules/scene/src/vkcv/scene/Node.cpp b/modules/scene/src/vkcv/scene/Node.cpp
index ab65091c..906e00e8 100644
--- a/modules/scene/src/vkcv/scene/Node.cpp
+++ b/modules/scene/src/vkcv/scene/Node.cpp
@@ -1,10 +1,13 @@
 
 #include "vkcv/scene/Node.hpp"
+#include "vkcv/scene/Scene.hpp"
 #include "Frustum.hpp"
 
+#include <algorithm>
+
 namespace vkcv::scene {
 	
-	Node::Node(Scene* scene) :
+	Node::Node(Scene& scene) :
 	m_scene(scene),
 	m_meshes(),
 	m_nodes(),
@@ -15,44 +18,47 @@ namespace vkcv::scene {
 		m_meshes.clear();
 	}
 	
-	Node::Node(const Node &other) :
-	m_scene(other.m_scene),
-	m_meshes(other.m_meshes),
-	m_nodes(other.m_nodes),
-	m_bounds(other.m_bounds) {}
-	
-	Node::Node(Node &&other) noexcept :
-	m_scene(other.m_scene),
-	m_meshes(other.m_meshes),
-	m_nodes(other.m_nodes),
-	m_bounds(other.m_bounds) {}
-	
 	Node &Node::operator=(const Node &other) {
 		if (&other == this) {
 			return *this;
 		}
 		
-		m_scene = other.m_scene;
-		m_meshes = std::vector<Mesh>(other.m_meshes);
-		m_nodes = std::vector<Node>(other.m_nodes);
+		m_meshes.resize(other.m_meshes.size(), Mesh(m_scene));
+		
+		for (size_t i = 0; i < m_meshes.size(); i++) {
+			m_meshes[i] = other.m_meshes[i];
+		}
+		
+		m_nodes.resize(other.m_nodes.size(), Node(m_scene));
+		
+		for (size_t i = 0; i < m_nodes.size(); i++) {
+			m_nodes[i] = other.m_nodes[i];
+		}
+		
 		m_bounds = other.m_bounds;
 		
 		return *this;
 	}
 	
 	Node &Node::operator=(Node &&other) noexcept {
-		m_scene = other.m_scene;
-		m_meshes = std::move(other.m_meshes);
-		m_nodes = std::move(other.m_nodes);
+		m_meshes.resize(other.m_meshes.size(), Mesh(m_scene));
+		
+		for (size_t i = 0; i < m_meshes.size(); i++) {
+			m_meshes[i] = std::move(other.m_meshes[i]);
+		}
+		
+		m_nodes.resize(other.m_nodes.size(), Node(m_scene));
+		
+		for (size_t i = 0; i < m_nodes.size(); i++) {
+			m_nodes[i] = std::move(other.m_nodes[i]);
+		}
+		
 		m_bounds = other.m_bounds;
 		
 		return *this;
 	}
 	
-	void Node::loadMesh(const asset::Scene &asset_scene, const asset::Mesh &asset_mesh) {
-		Mesh mesh (m_scene);
-		mesh.load(asset_scene, asset_mesh);
-		
+	void Node::addMesh(const Mesh& mesh) {
 		if (m_meshes.empty()) {
 			m_bounds = mesh.getBounds();
 		} else {
@@ -63,10 +69,25 @@ namespace vkcv::scene {
 		m_meshes.push_back(mesh);
 	}
 	
-	Node& Node::addNode() {
-		Node node (this->m_scene);
+	void Node::loadMesh(const asset::Scene &asset_scene, const asset::Mesh &asset_mesh) {
+		Mesh mesh (m_scene);
+		mesh.load(asset_scene, asset_mesh);
+		addMesh(mesh);
+	}
+	
+	size_t Node::addNode() {
+		const Node node (m_scene);
+		const size_t index = m_nodes.size();
 		m_nodes.push_back(node);
-		return m_nodes.back();
+		return index;
+	}
+	
+	Node& Node::getNode(size_t index) {
+		return m_nodes[index];
+	}
+	
+	const Node& Node::getNode(size_t index) const {
+		return m_nodes[index];
 	}
 	
 	void Node::recordDrawcalls(const glm::mat4& viewProjection,
@@ -85,6 +106,67 @@ namespace vkcv::scene {
 		}
 	}
 	
+	void Node::splitMeshesToSubNodes(size_t maxMeshesPerNode) {
+		if (m_meshes.size() <= maxMeshesPerNode) {
+			return;
+		}
+		
+		const auto split = m_bounds.getCenter();
+		int axis = 0;
+		
+		const auto size = m_bounds.getSize();
+		
+		if (size[1] > size[0]) {
+			if (size[2] > size[1]) {
+				axis = 2;
+			} else {
+				axis = 1;
+			}
+		} else
+		if (size[2] > size[0]) {
+			axis = 2;
+		}
+		
+		std::vector<size_t> left_meshes;
+		std::vector<size_t> right_meshes;
+		
+		for (size_t i = 0; i < m_meshes.size(); i++) {
+			const auto& bounds = m_meshes[i].getBounds();
+			
+			if (bounds.getMax()[axis] <= split[axis]) {
+				left_meshes.push_back(i);
+			} else
+			if (bounds.getMin()[axis] >= split[axis]) {
+				right_meshes.push_back(i);
+			}
+		}
+		
+		if ((left_meshes.empty()) || (right_meshes.empty())) {
+			return;
+		}
+		
+		const size_t left = addNode();
+		const size_t right = addNode();
+		
+		for (size_t i : left_meshes) {
+			getNode(left).addMesh(m_meshes[i]);
+		}
+		
+		for (size_t i : right_meshes) {
+			getNode(right).addMesh(m_meshes[i]);
+			left_meshes.push_back(i);
+		}
+		
+		std::sort(left_meshes.begin(), left_meshes.end(), std::greater());
+		
+		for (size_t i : left_meshes) {
+			m_meshes.erase(m_meshes.begin() + static_cast<long>(i));
+		}
+		
+		getNode(left).splitMeshesToSubNodes(maxMeshesPerNode);
+		getNode(right).splitMeshesToSubNodes(maxMeshesPerNode);
+	}
+	
 	size_t Node::getDrawcallCount() const {
 		size_t count = 0;
 		
diff --git a/modules/scene/src/vkcv/scene/Scene.cpp b/modules/scene/src/vkcv/scene/Scene.cpp
index da0f7fb6..1a5f76e5 100644
--- a/modules/scene/src/vkcv/scene/Scene.cpp
+++ b/modules/scene/src/vkcv/scene/Scene.cpp
@@ -19,12 +19,24 @@ namespace vkcv::scene {
 	Scene::Scene(const Scene &other) :
 	m_core(other.m_core),
 	m_materials(other.m_materials),
-	m_nodes(other.m_nodes) {}
+	m_nodes() {
+		m_nodes.resize(other.m_nodes.size(), Node(*this));
+		
+		for (size_t i = 0; i < m_nodes.size(); i++) {
+			m_nodes[i] = other.m_nodes[i];
+		}
+	}
 	
 	Scene::Scene(Scene &&other) noexcept :
 	m_core(other.m_core),
 	m_materials(other.m_materials),
-	m_nodes(other.m_nodes) {}
+	m_nodes() {
+		m_nodes.resize(other.m_nodes.size(), Node(*this));
+		
+		for (size_t i = 0; i < m_nodes.size(); i++) {
+			m_nodes[i] = std::move(other.m_nodes[i]);
+		}
+	}
 	
 	Scene &Scene::operator=(const Scene &other) {
 		if (&other == this) {
@@ -33,7 +45,12 @@ namespace vkcv::scene {
 		
 		m_core = other.m_core;
 		m_materials = std::vector<Material>(other.m_materials);
-		m_nodes = std::vector<Node>(other.m_nodes);
+		
+		m_nodes.resize(other.m_nodes.size(), Node(*this));
+		
+		for (size_t i = 0; i < m_nodes.size(); i++) {
+			m_nodes[i] = other.m_nodes[i];
+		}
 		
 		return *this;
 	}
@@ -41,15 +58,41 @@ namespace vkcv::scene {
 	Scene &Scene::operator=(Scene &&other) noexcept {
 		m_core = other.m_core;
 		m_materials = std::move(other.m_materials);
-		m_nodes = std::move(other.m_nodes);
+		
+		m_nodes.resize(other.m_nodes.size(), Node(*this));
+		
+		for (size_t i = 0; i < m_nodes.size(); i++) {
+			m_nodes[i] = std::move(other.m_nodes[i]);
+		}
 		
 		return *this;
 	}
 	
-	Node& Scene::addNode() {
-		Node node (this);
+	size_t Scene::addNode() {
+		const Node node (*this);
+		const size_t index = m_nodes.size();
 		m_nodes.push_back(node);
-		return m_nodes.back();
+		return index;
+	}
+	
+	Node& Scene::getNode(size_t index) {
+		return m_nodes[index];
+	}
+	
+	const Node& Scene::getNode(size_t index) const {
+		return m_nodes[index];
+	}
+	
+	void Scene::increaseMaterialUsage(size_t index) {
+		if (index < m_materials.size()) {
+			m_materials[index].m_usages++;
+		}
+	}
+	
+	void Scene::decreaseMaterialUsage(size_t index) {
+		if ((index < m_materials.size()) && (m_materials[index].m_usages > 0)) {
+			m_materials[index].m_usages--;
+		}
 	}
 	
 	size_t Scene::getMaterialCount() const {
@@ -100,6 +143,107 @@ namespace vkcv::scene {
 		return Scene(&core);
 	}
 	
+	static void loadImage(Core& core, const asset::Scene& asset_scene,
+						  const asset::Texture& asset_texture,
+						  const vk::Format& format,
+						  ImageHandle& image, SamplerHandle& sampler) {
+		asset::Sampler* asset_sampler = nullptr;
+		
+		if ((asset_texture.sampler >= 0) && (asset_texture.sampler < asset_scene.samplers.size())) {
+			//asset_sampler = &(asset_scene.samplers[asset_texture.sampler]); // TODO
+		}
+		
+		Image img = core.createImage(format, asset_texture.w, asset_texture.h);
+		img.fill(asset_texture.data.data());
+		image = img.getHandle();
+		
+		if (asset_sampler) {
+			//sampler = core.createSampler(asset_sampler) // TODO
+		} else {
+			sampler = core.createSampler(
+					vkcv::SamplerFilterType::LINEAR,
+					vkcv::SamplerFilterType::LINEAR,
+					vkcv::SamplerMipmapMode::LINEAR,
+					vkcv::SamplerAddressMode::REPEAT
+			);
+		}
+	}
+	
+	void Scene::loadMaterial(size_t index, const asset::Scene& scene,
+							 const asset::Material& material) {
+		if (index >= m_materials.size()) {
+			return;
+		}
+		
+		ImageHandle diffuseImg;
+		SamplerHandle diffuseSmp;
+		
+		if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) {
+			loadImage(*m_core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb,
+					  diffuseImg,diffuseSmp);
+		}
+		
+		ImageHandle normalImg;
+		SamplerHandle normalSmp;
+		
+		if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) {
+			loadImage(*m_core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb,
+					  diffuseImg,diffuseSmp);
+		}
+		
+		ImageHandle metalRoughImg;
+		SamplerHandle metalRoughSmp;
+		
+		if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) {
+			loadImage(*m_core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb,
+					  diffuseImg,diffuseSmp);
+		}
+		
+		ImageHandle occlusionImg;
+		SamplerHandle occlusionSmp;
+		
+		if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) {
+			loadImage(*m_core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb,
+					  diffuseImg,diffuseSmp);
+		}
+		
+		ImageHandle emissionImg;
+		SamplerHandle emissionSmp;
+		
+		if ((material.baseColor >= 0) && (material.baseColor < scene.textures.size())) {
+			loadImage(*m_core, scene, scene.textures[material.baseColor], vk::Format::eR8G8B8A8Srgb,
+					  diffuseImg,diffuseSmp);
+		}
+		
+		const float colorFactors [4] = {
+				material.baseColorFactor.r,
+				material.baseColorFactor.g,
+				material.baseColorFactor.b,
+				material.baseColorFactor.a
+		};
+		
+		const float emissionFactors[4] = {
+				material.emissiveFactor.r,
+				material.emissiveFactor.g,
+				material.emissiveFactor.b
+		};
+		
+		m_materials[index].m_data = material::Material::createPBR(
+				*m_core,
+				diffuseImg, diffuseSmp,
+				normalImg, normalSmp,
+				metalRoughImg, metalRoughSmp,
+				occlusionImg, occlusionSmp,
+				emissionImg, emissionSmp,
+				colorFactors,
+				material.normalScale,
+				material.metallicFactor,
+				material.roughnessFactor,
+				material.occlusionStrength,
+				emissionFactors
+		);
+	}
+	
 	Scene Scene::load(Core& core, const std::filesystem::path &path) {
 		asset::Scene asset_scene;
 		
@@ -116,12 +260,13 @@ namespace vkcv::scene {
 			});
 		}
 		
-		Node& node = scene.addNode();
+		const size_t root = scene.addNode();
 		
 		for (const auto& mesh : asset_scene.meshes) {
-			node.loadMesh(asset_scene, mesh);
+			scene.getNode(root).loadMesh(asset_scene, mesh);
 		}
 		
+		scene.getNode(root).splitMeshesToSubNodes(128);
 		return scene;
 	}
 	
-- 
GitLab