Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions facade-lib/include/facade/scene/material.hpp
Original file line number Diff line number Diff line change
@@ -1,25 +1,21 @@
#pragma once
#include <facade/scene/id.hpp>
#include <facade/util/colour_space.hpp>
#include <facade/vk/texture.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <optional>
#include <span>
#include <string>

namespace facade {
class Texture;
class Pipeline;

struct TextureProvider {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed anymore

virtual Texture const* get(std::size_t index, ColourSpace colour_space) const = 0;
};

struct TextureStore {
std::span<Texture const> textures;
Texture const& white;
TextureProvider const& provider;

Texture const& get(std::optional<std::size_t> index, ColourSpace colour_space) const;
Texture const& get(std::optional<std::size_t> index) const;
};

class Material {
Expand All @@ -43,7 +39,7 @@ class UnlitMaterial : public Material {
void write_sets(Pipeline& pipeline, TextureStore const& store) const override;
};

class TestMaterial : public Material {
class LitMaterial : public Material {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests have been successful, time to formalize this material

public:
glm::vec3 albedo{1.0f};
float metallic{0.5f};
Expand Down
6 changes: 2 additions & 4 deletions facade-lib/include/facade/scene/scene.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class Scene {
bool select_camera(Id<Camera> id);
Node& camera();

vk::Sampler sampler() const { return m_sampler.sampler(); }
vk::Sampler default_sampler() const { return m_sampler.sampler(); }
Texture make_texture(Image::View image) const;

void write_view(Pipeline& out_pipeline) const;
Expand Down Expand Up @@ -98,15 +98,13 @@ class Scene {
std::vector<Tree::Data> trees{};
};

using Tex = EnumArray<ColourSpace, std::optional<Texture>, 2>;

struct Storage {
std::vector<Camera> cameras{};
std::vector<Sampler> samplers{};
std::vector<std::unique_ptr<Material>> materials{};
std::vector<StaticMesh> static_meshes{};
std::vector<Image> images{};
std::vector<Tex> textures{};
std::vector<Texture> textures{};
std::vector<Mesh> meshes{};
std::vector<glm::mat4x4> instances{};
Data data{};
Expand Down
15 changes: 15 additions & 0 deletions facade-lib/src/detail/gltf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,21 @@ struct Data {
for (auto const& m : scene["materials"].array_view()) { material(m); }

for (auto const& m : scene["meshes"].array_view()) { mesh(m); }

// Texture will use ColourSpace::sRGB by default; change non-colour textures to be linear
auto set_linear = [this](std::size_t index) { storage.textures.at(index).colour_space = ColourSpace::eLinear; };

// Determine whether a texture points to colour data by referring to the material(s) it is used in
// In our case all material textures except pbr.base_colour_texture are linear
// The GLTF spec mandates image formats for corresponding material textures:
// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-material
for (auto const& m : storage.materials) {
if (m.pbr.metallic_roughness_texture) { set_linear(m.pbr.metallic_roughness_texture->texture); }
if (m.emissive_texture) { set_linear(m.emissive_texture->texture); }
if (m.occlusion_texture) { set_linear(m.occlusion_texture->info.texture); }
if (m.normal_texture) { set_linear(m.normal_texture->info.texture); }
}

return std::move(storage);
}
};
Expand Down
10 changes: 10 additions & 0 deletions facade-lib/src/detail/gltf.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <facade/scene/transform.hpp>
#include <facade/util/byte_buffer.hpp>
#include <facade/util/colour_space.hpp>
#include <facade/util/geometry.hpp>
#include <facade/util/image.hpp>
#include <glm/vec4.hpp>
Expand Down Expand Up @@ -114,6 +115,15 @@ struct Texture {
std::string name{};
std::optional<std::size_t> sampler{};
std::size_t source{};

///
/// \brief Describes whether to load the source image in sRGB or linear format
///
/// Textures with colour info are sRGB encoded, with other info (eg normal data) are linear encoded
/// This information is obtained from the material(s) textures are used in
/// Different materials using the same texture as colour and non-colour sources is undefined behaviour
///
ColourSpace colour_space{ColourSpace::eSrgb};
};

struct Node {
Expand Down
16 changes: 7 additions & 9 deletions facade-lib/src/scene/material.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include <facade/scene/material.hpp>
#include <facade/vk/pipeline.hpp>
#include <facade/vk/texture.hpp>
#include <glm/gtc/color_space.hpp>

namespace facade {
Expand All @@ -13,15 +12,14 @@ struct Mat {
glm::vec4 uncorrect(glm::vec4 const& in) { return glm::convertSRGBToLinear(in); }
} // namespace

Texture const& TextureStore::get(std::optional<std::size_t> const index, ColourSpace const colour_space) const {
if (!index) { return white; }
if (auto const* ret = provider.get(*index, colour_space)) { return *ret; }
return white;
Texture const& TextureStore::get(std::optional<std::size_t> const index) const {
if (!index || *index >= textures.size()) { return white; }
return textures[*index];
}

void UnlitMaterial::write_sets(Pipeline& pipeline, TextureStore const& store) const {
auto& set1 = pipeline.next_set(1);
set1.update(0, store.get(texture, ColourSpace::eSrgb).descriptor_image());
set1.update(0, store.get(texture).descriptor_image());
auto& set2 = pipeline.next_set(2);
auto const mat = Mat{
.albedo = uncorrect(tint),
Expand All @@ -32,10 +30,10 @@ void UnlitMaterial::write_sets(Pipeline& pipeline, TextureStore const& store) co
pipeline.bind(set2);
}

void TestMaterial::write_sets(Pipeline& pipeline, TextureStore const& store) const {
void LitMaterial::write_sets(Pipeline& pipeline, TextureStore const& store) const {
auto& set1 = pipeline.next_set(1);
set1.update(0, store.get(base_colour, ColourSpace::eSrgb).descriptor_image());
set1.update(1, store.get(roughness_metallic, ColourSpace::eLinear).descriptor_image());
set1.update(0, store.get(base_colour).descriptor_image());
set1.update(1, store.get(roughness_metallic).descriptor_image());
auto& set2 = pipeline.next_set(2);
auto const mat = Mat{
.albedo = uncorrect({albedo, 1.0f}),
Expand Down
44 changes: 19 additions & 25 deletions facade-lib/src/scene/scene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,12 @@ Sampler to_sampler(Gfx const& gfx, gltf::Sampler const& sampler) {
}

std::unique_ptr<Material> to_material(gltf::Material const& material) {
auto ret = std::make_unique<TestMaterial>();
auto ret = std::make_unique<LitMaterial>();
ret->albedo = material.pbr.base_colour_factor;
ret->metallic = material.pbr.metallic_factor;
ret->roughness = material.pbr.roughness_factor;
if (material.pbr.base_colour_texture) { ret->base_colour = material.pbr.base_colour_texture->texture; }
if (material.pbr.metallic_roughness_texture) { ret->roughness_metallic = material.pbr.metallic_roughness_texture->texture; }
// TODO: textures
return ret;
}

Expand All @@ -75,6 +74,10 @@ Mesh to_mesh(gltf::Mesh const& mesh) {
return ret;
}

Texture to_texture(Gfx const& gfx, vk::Sampler sampler, Image const& image, gltf::Texture const& texture) {
return Texture{gfx, sampler, image.view(), Texture::CreateInfo{.mip_mapped = true, .colour_space = texture.colour_space}};
}

struct Img1x1 {
std::byte bytes[4]{};

Expand Down Expand Up @@ -161,12 +164,19 @@ bool Scene::load_gltf(dj::Json const& root, DataProvider const& provider) noexce
}

m_storage.images = std::move(asset.images);
m_storage.textures.resize(m_storage.images.size());
for (auto const& sampler : asset.samplers) { add(to_sampler(m_gfx, sampler)); }
for (auto const& material : asset.materials) { add(to_material(material)); }
for (auto const& geometry : asset.geometries) { add(StaticMesh{m_gfx, geometry}); }
for (auto const& mesh : asset.meshes) { add(to_mesh(mesh)); }

auto get_sampler = [this](std::optional<std::size_t> sampler_id) {
if (!sampler_id || sampler_id >= m_storage.samplers.size()) { return default_sampler(); }
return m_storage.samplers[*sampler_id].sampler();
};
for (auto const& texture : asset.textures) {
m_storage.textures.push_back(to_texture(m_gfx, get_sampler(texture.sampler), m_storage.images.at(texture.source), texture));
}

for (auto& node : asset.nodes) {
m_storage.data.nodes.push_back(NodeData{node.transform, std::move(node.children), node.index, static_cast<NodeData::Type>(node.type)});
}
Expand Down Expand Up @@ -243,7 +253,7 @@ Node& Scene::camera() {
return *ret;
}

Texture Scene::make_texture(Image::View image) const { return Texture{m_gfx, sampler(), image}; }
Texture Scene::make_texture(Image::View image) const { return Texture{m_gfx, default_sampler(), image}; }

void Scene::write_view(Pipeline& out_pipeline) const {
auto& set0 = out_pipeline.next_set(0);
Expand Down Expand Up @@ -316,31 +326,15 @@ std::span<glm::mat4x4 const> Scene::make_instances(Node const& node, glm::mat4x4
}

void Scene::render(Renderer& renderer, vk::CommandBuffer cb, Node const& node, glm::mat4 const& parent) {
struct TexProvider : TextureProvider {
Scene& scene;

TexProvider(Scene& scene) : scene(scene) {}

Texture const* get(std::size_t index, ColourSpace colour_space) const override {
if (index >= scene.m_storage.textures.size()) { return {}; }
auto& ret = scene.m_storage.textures[index][colour_space];
if (!ret) {
assert(index < scene.m_storage.images.size());
ret.emplace(scene.m_gfx, scene.sampler(), scene.m_storage.images[index], Texture::CreateInfo{true, colour_space});
}
return &*ret;
}
};

if (auto const* mesh_id = node.find<Id<Mesh>>()) {
static auto const s_default_material = TestMaterial{};
static auto const s_default_material = LitMaterial{};
auto const& mesh = m_storage.meshes.at(*mesh_id);
for (auto const& primitive : mesh.primitives) {
auto const& material = primitive.material ? *m_storage.materials.at(primitive.material->value()) : static_cast<Material const&>(s_default_material);
auto pipeline = renderer.bind_pipeline(cb, {}, material.shader_id());

write_view(pipeline);
auto const store = TextureStore{m_white, TexProvider{*this}};
auto const store = TextureStore{m_storage.textures, m_white};
material.write_sets(pipeline, store);

auto const& static_mesh = m_storage.static_meshes.at(primitive.static_mesh);
Expand All @@ -367,9 +361,9 @@ void Scene::check(Node const& node) const noexcept(false) {
if (auto const* mesh_id = node.find<Id<Mesh>>(); mesh_id && *mesh_id >= m_storage.meshes.size()) {
throw Error{concat("Scene ", m_name, ": Invalid mesh [", *mesh_id, "] in node")};
}
// if (node.type == Node::Type::eCamera && node.index >= m_storage.cameras.size()) {
// throw Error{concat("Scene ", m_name, ": Invalid mesh [", node.index, "] in node")};
// }
if (auto const* camera_id = node.find<Id<Camera>>(); camera_id && *camera_id >= m_storage.cameras.size()) {
throw Error{concat("Scene ", m_name, ": Invalid camera [", *camera_id, "] in node")};
}
for (auto const& child : node.m_children) { check(child); }
}
} // namespace facade
2 changes: 1 addition & 1 deletion facade-lib/src/util/data_provider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ FileDataProvider::FileDataProvider(std::string_view directory) {
m_directory = path.generic_string();
}

FileDataProvider FileDataProvider::mount_parent_dir(std::string_view filename) { return {fs::path{filename}.parent_path().generic_string()}; }
FileDataProvider FileDataProvider::mount_parent_dir(std::string_view filename) { return FileDataProvider{fs::path{filename}.parent_path().generic_string()}; }

ByteBuffer FileDataProvider::load(std::string_view uri) const {
auto const path = absolute_path(m_directory, uri);
Expand Down
4 changes: 2 additions & 2 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ void run() {
auto post_scene_load = [&] {
scene.camera().transform.set_position({0.0f, 0.0f, 5.0f});

auto material = std::make_unique<TestMaterial>();
auto material = std::make_unique<LitMaterial>();
material->albedo = {1.0f, 0.0f, 0.0f};
material_id = scene.add(std::move(material));
auto static_mesh_id = scene.add(StaticMesh{gfx, make_cubed_sphere(1.0f, 32)});
Expand Down Expand Up @@ -243,7 +243,7 @@ void run() {

ImGui::SetNextWindowSize({250.0f, 100.0f}, ImGuiCond_Once);
if (ImGui::Begin("Material")) {
auto* mat = static_cast<TestMaterial*>(scene.find_material(material_id));
auto* mat = static_cast<LitMaterial*>(scene.find_material(material_id));
ImGui::SliderFloat("Metallic", &mat->metallic, 0.0f, 1.0f);
ImGui::SliderFloat("Roughness", &mat->roughness, 0.0f, 1.0f);
}
Expand Down