MXVK Vulkan Framework 0.24.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_Sprite3Doperator= (const VK_Sprite3D &)=delete
VK_Sprite3Doperator= (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 {
31 cleanup();
32 }
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 191 of file mxvk_sprite3d.cpp.

191 {
192 if (device != VK_NULL_HANDLE) {
193 vkDeviceWaitIdle(device);
194 }
195 drawQueue.clear();
196 destroyPipeline();
197 destroyDescriptors();
198 destroyCameraBuffers();
199 destroyBuffers();
200 destroyTexture();
201
202 device = VK_NULL_HANDLE;
203 physicalDevice = VK_NULL_HANDLE;
204 graphicsQueue = VK_NULL_HANDLE;
205 commandPool = VK_NULL_HANDLE;
206 colorAttachmentFormat = VK_FORMAT_UNDEFINED;
207 depthAttachmentFormat = VK_FORMAT_UNDEFINED;
208 imageCount = 0;
209 spriteLoaded = false;
210 }

◆ clearQueue()

void mxvk::VK_Sprite3D::clearQueue ( )

Discard all queued sprite draws without rendering them.

Definition at line 145 of file mxvk_sprite3d.cpp.

145 {
146 drawQueue.clear();
147 }

◆ 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 101 of file mxvk_sprite3d.cpp.

104 {
105 if (!spriteLoaded) {
106 throw mxvk::Exception("VK_Sprite3D::drawSprite called before sprite was loaded");
107 }
108 if (size.x <= 0.0f || size.y <= 0.0f) {
109 return;
110 }
111 drawQueue.push_back({position, size, color, rotationRadians});
112 }

◆ getHeight()

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

Definition at line 140 of file mxvk_sprite3d.hpp.

140{ return spriteHeight; }

◆ getWidth()

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

Definition at line 138 of file mxvk_sprite3d.hpp.

138{ 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 34 of file mxvk_sprite3d.cpp.

37 {
38 SDL_Surface *surface = mxvk::LoadPNG(pngPath.c_str());
39 if (surface == nullptr) {
40 throw mxvk::Exception("Failed to load 3D sprite image: " + pngPath);
41 }
42 load(window, surface, vertexPath, fragmentPath);
43 SDL_DestroySurface(surface);
44 std::cout << std::format("mxvk: Loaded 3D sprite PNG: {}\n", pngPath);
45 }
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:103

◆ 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 47 of file mxvk_sprite3d.cpp.

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

◆ loaded()

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

Definition at line 136 of file mxvk_sprite3d.hpp.

136{ 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 114 of file mxvk_sprite3d.cpp.

114 {
115 if (!spriteLoaded || drawQueue.empty() || imageIndex >= descriptorSets.size()) {
116 return;
117 }
118
119 vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
120 vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout,
121 0, 1, &descriptorSets[imageIndex], 0, nullptr);
122
123 VkBuffer vertexBuffers[] = {vertexBuffer};
124 VkDeviceSize offsets[] = {0};
125 vkCmdBindVertexBuffers(cmd, 0, 1, vertexBuffers, offsets);
126 vkCmdBindIndexBuffer(cmd, indexBuffer, 0, VK_INDEX_TYPE_UINT16);
127
128 struct PushConstants {
129 glm::vec4 positionSizeX;
130 glm::vec4 color;
131 glm::vec4 sizeYRotationAlpha;
132 };
133
134 for (const DrawCmd &draw : drawQueue) {
135 PushConstants pc{};
136 pc.positionSizeX = glm::vec4(draw.position, draw.size.x);
137 pc.color = draw.color;
138 pc.sizeYRotationAlpha = glm::vec4(draw.size.y, draw.rotationRadians, alphaDiscardThreshold, 0.0f);
139 vkCmdPushConstants(cmd, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
140 0, sizeof(PushConstants), &pc);
141 vkCmdDrawIndexed(cmd, 6, 1, 0, 0, 0);
142 }
143 }

◆ resize()

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

Rebuild swapchain-dependent resources after resize.

Parameters
windowActive MXVK window.

Definition at line 169 of file mxvk_sprite3d.cpp.

169 {
170 if (window == nullptr || !spriteLoaded) {
171 return;
172 }
173
174 colorAttachmentFormat = window->getSwapchainFormat();
175 depthAttachmentFormat = window->getDepthFormat();
176 const size_t newImageCount = window->getSwapchainImageCount();
177
178 if (newImageCount != imageCount) {
179 imageCount = newImageCount;
180 destroyDescriptors();
181 destroyCameraBuffers();
182 createDescriptorSetLayout();
183 createCameraBuffers();
184 createDescriptorPool();
185 createDescriptorSets();
186 }
187
188 createPipeline();
189 }

◆ 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 122 of file mxvk_sprite3d.hpp.

122{ 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 149 of file mxvk_sprite3d.cpp.

149 {
150 if (depthTestEnabled == enabled) {
151 return;
152 }
153 depthTestEnabled = enabled;
154 if (spriteLoaded) {
155 createPipeline();
156 }
157 }

◆ 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 159 of file mxvk_sprite3d.cpp.

159 {
160 if (depthWriteEnabled == enabled) {
161 return;
162 }
163 depthWriteEnabled = enabled;
164 if (spriteLoaded) {
165 createPipeline();
166 }
167 }

◆ 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 90 of file mxvk_sprite3d.cpp.

90 {
91 if (imageIndex >= cameraBuffersMapped.size() || cameraBuffersMapped[imageIndex] == nullptr) {
92 return;
93 }
94
95 CameraUBO camera{};
96 camera.view = view;
97 camera.proj = proj;
98 std::memcpy(cameraBuffersMapped[imageIndex], &camera, sizeof(camera));
99 }

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