Skip to content

Commit b2be8de

Browse files
Load OBJ sub-meshes and textures into arrays
1 parent 9579d9b commit b2be8de

File tree

1 file changed

+100
-15
lines changed

1 file changed

+100
-15
lines changed

attachments/38_ray_tracing.cpp

Lines changed: 100 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ constexpr uint32_t WIDTH = 800;
3838
constexpr uint32_t HEIGHT = 600;
3939
constexpr uint64_t FenceTimeout = 100000000;
4040
const std::string MODEL_PATH = "models/plant_on_table.obj";
41-
const std::string TEXTURE_PATH = "textures/nettle_plant_diff_4k.png";
4241
constexpr int MAX_FRAMES_IN_FLIGHT = 2;
4342

4443
const std::vector validationLayers = {
@@ -85,6 +84,10 @@ struct UniformBufferObject {
8584
alignas(16) glm::mat4 proj;
8685
};
8786

87+
struct PushConstant {
88+
uint32_t materialIndex;
89+
};
90+
8891
class HelloTriangleApplication {
8992
public:
9093
void run() {
@@ -122,9 +125,9 @@ class HelloTriangleApplication {
122125
vk::raii::DeviceMemory depthImageMemory = nullptr;
123126
vk::raii::ImageView depthImageView = nullptr;
124127

125-
vk::raii::Image textureImage = nullptr;
126-
vk::raii::DeviceMemory textureImageMemory = nullptr;
127-
vk::raii::ImageView textureImageView = nullptr;
128+
std::vector<vk::raii::Image> textureImages;
129+
std::vector<vk::raii::DeviceMemory> textureImageMemories;
130+
std::vector<vk::raii::ImageView> textureImageViews;
128131
vk::raii::Sampler textureSampler = nullptr;
129132

130133
std::vector<Vertex> vertices;
@@ -138,6 +141,17 @@ class HelloTriangleApplication {
138141
std::vector<vk::raii::DeviceMemory> uniformBuffersMemory;
139142
std::vector<void*> uniformBuffersMapped;
140143

144+
struct SubMesh {
145+
uint32_t indexOffset;
146+
uint32_t indexCount;
147+
int materialID;
148+
uint32_t firstVertex;
149+
uint32_t maxVertex;
150+
bool alphaCut;
151+
};
152+
std::vector<SubMesh> submeshes;
153+
std::vector<tinyobj::material_t> materials;
154+
141155
vk::raii::DescriptorPool descriptorPool = nullptr;
142156
std::vector<vk::raii::DescriptorSet> descriptorSets;
143157

@@ -187,8 +201,6 @@ class HelloTriangleApplication {
187201
createGraphicsPipeline();
188202
createCommandPool();
189203
createDepthResources();
190-
createTextureImage();
191-
createTextureImageView();
192204
createTextureSampler();
193205
loadModel();
194206
createVertexBuffer();
@@ -519,7 +531,13 @@ class HelloTriangleApplication {
519531
};
520532
vk::PipelineDynamicStateCreateInfo dynamicState{ .dynamicStateCount = static_cast<uint32_t>(dynamicStates.size()), .pDynamicStates = dynamicStates.data() };
521533

522-
vk::PipelineLayoutCreateInfo pipelineLayoutInfo{ .setLayoutCount = 1, .pSetLayouts = &*descriptorSetLayout, .pushConstantRangeCount = 0 };
534+
vk::PushConstantRange pushConstantRange {
535+
.stageFlags = vk::ShaderStageFlagBits::eFragment,
536+
.offset = 0,
537+
.size = sizeof(PushConstant)
538+
};
539+
540+
vk::PipelineLayoutCreateInfo pipelineLayoutInfo{ .setLayoutCount = 1, .pSetLayouts = &*descriptorSetLayout, .pushConstantRangeCount = 1, .pPushConstantRanges = &pushConstantRange };
523541

524542
pipelineLayout = vk::raii::PipelineLayout(device, pipelineLayoutInfo);
525543

@@ -589,9 +607,9 @@ class HelloTriangleApplication {
589607
return format == vk::Format::eD32SfloatS8Uint || format == vk::Format::eD24UnormS8Uint;
590608
}
591609

592-
void createTextureImage() {
610+
std::pair<vk::raii::Image, vk::raii::DeviceMemory> createTextureImage(const std::string& path) {
593611
int texWidth, texHeight, texChannels;
594-
stbi_uc* pixels = stbi_load(TEXTURE_PATH.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
612+
stbi_uc* pixels = stbi_load(path.c_str(), &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
595613
vk::DeviceSize imageSize = texWidth * texHeight * 4;
596614

597615
if (!pixels) {
@@ -608,15 +626,20 @@ class HelloTriangleApplication {
608626

609627
stbi_image_free(pixels);
610628

629+
vk::raii::Image textureImage = nullptr;
630+
vk::raii::DeviceMemory textureImageMemory = nullptr;
631+
611632
createImage(texWidth, texHeight, vk::Format::eR8G8B8A8Srgb, vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled, vk::MemoryPropertyFlagBits::eDeviceLocal, textureImage, textureImageMemory);
612633

613634
transitionImageLayout(textureImage, vk::ImageLayout::eUndefined, vk::ImageLayout::eTransferDstOptimal);
614635
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
615636
transitionImageLayout(textureImage, vk::ImageLayout::eTransferDstOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
637+
638+
return std::make_pair(std::move(textureImage), std::move(textureImageMemory));
616639
}
617640

618-
void createTextureImageView() {
619-
textureImageView = createImageView(textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageAspectFlagBits::eColor);
641+
vk::raii::ImageView createTextureImageView(vk::raii::Image& textureImage) {
642+
return createImageView(textureImage, vk::Format::eR8G8B8A8Srgb, vk::ImageAspectFlagBits::eColor);
620643
}
621644

622645
void createTextureSampler() {
@@ -720,16 +743,27 @@ class HelloTriangleApplication {
720743
void loadModel() {
721744
tinyobj::attrib_t attrib;
722745
std::vector<tinyobj::shape_t> shapes;
723-
std::vector<tinyobj::material_t> materials;
746+
std::vector<tinyobj::material_t> localMaterials;
724747
std::string warn, err;
725748

726-
if (!LoadObj(&attrib, &shapes, &materials, &warn, &err, MODEL_PATH.c_str())) {
749+
if (!LoadObj(&attrib, &shapes, &localMaterials, &warn, &err, MODEL_PATH.c_str(), MODEL_PATH.substr(0, MODEL_PATH.find_last_of("/\\")).c_str())) {
727750
throw std::runtime_error(warn + err);
728751
}
729752

753+
size_t materialOffset = materials.size();
754+
size_t oldTextureCount = textureImageViews.size();
755+
756+
materials.insert(materials.end(), localMaterials.begin(), localMaterials.end());
757+
730758
std::unordered_map<Vertex, uint32_t> uniqueVertices{};
759+
uint32_t indexOffset = 0;
731760

732761
for (const auto& shape : shapes) {
762+
std::cout << "Loading mesh: " << shape.name << ": " << shape.mesh.indices.size()/3 << " triangles\n";
763+
764+
uint32_t startOffset = indexOffset;
765+
uint32_t localMaxV = 0;
766+
733767
for (const auto& index : shape.mesh.indices) {
734768
Vertex vertex{};
735769

@@ -752,6 +786,51 @@ class HelloTriangleApplication {
752786
}
753787

754788
indices.push_back(uniqueVertices[vertex]);
789+
790+
indexOffset++;
791+
792+
uint32_t vi;
793+
auto it = uniqueVertices.find(vertex);
794+
if (it != uniqueVertices.end()) {
795+
vi = it->second;
796+
} else {
797+
vi = static_cast<uint32_t>(vertices.size());
798+
uniqueVertices[vertex] = vi;
799+
vertices.push_back(vertex);
800+
}
801+
802+
localMaxV = std::max(localMaxV, vi);
803+
}
804+
805+
int localMaterialID = shape.mesh.material_ids.empty() ? -1 : shape.mesh.material_ids[0];
806+
int globalMaterialID = (localMaterialID < 0) ? -1 : static_cast<int>(materialOffset + localMaterialID);
807+
808+
uint32_t indexCount = indexOffset - startOffset;
809+
810+
// Note that this is only valid for this particular MODEL_PATH
811+
bool alphaCut = (shape.name.find("nettle_plant") != std::string::npos);
812+
813+
submeshes.push_back({
814+
.indexOffset = startOffset,
815+
.indexCount = indexCount,
816+
.materialID = globalMaterialID,
817+
.firstVertex = 0u,
818+
.maxVertex = localMaxV + 1,
819+
.alphaCut = alphaCut
820+
});
821+
}
822+
823+
for (size_t i = 0; i < localMaterials.size(); ++i) {
824+
const auto& material = localMaterials[i];
825+
826+
if (!material.diffuse_texname.empty()) {
827+
std::string texturePath = MODEL_PATH.substr(0, MODEL_PATH.find_last_of("/\\")) + "/" + material.diffuse_texname;
828+
auto [img, mem] = createTextureImage(texturePath);
829+
textureImages.push_back(std::move(img));
830+
textureImageMemories.push_back(std::move(mem));
831+
textureImageViews.emplace_back(createTextureImageView(textureImages.back()));
832+
} else {
833+
std::cout << "No texture for material: " << material.name << std::endl;
755834
}
756835
}
757836
}
@@ -836,7 +915,7 @@ class HelloTriangleApplication {
836915
};
837916
vk::DescriptorImageInfo imageInfo{
838917
.sampler = textureSampler,
839-
.imageView = textureImageView,
918+
.imageView = textureImageViews[0],
840919
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal
841920
};
842921
std::array descriptorWrites{
@@ -1001,7 +1080,13 @@ class HelloTriangleApplication {
10011080
commandBuffers[currentFrame].bindVertexBuffers(0, *vertexBuffer, {0});
10021081
commandBuffers[currentFrame].bindIndexBuffer( *indexBuffer, 0, vk::IndexType::eUint32 );
10031082
commandBuffers[currentFrame].bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, *descriptorSets[currentFrame], nullptr);
1004-
commandBuffers[currentFrame].drawIndexed(indices.size(), 1, 0, 0, 0);
1083+
1084+
for (auto& sub : submeshes) {
1085+
uint32_t idx = sub.materialID < 0 ? 0u : static_cast<uint32_t>(sub.materialID);
1086+
commandBuffers[currentFrame].pushConstants<PushConstant>(pipelineLayout, vk::ShaderStageFlagBits::eFragment, 0, PushConstant{ .materialIndex = idx });
1087+
commandBuffers[currentFrame].drawIndexed(sub.indexCount, 1, sub.indexOffset, 0, 0);
1088+
}
1089+
10051090
commandBuffers[currentFrame].endRendering();
10061091
// After rendering, transition the swapchain image to PRESENT_SRC
10071092
transition_image_layout(

0 commit comments

Comments
 (0)