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{};
|
||||||
|
@ -902,7 +944,6 @@ void glTFModel::Model::loadNode(glTFModel::Node* parent, const tinygltf::Node& n
|
||||||
newNode->skinIndex = node.skin;
|
newNode->skinIndex = node.skin;
|
||||||
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
|
||||||
|
@ -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