MXVK Vulkan Framework 0.35.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
mxvk::VK_Sprite3D Class Reference

Depth-tested 3D billboard sprite batch. More...

#include <mxvk/include/mxvk/mxvk_sprite3d.hpp>

Public Member Functions

void cleanup ()
 Destroy all owned Vulkan resources.
void clearQueue ()
 Discard all queued sprite draws without rendering them.
void drawSprite (const glm::vec3 &position, const glm::vec2 &size, const glm::vec4 &color=glm::vec4(1.0f), float rotationRadians=0.0f)
 Queue a billboard sprite for rendering.
int getHeight () const
int getWidth () const
void load (VK_Window *window, const std::string &pngPath, const std::string &vertexShaderPath="", const std::string &fragmentShaderPath="")
 Load sprite texture and build the 3D billboard pipeline from a PNG file.
void load (VK_Window *window, SDL_Surface *surface, const std::string &vertexShaderPath="", const std::string &fragmentShaderPath="")
 Load sprite texture and build the 3D billboard pipeline from an SDL surface.
bool loaded () const
VK_Sprite3D & operator= (const VK_Sprite3D &)=delete
VK_Sprite3D & operator= (VK_Sprite3D &&)=delete
void render (VkCommandBuffer cmd, uint32_t imageIndex)
 Record all queued billboard draws into the given command buffer.
void resize (VK_Window *window)
 Rebuild swapchain-dependent resources after resize.
void setAlphaDiscardThreshold (float threshold)
 Set the alpha threshold used to discard transparent texels.
void setDepthTestEnabled (bool enabled)
 Enable or disable depth testing for the 3D sprite pipeline.
void setDepthWriteEnabled (bool enabled)
 Enable or disable depth writes for the 3D sprite pipeline.
void updateCamera (uint32_t imageIndex, const glm::mat4 &view, const glm::mat4 &proj)
 Upload the current camera matrices for one swapchain image.
 VK_Sprite3D ()=default
 Construct an empty 3D sprite batch.
 VK_Sprite3D (const VK_Sprite3D &)=delete
 VK_Sprite3D (VK_Sprite3D &&)=delete
 ~VK_Sprite3D ()
 Destroy owned Vulkan resources.

Detailed Description

Depth-tested 3D billboard sprite batch.

VK_Sprite3D renders textured quads in world space. Each queued sprite is camera-facing, uses the view/projection matrix supplied with updateCamera(), and participates in the same dynamic-rendering pass as models.

Definition at line 33 of file mxvk_sprite3d.hpp.

Constructor & Destructor Documentation

◆ VK_Sprite3D() [1/3]

mxvk::VK_Sprite3D::VK_Sprite3D ( )
default

Construct an empty 3D sprite batch.

◆ ~VK_Sprite3D()

mxvk::VK_Sprite3D::~VK_Sprite3D ( )

Destroy owned Vulkan resources.

Definition at line 30 of file mxvk_sprite3d.cpp.

30{ cleanup(); }
void cleanup()
Destroy all owned Vulkan resources.

◆ VK_Sprite3D() [2/3]

mxvk::VK_Sprite3D::VK_Sprite3D ( const VK_Sprite3D & )
delete

◆ VK_Sprite3D() [3/3]

mxvk::VK_Sprite3D::VK_Sprite3D ( VK_Sprite3D && )
delete

Member Function Documentation

◆ cleanup()

void mxvk::VK_Sprite3D::cleanup ( )

Destroy all owned Vulkan resources.

Definition at line 176 of file mxvk_sprite3d.cpp.

176 {
177 if (device != VK_NULL_HANDLE) {
178 vkDeviceWaitIdle(device);
179 }
180 drawQueue.clear();
181 destroyPipeline();
182 destroyDescriptors();
183 destroyCameraBuffers();
184 destroyBuffers();
185 destroyTexture();
186
187 device = VK_NULL_HANDLE;
188 physicalDevice = VK_NULL_HANDLE;
189 graphicsQueue = VK_NULL_HANDLE;
190 commandPool = VK_NULL_HANDLE;
191 colorAttachmentFormat = VK_FORMAT_UNDEFINED;
192 depthAttachmentFormat = VK_FORMAT_UNDEFINED;
193 imageCount = 0;
194 spriteLoaded = false;
195 }

◆ clearQueue()

void mxvk::VK_Sprite3D::clearQueue ( )

Discard all queued sprite draws without rendering them.

Definition at line 132 of file mxvk_sprite3d.cpp.

132{ drawQueue.clear(); }

◆ drawSprite()

void mxvk::VK_Sprite3D::drawSprite ( const glm::vec3 & position,
const glm::vec2 & size,
const glm::vec4 & color = glm::vec4(1.0f),
float rotationRadians = 0.0f )

Queue a billboard sprite for rendering.

Parameters
positionWorld-space center position.
sizeBillboard size in world units.
colorPer-sprite tint color.
rotationRadiansRotation around the camera-facing axis.

