reconstruct gltf loader
							parent
							
								
									f5096914ae
								
							
						
					
					
						commit
						93ceae3657
					
				| 
						 | 
					@ -432,148 +432,190 @@ void glTFModel::Texture::fromglTfImage(tinygltf::Image& gltfImage, std::string p
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					void glTFModel::Model::loadImages(tinygltf::Model& gltfModel, vks::VulkanDevice* device, VkQueue transferQueue)
 | 
				
			||||||
 | 
					 | 
				
			||||||
void VulkanglTFModel::loadTextures(tinygltf::Model& input)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	textures.resize(input.textures.size());
 | 
						for (tinygltf::Image& image : gltfModel.images) {
 | 
				
			||||||
	for (size_t i = 0; i < input.textures.size(); i++) {
 | 
							glTFModel::Texture texture;
 | 
				
			||||||
		textures[i].imageIndex = input.textures[i].source;
 | 
							texture.fromglTfImage(image, path, device, transferQueue);
 | 
				
			||||||
 | 
							textures.push_back(texture);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// Create an empty texture to be used for empty material images
 | 
				
			||||||
 | 
						createEmptyTexture(transferQueue);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void VulkanglTFModel::loadAnimations(tinygltf::Model& input)
 | 
					
 | 
				
			||||||
 | 
					void glTFModel::Model::loadAnimations(tinygltf::Model& gltfModel)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	animations.resize(input.animations.size());
 | 
						for (tinygltf::Animation& anim : gltfModel.animations) {
 | 
				
			||||||
 | 
							glTFModel::Animation animation{};
 | 
				
			||||||
 | 
							animation.name = anim.name;
 | 
				
			||||||
 | 
							if (anim.name.empty()) {
 | 
				
			||||||
 | 
								animation.name = std::to_string(animations.size());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (size_t i = 0; i < input.animations.size(); ++i)
 | 
							// Samplers
 | 
				
			||||||
	{
 | 
							for (auto& samp : anim.samplers) {
 | 
				
			||||||
		auto glTFAnimation = input.animations[i];
 | 
								glTFModel::AnimationSampler sampler{};
 | 
				
			||||||
		animations[i].name = glTFAnimation.name;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Samplers
 | 
								if (samp.interpolation == "LINEAR") {
 | 
				
			||||||
		animations[i].samplers.resize(glTFAnimation.samplers.size());
 | 
									sampler.interpolation = AnimationSampler::InterpolationType::LINEAR;
 | 
				
			||||||
		for (size_t j = 0; j < glTFAnimation.samplers.size(); ++j)
 | 
								}
 | 
				
			||||||
		{
 | 
								if (samp.interpolation == "STEP") {
 | 
				
			||||||
			auto glTFSampler = glTFAnimation.samplers[j];
 | 
									sampler.interpolation = AnimationSampler::InterpolationType::STEP;
 | 
				
			||||||
			auto& dstSampler = animations[i].samplers[j];
 | 
								}
 | 
				
			||||||
			dstSampler.interpolation = glTFSampler.interpolation;
 | 
								if (samp.interpolation == "CUBICSPLINE") {
 | 
				
			||||||
 | 
									sampler.interpolation = AnimationSampler::InterpolationType::CUBICSPLINE;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Read sampler keyframe input time values
 | 
								// Read sampler input time values
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				const auto& accessor = input.accessors[glTFSampler.input];
 | 
									const tinygltf::Accessor& accessor = gltfModel.accessors[samp.input];
 | 
				
			||||||
				const auto& bufferView = input.bufferViews[accessor.bufferView];
 | 
									const tinygltf::BufferView& bufferView = gltfModel.bufferViews[accessor.bufferView];
 | 
				
			||||||
				const auto& buffer = input.buffers[bufferView.buffer];
 | 
									const tinygltf::Buffer& buffer = gltfModel.buffers[bufferView.buffer];
 | 
				
			||||||
				const void* dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
 | 
					
 | 
				
			||||||
				const float* buf = static_cast<const float*>(dataPtr);
 | 
									assert(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
 | 
				
			||||||
				for (size_t index = 0; index < accessor.count; ++index)
 | 
					
 | 
				
			||||||
				{
 | 
									float* buf = new float[accessor.count];
 | 
				
			||||||
					dstSampler.inputs.push_back(buf[index]);
 | 
									memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(float));
 | 
				
			||||||
 | 
									for (size_t index = 0; index < accessor.count; index++) {
 | 
				
			||||||
 | 
										sampler.inputs.push_back(buf[index]);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				// Adjust animation's start and end times
 | 
									delete[] buf;
 | 
				
			||||||
				for (auto input : animations[i].samplers[j].inputs)
 | 
									for (auto input : sampler.inputs) {
 | 
				
			||||||
				{
 | 
										if (input < animation.start) {
 | 
				
			||||||
					if (input < animations[i].start)
 | 
											animation.start = input;
 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						animations[i].start = input;
 | 
					 | 
				
			||||||
					};
 | 
										};
 | 
				
			||||||
					if (input > animations[i].end)
 | 
										if (input > animation.end) {
 | 
				
			||||||
					{
 | 
											animation.end = input;
 | 
				
			||||||
						animations[i].end = input;
 | 
					 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// Read sampler keyframe output translate/rotate/scale values
 | 
								// Read sampler output T/R/S values 
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				const auto& accessor = input.accessors[glTFSampler.output];
 | 
									const tinygltf::Accessor& accessor = gltfModel.accessors[samp.output];
 | 
				
			||||||
				const auto& bufferView = input.bufferViews[accessor.bufferView];
 | 
									const tinygltf::BufferView& bufferView = gltfModel.bufferViews[accessor.bufferView];
 | 
				
			||||||
				const auto& buffer = input.buffers[bufferView.buffer];
 | 
									const tinygltf::Buffer& buffer = gltfModel.buffers[bufferView.buffer];
 | 
				
			||||||
				const void* dataPtr = &buffer.data[accessor.byteOffset + bufferView.byteOffset];
 | 
					
 | 
				
			||||||
				switch (accessor.type)
 | 
									assert(accessor.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT);
 | 
				
			||||||
				{
 | 
					
 | 
				
			||||||
				case TINYGLTF_TYPE_VEC3:
 | 
									switch (accessor.type) {
 | 
				
			||||||
				{
 | 
									case TINYGLTF_TYPE_VEC3: {
 | 
				
			||||||
					const glm::vec3* buf = static_cast<const glm::vec3*>(dataPtr);
 | 
										glm::vec3* buf = new glm::vec3[accessor.count];
 | 
				
			||||||
					for (size_t index = 0; index < accessor.count; index++)
 | 
										memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(glm::vec3));
 | 
				
			||||||
					{
 | 
										for (size_t index = 0; index < accessor.count; index++) {
 | 
				
			||||||
						dstSampler.outputsVec4.push_back(glm::vec4(buf[index], 0.0f));
 | 
											sampler.outputsVec4.push_back(glm::vec4(buf[index], 0.0f));
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										delete[] buf;
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				case TINYGLTF_TYPE_VEC4:
 | 
									case TINYGLTF_TYPE_VEC4: {
 | 
				
			||||||
				{
 | 
										glm::vec4* buf = new glm::vec4[accessor.count];
 | 
				
			||||||
					const glm::vec4* buf = static_cast<const glm::vec4*>(dataPtr);
 | 
										memcpy(buf, &buffer.data[accessor.byteOffset + bufferView.byteOffset], accessor.count * sizeof(glm::vec4));
 | 
				
			||||||
					for (size_t index = 0; index < accessor.count; index++)
 | 
										for (size_t index = 0; index < accessor.count; index++) {
 | 
				
			||||||
					{
 | 
											sampler.outputsVec4.push_back(buf[index]);
 | 
				
			||||||
						dstSampler.outputsVec4.push_back(buf[index]);
 | 
					 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
										delete[] buf;
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				default:
 | 
									default: {
 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					std::cout << "unknown type" << std::endl;
 | 
										std::cout << "unknown type" << std::endl;
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								animation.samplers.push_back(sampler);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		animations[i].channels.resize(glTFAnimation.channels.size());
 | 
							// Channels
 | 
				
			||||||
		for (size_t j = 0; j < glTFAnimation.channels.size(); ++j)
 | 
							for (auto& source : anim.channels) {
 | 
				
			||||||
		{
 | 
								glTFModel::AnimationChannel channel{};
 | 
				
			||||||
			auto glTFChannel = glTFAnimation.channels[j];
 | 
					
 | 
				
			||||||
			auto& dstChannel = animations[i].channels[j];
 | 
								if (source.target_path == "rotation") {
 | 
				
			||||||
			dstChannel.path = glTFChannel.target_path;
 | 
									channel.path = AnimationChannel::PathType::ROTATION;
 | 
				
			||||||
			dstChannel.samplerIndex = glTFChannel.sampler;
 | 
								}
 | 
				
			||||||
			dstChannel.node = nodeFromIndex(glTFChannel.target_node);
 | 
								if (source.target_path == "translation") {
 | 
				
			||||||
 | 
									channel.path = AnimationChannel::PathType::TRANSLATION;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (source.target_path == "scale") {
 | 
				
			||||||
 | 
									channel.path = AnimationChannel::PathType::SCALE;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (source.target_path == "weights") {
 | 
				
			||||||
 | 
									std::cout << "weights not yet supported, skipping channel" << std::endl;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								channel.samplerIndex = source.sampler;
 | 
				
			||||||
 | 
								channel.node = nodeFromIndex(source.target_node);
 | 
				
			||||||
 | 
								if (!channel.node) {
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								animation.channels.push_back(channel);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							animations.push_back(animation);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
void VulkanglTFModel::loadMaterials(tinygltf::Model& input)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	materials.resize(input.materials.size());
 | 
					 | 
				
			||||||
	for (size_t i = 0; i < input.materials.size(); i++) {
 | 
					 | 
				
			||||||
		// We only read the most basic properties required for our sample
 | 
					 | 
				
			||||||
		tinygltf::Material glTFMaterial = input.materials[i];
 | 
					 | 
				
			||||||
		// Get the base color factor
 | 
					 | 
				
			||||||
		if (glTFMaterial.values.find("baseColorFactor") != glTFMaterial.values.end()) {
 | 
					 | 
				
			||||||
			materials[i].baseColorFactor = glm::make_vec4(glTFMaterial.values["baseColorFactor"].ColorFactor().data());
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		// Get base color texture index
 | 
					 | 
				
			||||||
		if (glTFMaterial.values.find("baseColorTexture") != glTFMaterial.values.end()) {
 | 
					 | 
				
			||||||
			materials[i].baseColorTextureIndex = glTFMaterial.values["baseColorTexture"].TextureIndex();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (glTFMaterial.values.find("metallicRoughnessTexture") != glTFMaterial.values.end()) {
 | 
					 | 
				
			||||||
			materials[i].matalicRoughTextureIndex = glTFMaterial.values["metallicRoughnessTexture"].TextureIndex();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (glTFMaterial.additionalValues.find("normalTexture") != glTFMaterial.additionalValues.end())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			materials[i].normalMapTextureIndex = glTFMaterial.additionalValues["normalTexture"].TextureIndex();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (glTFMaterial.emissiveTexture.index != -1)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			materials[i].emissiveTextureIndex = glTFMaterial.emissiveTexture.index;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (glTFMaterial.emissiveFactor.size() == 3)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			materials[i].materialData.values.emissiveFactor = glm::make_vec3(glTFMaterial.emissiveFactor.data());
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (glTFMaterial.values.find("baseColorFactor") != glTFMaterial.values.end())
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			materials[i].materialData.values.baseColorFactor = glm::make_vec4(glTFMaterial.values["baseColorFactor"].ColorFactor().data());
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
	glTF material
 | 
						glTF material
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void glTFModel::Model::loadMaterials(tinygltf::Model& gltfModel)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						for (tinygltf::Material& mat : gltfModel.materials) {
 | 
				
			||||||
 | 
							glTFModel::Material material(device);
 | 
				
			||||||
 | 
							if (mat.values.find("baseColorTexture") != mat.values.end()) {
 | 
				
			||||||
 | 
								material.baseColorTexture = getTexture(gltfModel.textures[mat.values["baseColorTexture"].TextureIndex()].source);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// Metallic roughness workflow
 | 
				
			||||||
 | 
							if (mat.values.find("metallicRoughnessTexture") != mat.values.end()) {
 | 
				
			||||||
 | 
								material.metallicRoughnessTexture = getTexture(gltfModel.textures[mat.values["metallicRoughnessTexture"].TextureIndex()].source);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (mat.values.find("roughnessFactor") != mat.values.end()) {
 | 
				
			||||||
 | 
								material.roughnessFactor = static_cast<float>(mat.values["roughnessFactor"].Factor());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (mat.values.find("metallicFactor") != mat.values.end()) {
 | 
				
			||||||
 | 
								material.metallicFactor = static_cast<float>(mat.values["metallicFactor"].Factor());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (mat.values.find("baseColorFactor") != mat.values.end()) {
 | 
				
			||||||
 | 
								material.baseColorFactor = glm::make_vec4(mat.values["baseColorFactor"].ColorFactor().data());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (mat.additionalValues.find("normalTexture") != mat.additionalValues.end()) {
 | 
				
			||||||
 | 
								material.normalTexture = getTexture(gltfModel.textures[mat.additionalValues["normalTexture"].TextureIndex()].source);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								material.normalTexture = &emptyTexture;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (mat.additionalValues.find("emissiveTexture") != mat.additionalValues.end()) {
 | 
				
			||||||
 | 
								material.emissiveTexture = getTexture(gltfModel.textures[mat.additionalValues["emissiveTexture"].TextureIndex()].source);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (mat.additionalValues.find("occlusionTexture") != mat.additionalValues.end()) {
 | 
				
			||||||
 | 
								material.occlusionTexture = getTexture(gltfModel.textures[mat.additionalValues["occlusionTexture"].TextureIndex()].source);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (mat.additionalValues.find("alphaMode") != mat.additionalValues.end()) {
 | 
				
			||||||
 | 
								tinygltf::Parameter param = mat.additionalValues["alphaMode"];
 | 
				
			||||||
 | 
								if (param.string_value == "BLEND") {
 | 
				
			||||||
 | 
									material.alphaMode = Material::ALPHAMODE_BLEND;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (param.string_value == "MASK") {
 | 
				
			||||||
 | 
									material.alphaMode = Material::ALPHAMODE_MASK;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (mat.additionalValues.find("alphaCutoff") != mat.additionalValues.end()) {
 | 
				
			||||||
 | 
								material.alphaCutoff = static_cast<float>(mat.additionalValues["alphaCutoff"].Factor());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							materials.push_back(material);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// Push a default material at the end of the list for meshes with no material assigned
 | 
				
			||||||
 | 
						materials.push_back(Material(device));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void glTFModel::Material::createDescriptorSet(VkDescriptorPool descriptorPool, VkDescriptorSetLayout descriptorSetLayout, uint32_t descriptorBindingFlags)
 | 
					void glTFModel::Material::createDescriptorSet(VkDescriptorPool descriptorPool, VkDescriptorSetLayout descriptorSetLayout, uint32_t descriptorBindingFlags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
 | 
						VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
 | 
				
			||||||
| 
						 | 
					@ -903,7 +945,6 @@ void glTFModel::Model::loadNode(glTFModel::Node* parent, const tinygltf::Node& n
 | 
				
			||||||
	newNode->matrix = glm::mat4(1.0f);
 | 
						newNode->matrix = glm::mat4(1.0f);
 | 
				
			||||||
	newNode->parent = parent;
 | 
						newNode->parent = parent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Get the local node matrix
 | 
						// Get the local node matrix
 | 
				
			||||||
	// It's either made up from translation, rotation, scale or a 4x4 matrix
 | 
						// It's either made up from translation, rotation, scale or a 4x4 matrix
 | 
				
			||||||
	glm::vec3 translation = glm::vec3(0.0f);
 | 
						glm::vec3 translation = glm::vec3(0.0f);
 | 
				
			||||||
| 
						 | 
					@ -1112,7 +1153,294 @@ void glTFModel::Model::loadNode(glTFModel::Node* parent, const tinygltf::Node& n
 | 
				
			||||||
	linearNodes.push_back(newNode);
 | 
						linearNodes.push_back(newNode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VulkanglTFModel::Node* VulkanglTFModel::findNode(Node* parent, uint32_t index)
 | 
					// file loader function
 | 
				
			||||||
 | 
					void glTFModel::Model::loadFromFile(std::string filename, vks::VulkanDevice* device, VkQueue transferQueue, uint32_t fileLoadingFlags, float scale)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						tinygltf::Model gltfModel;
 | 
				
			||||||
 | 
						tinygltf::TinyGLTF gltfContext;
 | 
				
			||||||
 | 
						if (fileLoadingFlags & FileLoadingFlags::DontLoadImages) {
 | 
				
			||||||
 | 
							gltfContext.SetImageLoader(loadImageDataFuncEmpty, nullptr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							gltfContext.SetImageLoader(loadImageDataFunc, nullptr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#if defined(__ANDROID__)
 | 
				
			||||||
 | 
						// On Android all assets are packed with the apk in a compressed form, so we need to open them using the asset manager
 | 
				
			||||||
 | 
						// We let tinygltf handle this, by passing the asset manager of our app
 | 
				
			||||||
 | 
						tinygltf::asset_manager = androidApp->activity->assetManager;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						size_t pos = filename.find_last_of('/');
 | 
				
			||||||
 | 
						path = filename.substr(0, pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::string error, warning;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->device = device;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__ANDROID__)
 | 
				
			||||||
 | 
						// On Android all assets are packed with the apk in a compressed form, so we need to open them using the asset manager
 | 
				
			||||||
 | 
						// We let tinygltf handle this, by passing the asset manager of our app
 | 
				
			||||||
 | 
						tinygltf::asset_manager = androidApp->activity->assetManager;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						bool fileLoaded = gltfContext.LoadASCIIFromFile(&gltfModel, &error, &warning, filename);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						std::vector<uint32_t> indexBuffer;
 | 
				
			||||||
 | 
						std::vector<Vertex> vertexBuffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (fileLoaded) {
 | 
				
			||||||
 | 
							if (!(fileLoadingFlags & FileLoadingFlags::DontLoadImages)) {
 | 
				
			||||||
 | 
								loadImages(gltfModel, device, transferQueue);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							loadMaterials(gltfModel);
 | 
				
			||||||
 | 
							const tinygltf::Scene& scene = gltfModel.scenes[gltfModel.defaultScene > -1 ? gltfModel.defaultScene : 0];
 | 
				
			||||||
 | 
							for (size_t i = 0; i < scene.nodes.size(); i++) {
 | 
				
			||||||
 | 
								const tinygltf::Node node = gltfModel.nodes[scene.nodes[i]];
 | 
				
			||||||
 | 
								loadNode(nullptr, node, scene.nodes[i], gltfModel, indexBuffer, vertexBuffer, scale);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (gltfModel.animations.size() > 0) {
 | 
				
			||||||
 | 
								loadAnimations(gltfModel);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							loadSkins(gltfModel);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (auto node : linearNodes) {
 | 
				
			||||||
 | 
								// Assign skins
 | 
				
			||||||
 | 
								if (node->skinIndex > -1) {
 | 
				
			||||||
 | 
									node->skin = skins[node->skinIndex];
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// Initial pose
 | 
				
			||||||
 | 
								if (node->mesh) {
 | 
				
			||||||
 | 
									node->update();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							// TODO: throw
 | 
				
			||||||
 | 
							vks::tools::exitFatal("Could not load glTF file \"" + filename + "\": " + error, -1);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Pre-Calculations for requested features
 | 
				
			||||||
 | 
						if ((fileLoadingFlags & FileLoadingFlags::PreTransformVertices) || (fileLoadingFlags & FileLoadingFlags::PreMultiplyVertexColors) || (fileLoadingFlags & FileLoadingFlags::FlipY)) {
 | 
				
			||||||
 | 
							const bool preTransform = fileLoadingFlags & FileLoadingFlags::PreTransformVertices;
 | 
				
			||||||
 | 
							const bool preMultiplyColor = fileLoadingFlags & FileLoadingFlags::PreMultiplyVertexColors;
 | 
				
			||||||
 | 
							const bool flipY = fileLoadingFlags & FileLoadingFlags::FlipY;
 | 
				
			||||||
 | 
							for (Node* node : linearNodes) {
 | 
				
			||||||
 | 
								if (node->mesh) {
 | 
				
			||||||
 | 
									const glm::mat4 localMatrix = node->getMatrix();
 | 
				
			||||||
 | 
									for (Primitive* primitive : node->mesh->primitives) {
 | 
				
			||||||
 | 
										for (uint32_t i = 0; i < primitive->vertexCount; i++) {
 | 
				
			||||||
 | 
											Vertex& vertex = vertexBuffer[primitive->firstVertex + i];
 | 
				
			||||||
 | 
											// Pre-transform vertex positions by node-hierarchy
 | 
				
			||||||
 | 
											if (preTransform) {
 | 
				
			||||||
 | 
												vertex.pos = glm::vec3(localMatrix * glm::vec4(vertex.pos, 1.0f));
 | 
				
			||||||
 | 
												vertex.normal = glm::normalize(glm::mat3(localMatrix) * vertex.normal);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											// Flip Y-Axis of vertex positions
 | 
				
			||||||
 | 
											if (flipY) {
 | 
				
			||||||
 | 
												vertex.pos.y *= -1.0f;
 | 
				
			||||||
 | 
												vertex.normal.y *= -1.0f;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
											// Pre-Multiply vertex colors with material base color
 | 
				
			||||||
 | 
											if (preMultiplyColor) {
 | 
				
			||||||
 | 
												vertex.color = primitive->material.baseColorFactor * vertex.color;
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (auto extension : gltfModel.extensionsUsed) {
 | 
				
			||||||
 | 
							if (extension == "KHR_materials_pbrSpecularGlossiness") {
 | 
				
			||||||
 | 
								std::cout << "Required extension: " << extension;
 | 
				
			||||||
 | 
								metallicRoughnessWorkflow = false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t vertexBufferSize = vertexBuffer.size() * sizeof(Vertex);
 | 
				
			||||||
 | 
						size_t indexBufferSize = indexBuffer.size() * sizeof(uint32_t);
 | 
				
			||||||
 | 
						indices.count = static_cast<uint32_t>(indexBuffer.size());
 | 
				
			||||||
 | 
						vertices.count = static_cast<uint32_t>(vertexBuffer.size());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						assert((vertexBufferSize > 0) && (indexBufferSize > 0));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct StagingBuffer {
 | 
				
			||||||
 | 
							VkBuffer buffer;
 | 
				
			||||||
 | 
							VkDeviceMemory memory;
 | 
				
			||||||
 | 
						} vertexStaging, indexStaging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create staging buffers
 | 
				
			||||||
 | 
						// Vertex data
 | 
				
			||||||
 | 
						VK_CHECK_RESULT(device->createBuffer(
 | 
				
			||||||
 | 
							VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
 | 
				
			||||||
 | 
							VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
 | 
				
			||||||
 | 
							vertexBufferSize,
 | 
				
			||||||
 | 
							&vertexStaging.buffer,
 | 
				
			||||||
 | 
							&vertexStaging.memory,
 | 
				
			||||||
 | 
							vertexBuffer.data()));
 | 
				
			||||||
 | 
						// Index data
 | 
				
			||||||
 | 
						VK_CHECK_RESULT(device->createBuffer(
 | 
				
			||||||
 | 
							VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
 | 
				
			||||||
 | 
							VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT,
 | 
				
			||||||
 | 
							indexBufferSize,
 | 
				
			||||||
 | 
							&indexStaging.buffer,
 | 
				
			||||||
 | 
							&indexStaging.memory,
 | 
				
			||||||
 | 
							indexBuffer.data()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create device local buffers
 | 
				
			||||||
 | 
						// Vertex buffer
 | 
				
			||||||
 | 
						VK_CHECK_RESULT(device->createBuffer(
 | 
				
			||||||
 | 
							VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | memoryPropertyFlags,
 | 
				
			||||||
 | 
							VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
 | 
				
			||||||
 | 
							vertexBufferSize,
 | 
				
			||||||
 | 
							&vertices.buffer,
 | 
				
			||||||
 | 
							&vertices.memory));
 | 
				
			||||||
 | 
						// Index buffer
 | 
				
			||||||
 | 
						VK_CHECK_RESULT(device->createBuffer(
 | 
				
			||||||
 | 
							VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | memoryPropertyFlags,
 | 
				
			||||||
 | 
							VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
 | 
				
			||||||
 | 
							indexBufferSize,
 | 
				
			||||||
 | 
							&indices.buffer,
 | 
				
			||||||
 | 
							&indices.memory));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Copy from staging buffers
 | 
				
			||||||
 | 
						VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						VkBufferCopy copyRegion = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						copyRegion.size = vertexBufferSize;
 | 
				
			||||||
 | 
						vkCmdCopyBuffer(copyCmd, vertexStaging.buffer, vertices.buffer, 1, ©Region);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						copyRegion.size = indexBufferSize;
 | 
				
			||||||
 | 
						vkCmdCopyBuffer(copyCmd, indexStaging.buffer, indices.buffer, 1, ©Region);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						device->flushCommandBuffer(copyCmd, transferQueue, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vkDestroyBuffer(device->logicalDevice, vertexStaging.buffer, nullptr);
 | 
				
			||||||
 | 
						vkFreeMemory(device->logicalDevice, vertexStaging.memory, nullptr);
 | 
				
			||||||
 | 
						vkDestroyBuffer(device->logicalDevice, indexStaging.buffer, nullptr);
 | 
				
			||||||
 | 
						vkFreeMemory(device->logicalDevice, indexStaging.memory, nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						getSceneDimensions();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Setup descriptors
 | 
				
			||||||
 | 
						uint32_t uboCount{ 0 };
 | 
				
			||||||
 | 
						uint32_t imageCount{ 0 };
 | 
				
			||||||
 | 
						for (auto node : linearNodes) {
 | 
				
			||||||
 | 
							if (node->mesh) {
 | 
				
			||||||
 | 
								uboCount++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for (auto material : materials) {
 | 
				
			||||||
 | 
							if (material.baseColorTexture != nullptr) {
 | 
				
			||||||
 | 
								imageCount++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						std::vector<VkDescriptorPoolSize> poolSizes = {
 | 
				
			||||||
 | 
							{ VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, uboCount },
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						if (imageCount > 0) {
 | 
				
			||||||
 | 
							if (descriptorBindingFlags & DescriptorBindingFlags::ImageBaseColor) {
 | 
				
			||||||
 | 
								poolSizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageCount });
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (descriptorBindingFlags & DescriptorBindingFlags::ImageNormalMap) {
 | 
				
			||||||
 | 
								poolSizes.push_back({ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, imageCount });
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						VkDescriptorPoolCreateInfo descriptorPoolCI{};
 | 
				
			||||||
 | 
						descriptorPoolCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
 | 
				
			||||||
 | 
						descriptorPoolCI.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
 | 
				
			||||||
 | 
						descriptorPoolCI.pPoolSizes = poolSizes.data();
 | 
				
			||||||
 | 
						descriptorPoolCI.maxSets = uboCount + imageCount;
 | 
				
			||||||
 | 
						VK_CHECK_RESULT(vkCreateDescriptorPool(device->logicalDevice, &descriptorPoolCI, nullptr, &descriptorPool));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Descriptors for per-node uniform buffers
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Layout is global, so only create if it hasn't already been created before
 | 
				
			||||||
 | 
							if (descriptorSetLayoutUbo == VK_NULL_HANDLE) {
 | 
				
			||||||
 | 
								std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings = {
 | 
				
			||||||
 | 
									vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT, 0),
 | 
				
			||||||
 | 
								};
 | 
				
			||||||
 | 
								VkDescriptorSetLayoutCreateInfo descriptorLayoutCI{};
 | 
				
			||||||
 | 
								descriptorLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
 | 
				
			||||||
 | 
								descriptorLayoutCI.bindingCount = static_cast<uint32_t>(setLayoutBindings.size());
 | 
				
			||||||
 | 
								descriptorLayoutCI.pBindings = setLayoutBindings.data();
 | 
				
			||||||
 | 
								VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device->logicalDevice, &descriptorLayoutCI, nullptr, &descriptorSetLayoutUbo));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for (auto node : nodes) {
 | 
				
			||||||
 | 
								prepareNodeDescriptor(node, descriptorSetLayoutUbo);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Descriptors for per-material images
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							// Layout is global, so only create if it hasn't already been created before
 | 
				
			||||||
 | 
							if (descriptorSetLayoutImage == VK_NULL_HANDLE) {
 | 
				
			||||||
 | 
								std::vector<VkDescriptorSetLayoutBinding> setLayoutBindings{};
 | 
				
			||||||
 | 
								if (descriptorBindingFlags & DescriptorBindingFlags::ImageBaseColor) {
 | 
				
			||||||
 | 
									setLayoutBindings.push_back(vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, static_cast<uint32_t>(setLayoutBindings.size())));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (descriptorBindingFlags & DescriptorBindingFlags::ImageNormalMap) {
 | 
				
			||||||
 | 
									setLayoutBindings.push_back(vks::initializers::descriptorSetLayoutBinding(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT, static_cast<uint32_t>(setLayoutBindings.size())));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								VkDescriptorSetLayoutCreateInfo descriptorLayoutCI{};
 | 
				
			||||||
 | 
								descriptorLayoutCI.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
 | 
				
			||||||
 | 
								descriptorLayoutCI.bindingCount = static_cast<uint32_t>(setLayoutBindings.size());
 | 
				
			||||||
 | 
								descriptorLayoutCI.pBindings = setLayoutBindings.data();
 | 
				
			||||||
 | 
								VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device->logicalDevice, &descriptorLayoutCI, nullptr, &descriptorSetLayoutImage));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							for (auto& material : materials) {
 | 
				
			||||||
 | 
								if (material.baseColorTexture != nullptr) {
 | 
				
			||||||
 | 
									material.createDescriptorSet(descriptorPool, glTFModel::descriptorSetLayoutImage, descriptorBindingFlags);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void glTFModel::Model::bindBuffers(VkCommandBuffer commandBuffer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const VkDeviceSize offsets[1] = { 0 };
 | 
				
			||||||
 | 
						vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertices.buffer, offsets);
 | 
				
			||||||
 | 
						vkCmdBindIndexBuffer(commandBuffer, indices.buffer, 0, VK_INDEX_TYPE_UINT32);
 | 
				
			||||||
 | 
						buffersBound = true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
						helper function
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void glTFModel::Model::getNodeDimensions(Node* node, glm::vec3& min, glm::vec3& max)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (node->mesh) {
 | 
				
			||||||
 | 
							for (Primitive* primitive : node->mesh->primitives) {
 | 
				
			||||||
 | 
								glm::vec4 locMin = glm::vec4(primitive->dimensions.min, 1.0f) * node->getMatrix();
 | 
				
			||||||
 | 
								glm::vec4 locMax = glm::vec4(primitive->dimensions.max, 1.0f) * node->getMatrix();
 | 
				
			||||||
 | 
								if (locMin.x < min.x) { min.x = locMin.x; }
 | 
				
			||||||
 | 
								if (locMin.y < min.y) { min.y = locMin.y; }
 | 
				
			||||||
 | 
								if (locMin.z < min.z) { min.z = locMin.z; }
 | 
				
			||||||
 | 
								if (locMax.x > max.x) { max.x = locMax.x; }
 | 
				
			||||||
 | 
								if (locMax.y > max.y) { max.y = locMax.y; }
 | 
				
			||||||
 | 
								if (locMax.z > max.z) { max.z = locMax.z; }
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for (auto child : node->children) {
 | 
				
			||||||
 | 
							getNodeDimensions(child, min, max);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void glTFModel::Model::getSceneDimensions()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						dimensions.min = glm::vec3(FLT_MAX);
 | 
				
			||||||
 | 
						dimensions.max = glm::vec3(-FLT_MAX);
 | 
				
			||||||
 | 
						for (auto node : nodes) {
 | 
				
			||||||
 | 
							getNodeDimensions(node, dimensions.min, dimensions.max);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						dimensions.size = dimensions.max - dimensions.min;
 | 
				
			||||||
 | 
						dimensions.center = (dimensions.min + dimensions.max) / 2.0f;
 | 
				
			||||||
 | 
						dimensions.radius = glm::distance(dimensions.min, dimensions.max) / 2.0f;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					glTFModel::Node* glTFModel::Model::findNode(Node* parent, uint32_t index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Node* nodeFound = nullptr;
 | 
						Node* nodeFound = nullptr;
 | 
				
			||||||
	if (parent->index == index)
 | 
						if (parent->index == index)
 | 
				
			||||||
| 
						 | 
					@ -1130,7 +1458,7 @@ VulkanglTFModel::Node* VulkanglTFModel::findNode(Node* parent, uint32_t index)
 | 
				
			||||||
	return nodeFound;
 | 
						return nodeFound;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VulkanglTFModel::Node* VulkanglTFModel::nodeFromIndex(uint32_t index)
 | 
					glTFModel::Node* glTFModel::Model::nodeFromIndex(uint32_t index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Node* nodeFound = nullptr;
 | 
						Node* nodeFound = nullptr;
 | 
				
			||||||
	for (auto& node : nodes)
 | 
						for (auto& node : nodes)
 | 
				
			||||||
| 
						 | 
					@ -1144,67 +1472,72 @@ VulkanglTFModel::Node* VulkanglTFModel::nodeFromIndex(uint32_t index)
 | 
				
			||||||
	return nodeFound;
 | 
						return nodeFound;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void VulkanglTFModel::updateAnimation(float deltaTime, vks::Buffer& buffer)
 | 
					/*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gltf update function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void glTFModel::Model::updateAnimation(uint32_t index, float time)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	constexpr uint32_t activeAnimation = 0;
 | 
						if (index > static_cast<uint32_t>(animations.size()) - 1) {
 | 
				
			||||||
	Animation& animation = animations[activeAnimation];
 | 
							std::cout << "No animation with index " << index << std::endl;
 | 
				
			||||||
	animation.currentTime += deltaTime;
 | 
							return;
 | 
				
			||||||
	if (animation.currentTime > animation.end)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		animation.currentTime -= animation.end;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						Animation& animation = animations[index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (auto& channel : animation.channels)
 | 
						bool updated = false;
 | 
				
			||||||
	{
 | 
						for (auto& channel : animation.channels) {
 | 
				
			||||||
		auto& sampler = animation.samplers[channel.samplerIndex];
 | 
							glTFModel::AnimationSampler& sampler = animation.samplers[channel.samplerIndex];
 | 
				
			||||||
		for (size_t i = 0; i < sampler.inputs.size() - 1; ++i)
 | 
							if (sampler.inputs.size() > sampler.outputsVec4.size()) {
 | 
				
			||||||
		{
 | 
								continue;
 | 
				
			||||||
			if (sampler.interpolation != "LINEAR")
 | 
							}
 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				std::cout << "This sample only supports linear interpolations\n";
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if ((animation.currentTime >= sampler.inputs[i]) && (animation.currentTime <= sampler.inputs[i + 1]))
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				float ratio = (animation.currentTime - sampler.inputs[i]) / (sampler.inputs[i + 1] - sampler.inputs[i]);
 | 
					 | 
				
			||||||
				if (channel.path == "translation")
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					channel.node->translation = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], ratio);
 | 
					 | 
				
			||||||
					channel.node->bAnimateNode = true;
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
				if (channel.path == "rotation")
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					glm::quat q1;
 | 
					 | 
				
			||||||
					q1.x = sampler.outputsVec4[i].x;
 | 
					 | 
				
			||||||
					q1.y = sampler.outputsVec4[i].y;
 | 
					 | 
				
			||||||
					q1.z = sampler.outputsVec4[i].z;
 | 
					 | 
				
			||||||
					q1.w = sampler.outputsVec4[i].w;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
					glm::quat q2;
 | 
							for (auto i = 0; i < sampler.inputs.size() - 1; i++) {
 | 
				
			||||||
					q2.x = sampler.outputsVec4[i + 1].x;
 | 
								if ((time >= sampler.inputs[i]) && (time <= sampler.inputs[i + 1])) {
 | 
				
			||||||
					q2.y = sampler.outputsVec4[i + 1].y;
 | 
									float u = std::max(0.0f, time - sampler.inputs[i]) / (sampler.inputs[i + 1] - sampler.inputs[i]);
 | 
				
			||||||
					q2.z = sampler.outputsVec4[i + 1].z;
 | 
									if (u <= 1.0f) {
 | 
				
			||||||
					q2.w = sampler.outputsVec4[i + 1].w;
 | 
										switch (channel.path) {
 | 
				
			||||||
 | 
										case glTFModel::AnimationChannel::PathType::TRANSLATION: {
 | 
				
			||||||
					channel.node->rotation = glm::normalize(glm::slerp(q1, q2, ratio));
 | 
											glm::vec4 trans = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], u);
 | 
				
			||||||
					channel.node->bAnimateNode = true;
 | 
											channel.node->translation = glm::vec3(trans);
 | 
				
			||||||
				}
 | 
											break;
 | 
				
			||||||
				if (channel.path == "scale")
 | 
										}
 | 
				
			||||||
				{
 | 
										case glTFModel::AnimationChannel::PathType::SCALE: {
 | 
				
			||||||
					channel.node->scale = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], ratio);
 | 
											glm::vec4 trans = glm::mix(sampler.outputsVec4[i], sampler.outputsVec4[i + 1], u);
 | 
				
			||||||
					channel.node->bAnimateNode = true;
 | 
											channel.node->scale = glm::vec3(trans);
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										case glTFModel::AnimationChannel::PathType::ROTATION: {
 | 
				
			||||||
 | 
											glm::quat q1;
 | 
				
			||||||
 | 
											q1.x = sampler.outputsVec4[i].x;
 | 
				
			||||||
 | 
											q1.y = sampler.outputsVec4[i].y;
 | 
				
			||||||
 | 
											q1.z = sampler.outputsVec4[i].z;
 | 
				
			||||||
 | 
											q1.w = sampler.outputsVec4[i].w;
 | 
				
			||||||
 | 
											glm::quat q2;
 | 
				
			||||||
 | 
											q2.x = sampler.outputsVec4[i + 1].x;
 | 
				
			||||||
 | 
											q2.y = sampler.outputsVec4[i + 1].y;
 | 
				
			||||||
 | 
											q2.z = sampler.outputsVec4[i + 1].z;
 | 
				
			||||||
 | 
											q2.w = sampler.outputsVec4[i + 1].w;
 | 
				
			||||||
 | 
											channel.node->rotation = glm::normalize(glm::slerp(q1, q2, u));
 | 
				
			||||||
 | 
											break;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										updated = true;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	std::vector<glm::mat4> nodeMatrics(nodeCount);
 | 
						if (updated) {
 | 
				
			||||||
	for (auto& node : nodes)
 | 
							for (auto& node : nodes) {
 | 
				
			||||||
	{
 | 
								node->update();
 | 
				
			||||||
		updateNodeMatrix(node, nodeMatrics);
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	buffer.copyTo(nodeMatrics.data(), nodeCount * sizeof(glm::mat4));
 | 
						
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
void VulkanglTFModel::updateNodeMatrix(Node* node, std::vector<glm::mat4>& nodeMatrics)
 | 
					void VulkanglTFModel::updateNodeMatrix(Node* node, std::vector<glm::mat4>& nodeMatrics)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	nodeMatrics[node->index] = getNodeMatrix(node);
 | 
						nodeMatrics[node->index] = getNodeMatrix(node);
 | 
				
			||||||
| 
						 | 
					@ -1225,79 +1558,73 @@ glm::mat4 VulkanglTFModel::getNodeMatrix(Node* node)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nodeMatrix;
 | 
						return nodeMatrix;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void glTFModel::Model::prepareNodeDescriptor(glTFModel::Node* node, VkDescriptorSetLayout descriptorSetLayout) {
 | 
				
			||||||
 | 
						if (node->mesh) {
 | 
				
			||||||
 | 
							VkDescriptorSetAllocateInfo descriptorSetAllocInfo{};
 | 
				
			||||||
 | 
							descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
 | 
				
			||||||
 | 
							descriptorSetAllocInfo.descriptorPool = descriptorPool;
 | 
				
			||||||
 | 
							descriptorSetAllocInfo.pSetLayouts = &descriptorSetLayout;
 | 
				
			||||||
 | 
							descriptorSetAllocInfo.descriptorSetCount = 1;
 | 
				
			||||||
 | 
							VK_CHECK_RESULT(vkAllocateDescriptorSets(device->logicalDevice, &descriptorSetAllocInfo, &node->mesh->uniformBuffer.descriptorSet));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							VkWriteDescriptorSet writeDescriptorSet{};
 | 
				
			||||||
 | 
							writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
 | 
				
			||||||
 | 
							writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
 | 
				
			||||||
 | 
							writeDescriptorSet.descriptorCount = 1;
 | 
				
			||||||
 | 
							writeDescriptorSet.dstSet = node->mesh->uniformBuffer.descriptorSet;
 | 
				
			||||||
 | 
							writeDescriptorSet.dstBinding = 0;
 | 
				
			||||||
 | 
							writeDescriptorSet.pBufferInfo = &node->mesh->uniformBuffer.descriptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							vkUpdateDescriptorSets(device->logicalDevice, 1, &writeDescriptorSet, 0, nullptr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for (auto& child : node->children) {
 | 
				
			||||||
 | 
							prepareNodeDescriptor(child, descriptorSetLayout);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
	glTF rendering functions
 | 
						glTF rendering functions
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Draw a single node including child nodes (if present)
 | 
					void glTFModel::Model::drawNode(Node* node, VkCommandBuffer commandBuffer, uint32_t renderFlags, VkPipelineLayout pipelineLayout, uint32_t bindImageSet)
 | 
				
			||||||
void VulkanglTFModel::drawNode(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, VulkanglTFModel::Node* node, bool bPushConstants)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (node->mesh.primitives.size() > 0) {
 | 
						if (node->mesh) {
 | 
				
			||||||
		// Pass the node's matrix via push constants
 | 
							for (Primitive* primitive : node->mesh->primitives) {
 | 
				
			||||||
		// Traverse the node hierarchy to the top-most parent to get the final matrix of the current node
 | 
								bool skip = false;
 | 
				
			||||||
		glm::mat4 nodeMatrix = node->matrix;
 | 
								const glTFModel::Material& material = primitive->material;
 | 
				
			||||||
		VulkanglTFModel::Node* currentParent = node->parent;
 | 
								if (renderFlags & RenderFlags::RenderOpaqueNodes) {
 | 
				
			||||||
		while (currentParent) {
 | 
									skip = (material.alphaMode != Material::ALPHAMODE_OPAQUE);
 | 
				
			||||||
			nodeMatrix = currentParent->matrix * nodeMatrix;
 | 
								}
 | 
				
			||||||
			currentParent = currentParent->parent;
 | 
								if (renderFlags & RenderFlags::RenderAlphaMaskedNodes) {
 | 
				
			||||||
		}
 | 
									skip = (material.alphaMode != Material::ALPHAMODE_MASK);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		for (VulkanglTFModel::Primitive& primitive : node->mesh.primitives) {
 | 
								if (renderFlags & RenderFlags::RenderAlphaBlendedNodes) {
 | 
				
			||||||
			if (primitive.indexCount > 0) {
 | 
									skip = (material.alphaMode != Material::ALPHAMODE_BLEND);
 | 
				
			||||||
				// Get the texture index for this primitive
 | 
								}
 | 
				
			||||||
				if (textures.size() > 0)
 | 
								if (!skip) {
 | 
				
			||||||
				{
 | 
									if (renderFlags & RenderFlags::BindImages) {
 | 
				
			||||||
					//binding base color texture
 | 
										vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, bindImageSet, 1, &material.descriptorSet, 0, nullptr);
 | 
				
			||||||
					if (materials[primitive.materialIndex].baseColorTextureIndex < textures.size())
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						VulkanglTFModel::Texture texture = textures[materials[primitive.materialIndex].baseColorTextureIndex];
 | 
					 | 
				
			||||||
						vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &images[texture.imageIndex].descriptorSet, 0, nullptr);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					
 | 
					 | 
				
			||||||
					//normal map binding
 | 
					 | 
				
			||||||
					if (materials[primitive.materialIndex].normalMapTextureIndex < textures.size())
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						auto normalMap = textures[materials[primitive.materialIndex].normalMapTextureIndex];
 | 
					 | 
				
			||||||
						vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 2, 1, &images[normalMap.imageIndex].descriptorSet, 0, nullptr);
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					//rough map binding
 | 
					 | 
				
			||||||
					if (materials[primitive.materialIndex].matalicRoughTextureIndex < textures.size())
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						auto roughMetalMap = textures[materials[primitive.materialIndex].matalicRoughTextureIndex];
 | 
					 | 
				
			||||||
						vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 3, 1, &images[roughMetalMap.imageIndex].descriptorSet, 0, nullptr);
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
					
 | 
					 | 
				
			||||||
					//emissive texture binding
 | 
					 | 
				
			||||||
					if (materials[primitive.materialIndex].emissiveTextureIndex >= 0 && materials[primitive.materialIndex].emissiveTextureIndex < textures.size())
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						auto emissiveMap = textures[materials[primitive.materialIndex].emissiveTextureIndex];
 | 
					 | 
				
			||||||
						vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 4, 1, &images[emissiveMap.imageIndex].descriptorSet, 0, nullptr);
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
					// Bind the descriptor for the current primitive's texture
 | 
					 | 
				
			||||||
					
 | 
					 | 
				
			||||||
					vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 5, 1, &materials[primitive.materialIndex].materialData.descriptorSet, 0, nullptr);
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				vkCmdDrawIndexed(commandBuffer, primitive.indexCount, 1, primitive.firstIndex, 0, 0);
 | 
									vkCmdDrawIndexed(commandBuffer, primitive->indexCount, 1, primitive->firstIndex, 0, 0);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for (auto& child : node->children) {
 | 
						for (auto& child : node->children) {
 | 
				
			||||||
		drawNode(commandBuffer, pipelineLayout, child, bPushConstants);
 | 
							drawNode(child, commandBuffer, renderFlags, pipelineLayout, bindImageSet);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Draw the glTF scene starting at the top-level-nodes
 | 
					// Draw the glTF scene starting at the top-level-nodes
 | 
				
			||||||
void VulkanglTFModel::draw(VkCommandBuffer commandBuffer, VkPipelineLayout pipelineLayout, bool flag = true)
 | 
					void glTFModel::Model::draw(VkCommandBuffer commandBuffer, uint32_t renderFlags, VkPipelineLayout pipelineLayout, uint32_t bindImageSet)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	// All vertices and indices are stored in single buffers, so we only need to bind once
 | 
						if (!buffersBound) {
 | 
				
			||||||
	VkDeviceSize offsets[1] = { 0 };
 | 
							const VkDeviceSize offsets[1] = { 0 };
 | 
				
			||||||
	vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertices.buffer, offsets);
 | 
							vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vertices.buffer, offsets);
 | 
				
			||||||
	vkCmdBindIndexBuffer(commandBuffer, indices.buffer, 0, VK_INDEX_TYPE_UINT32);
 | 
							vkCmdBindIndexBuffer(commandBuffer, indices.buffer, 0, VK_INDEX_TYPE_UINT32);
 | 
				
			||||||
	// Render all nodes at top-level
 | 
						}
 | 
				
			||||||
	for (auto& node : nodes) {
 | 
						for (auto& node : nodes) {
 | 
				
			||||||
		drawNode(commandBuffer, pipelineLayout, node, flag);
 | 
							drawNode(node, commandBuffer, renderFlags, pipelineLayout, bindImageSet);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue