Self-contained model loading (from ASSIMP) for better comprehensibility

This commit is contained in:
saschawillems 2017-02-10 21:27:23 +01:00
parent d26fb8831e
commit a91be23d76

View file

@ -16,6 +16,12 @@
#define GLM_FORCE_DEPTH_ZERO_TO_ONE #define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <assimp/cimport.h>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include "vulkanexamplebase.h" #include "vulkanexamplebase.h"
@ -181,45 +187,80 @@ public:
// The other example will use the VulkanMesh loader which has some additional functionality for loading meshes // The other example will use the VulkanMesh loader which has some additional functionality for loading meshes
void loadMesh() void loadMesh()
{ {
VulkanMeshLoader *meshLoader = new VulkanMeshLoader(vulkanDevice); std::string filename = getAssetPath() + "models/voyager/voyager.dae";
#if defined(__ANDROID__)
meshLoader->assetManager = androidApp->activity->assetManager;
#endif
meshLoader->LoadMesh(getAssetPath() + "models/voyager/voyager.dae");
// Generate vertex buffer // Load the model from file using ASSIMP
const aiScene* scene;
Assimp::Importer Importer;
// Flags for loading the mesh
static const int assimpFlags = aiProcess_FlipWindingOrder | aiProcess_Triangulate | aiProcess_PreTransformVertices;
#if defined(__ANDROID__)
// Meshes are stored inside the apk on Android (compressed)
// So they need to be loaded via the asset manager
AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING);
assert(asset);
size_t size = AAsset_getLength(asset);
assert(size > 0);
void *meshData = malloc(size);
AAsset_read(asset, meshData, size);
AAsset_close(asset);
scene = Importer.ReadFileFromMemory(meshData, size, assimpFlags);
free(meshData);
#else
scene = Importer.ReadFile(filename.c_str(), assimpFlags);
#endif
// Generate vertex buffer from ASSIMP scene data
float scale = 1.0f; float scale = 1.0f;
std::vector<Vertex> vertexBuffer; std::vector<Vertex> vertexBuffer;
// Iterate through all meshes in the file
// and extract the vertex information used in this demo // Iterate through all meshes in the file and extract the vertex components
for (uint32_t m = 0; m < meshLoader->m_Entries.size(); m++) for (uint32_t m = 0; m < scene->mNumMeshes; m++)
{ {
for (uint32_t i = 0; i < meshLoader->m_Entries[m].Vertices.size(); i++) for (uint32_t v = 0; v < scene->mMeshes[m]->mNumVertices; v++)
{ {
Vertex vertex; Vertex vertex;
vertex.pos = meshLoader->m_Entries[m].Vertices[i].m_pos * scale; // Use glm make_* functions to convert ASSIMP vectors to glm vectors
vertex.normal = meshLoader->m_Entries[m].Vertices[i].m_normal; vertex.pos = glm::make_vec3(&scene->mMeshes[m]->mVertices[v].x) * scale;
vertex.uv = meshLoader->m_Entries[m].Vertices[i].m_tex; vertex.normal = glm::make_vec3(&scene->mMeshes[m]->mNormals[v].x);
vertex.color = meshLoader->m_Entries[m].Vertices[i].m_color; // Texture coordinates and colors may have multiple channels, we only use the first [0] one
vertex.uv = glm::make_vec2(&scene->mMeshes[m]->mTextureCoords[0][v].x);
// Mesh may not have vertex colors
vertex.color = (scene->mMeshes[m]->HasVertexColors(0)) ? glm::make_vec3(&scene->mMeshes[m]->mColors[0][v].r) : glm::vec3(1.0f);
// Vulkan uses a right-handed NDC (contrary to OpenGL), so simply flip Y-Axis
vertex.pos.y *= -1.0f;
vertexBuffer.push_back(vertex); vertexBuffer.push_back(vertex);
} }
} }
uint32_t vertexBufferSize = vertexBuffer.size() * sizeof(Vertex); size_t vertexBufferSize = vertexBuffer.size() * sizeof(Vertex);
// Generate index buffer from loaded mesh file // Generate index buffer from ASSIMP scene data
std::vector<uint32_t> indexBuffer; std::vector<uint32_t> indexBuffer;
for (uint32_t m = 0; m < meshLoader->m_Entries.size(); m++) for (uint32_t m = 0; m < scene->mNumMeshes; m++)
{ {
uint32_t indexBase = indexBuffer.size(); uint32_t indexBase = static_cast<uint32_t>(indexBuffer.size());
for (uint32_t i = 0; i < meshLoader->m_Entries[m].Indices.size(); i++) for (uint32_t f = 0; f < scene->mMeshes[m]->mNumFaces; f++)
{ {
indexBuffer.push_back(meshLoader->m_Entries[m].Indices[i] + indexBase); // We assume that all faces are triangulated
for (uint32_t i = 0; i < 3; i++)
{
indexBuffer.push_back(scene->mMeshes[m]->mFaces[f].mIndices[i] + indexBase);
} }
} }
uint32_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t); }
mesh.indices.count = indexBuffer.size(); size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t);
mesh.indices.count = static_cast<uint32_t>(indexBuffer.size());
// Static mesh should always be device local // Static mesh should always be device local
@ -313,8 +354,6 @@ public:
&mesh.indices.mem, &mesh.indices.mem,
indexBuffer.data())); indexBuffer.data()));
} }
delete(meshLoader);
} }
void loadAssets() void loadAssets()
@ -341,33 +380,33 @@ public:
VERTEX_BUFFER_BIND_ID, VERTEX_BUFFER_BIND_ID,
0, 0,
VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
0); offsetof(Vertex, pos));
// Location 1 : Normal // Location 1 : Normal
vertices.attributeDescriptions[1] = vertices.attributeDescriptions[1] =
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID, VERTEX_BUFFER_BIND_ID,
1, 1,
VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 3); offsetof(Vertex, normal));
// Location 2 : Texture coordinates // Location 2 : Texture coordinates
vertices.attributeDescriptions[2] = vertices.attributeDescriptions[2] =
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID, VERTEX_BUFFER_BIND_ID,
2, 2,
VK_FORMAT_R32G32_SFLOAT, VK_FORMAT_R32G32_SFLOAT,
sizeof(float) * 6); offsetof(Vertex, uv));
// Location 3 : Color // Location 3 : Color
vertices.attributeDescriptions[3] = vertices.attributeDescriptions[3] =
vkTools::initializers::vertexInputAttributeDescription( vkTools::initializers::vertexInputAttributeDescription(
VERTEX_BUFFER_BIND_ID, VERTEX_BUFFER_BIND_ID,
3, 3,
VK_FORMAT_R32G32B32_SFLOAT, VK_FORMAT_R32G32B32_SFLOAT,
sizeof(float) * 8); offsetof(Vertex, color));
vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo(); vertices.inputState = vkTools::initializers::pipelineVertexInputStateCreateInfo();
vertices.inputState.vertexBindingDescriptionCount = vertices.bindingDescriptions.size(); vertices.inputState.vertexBindingDescriptionCount = static_cast<uint32_t>(vertices.bindingDescriptions.size());
vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data(); vertices.inputState.pVertexBindingDescriptions = vertices.bindingDescriptions.data();
vertices.inputState.vertexAttributeDescriptionCount = vertices.attributeDescriptions.size(); vertices.inputState.vertexAttributeDescriptionCount = static_cast<uint32_t>(vertices.attributeDescriptions.size());
vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data(); vertices.inputState.pVertexAttributeDescriptions = vertices.attributeDescriptions.data();
} }
@ -382,7 +421,7 @@ public:
VkDescriptorPoolCreateInfo descriptorPoolInfo = VkDescriptorPoolCreateInfo descriptorPoolInfo =
vkTools::initializers::descriptorPoolCreateInfo( vkTools::initializers::descriptorPoolCreateInfo(
poolSizes.size(), static_cast<uint32_t>(poolSizes.size()),
poolSizes.data(), poolSizes.data(),
1); 1);
@ -408,7 +447,7 @@ public:
VkDescriptorSetLayoutCreateInfo descriptorLayout = VkDescriptorSetLayoutCreateInfo descriptorLayout =
vkTools::initializers::descriptorSetLayoutCreateInfo( vkTools::initializers::descriptorSetLayoutCreateInfo(
setLayoutBindings.data(), setLayoutBindings.data(),
setLayoutBindings.size()); static_cast<uint32_t>(setLayoutBindings.size()));
VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout)); VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorLayout, nullptr, &descriptorSetLayout));
@ -452,7 +491,7 @@ public:
&texDescriptor) &texDescriptor)
}; };
vkUpdateDescriptorSets(device, writeDescriptorSets.size(), writeDescriptorSets.data(), 0, NULL); vkUpdateDescriptorSets(device, static_cast<uint32_t>(writeDescriptorSets.size()), writeDescriptorSets.data(), 0, NULL);
} }
void preparePipelines() void preparePipelines()
@ -501,7 +540,7 @@ public:
VkPipelineDynamicStateCreateInfo dynamicState = VkPipelineDynamicStateCreateInfo dynamicState =
vkTools::initializers::pipelineDynamicStateCreateInfo( vkTools::initializers::pipelineDynamicStateCreateInfo(
dynamicStateEnables.data(), dynamicStateEnables.data(),
dynamicStateEnables.size(), static_cast<uint32_t>(dynamicStateEnables.size()),
0); 0);
// Solid rendering pipeline // Solid rendering pipeline
@ -525,7 +564,7 @@ public:
pipelineCreateInfo.pViewportState = &viewportState; pipelineCreateInfo.pViewportState = &viewportState;
pipelineCreateInfo.pDepthStencilState = &depthStencilState; pipelineCreateInfo.pDepthStencilState = &depthStencilState;
pipelineCreateInfo.pDynamicState = &dynamicState; pipelineCreateInfo.pDynamicState = &dynamicState;
pipelineCreateInfo.stageCount = shaderStages.size(); pipelineCreateInfo.stageCount = static_cast<uint32_t>(shaderStages.size());
pipelineCreateInfo.pStages = shaderStages.data(); pipelineCreateInfo.pStages = shaderStages.data();
VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.solid)); VK_CHECK_RESULT(vkCreateGraphicsPipelines(device, pipelineCache, 1, &pipelineCreateInfo, nullptr, &pipelines.solid));