Definition at line 93 of file mxvk_sprite3d.cpp.

93 {
94 if (!spriteLoaded) {
95 throw mxvk::Exception("VK_Sprite3D::drawSprite called before sprite was loaded");
96 }
97 if (size.x <= 0.0f || size.y <= 0.0f) {
98 return;
99 }
100 drawQueue.push_back({position, size, color, rotationRadians});
101 }

◆ getHeight()

int mxvk::VK_Sprite3D::getHeight ( ) const
inlinenodiscard
Returns
Sprite texture height in pixels.

Definition at line 131 of file mxvk_sprite3d.hpp.

131{ return spriteHeight; }

◆ getWidth()

int mxvk::VK_Sprite3D::getWidth ( ) const
inlinenodiscard
Returns
Sprite texture width in pixels.

Definition at line 129 of file mxvk_sprite3d.hpp.

129{ return spriteWidth; }

◆ load() [1/2]

void mxvk::VK_Sprite3D::load ( VK_Window * window,
const std::string & pngPath,
const std::string & vertexShaderPath = "",
const std::string & fragmentShaderPath = "" )

Load sprite texture and build the 3D billboard pipeline from a PNG file.

Parameters
windowActive MXVK window.
pngPathPath to the PNG file.
vertexShaderPathOptional custom vertex shader SPIR-V path.
fragmentShaderPathOptional custom fragment shader SPIR-V path.

Definition at line 32 of file mxvk_sprite3d.cpp.

32 {
33 SDL_Surface *surface = mxvk::LoadPNG(pngPath.c_str());
34 if (surface == nullptr) {
35 throw mxvk::Exception("Failed to load 3D sprite image: " + pngPath);
36 }
37 load(window, surface, vertexPath, fragmentPath);
38 SDL_DestroySurface(surface);
39 std::cout << std::format("mxvk: Loaded 3D sprite PNG: {}\n", pngPath);
40 }
void load(VK_Window *window, const std::string &pngPath, const std::string &vertexShaderPath="", const std::string &fragmentShaderPath="")
Load sprite texture and build the 3D billboard pipeline from a PNG file.
SDL_Surface * LoadPNG(const char *file)
Load a PNG file into an SDL_Surface.
Definition mxvk_png.cpp:89

◆ load() [2/2]

void mxvk::VK_Sprite3D::load ( VK_Window * window,
SDL_Surface * surface,
const std::string & vertexShaderPath = "",
const std::string & fragmentShaderPath = "" )

Load sprite texture and build the 3D billboard pipeline from an SDL surface.

Parameters
windowActive MXVK window.
surfaceSource surface pointer.
vertexShaderPathOptional custom vertex shader SPIR-V path.
fragmentShaderPathOptional custom fragment shader SPIR-V path.

Definition at line 42 of file mxvk_sprite3d.cpp.

42 {
43 if (window == nullptr) {
44 throw mxvk::Exception("VK_Sprite3D::load called with null window");
45 }
46 if (surface == nullptr) {
47 throw mxvk::Exception("VK_Sprite3D::load called with null surface");
48 }
49
50 cleanup();
51
52 device = window->getDevice();
53 physicalDevice = window->getPhysicalDevice();
54 graphicsQueue = window->getGraphicsQueue();
55 commandPool = window->getCommandPool();
56 pipelineCache = window->getPipelineCache();
57 colorAttachmentFormat = window->getSwapchainFormat();
58 depthAttachmentFormat = window->getDepthFormat();
59 imageCount = window->getSwapchainImageCount();
60 vertexShaderPath = vertexPath.empty() ? (std::filesystem::path(MXVK_SPRITE3D_SHADER_DIR) / "sprite3d.vert.spv").string() : vertexPath;
61 fragmentShaderPath = fragmentPath.empty() ? (std::filesystem::path(MXVK_SPRITE3D_SHADER_DIR) / "sprite3d.frag.spv").string() : fragmentPath;
62
63 if (device == VK_NULL_HANDLE || physicalDevice == VK_NULL_HANDLE || graphicsQueue == VK_NULL_HANDLE || commandPool == VK_NULL_HANDLE) {
64 throw mxvk::Exception("Cannot create 3D sprite before Vulkan render resources are available");
65 }
66 if (colorAttachmentFormat == VK_FORMAT_UNDEFINED || imageCount == 0) {
67 throw mxvk::Exception("Cannot create 3D sprite before swapchain resources are available");
68 }
69
70 createTexture(surface);
71 createSampler();
72 createQuadBuffers();
73 createDescriptorSetLayout();
74 createCameraBuffers();
75 createDescriptorPool();
76 createDescriptorSets();
77 createPipeline();
78 spriteLoaded = true;
79 std::cout << std::format("mxvk: Created 3D sprite: {}x{}\n", spriteWidth, spriteHeight);
80 }

◆ loaded()

bool mxvk::VK_Sprite3D::loaded ( ) const
inlinenodiscard
Returns
true if the sprite texture and pipeline are loaded.

