Skip to content

Commit 7782fa7

Browse files
committed
Add support for cubemaps and skybox
Currently not set up to be used in a Scene: will need external resources first.
1 parent 7895bfd commit 7782fa7

File tree

18 files changed

+261
-76
lines changed

18 files changed

+261
-76
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,18 @@ if(FACADE_BUILD_EXE AND FACADE_BUILD_SHADERS)
3737
${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/default.vert
3838
${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/unlit.frag
3939
${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/lit.frag
40+
${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/skybox.frag
4041

4142
OUTPUT
4243
${CMAKE_CURRENT_SOURCE_DIR}/src/bin/default_vert.spv.hpp
4344
${CMAKE_CURRENT_SOURCE_DIR}/src/bin/unlit_frag.spv.hpp
4445
${CMAKE_CURRENT_SOURCE_DIR}/src/bin/lit_frag.spv.hpp
46+
${CMAKE_CURRENT_SOURCE_DIR}/src/bin/skybox_frag.spv.hpp
4547

4648
COMMAND embed-shader ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/default.vert > ${CMAKE_CURRENT_SOURCE_DIR}/src/bin/default_vert.spv.hpp
4749
COMMAND embed-shader ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/unlit.frag > ${CMAKE_CURRENT_SOURCE_DIR}/src/bin/unlit_frag.spv.hpp
4850
COMMAND embed-shader ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/lit.frag > ${CMAKE_CURRENT_SOURCE_DIR}/src/bin/lit_frag.spv.hpp
51+
COMMAND embed-shader ${CMAKE_CURRENT_SOURCE_DIR}/src/shaders/skybox.frag > ${CMAKE_CURRENT_SOURCE_DIR}/src/bin/skybox_frag.spv.hpp
4952
)
5053
endif()
5154

lib/engine/include/facade/engine/scene_renderer.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <facade/render/renderer.hpp>
33
#include <facade/scene/scene.hpp>
44
#include <facade/vk/buffer.hpp>
5+
#include <facade/vk/skybox.hpp>
56

67
namespace facade {
78
class SceneRenderer {
@@ -13,9 +14,10 @@ class SceneRenderer {
1314
private:
1415
void write_view(glm::vec2 const extent);
1516
void update_view(Pipeline& out_pipeline) const;
16-
std::span<glm::mat4x4 const> make_instances(Node const& node, glm::mat4x4 const& parent);
17+
std::span<glm::mat4x4 const> make_instances(Node const& node, glm::mat4x4 const& parent) const;
1718

18-
void render(Renderer& renderer, vk::CommandBuffer cb, Node const& node, glm::mat4 const& parent = matrix_identity_v);
19+
void render(Renderer& renderer, vk::CommandBuffer cb, Skybox const& skybox) const;
20+
void render(Renderer& renderer, vk::CommandBuffer cb, Node const& node, glm::mat4 const& parent = matrix_identity_v) const;
1921

2022
Gfx m_gfx;
2123
Sampler m_sampler;
@@ -24,7 +26,7 @@ class SceneRenderer {
2426
Texture m_white;
2527
Texture m_black;
2628

27-
std::vector<glm::mat4x4> m_instance_mats{};
29+
mutable std::vector<glm::mat4x4> m_instance_mats{};
2830
Scene const* m_scene{};
2931
};
3032
} // namespace facade

lib/engine/src/scene_renderer.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ void SceneRenderer::update_view(Pipeline& out_pipeline) const {
7777
out_pipeline.bind(set0);
7878
}
7979

80-
std::span<glm::mat4x4 const> SceneRenderer::make_instances(Node const& node, glm::mat4x4 const& parent) {
80+
std::span<glm::mat4x4 const> SceneRenderer::make_instances(Node const& node, glm::mat4x4 const& parent) const {
8181
m_instance_mats.clear();
8282
if (node.instances.empty()) {
8383
m_instance_mats.reserve(1);
@@ -89,7 +89,20 @@ std::span<glm::mat4x4 const> SceneRenderer::make_instances(Node const& node, glm
8989
return m_instance_mats;
9090
}
9191

92-
void SceneRenderer::render(Renderer& renderer, vk::CommandBuffer cb, Node const& node, glm::mat4 const& parent) {
92+
void SceneRenderer::render(Renderer& renderer, vk::CommandBuffer cb, Skybox const& skybox) const {
93+
auto state = m_scene->pipeline_state;
94+
state.depth_test = false;
95+
auto pipeline = renderer.bind_pipeline(cb, state, "skybox");
96+
pipeline.set_line_width(1.0f);
97+
update_view(pipeline);
98+
auto& set1 = pipeline.next_set(1);
99+
set1.update(0, skybox.cubemap().descriptor_image());
100+
pipeline.bind(set1);
101+
auto const instance = glm::translate(matrix_identity_v, m_scene->camera().transform.position());
102+
renderer.draw(pipeline, skybox.static_mesh(), {&instance, 1});
103+
}
104+
105+
void SceneRenderer::render(Renderer& renderer, vk::CommandBuffer cb, Node const& node, glm::mat4 const& parent) const {
93106
auto const& resources = m_scene->resources();
94107
if (auto const* mesh_id = node.find<Id<Mesh>>()) {
95108
static auto const s_default_material = Material{std::make_unique<LitMaterial>()};

lib/scene/include/facade/scene/camera.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ struct ViewPlane {
2222
///
2323
struct Camera {
2424
struct Perspective {
25-
ViewPlane view_plane{1.0f, 1000.0f};
25+
ViewPlane view_plane{0.1f, 1000.0f};
2626
float field_of_view{glm::radians(45.0f)};
2727
};
2828

lib/vk/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ target_sources(${PROJECT_NAME} PRIVATE
6262
include/${target_prefix}/vk/rotator.hpp
6363
include/${target_prefix}/vk/set_allocator.hpp
6464
include/${target_prefix}/vk/shader.hpp
65+
include/${target_prefix}/vk/skybox.hpp
6566
include/${target_prefix}/vk/spir_v.hpp
6667
include/${target_prefix}/vk/static_mesh.hpp
6768
include/${target_prefix}/vk/swapchain.hpp
@@ -82,6 +83,7 @@ target_sources(${PROJECT_NAME} PRIVATE
8283
src/render_pass.cpp
8384
src/set_allocator.cpp
8485
src/shader.cpp
86+
src/skybox.cpp
8587
src/spir_v.cpp
8688
src/static_mesh.cpp
8789
src/swapchain.cpp

lib/vk/include/facade/vk/skybox.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#pragma once
2+
#include <facade/vk/static_mesh.hpp>
3+
#include <facade/vk/texture.hpp>
4+
5+
namespace facade {
6+
class Skybox {
7+
public:
8+
struct Images;
9+
10+
Skybox(Gfx const& gfx, Images const& images);
11+
12+
void set_cubemap(Images const& images);
13+
14+
StaticMesh const& static_mesh() const { return m_cube; }
15+
Cubemap const& cubemap() const { return m_cubemap; }
16+
17+
private:
18+
Sampler m_sampler;
19+
StaticMesh m_cube;
20+
Cubemap m_cubemap;
21+
Gfx m_gfx;
22+
};
23+
24+
struct Skybox::Images {
25+
Image::View right{};
26+
Image::View left{};
27+
Image::View top{};
28+
Image::View bottom{};
29+
Image::View front{};
30+
Image::View back{};
31+
};
32+
} // namespace facade

lib/vk/include/facade/vk/texture.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,18 @@ class Texture {
5050

5151
vk::Sampler sampler{};
5252

53-
private:
53+
protected:
54+
Texture(Gfx const& gfx, vk::Sampler sampler, std::string name);
55+
5456
Defer<UniqueImage> m_image{};
5557
Gfx m_gfx{};
5658
ImageCreateInfo m_info{};
5759
vk::ImageLayout m_layout{vk::ImageLayout::eUndefined};
5860
std::string m_name{};
5961
};
62+
63+
class Cubemap : public Texture {
64+
public:
65+
Cubemap(Gfx const& gfx, vk::Sampler sampler, std::span<Image::View const> images, std::string name = {});
66+
};
6067
} // namespace facade

lib/vk/include/facade/vk/vma.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,9 @@ struct Vma {
120120
VmaAllocator allocator{};
121121

122122
Unique<Buffer, Deleter> make_buffer(vk::BufferUsageFlags usage, vk::DeviceSize size, bool host_visible) const;
123-
Unique<Image, Deleter> make_image(ImageCreateInfo const& info, vk::Extent2D extent) const;
124-
vk::UniqueImageView make_image_view(vk::Image const image, vk::Format const format, vk::ImageSubresourceRange isr = isr_v) const;
123+
Unique<Image, Deleter> make_image(ImageCreateInfo const& info, vk::Extent2D extent, vk::ImageViewType type = vk::ImageViewType::e2D) const;
124+
vk::UniqueImageView make_image_view(vk::Image const image, vk::Format const format, vk::ImageSubresourceRange isr = isr_v,
125+
vk::ImageViewType type = vk::ImageViewType::e2D) const;
125126
};
126127

127128
struct Vma::Allocation {

lib/vk/src/skybox.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <facade/vk/cmd.hpp>
2+
#include <facade/vk/geometry.hpp>
3+
#include <facade/vk/skybox.hpp>
4+
#include <numeric>
5+
6+
namespace facade {
7+
namespace {
8+
std::array<Image::View const, 6> make_cubemap_images(Skybox::Images const& images) {
9+
return {
10+
images.right, images.left, images.top, images.bottom, images.front, images.back,
11+
};
12+
}
13+
} // namespace
14+
15+
Skybox::Skybox(Gfx const& gfx, Images const& images)
16+
: m_sampler(gfx, Sampler::CreateInfo{.min = vk::Filter::eNearest, .mag = vk::Filter::eNearest}), m_cube(gfx, make_cube(glm::vec3{1.0f})),
17+
m_cubemap(gfx, m_sampler.sampler(), make_cubemap_images(images), "skybox"), m_gfx(gfx) {}
18+
19+
void Skybox::set_cubemap(Images const& images) { m_cubemap = {m_gfx, m_sampler.sampler(), make_cubemap_images(images), "skybox"}; }
20+
} // namespace facade

lib/vk/src/texture.cpp

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <facade/vk/cmd.hpp>
33
#include <facade/vk/texture.hpp>
44
#include <cmath>
5+
#include <numeric>
56

67
namespace facade {
78
namespace {
@@ -86,6 +87,38 @@ bool can_mip(vk::PhysicalDevice const gpu, vk::Format const format) {
8687
auto const fsrc = gpu.getFormatProperties(format);
8788
return (fsrc.optimalTilingFeatures & flags_v) != vk::FormatFeatureFlags{};
8889
}
90+
91+
Defer<UniqueImage> make_image(Gfx const& gfx, std::span<Image::View const> images, ImageCreateInfo const& info, vk::ImageViewType type) {
92+
auto const extent = vk::Extent2D{images[0].extent.x, images[0].extent.y};
93+
auto ret = Defer<UniqueImage>{gfx.vma.make_image(info, extent, type), gfx.shared->defer_queue};
94+
95+
auto const accumulate_size = [](std::size_t total, Image::View const& i) { return total + i.bytes.size(); };
96+
auto const size = std::accumulate(images.begin(), images.end(), std::size_t{}, accumulate_size);
97+
auto staging = gfx.vma.make_buffer(vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst, size, true);
98+
if (!staging.get().buffer) {
99+
// TODO error
100+
return {};
101+
}
102+
103+
auto* ptr = static_cast<std::byte*>(staging.get().ptr);
104+
for (auto const& image : images) {
105+
std::memcpy(ptr, image.bytes.data(), image.bytes.size());
106+
ptr += image.bytes.size();
107+
}
108+
109+
auto isrl = vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, info.array_layers);
110+
auto icr = vk::ImageCopy(isrl, {}, isrl, {}, vk::Extent3D{extent, 1});
111+
auto bic = vk::BufferImageCopy({}, {}, {}, isrl, {}, icr.extent);
112+
auto cmd = Cmd{gfx};
113+
full_barrier(ret.get().get().image_view(), info.mip_levels, info.array_layers, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal)
114+
.transition(cmd.cb);
115+
cmd.cb.copyBufferToImage(staging.get().buffer, ret.get().get().image, vk::ImageLayout::eTransferDstOptimal, bic);
116+
full_barrier(ret.get().get().image_view(), info.mip_levels, info.array_layers, vk::ImageLayout::eTransferDstOptimal,
117+
vk::ImageLayout::eShaderReadOnlyOptimal)
118+
.transition(cmd.cb);
119+
if (info.mip_levels > 1) { MipMapWriter{ret.get().get().image, ret.get().get().extent, cmd.cb, info.mip_levels}(); }
120+
return ret;
121+
}
89122
} // namespace
90123

91124
Sampler::Sampler(Gfx const& gfx, CreateInfo info) {
@@ -106,7 +139,7 @@ Sampler::Sampler(Gfx const& gfx, CreateInfo info) {
106139

107140
std::uint32_t Texture::mip_levels(vk::Extent2D extent) { return static_cast<std::uint32_t>(std::floor(std::log2(std::max(extent.width, extent.height)))) + 1U; }
108141

109-
Texture::Texture(Gfx const& gfx, vk::Sampler sampler, Image::View image, CreateInfo info) : sampler{sampler}, m_gfx{gfx}, m_name(std::move(info.name)) {
142+
Texture::Texture(Gfx const& gfx, vk::Sampler sampler, Image::View image, CreateInfo info) : Texture(gfx, sampler, std::move(info.name)) {
110143
static constexpr std::uint8_t magenta_v[] = {0xff, 0x0, 0xff, 0xff};
111144
m_info.format = info.colour_space == ColourSpace::eLinear ? vk::Format::eR8G8B8A8Unorm : vk::Format::eR8G8B8A8Srgb;
112145
bool mip_mapped = info.mip_mapped;
@@ -116,25 +149,18 @@ Texture::Texture(Gfx const& gfx, vk::Sampler sampler, Image::View image, CreateI
116149
image.bytes = {reinterpret_cast<std::byte const*>(magenta_v), std::size(magenta_v)};
117150
mip_mapped = false;
118151
}
119-
auto const extent = vk::Extent2D{image.extent.x, image.extent.y};
120-
if (mip_mapped && can_mip(m_gfx.gpu, m_info.format)) { m_info.mip_levels = mip_levels(extent); }
121-
m_image = {m_gfx.vma.make_image(m_info, extent), m_gfx.shared->defer_queue};
152+
if (mip_mapped && can_mip(m_gfx.gpu, m_info.format)) { m_info.mip_levels = mip_levels({image.extent.x, image.extent.y}); }
153+
m_image = make_image(m_gfx, {&image, 1}, m_info, vk::ImageViewType::e2D);
154+
m_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
155+
}
122156

123-
auto staging = m_gfx.vma.make_buffer(vk::BufferUsageFlagBits::eTransferSrc | vk::BufferUsageFlagBits::eTransferDst, image.bytes.size(), true);
124-
if (!staging.get().buffer) {
125-
// TODO error
126-
return;
127-
}
157+
Texture::Texture(Gfx const& gfx, vk::Sampler sampler, std::string name) : sampler(sampler), m_gfx(gfx), m_name(std::move(name)) {}
128158

129-
std::memcpy(staging.get().ptr, image.bytes.data(), image.bytes.size());
130-
auto isrl = vk::ImageSubresourceLayers(vk::ImageAspectFlagBits::eColor, 0, 0, 1);
131-
auto icr = vk::ImageCopy(isrl, {}, isrl, {}, vk::Extent3D{extent, 1});
132-
auto bic = vk::BufferImageCopy({}, {}, {}, isrl, {}, icr.extent);
133-
auto cmd = Cmd{m_gfx};
134-
full_barrier(m_image.get().get().image_view(), m_info.mip_levels, 1, m_layout, vk::ImageLayout::eTransferDstOptimal).transition(cmd.cb);
135-
cmd.cb.copyBufferToImage(staging.get().buffer, m_image.get().get().image, vk::ImageLayout::eTransferDstOptimal, bic);
159+
Cubemap::Cubemap(Gfx const& gfx, vk::Sampler sampler, std::span<Image::View const> images, std::string name) : Texture(gfx, sampler, std::move(name)) {
160+
assert(!images.empty());
161+
m_info.format = vk::Format::eR8G8B8A8Srgb;
162+
m_info.array_layers = 6;
163+
m_image = make_image(m_gfx, images, m_info, vk::ImageViewType::eCube);
136164
m_layout = vk::ImageLayout::eShaderReadOnlyOptimal;
137-
full_barrier(m_image.get().get().image_view(), m_info.mip_levels, 1, vk::ImageLayout::eTransferDstOptimal, m_layout).transition(cmd.cb);
138-
if (m_info.mip_levels > 1) { MipMapWriter{m_image.get().get().image, m_image.get().get().extent, cmd.cb, m_info.mip_levels}(); }
139165
}
140166
} // namespace facade

lib/vk/src/vk.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ vk::UniqueDebugUtilsMessengerEXT make_debug_messenger(vk::Instance instance) {
5959
auto const msg = fmt::format("[vk] {}", pCallbackData && pCallbackData->pMessage ? pCallbackData->pMessage : "UNKNOWN");
6060
switch (messageSeverity) {
6161
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: {
62+
logger::error("{}", msg);
6263
throw ValidationError{msg};
6364
}
6465
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: logger::warn("{}", msg); break;

lib/vk/src/vma.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,14 @@ UniqueBuffer Vma::make_buffer(vk::BufferUsageFlags const usage, vk::DeviceSize c
3535
return UniqueBuffer{std::move(ret)};
3636
}
3737

38-
UniqueImage Vma::make_image(ImageCreateInfo const& info, vk::Extent2D const extent) const {
38+
UniqueImage Vma::make_image(ImageCreateInfo const& info, vk::Extent2D const extent, vk::ImageViewType type) const {
3939
if (extent.width == 0 || extent.height == 0) { throw Error{"Attempt to allocate 0-sized image"}; }
4040
auto vaci = VmaAllocationCreateInfo{};
4141
vaci.usage = VMA_MEMORY_USAGE_AUTO;
4242
auto ici = vk::ImageCreateInfo{};
4343
ici.usage = info.usage;
4444
ici.imageType = vk::ImageType::e2D;
45+
if (type == vk::ImageViewType::eCube) { ici.flags |= vk::ImageCreateFlagBits::eCubeCompatible; }
4546
ici.tiling = info.tiling;
4647
ici.arrayLayers = info.array_layers;
4748
ici.mipLevels = info.mip_levels;
@@ -52,16 +53,16 @@ UniqueImage Vma::make_image(ImageCreateInfo const& info, vk::Extent2D const exte
5253
auto image = VkImage{};
5354
auto ret = Image{};
5455
if (vmaCreateImage(allocator, &vici, &vaci, &image, &ret.allocation.allocation, {}) != VK_SUCCESS) { throw Error{"Failed to allocate Vulkan Image"}; }
55-
ret.view = make_image_view(image, info.format, {info.aspect, 0, info.mip_levels, 0, info.array_layers});
56+
ret.view = make_image_view(image, info.format, {info.aspect, 0, info.mip_levels, 0, info.array_layers}, type);
5657
ret.image = image;
5758
ret.allocation.vma = *this;
5859
ret.extent = extent;
5960
return UniqueImage{std::move(ret)};
6061
}
6162

62-
vk::UniqueImageView Vma::make_image_view(vk::Image const image, vk::Format const format, vk::ImageSubresourceRange isr) const {
63+
vk::UniqueImageView Vma::make_image_view(vk::Image const image, vk::Format const format, vk::ImageSubresourceRange isr, vk::ImageViewType type) const {
6364
vk::ImageViewCreateInfo info;
64-
info.viewType = vk::ImageViewType::e2D;
65+
info.viewType = type;
6566
info.format = format;
6667
info.components.r = info.components.g = info.components.b = info.components.a = vk::ComponentSwizzle::eIdentity;
6768
info.subresourceRange = isr;

src/bin/shaders.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <bin/shaders.hpp>
22
#include <bin/default_vert.spv.hpp>
33
#include <bin/lit_frag.spv.hpp>
4+
#include <bin/skybox_frag.spv.hpp>
45
#include <bin/unlit_frag.spv.hpp>
56

67
namespace facade {
@@ -26,4 +27,12 @@ Shader shaders::lit() {
2627
.frag = SpirV::View::from_bytes(to_bytes(lit_frag_v)),
2728
};
2829
}
30+
31+
Shader shaders::skybox() {
32+
return {
33+
.id = "skybox",
34+
.vert = SpirV::View::from_bytes(to_bytes(default_vert_v)),
35+
.frag = SpirV::View::from_bytes(to_bytes(skybox_frag_v)),
36+
};
37+
}
2938
} // namespace facade

src/bin/shaders.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
namespace facade::shaders {
55
Shader unlit();
66
Shader lit();
7+
Shader skybox();
78
} // namespace facade::shaders

0 commit comments

Comments
 (0)