前言
- 加快vulkan的应用速度,直接分析model加载的代码。
- 这些示例详细展示了如何实现 glTF 2.0 3D 格式 3D 传输文件格式的不同功能。
- 展示如何从 glTF 2.0 文件加载完整的场景。 glTF 2.0 场景的结构被转换为使用 Vulkan 渲染场景所需的数据结构。
一、文件结构分析
- 直接定义了一个VulkanglTFModel类
- 包含在 Vulkan 中渲染 glTF 模型所需的一切,此类经过了大量简化(与 glTF 的功能集相比),但保留了基本的 glTF 结构。
- 包括基本的vulkan设置以及功能函数。
二、代码分析
1.VulkanglTFModel类的变量
变量代码如下(VulkanglTFModel):
class VulkanglTFModel
{
public:
// The class requires some Vulkan objects so it can create it's own resources
vks::VulkanDevice* vulkanDevice;
VkQueue copyQueue;
// The vertex layout for the samples' model
struct Vertex {
glm::vec3 pos;
glm::vec3 normal;
glm::vec2 uv;
glm::vec3 color;
};
// Single vertex buffer for all primitives
struct {
VkBuffer buffer;
VkDeviceMemory memory;
} vertices;
// Single index buffer for all primitives
struct {
int count;
VkBuffer buffer;
VkDeviceMemory memory;
} indices;
// The following structures roughly represent the glTF scene structure
// To keep things simple, they only contain those properties that are required for this sample
struct Node;
// A primitive contains the data for a single draw call
struct Primitive {
uint32_t firstIndex;
uint32_t indexCount;
int32_t materialIndex;
};
// Contains the node's (optional) geometry and can be made up of an arbitrary number of primitives
struct Mesh {
std::vector<Primitive> primitives;
};
// A node represents an object in the glTF scene graph
struct Node {
Node* parent;
std::vector<Node> children;
Mesh mesh;
glm::mat4 matrix;
};
// A glTF material stores information in e.g. the texture that is attached to it and colors
struct Material {
glm::vec4 baseColorFactor = glm::vec4(1.0f);
uint32_t baseColorTextureIndex;
};
// Contains the texture for a single glTF image
// Images may be reused by texture objects and are as such separated
struct Image {
vks::Texture2D texture;
// We also store (and create) a descriptor set that's used to access this texture from the fragment shader
VkDescriptorSet descriptorSet;
};
// A glTF texture stores a reference to the image and a sampler
// In this sample, we are only interested in the image
struct Texture {
int32_t imageIndex;
};
/*
Model data
*/
std::vector<Image> images;
std::vector<Texture> textures;
std::vector<Material> materials;
std::vector<Node> nodes;
函数代码如下:
-
析构函数
-
glTF 加载函数:以下函数采用通过 tinyglTF 加载的 glTF 输入模型,并将所有必需的数据转换为我们自己的结构
//图片加载函数 //图像可以存储在glTF中(示例模型就是这种情况) //因此我们不是直接从磁盘加载它们 //而是从glTF加载器中获取它们并上传缓冲区 void loadImages(tinygltf::Model& input) { ... // Load texture from image buffer images[i].texture.fromBuffer(buffer, bufferSize, VK_FORMAT_R8G8B8A8_UNORM, glTFImage.width, glTFImage.height, vulkanDevice, copyQueue); } void loadTextures(tinygltf::Model& input) { textures.resize(input.textures.size()); for (size_t i = 0; i < input.textures.size(); i++) { textures[i].imageIndex = input.textures[i].source; } } void loadMaterials(tinygltf::Model& input) { ... } //加载节点 //这部分比较详细且复杂 //最终将用到的数据都放到nodes当中 void loadNode(const tinygltf::Node& inputNode, const tinygltf::Model& input, VulkanglTFModel::Node* parent, std::vector<uint32_t>& indexBuffer, std::vector<VulkanglTFModel::Vertex>& vertexBuffer) { ... }
-
glTF 渲染函数:绘制包含子节点的单个节点(如果存在)
void drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node node) { if (node.mesh.primitives.size() > 0) { // Pass the node's matrix via push constants // Traverse the node hierarchy to the top-most parent to get the final matrix of the current node glm::mat4 nodeMatrix = node.matrix; VulkanglTFModel::Node* currentParent = node.parent; while (currentParent) { nodeMatrix = currentParent->matrix * nodeMatrix; currentParent = currentParent->parent; } // Pass the final matrix to the vertex shader using push constants vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &nodeMatrix); for (VulkanglTFModel::Primitive& primitive : node.mesh.primitives) { if (primitive.indexCount > 0) { // Get the texture index for this primitive VulkanglTFModel::Texture texture = textures[materials[primitive.materialIndex].baseColorTextureIndex]; // Bind the descriptor for the current primitive's texture vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &images[texture.imageIndex].descriptorSet, 0, nullptr); vkCmdDrawIndexed(commandBuffer, primitive.indexCount, 1, primitive.firstIndex, 0, 0); } } } for (auto& child : node.children) { drawNode(commandBuffer, pipelineLayout, child); } }
-
从顶级节点开始绘制 glTF 场景
void draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout) { // All vertices and indices are stored in single buffers, so we only need to bind once VkDeviceSize offsets[1] = { 0 }; vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertices.buffer, offsets); vkCmdBindIndexBuffer(commandBuffer, indices.buffer, 0, VK_INDEX_TYPE_UINT32); // Render all nodes at top-level for (auto& node : nodes) { drawNode(commandBuffer, pipelineLayout, node); } }
2.VulkanExample类
-
变量
class VulkanExample : public VulkanExampleBase { public: bool wireframe = false; VulkanglTFModel glTFModel; struct ShaderData { vks::Buffer buffer; struct Values { glm::mat4 projection; glm::mat4 model; glm::vec4 lightPos = glm::vec4(5.0f, 5.0f, -5.0f, 1.0f); } values; } shaderData; struct Pipelines { VkPipeline solid; VkPipeline wireframe = VK_NULL_HANDLE; } pipelines; VkPipelineLayout pipelineLayout; VkDescriptorSet descriptorSet; struct DescriptorSetLayouts { VkDescriptorSetLayout matrices; VkDescriptorSetLayout textures; } descriptorSetLayouts; ...
-
函数:
//构造函数 VulkanExample() : VulkanExampleBase(ENABLE_VALIDATION) { ... } //析构函数 ~VulkanExample() { ... } Fill mode non solid is required for wireframe display virtual void getEnabledFeatures(); void buildCommandBuffers(); //加载gltf文件 //创建和上传顶点和索引缓冲区 //我们将对整个 glTF 场景使用一个顶点缓冲区和一个索引缓冲区 //然后,(glTF模型的)基元将使用索引偏移量索引到这些基元中 void loadglTFFile(std::string filename) { bool fileLoaded = gltfContext.LoadASCIIFromFile(&glTFInput, &error, &warning, filename); // Pass some Vulkan resources required for setup and rendering to the glTF model loading class glTFModel.vulkanDevice = vulkanDevice; glTFModel.copyQueue = queue; std::vector<uint32_t> indexBuffer; std::vector<VulkanglTFModel::Vertex> vertexBuffer; if (fileLoaded) { glTFModel.loadImages(glTFInput); glTFModel.loadMaterials(glTFInput); glTFModel.loadTextures(glTFInput); const tinygltf::Scene& scene = glTFInput.scenes[0]; for (size_t i = 0; i < scene.nodes.size(); i++) { const tinygltf::Node node = glTFInput.nodes[scene.nodes[i]]; glTFModel.loadNode(node, glTFInput, nullptr, indexBuffer, vertexBuffer); } }else { vks::tools::exitFatal("Could not open the glTF file.\n\nThe file is part of the additional asset pack.\n\nRun \"download_assets.py\" in the repository root to download the latest version.", -1); return; } ... Create host visible staging buffers (source) Index data Create device local buffers (target) ... //Copy data from staging buffers (host) do device local buffer (gpu) //从暂存缓冲区(主机)复制数据,执行设备本地缓冲区 (GPU) VkCommandBuffer copyCmd = vulkanDevice->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); VkBufferCopy copyRegion = {}; copyRegion.size = vertexBufferSize; vkCmdCopyBuffer( copyCmd, vertexStaging.buffer, glTFModel.vertices.buffer, 1, ©Region); copyRegion.size = indexBufferSize; vkCmdCopyBuffer( copyCmd, indexStaging.buffer, glTFModel.indices.buffer, 1, ©Region); vulkanDevice->flushCommandBuffer(copyCmd, queue, true); // 释放暂存资源 vkDestroyBuffer(device, vertexStaging.buffer, nullptr); vkFreeMemory(device, vertexStaging.memory, nullptr); vkDestroyBuffer(device, indexStaging.buffer, nullptr); vkFreeMemory(device, indexStaging.memory, nullptr); } void loadAssets(); void setupDescriptors(); void preparePipelines(); // Prepare and initialize uniform buffer containing shader uniforms void prepareUniformBuffers(); void updateUniformBuffers(); void prepare(); virtual void render() { renderFrame(); if (camera.updated) { updateUniformBuffers(); }
}
VULKAN_EXAMPLE_MAIN():位于vulkanexamplebase.h中的宏变量函数
```c
data = pd.read_csv(
'https://labfile.oss.aliyuncs.com/courses/1283/adult.data.csv')
print(data.head())
该处使用的url网络请求的数据。
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。