Definition at line 127 of file mxvk_sprite3d.hpp.

127{ return spriteLoaded; }

◆ operator=() [1/2]

VK_Sprite3D & mxvk::VK_Sprite3D::operator= ( const VK_Sprite3D & )
delete

◆ operator=() [2/2]

VK_Sprite3D & mxvk::VK_Sprite3D::operator= ( VK_Sprite3D && )
delete

◆ render()

void mxvk::VK_Sprite3D::render ( VkCommandBuffer cmd,
uint32_t imageIndex )

Record all queued billboard draws into the given command buffer.

Parameters
cmdActive command buffer.
imageIndexCurrent swapchain image index.

Definition at line 103 of file mxvk_sprite3d.cpp.

103 {
104 if (!spriteLoaded || drawQueue.empty() || imageIndex >= descriptorSets.size()) {
105 return;
106 }
107
108 vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
109 vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[imageIndex], 0, nullptr);
110
111 VkBuffer vertexBuffers[] = {vertexBuffer};
112 VkDeviceSize offsets[] = {0};
113 vkCmdBindVertexBuffers(cmd, 0, 1, vertexBuffers, offsets);
114 vkCmdBindIndexBuffer(cmd, indexBuffer, 0, VK_INDEX_TYPE_UINT16);
115
116 struct PushConstants {
117 glm::vec4 positionSizeX;
118 glm::vec4 color;
119 glm::vec4 sizeYRotationAlpha;
120 };
121
122 for (const DrawCmd &draw : drawQueue) {
123 PushConstants pc{};
124 pc.positionSizeX = glm::vec4(draw.position, draw.size.x);
125 pc.color = draw.color;
126 pc.sizeYRotationAlpha = glm::vec4(draw.size.y, draw.rotationRadians, alphaDiscardThreshold, 0.0f);
127 vkCmdPushConstants(cmd, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants), &pc);
128 vkCmdDrawIndexed(cmd, 6, 1, 0, 0, 0);
129 }
130 }

◆ resize()

void mxvk::VK_Sprite3D::resize ( VK_Window * window)

Rebuild swapchain-dependent resources after resize.

Parameters
windowActive MXVK window.

Definition at line 154 of file mxvk_sprite3d.cpp.

154 {
155 if (window == nullptr || !spriteLoaded) {
156 return;
157 }
158
159 colorAttachmentFormat = window->getSwapchainFormat();
160 depthAttachmentFormat = window->getDepthFormat();
161 const size_t newImageCount = window->getSwapchainImageCount();
162
163 if (newImageCount != imageCount) {
164 imageCount = newImageCount;
165 destroyDescriptors();
166 destroyCameraBuffers();
167 createDescriptorSetLayout();
168 createCameraBuffers();
169 createDescriptorPool();
170 createDescriptorSets();
171 }
172
173 createPipeline();
174 }

◆ setAlphaDiscardThreshold()

void mxvk::VK_Sprite3D::setAlphaDiscardThreshold ( float threshold)
inline

Set the alpha threshold used to discard transparent texels.

Parameters
thresholdAlpha cutoff value.

Definition at line 113 of file mxvk_sprite3d.hpp.

113{ alphaDiscardThreshold = threshold; }

◆ setDepthTestEnabled()

void mxvk::VK_Sprite3D::setDepthTestEnabled ( bool enabled)

Enable or disable depth testing for the 3D sprite pipeline.

Parameters
enabledtrue to enable depth testing.

Definition at line 134 of file mxvk_sprite3d.cpp.

134 {
135 if (depthTestEnabled == enabled) {
136 return;
137 }
138 depthTestEnabled = enabled;
139 if (spriteLoaded) {
140 createPipeline();
141 }
142 }

◆ setDepthWriteEnabled()

void mxvk::VK_Sprite3D::setDepthWriteEnabled ( bool enabled)

Enable or disable depth writes for the 3D sprite pipeline.

Parameters
enabledtrue to write depth values.

Definition at line 144 of file mxvk_sprite3d.cpp.

144 {
145 if (depthWriteEnabled == enabled) {
146 return;
147 }
148 depthWriteEnabled = enabled;
149 if (spriteLoaded) {
150 createPipeline();
151 }
152 }

◆ updateCamera()

void mxvk::VK_Sprite3D::updateCamera ( uint32_t imageIndex,
const glm::mat4 & view,
const glm::mat4 & proj )

Upload the current camera matrices for one swapchain image.

Parameters
imageIndexSwapchain image index.
viewView matrix.
projProjection matrix.

Definition at line 82 of file mxvk_sprite3d.cpp.

82 {
83 if (imageIndex >= cameraBuffersMapped.size() || cameraBuffersMapped[imageIndex] == nullptr) {
84 return;
85 }
86
87 CameraUBO camera{};
88 camera.view = view;
89 camera.proj = proj;
90 std::memcpy(cameraBuffersMapped[imageIndex], &camera, sizeof(camera));
91 }

The documentation for this class was generated from the following files: