Vulkan-官方示例解读-glTF model loading and rendering


前言

  • 加快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,
    			&copyRegion);
    
    		copyRegion.size = indexBufferSize;
    		vkCmdCopyBuffer(
    			copyCmd,
    			indexStaging.buffer,
    			glTFModel.indices.buffer,
    			1,
    			&copyRegion);
    
    		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提供了大量能使我们快速便捷地处理数据的函数和方法。

realesrgan-ncnn-vulkan-20211212-windows是一个基于ncnn框架和Vulkan图形API开发的图像超分辨率增强模型。它是由GitHub用户realsrgan开发的最新版本,最新发布日期为2021年12月12日,专为Windows操作系统而设计。 该模型的主要应用是图像超分辨率增强,通过提高图像的分辨率和细节,使图像看起来更加清晰和真实。它采用深度学习和卷积神经网络等先进的技术,能够将低分辨率的图像转换成高分辨率的图像,从而提升图像的质量和视觉效果。 realesrgan-ncnn-vulkan-20211212-windows的开发使用了ncnn框架和Vulkan图形API,这使得它能够在Windows系统上实现快速且高效的图像处理。ncnn是一个轻量级的深度学习框架,专注于在移动平台和嵌入式设备上实现高性能和低延迟的推理。而Vulkan图形API是一种跨平台的图形渲染和计算API,可以充分利用计算设备的性能,提供高效的图像处理和渲染能力。 realesrgan-ncnn-vulkan-20211212-windows的使用可以通过命令行或者图形界面进行,用户可以根据自己的需求和偏好选择适合的方式。该模型提供了训练好的权重参数,用户可以直接加载这些参数并进行图像超分辨率增强。此外,该模型还支持批量处理和视频处理,方便用户对多个图像进行处理。 总之,realesrgan-ncnn-vulkan-20211212-windows是一个高效、快速且易于使用的图像超分辨率增强模型,适用于Windows系统,并利用了ncnn框架和Vulkan图形API的优势,为用户提供了出色的图像处理效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值