2016-02-16 15:07:25 +01:00
/*
2020-04-19 10:59:16 +02:00
* Vulkan Example - glTF scene loading and rendering
2016-02-16 15:07:25 +01:00
*
2020-04-19 10:59:16 +02:00
* Copyright ( C ) 2020 by Sascha Willems - www . saschawillems . de
2016-02-16 15:07:25 +01:00
*
* This code is licensed under the MIT license ( MIT ) ( http : //opensource.org/licenses/MIT)
*/
2020-04-12 18:37:25 +02:00
/*
2020-04-19 10:59:16 +02:00
* Shows how to load and display a simple scene from a glTF file
2020-04-12 18:37:25 +02:00
* Note that this isn ' t a complete glTF loader and only basic functions are shown here
2020-04-13 16:26:40 +02:00
* This means no complex materials , no animations , no skins , etc .
2020-04-12 18:37:25 +02:00
* For details on how glTF 2.0 works , see the official spec at https : //github.com/KhronosGroup/glTF/tree/master/specification/2.0
2020-04-12 21:59:26 +02:00
*
* Other samples will load models using a dedicated model loader with more features ( see base / VulkanglTFModel . hpp )
2020-05-29 16:08:53 +01:00
*
2020-04-12 18:37:25 +02:00
* If you are looking for a complete glTF implementation , check out https : //github.com/SaschaWillems/Vulkan-glTF-PBR/
*/
2016-02-16 15:07:25 +01:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <assert.h>
# include <vector>
# define GLM_FORCE_RADIANS
2016-03-08 21:52:40 +01:00
# define GLM_FORCE_DEPTH_ZERO_TO_ONE
2016-02-16 15:07:25 +01:00
# include <glm/glm.hpp>
# include <glm/gtc/matrix_transform.hpp>
2017-02-10 21:27:23 +01:00
# include <glm/gtc/type_ptr.hpp>
2020-04-12 18:37:25 +02:00
# define TINYGLTF_IMPLEMENTATION
# define STB_IMAGE_IMPLEMENTATION
# define TINYGLTF_NO_STB_IMAGE_WRITE
2020-04-19 16:43:25 +02:00
# ifdef VK_USE_PLATFORM_ANDROID_KHR
# define TINYGLTF_ANDROID_LOAD_FROM_ASSETS
# endif
2020-04-12 18:37:25 +02:00
# include "tiny_gltf.h"
2016-02-16 15:07:25 +01:00
# include <vulkan/vulkan.h>
# include "vulkanexamplebase.h"
2017-02-09 21:55:35 +01:00
# include "VulkanTexture.hpp"
2016-02-16 15:07:25 +01:00
# define ENABLE_VALIDATION false
2020-04-12 21:24:33 +02:00
// Contains everything required to render a glTF model in Vulkan
2020-04-12 22:07:54 +02:00
// This class is heavily simplified (compared to glTF's feature set) but retains the basic glTF structure
2020-05-29 16:08:53 +01:00
class VulkanglTFModel
2016-02-16 15:07:25 +01:00
{
public :
2020-04-12 21:59:26 +02:00
// The class requires some Vulkan objects so it can create it's own resources
vks : : VulkanDevice * vulkanDevice ;
2020-05-29 16:08:53 +01:00
VkQueue copyQueue ;
2016-05-15 11:13:57 +02:00
2020-04-12 21:59:26 +02:00
// The vertex layout for the samples' model
2017-02-11 09:41:14 +01:00
struct Vertex {
glm : : vec3 pos ;
glm : : vec3 normal ;
glm : : vec2 uv ;
glm : : vec3 color ;
} ;
2020-04-12 21:59:26 +02:00
// Single vertex buffer for all primitives
struct {
VkBuffer buffer ;
VkDeviceMemory memory ;
} vertices ;
2020-05-29 16:08:53 +01:00
2020-04-12 21:59:26 +02:00
// Single index buffer for all primitives
struct {
int count ;
VkBuffer buffer ;
VkDeviceMemory memory ;
} indices ;
2020-05-29 16:08:53 +01:00
// The following structures roughly represent the glTF scene structure
2020-04-12 21:59:26 +02:00
// To keep things simple, they only contain those properties that are required for this sample
struct Node ;
2020-04-12 18:37:25 +02:00
2020-04-12 21:24:33 +02:00
// A primitive contains the data for a single draw call
struct Primitive {
2020-04-12 18:37:25 +02:00
uint32_t firstIndex ;
uint32_t indexCount ;
2020-04-12 21:24:33 +02:00
int32_t materialIndex ;
} ;
2020-04-12 21:59:26 +02:00
// Contains the node's (optional) geometry and can be made up of an arbitrary number of primitives
2020-04-12 21:24:33 +02:00
struct Mesh {
std : : vector < Primitive > primitives ;
} ;
// A node represents an object in the glTF scene graph
2020-04-12 21:59:26 +02:00
struct Node {
Node * parent ;
std : : vector < Node > children ;
2020-04-12 21:24:33 +02:00
Mesh mesh ;
glm : : mat4 matrix ;
2020-04-12 18:37:25 +02:00
} ;
2020-08-08 13:59:58 +02:00
// A glTF material stores information in e.g. the texture that is attached to it and colors
2020-04-12 21:59:26 +02:00
struct Material {
2020-04-12 18:37:25 +02:00
glm : : vec4 baseColorFactor = glm : : vec4 ( 1.0f ) ;
uint32_t baseColorTextureIndex ;
} ;
2020-04-12 21:59:26 +02:00
// Contains the texture for a single glTF image
// Images may be reused by texture objects and are as such separted
struct Image {
2020-04-12 21:24:33 +02:00
vks : : Texture2D texture ;
2020-04-12 21:59:26 +02:00
// We also store (and create) a descriptor set that's used to access this texture from the fragment shader
2020-04-12 21:24:33 +02:00
VkDescriptorSet descriptorSet ;
} ;
2020-04-12 21:59:26 +02:00
// A glTF texture stores a reference to the image and a sampler
// In this sample, we are only interested in the image
struct Texture {
int32_t imageIndex ;
} ;
2016-02-16 15:07:25 +01:00
2020-04-12 21:59:26 +02:00
/*
Model data
*/
std : : vector < Image > images ;
std : : vector < Texture > textures ;
std : : vector < Material > materials ;
std : : vector < Node > nodes ;
2017-02-10 21:27:23 +01:00
2020-04-13 18:58:02 +02:00
~ VulkanglTFModel ( )
{
// Release all Vulkan resources allocated for the model
vkDestroyBuffer ( vulkanDevice - > logicalDevice , vertices . buffer , nullptr ) ;
vkFreeMemory ( vulkanDevice - > logicalDevice , vertices . memory , nullptr ) ;
vkDestroyBuffer ( vulkanDevice - > logicalDevice , indices . buffer , nullptr ) ;
vkFreeMemory ( vulkanDevice - > logicalDevice , indices . memory , nullptr ) ;
for ( Image image : images ) {
vkDestroyImageView ( vulkanDevice - > logicalDevice , image . texture . view , nullptr ) ;
vkDestroyImage ( vulkanDevice - > logicalDevice , image . texture . image , nullptr ) ;
vkDestroySampler ( vulkanDevice - > logicalDevice , image . texture . sampler , nullptr ) ;
vkFreeMemory ( vulkanDevice - > logicalDevice , image . texture . deviceMemory , nullptr ) ;
}
}
2020-04-12 18:37:25 +02:00
/*
2020-04-12 21:59:26 +02:00
glTF loading functions
The following functions take a glTF input model loaded via tinyglTF and convert all required data into our own structure
2020-04-12 18:37:25 +02:00
*/
2020-04-12 21:59:26 +02:00
void loadImages ( tinygltf : : Model & input )
2020-04-12 18:37:25 +02:00
{
2020-04-12 21:59:26 +02:00
// Images can be stored inside the glTF (which is the case for the sample model), so instead of directly
// loading them from disk, we fetch them from the glTF loader and upload the buffers
images . resize ( input . images . size ( ) ) ;
for ( size_t i = 0 ; i < input . images . size ( ) ; i + + ) {
tinygltf : : Image & glTFImage = input . images [ i ] ;
2020-04-12 18:37:25 +02:00
// Get the image data from the glTF loader
unsigned char * buffer = nullptr ;
VkDeviceSize bufferSize = 0 ;
bool deleteBuffer = false ;
// We convert RGB-only images to RGBA, as most devices don't support RGB-formats in Vulkan
if ( glTFImage . component = = 3 ) {
bufferSize = glTFImage . width * glTFImage . height * 4 ;
buffer = new unsigned char [ bufferSize ] ;
unsigned char * rgba = buffer ;
unsigned char * rgb = & glTFImage . image [ 0 ] ;
for ( size_t i = 0 ; i < glTFImage . width * glTFImage . height ; + + i ) {
2020-05-15 07:11:47 +02:00
memcpy ( rgba , rgb , sizeof ( unsigned char ) * 3 ) ;
2020-04-12 18:37:25 +02:00
rgba + = 4 ;
rgb + = 3 ;
}
deleteBuffer = true ;
}
else {
buffer = & glTFImage . image [ 0 ] ;
bufferSize = glTFImage . image . size ( ) ;
}
2020-04-12 21:24:33 +02:00
// Load texture from image buffer
2020-04-12 21:59:26 +02:00
images [ i ] . texture . fromBuffer ( buffer , bufferSize , VK_FORMAT_R8G8B8A8_UNORM , glTFImage . width , glTFImage . height , vulkanDevice , copyQueue ) ;
2020-05-15 07:11:47 +02:00
if ( deleteBuffer ) {
delete buffer ;
}
2020-04-12 18:37:25 +02:00
}
}
2017-02-10 21:27:23 +01:00
2020-04-12 21:59:26 +02:00
void loadTextures ( tinygltf : : Model & input )
2020-04-12 18:37:25 +02:00
{
2020-04-12 21:59:26 +02:00
textures . resize ( input . textures . size ( ) ) ;
for ( size_t i = 0 ; i < input . textures . size ( ) ; i + + ) {
textures [ i ] . imageIndex = input . textures [ i ] . source ;
2020-04-12 18:37:25 +02:00
}
}
2017-02-10 21:27:23 +01:00
2020-04-12 21:59:26 +02:00
void loadMaterials ( tinygltf : : Model & input )
2020-04-12 18:37:25 +02:00
{
2020-04-12 21:59:26 +02:00
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 ] ;
2020-04-12 18:37:25 +02:00
// Get the base color factor
if ( glTFMaterial . values . find ( " baseColorFactor " ) ! = glTFMaterial . values . end ( ) ) {
2020-04-12 21:59:26 +02:00
materials [ i ] . baseColorFactor = glm : : make_vec4 ( glTFMaterial . values [ " baseColorFactor " ] . ColorFactor ( ) . data ( ) ) ;
2020-04-12 18:37:25 +02:00
}
// Get base color texture index
if ( glTFMaterial . values . find ( " baseColorTexture " ) ! = glTFMaterial . values . end ( ) ) {
2020-04-12 21:59:26 +02:00
materials [ i ] . baseColorTextureIndex = glTFMaterial . values [ " baseColorTexture " ] . TextureIndex ( ) ;
2020-04-12 18:37:25 +02:00
}
}
}
2020-04-12 21:59:26 +02:00
void loadNode ( const tinygltf : : Node & inputNode , const tinygltf : : Model & input , VulkanglTFModel : : Node * parent , std : : vector < uint32_t > & indexBuffer , std : : vector < VulkanglTFModel : : Vertex > & vertexBuffer )
2020-04-12 18:37:25 +02:00
{
2020-04-12 21:59:26 +02:00
VulkanglTFModel : : Node node { } ;
2020-04-12 18:37:25 +02:00
node . matrix = glm : : mat4 ( 1.0f ) ;
// Get the local node matrix
// It's either made up from translation, rotation, scale or a 4x4 matrix
2020-04-12 21:59:26 +02:00
if ( inputNode . translation . size ( ) = = 3 ) {
node . matrix = glm : : translate ( node . matrix , glm : : vec3 ( glm : : make_vec3 ( inputNode . translation . data ( ) ) ) ) ;
2020-04-12 18:37:25 +02:00
}
2020-04-12 21:59:26 +02:00
if ( inputNode . rotation . size ( ) = = 4 ) {
glm : : quat q = glm : : make_quat ( inputNode . rotation . data ( ) ) ;
2020-04-12 18:37:25 +02:00
node . matrix * = glm : : mat4 ( q ) ;
}
2020-04-12 21:59:26 +02:00
if ( inputNode . scale . size ( ) = = 3 ) {
2020-04-13 16:26:40 +02:00
node . matrix = glm : : scale ( node . matrix , glm : : vec3 ( glm : : make_vec3 ( inputNode . scale . data ( ) ) ) ) ;
2020-04-12 18:37:25 +02:00
}
2020-04-12 21:59:26 +02:00
if ( inputNode . matrix . size ( ) = = 16 ) {
node . matrix = glm : : make_mat4x4 ( inputNode . matrix . data ( ) ) ;
2020-04-12 18:37:25 +02:00
} ;
2017-02-10 21:27:23 +01:00
2020-05-29 16:08:53 +01:00
// Load node's children
2020-04-12 21:59:26 +02:00
if ( inputNode . children . size ( ) > 0 ) {
for ( size_t i = 0 ; i < inputNode . children . size ( ) ; i + + ) {
loadNode ( input . nodes [ inputNode . children [ i ] ] , input , & node , indexBuffer , vertexBuffer ) ;
2020-04-12 18:37:25 +02:00
}
}
2020-08-08 13:59:58 +02:00
// If the node contains mesh data, we load vertices and indices from the buffers
2020-04-12 18:37:25 +02:00
// In glTF this is done via accessors and buffer views
2020-04-12 21:59:26 +02:00
if ( inputNode . mesh > - 1 ) {
const tinygltf : : Mesh mesh = input . meshes [ inputNode . mesh ] ;
2020-04-12 18:37:25 +02:00
// Iterate through all primitives of this node's mesh
for ( size_t i = 0 ; i < mesh . primitives . size ( ) ; i + + ) {
2020-04-12 21:24:33 +02:00
const tinygltf : : Primitive & glTFPrimitive = mesh . primitives [ i ] ;
uint32_t firstIndex = static_cast < uint32_t > ( indexBuffer . size ( ) ) ;
uint32_t vertexStart = static_cast < uint32_t > ( vertexBuffer . size ( ) ) ;
uint32_t indexCount = 0 ;
2020-04-12 18:37:25 +02:00
// Vertices
{
const float * positionBuffer = nullptr ;
const float * normalsBuffer = nullptr ;
const float * texCoordsBuffer = nullptr ;
size_t vertexCount = 0 ;
// Get buffer data for vertex normals
2020-04-12 21:24:33 +02:00
if ( glTFPrimitive . attributes . find ( " POSITION " ) ! = glTFPrimitive . attributes . end ( ) ) {
2020-04-12 21:59:26 +02:00
const tinygltf : : Accessor & accessor = input . accessors [ glTFPrimitive . attributes . find ( " POSITION " ) - > second ] ;
const tinygltf : : BufferView & view = input . bufferViews [ accessor . bufferView ] ;
positionBuffer = reinterpret_cast < const float * > ( & ( input . buffers [ view . buffer ] . data [ accessor . byteOffset + view . byteOffset ] ) ) ;
2020-04-12 18:37:25 +02:00
vertexCount = accessor . count ;
}
// Get buffer data for vertex normals
2020-04-12 21:24:33 +02:00
if ( glTFPrimitive . attributes . find ( " NORMAL " ) ! = glTFPrimitive . attributes . end ( ) ) {
2020-04-12 21:59:26 +02:00
const tinygltf : : Accessor & accessor = input . accessors [ glTFPrimitive . attributes . find ( " NORMAL " ) - > second ] ;
const tinygltf : : BufferView & view = input . bufferViews [ accessor . bufferView ] ;
normalsBuffer = reinterpret_cast < const float * > ( & ( input . buffers [ view . buffer ] . data [ accessor . byteOffset + view . byteOffset ] ) ) ;
2020-04-12 18:37:25 +02:00
}
// Get buffer data for vertex texture coordinates
// glTF supports multiple sets, we only load the first one
2020-04-12 21:24:33 +02:00
if ( glTFPrimitive . attributes . find ( " TEXCOORD_0 " ) ! = glTFPrimitive . attributes . end ( ) ) {
2020-04-12 21:59:26 +02:00
const tinygltf : : Accessor & accessor = input . accessors [ glTFPrimitive . attributes . find ( " TEXCOORD_0 " ) - > second ] ;
const tinygltf : : BufferView & view = input . bufferViews [ accessor . bufferView ] ;
texCoordsBuffer = reinterpret_cast < const float * > ( & ( input . buffers [ view . buffer ] . data [ accessor . byteOffset + view . byteOffset ] ) ) ;
2020-04-12 18:37:25 +02:00
}
// Append data to model's vertex buffer
for ( size_t v = 0 ; v < vertexCount ; v + + ) {
Vertex vert { } ;
vert . pos = glm : : vec4 ( glm : : make_vec3 ( & positionBuffer [ v * 3 ] ) , 1.0f ) ;
vert . normal = glm : : normalize ( glm : : vec3 ( normalsBuffer ? glm : : make_vec3 ( & normalsBuffer [ v * 3 ] ) : glm : : vec3 ( 0.0f ) ) ) ;
vert . uv = texCoordsBuffer ? glm : : make_vec2 ( & texCoordsBuffer [ v * 2 ] ) : glm : : vec3 ( 0.0f ) ;
2020-04-12 21:24:33 +02:00
vert . color = glm : : vec3 ( 1.0f ) ;
2020-04-12 18:37:25 +02:00
vertexBuffer . push_back ( vert ) ;
}
}
// Indices
{
2020-04-12 21:59:26 +02:00
const tinygltf : : Accessor & accessor = input . accessors [ glTFPrimitive . indices ] ;
const tinygltf : : BufferView & bufferView = input . bufferViews [ accessor . bufferView ] ;
const tinygltf : : Buffer & buffer = input . buffers [ bufferView . buffer ] ;
2020-04-12 18:37:25 +02:00
indexCount + = static_cast < uint32_t > ( accessor . count ) ;
2020-04-12 21:24:33 +02:00
// glTF supports different component types of indices
2020-04-12 18:37:25 +02:00
switch ( accessor . componentType ) {
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT : {
uint32_t * buf = new uint32_t [ accessor . count ] ;
memcpy ( buf , & buffer . data [ accessor . byteOffset + bufferView . byteOffset ] , accessor . count * sizeof ( uint32_t ) ) ;
for ( size_t index = 0 ; index < accessor . count ; index + + ) {
indexBuffer . push_back ( buf [ index ] + vertexStart ) ;
}
break ;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT : {
uint16_t * buf = new uint16_t [ accessor . count ] ;
memcpy ( buf , & buffer . data [ accessor . byteOffset + bufferView . byteOffset ] , accessor . count * sizeof ( uint16_t ) ) ;
for ( size_t index = 0 ; index < accessor . count ; index + + ) {
indexBuffer . push_back ( buf [ index ] + vertexStart ) ;
}
break ;
}
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE : {
uint8_t * buf = new uint8_t [ accessor . count ] ;
memcpy ( buf , & buffer . data [ accessor . byteOffset + bufferView . byteOffset ] , accessor . count * sizeof ( uint8_t ) ) ;
for ( size_t index = 0 ; index < accessor . count ; index + + ) {
indexBuffer . push_back ( buf [ index ] + vertexStart ) ;
}
break ;
}
default :
std : : cerr < < " Index component type " < < accessor . componentType < < " not supported! " < < std : : endl ;
return ;
}
}
2020-04-12 21:24:33 +02:00
Primitive primitive { } ;
primitive . firstIndex = firstIndex ;
primitive . indexCount = indexCount ;
primitive . materialIndex = glTFPrimitive . material ;
node . mesh . primitives . push_back ( primitive ) ;
2020-04-12 18:37:25 +02:00
}
}
if ( parent ) {
parent - > children . push_back ( node ) ;
}
else {
2020-04-12 21:59:26 +02:00
nodes . push_back ( node ) ;
}
}
2020-04-12 22:07:54 +02:00
/*
glTF rendering functions
*/
2020-05-29 16:08:53 +01:00
2020-04-12 22:07:54 +02:00
// Draw a single node including child nodes (if present)
2020-04-13 18:58:02 +02:00
void drawNode ( VkCommandBuffer commandBuffer , VkPipelineLayout pipelineLayout , VulkanglTFModel : : Node node )
2020-04-12 22:07:54 +02:00
{
if ( node . mesh . primitives . size ( ) > 0 ) {
2020-04-13 16:26:40 +02:00
// Pass the node's matrix via push constanst
// Traverse the node hierarchy to the top-most parent to get the final matrix of the current node
glm : : mat4 nodeMatrix = node . matrix ;
VulkanglTFModel : : Node * currentParent = node . parent ;
while ( currentParent ) {
nodeMatrix = currentParent - > matrix * nodeMatrix ;
currentParent = currentParent - > parent ;
}
// Pass the final matrix to the vertex shader using push constants
vkCmdPushConstants ( commandBuffer , pipelineLayout , VK_SHADER_STAGE_VERTEX_BIT , 0 , sizeof ( glm : : mat4 ) , & nodeMatrix ) ;
2020-04-12 22:07:54 +02:00
for ( VulkanglTFModel : : Primitive & primitive : node . mesh . primitives ) {
if ( primitive . indexCount > 0 ) {
// Get the texture index for this primitive
VulkanglTFModel : : Texture texture = textures [ materials [ primitive . materialIndex ] . baseColorTextureIndex ] ;
2020-04-13 16:26:40 +02:00
// Bind the descriptor for the current primitive's texture
2020-04-12 22:07:54 +02:00
vkCmdBindDescriptorSets ( commandBuffer , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 1 , 1 , & images [ texture . imageIndex ] . descriptorSet , 0 , nullptr ) ;
vkCmdDrawIndexed ( commandBuffer , primitive . indexCount , 1 , primitive . firstIndex , 0 , 0 ) ;
}
}
}
for ( auto & child : node . children ) {
2020-04-13 18:58:02 +02:00
drawNode ( commandBuffer , pipelineLayout , child ) ;
2020-04-12 22:07:54 +02:00
}
}
// Draw the glTF scene starting at the top-level-nodes
void draw ( VkCommandBuffer commandBuffer , VkPipelineLayout pipelineLayout )
{
2020-05-29 16:08:53 +01:00
// All vertices and indices are stored in single buffers, so we only need to bind once
2020-04-12 22:07:54 +02:00
VkDeviceSize offsets [ 1 ] = { 0 } ;
vkCmdBindVertexBuffers ( commandBuffer , 0 , 1 , & vertices . buffer , offsets ) ;
vkCmdBindIndexBuffer ( commandBuffer , indices . buffer , 0 , VK_INDEX_TYPE_UINT32 ) ;
// Render all nodes at top-level
for ( auto & node : nodes ) {
2020-04-13 18:58:02 +02:00
drawNode ( commandBuffer , pipelineLayout , node ) ;
2020-04-12 22:07:54 +02:00
}
}
2020-04-12 21:59:26 +02:00
} ;
class VulkanExample : public VulkanExampleBase
{
public :
bool wireframe = false ;
VulkanglTFModel glTFModel ;
2020-04-19 10:59:16 +02:00
struct ShaderData {
vks : : Buffer buffer ;
struct Values {
glm : : mat4 projection ;
glm : : mat4 model ;
glm : : vec4 lightPos = glm : : vec4 ( 5.0f , 5.0f , - 5.0f , 1.0f ) ;
} values ;
} shaderData ;
2020-04-12 21:59:26 +02:00
struct Pipelines {
VkPipeline solid ;
VkPipeline wireframe = VK_NULL_HANDLE ;
} pipelines ;
VkPipelineLayout pipelineLayout ;
VkDescriptorSet descriptorSet ;
struct DescriptorSetLayouts {
VkDescriptorSetLayout matrices ;
VkDescriptorSetLayout textures ;
} descriptorSetLayouts ;
VulkanExample ( ) : VulkanExampleBase ( ENABLE_VALIDATION )
{
title = " glTF model rendering " ;
2020-04-12 22:12:44 +02:00
camera . type = Camera : : CameraType : : lookat ;
2020-04-13 16:26:40 +02:00
camera . flipY = true ;
2020-04-19 10:59:16 +02:00
camera . setPosition ( glm : : vec3 ( 0.0f , - 0.1f , - 1.0f ) ) ;
camera . setRotation ( glm : : vec3 ( 0.0f , - 135.0f , 0.0f ) ) ;
2020-04-12 22:12:44 +02:00
camera . setPerspective ( 60.0f , ( float ) width / ( float ) height , 0.1f , 256.0f ) ;
2020-04-12 21:59:26 +02:00
settings . overlay = true ;
}
~ VulkanExample ( )
{
2020-05-29 16:08:53 +01:00
// Clean up used Vulkan resources
2020-04-12 21:59:26 +02:00
// Note : Inherited destructor cleans up resources stored in base class
vkDestroyPipeline ( device , pipelines . solid , nullptr ) ;
if ( pipelines . wireframe ! = VK_NULL_HANDLE ) {
vkDestroyPipeline ( device , pipelines . wireframe , nullptr ) ;
}
vkDestroyPipelineLayout ( device , pipelineLayout , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayouts . matrices , nullptr ) ;
vkDestroyDescriptorSetLayout ( device , descriptorSetLayouts . textures , nullptr ) ;
2020-04-19 10:59:16 +02:00
shaderData . buffer . destroy ( ) ;
2020-04-12 21:59:26 +02:00
}
virtual void getEnabledFeatures ( )
{
// Fill mode non solid is required for wireframe display
if ( deviceFeatures . fillModeNonSolid ) {
enabledFeatures . fillModeNonSolid = VK_TRUE ;
} ;
}
void buildCommandBuffers ( )
{
VkCommandBufferBeginInfo cmdBufInfo = vks : : initializers : : commandBufferBeginInfo ( ) ;
VkClearValue clearValues [ 2 ] ;
clearValues [ 0 ] . color = defaultClearColor ;
2020-04-19 11:50:46 +02:00
clearValues [ 0 ] . color = { { 0.25f , 0.25f , 0.25f , 1.0f } } ; ;
2020-04-12 21:59:26 +02:00
clearValues [ 1 ] . depthStencil = { 1.0f , 0 } ;
VkRenderPassBeginInfo renderPassBeginInfo = vks : : initializers : : renderPassBeginInfo ( ) ;
renderPassBeginInfo . renderPass = renderPass ;
renderPassBeginInfo . renderArea . offset . x = 0 ;
renderPassBeginInfo . renderArea . offset . y = 0 ;
renderPassBeginInfo . renderArea . extent . width = width ;
renderPassBeginInfo . renderArea . extent . height = height ;
renderPassBeginInfo . clearValueCount = 2 ;
renderPassBeginInfo . pClearValues = clearValues ;
const VkViewport viewport = vks : : initializers : : viewport ( ( float ) width , ( float ) height , 0.0f , 1.0f ) ;
const VkRect2D scissor = vks : : initializers : : rect2D ( width , height , 0 , 0 ) ;
for ( int32_t i = 0 ; i < drawCmdBuffers . size ( ) ; + + i )
{
renderPassBeginInfo . framebuffer = frameBuffers [ i ] ;
VK_CHECK_RESULT ( vkBeginCommandBuffer ( drawCmdBuffers [ i ] , & cmdBufInfo ) ) ;
vkCmdBeginRenderPass ( drawCmdBuffers [ i ] , & renderPassBeginInfo , VK_SUBPASS_CONTENTS_INLINE ) ;
vkCmdSetViewport ( drawCmdBuffers [ i ] , 0 , 1 , & viewport ) ;
vkCmdSetScissor ( drawCmdBuffers [ i ] , 0 , 1 , & scissor ) ;
// Bind scene matrices descriptor to set 0
vkCmdBindDescriptorSets ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , pipelineLayout , 0 , 1 , & descriptorSet , 0 , nullptr ) ;
vkCmdBindPipeline ( drawCmdBuffers [ i ] , VK_PIPELINE_BIND_POINT_GRAPHICS , wireframe ? pipelines . wireframe : pipelines . solid ) ;
2020-04-12 22:07:54 +02:00
glTFModel . draw ( drawCmdBuffers [ i ] , pipelineLayout ) ;
2020-04-12 21:59:26 +02:00
drawUI ( drawCmdBuffers [ i ] ) ;
vkCmdEndRenderPass ( drawCmdBuffers [ i ] ) ;
VK_CHECK_RESULT ( vkEndCommandBuffer ( drawCmdBuffers [ i ] ) ) ;
2020-04-12 18:37:25 +02:00
}
}
2020-04-19 10:59:16 +02:00
void loadglTFFile ( std : : string filename )
2020-04-12 18:37:25 +02:00
{
2020-04-12 21:59:26 +02:00
tinygltf : : Model glTFInput ;
2020-04-12 18:37:25 +02:00
tinygltf : : TinyGLTF gltfContext ;
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
2020-04-19 16:43:25 +02:00
// We let tinygltf handle this, by passing the asset manager of our app
tinygltf : : asset_manager = androidApp - > activity - > assetManager ;
2016-03-22 22:28:08 +01:00
# endif
2020-04-19 16:43:25 +02:00
bool fileLoaded = gltfContext . LoadASCIIFromFile ( & glTFInput , & error , & warning , filename ) ;
2020-04-12 21:59:26 +02:00
2020-04-12 22:07:54 +02:00
// Pass some Vulkan resources required for setup and rendering to the glTF model loading class
2020-04-12 21:59:26 +02:00
glTFModel . vulkanDevice = vulkanDevice ;
glTFModel . copyQueue = queue ;
2020-04-12 18:37:25 +02:00
std : : vector < uint32_t > indexBuffer ;
2020-04-12 21:59:26 +02:00
std : : vector < VulkanglTFModel : : Vertex > vertexBuffer ;
2017-02-10 21:27:23 +01:00
2020-04-12 18:37:25 +02:00
if ( fileLoaded ) {
2020-04-12 21:59:26 +02:00
glTFModel . loadImages ( glTFInput ) ;
glTFModel . loadMaterials ( glTFInput ) ;
glTFModel . loadTextures ( glTFInput ) ;
const tinygltf : : Scene & scene = glTFInput . scenes [ 0 ] ;
2020-04-12 18:37:25 +02:00
for ( size_t i = 0 ; i < scene . nodes . size ( ) ; i + + ) {
2020-04-12 21:59:26 +02:00
const tinygltf : : Node node = glTFInput . nodes [ scene . nodes [ i ] ] ;
glTFModel . loadNode ( node , glTFInput , nullptr , indexBuffer , vertexBuffer ) ;
2016-02-16 15:07:25 +01:00
}
}
2020-04-12 18:37:25 +02:00
else {
2020-04-20 20:29:15 +02:00
vks : : tools : : exitFatal ( " Could not open the glTF file. \n \n The file is part of the additional asset pack. \n \n Run \" download_assets.py \" in the repository root to download the latest version. " , - 1 ) ;
2020-04-12 18:37:25 +02:00
return ;
2016-02-16 15:07:25 +01:00
}
2020-04-12 18:37:25 +02:00
2020-04-12 22:07:54 +02:00
// Create and upload vertex and index buffer
// We will be using one single vertex buffer and one single index buffer for the whole glTF scene
// Primitives (of the glTF model) will then index into these using index offsets
2020-04-12 21:59:26 +02:00
size_t vertexBufferSize = vertexBuffer . size ( ) * sizeof ( VulkanglTFModel : : Vertex ) ;
2017-02-10 21:27:23 +01:00
size_t indexBufferSize = indexBuffer . size ( ) * sizeof ( uint32_t ) ;
2020-04-12 21:59:26 +02:00
glTFModel . indices . count = static_cast < uint32_t > ( indexBuffer . size ( ) ) ;
2016-02-16 15:07:25 +01:00
2020-04-12 18:37:25 +02:00
struct StagingBuffer {
VkBuffer buffer ;
VkDeviceMemory memory ;
} vertexStaging , indexStaging ;
2016-05-08 11:30:04 +02:00
2020-04-12 22:07:54 +02:00
// Create host visible staging buffers (source)
2020-04-12 18:37:25 +02:00
VK_CHECK_RESULT ( vulkanDevice - > 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 ( vulkanDevice - > 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 ( ) ) ) ;
2020-08-08 13:59:58 +02:00
// Create device local buffers (target)
2020-04-12 18:37:25 +02:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT ,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ,
vertexBufferSize ,
2020-04-12 21:59:26 +02:00
& glTFModel . vertices . buffer ,
& glTFModel . vertices . memory ) ) ;
2020-04-12 18:37:25 +02:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT ,
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ,
indexBufferSize ,
2020-04-12 21:59:26 +02:00
& glTFModel . indices . buffer ,
& glTFModel . indices . memory ) ) ;
2020-04-12 18:37:25 +02:00
// Copy data from staging buffers (host) do device local buffer (gpu)
2020-04-20 22:13:51 +02:00
VkCommandBuffer copyCmd = vulkanDevice - > createCommandBuffer ( VK_COMMAND_BUFFER_LEVEL_PRIMARY , true ) ;
2020-04-12 18:37:25 +02:00
VkBufferCopy copyRegion = { } ;
copyRegion . size = vertexBufferSize ;
vkCmdCopyBuffer (
copyCmd ,
vertexStaging . buffer ,
2020-04-12 21:59:26 +02:00
glTFModel . vertices . buffer ,
2020-04-12 18:37:25 +02:00
1 ,
& copyRegion ) ;
copyRegion . size = indexBufferSize ;
vkCmdCopyBuffer (
copyCmd ,
indexStaging . buffer ,
2020-04-12 21:59:26 +02:00
glTFModel . indices . buffer ,
2020-04-12 18:37:25 +02:00
1 ,
& copyRegion ) ;
2020-04-20 22:13:51 +02:00
vulkanDevice - > flushCommandBuffer ( copyCmd , queue , true ) ;
2020-04-12 18:37:25 +02:00
2020-04-12 22:07:54 +02:00
// Free staging resources
2020-04-12 18:37:25 +02:00
vkDestroyBuffer ( device , vertexStaging . buffer , nullptr ) ;
vkFreeMemory ( device , vertexStaging . memory , nullptr ) ;
vkDestroyBuffer ( device , indexStaging . buffer , nullptr ) ;
vkFreeMemory ( device , indexStaging . memory , nullptr ) ;
2016-02-16 15:07:25 +01:00
}
2017-02-09 21:55:35 +01:00
void loadAssets ( )
2016-02-16 15:07:25 +01:00
{
2020-04-19 10:59:16 +02:00
loadglTFFile ( getAssetPath ( ) + " models/FlightHelmet/glTF/FlightHelmet.gltf " ) ;
2016-02-16 15:07:25 +01:00
}
2020-04-12 21:24:33 +02:00
void setupDescriptors ( )
2016-02-16 15:07:25 +01:00
{
2020-04-12 21:24:33 +02:00
/*
This sample uses separate descriptor sets ( and layouts ) for the matrices and materials ( textures )
*/
std : : vector < VkDescriptorPoolSize > poolSizes = {
2017-02-12 11:12:42 +01:00
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 1 ) ,
2020-04-12 21:24:33 +02:00
// One combined image sampler per model image/texture
2020-04-12 21:59:26 +02:00
vks : : initializers : : descriptorPoolSize ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , static_cast < uint32_t > ( glTFModel . images . size ( ) ) ) ,
2016-02-16 15:07:25 +01:00
} ;
2020-04-12 21:24:33 +02:00
// One set for matrices and one per model image/texture
2020-04-12 21:59:26 +02:00
const uint32_t maxSetCount = static_cast < uint32_t > ( glTFModel . images . size ( ) ) + 1 ;
2020-04-12 21:24:33 +02:00
VkDescriptorPoolCreateInfo descriptorPoolInfo = vks : : initializers : : descriptorPoolCreateInfo ( poolSizes , maxSetCount ) ;
2016-05-08 11:30:04 +02:00
VK_CHECK_RESULT ( vkCreateDescriptorPool ( device , & descriptorPoolInfo , nullptr , & descriptorPool ) ) ;
2016-02-16 15:07:25 +01:00
2020-04-12 21:24:33 +02:00
// Descriptor set layout for passing matrices
VkDescriptorSetLayoutBinding setLayoutBinding = vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , VK_SHADER_STAGE_VERTEX_BIT , 0 ) ;
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCI = vks : : initializers : : descriptorSetLayoutCreateInfo ( & setLayoutBinding , 1 ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayouts . matrices ) ) ;
// Descriptor set layout for passing material textures
setLayoutBinding = vks : : initializers : : descriptorSetLayoutBinding ( VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , VK_SHADER_STAGE_FRAGMENT_BIT , 0 ) ;
VK_CHECK_RESULT ( vkCreateDescriptorSetLayout ( device , & descriptorSetLayoutCI , nullptr , & descriptorSetLayouts . textures ) ) ;
// Pipeline layout using both descriptor sets (set 0 = matrices, set 1 = material)
std : : array < VkDescriptorSetLayout , 2 > setLayouts = { descriptorSetLayouts . matrices , descriptorSetLayouts . textures } ;
VkPipelineLayoutCreateInfo pipelineLayoutCI = vks : : initializers : : pipelineLayoutCreateInfo ( setLayouts . data ( ) , static_cast < uint32_t > ( setLayouts . size ( ) ) ) ;
2020-04-13 16:26:40 +02:00
// We will use push constants to push the local matrices of a primitive to the vertex shader
VkPushConstantRange pushConstantRange = vks : : initializers : : pushConstantRange ( VK_SHADER_STAGE_VERTEX_BIT , sizeof ( glm : : mat4 ) , 0 ) ;
// Push constant ranges are part of the pipeline layout
pipelineLayoutCI . pushConstantRangeCount = 1 ;
pipelineLayoutCI . pPushConstantRanges = & pushConstantRange ;
2020-04-12 21:24:33 +02:00
VK_CHECK_RESULT ( vkCreatePipelineLayout ( device , & pipelineLayoutCI , nullptr , & pipelineLayout ) ) ;
// Descriptor set for scene matrices
VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayouts . matrices , 1 ) ;
2016-05-08 11:30:04 +02:00
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & descriptorSet ) ) ;
2020-04-19 10:59:16 +02:00
VkWriteDescriptorSet writeDescriptorSet = vks : : initializers : : writeDescriptorSet ( descriptorSet , VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER , 0 , & shaderData . buffer . descriptor ) ;
2020-04-12 21:24:33 +02:00
vkUpdateDescriptorSets ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
// Descriptor sets for materials
2020-04-12 21:59:26 +02:00
for ( auto & image : glTFModel . images ) {
2020-04-12 21:24:33 +02:00
const VkDescriptorSetAllocateInfo allocInfo = vks : : initializers : : descriptorSetAllocateInfo ( descriptorPool , & descriptorSetLayouts . textures , 1 ) ;
VK_CHECK_RESULT ( vkAllocateDescriptorSets ( device , & allocInfo , & image . descriptorSet ) ) ;
VkWriteDescriptorSet writeDescriptorSet = vks : : initializers : : writeDescriptorSet ( image . descriptorSet , VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER , 0 , & image . texture . descriptor ) ;
vkUpdateDescriptorSets ( device , 1 , & writeDescriptorSet , 0 , nullptr ) ;
}
2016-02-16 15:07:25 +01:00
}
void preparePipelines ( )
{
2020-04-12 18:37:25 +02:00
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCI = vks : : initializers : : pipelineInputAssemblyStateCreateInfo ( VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST , 0 , VK_FALSE ) ;
2020-04-12 21:24:33 +02:00
VkPipelineRasterizationStateCreateInfo rasterizationStateCI = vks : : initializers : : pipelineRasterizationStateCreateInfo ( VK_POLYGON_MODE_FILL , VK_CULL_MODE_BACK_BIT , VK_FRONT_FACE_COUNTER_CLOCKWISE , 0 ) ;
2020-04-12 18:37:25 +02:00
VkPipelineColorBlendAttachmentState blendAttachmentStateCI = vks : : initializers : : pipelineColorBlendAttachmentState ( 0xf , VK_FALSE ) ;
VkPipelineColorBlendStateCreateInfo colorBlendStateCI = vks : : initializers : : pipelineColorBlendStateCreateInfo ( 1 , & blendAttachmentStateCI ) ;
VkPipelineDepthStencilStateCreateInfo depthStencilStateCI = vks : : initializers : : pipelineDepthStencilStateCreateInfo ( VK_TRUE , VK_TRUE , VK_COMPARE_OP_LESS_OR_EQUAL ) ;
VkPipelineViewportStateCreateInfo viewportStateCI = vks : : initializers : : pipelineViewportStateCreateInfo ( 1 , 1 , 0 ) ;
VkPipelineMultisampleStateCreateInfo multisampleStateCI = vks : : initializers : : pipelineMultisampleStateCreateInfo ( VK_SAMPLE_COUNT_1_BIT , 0 ) ;
const std : : vector < VkDynamicState > dynamicStateEnables = { VK_DYNAMIC_STATE_VIEWPORT , VK_DYNAMIC_STATE_SCISSOR } ;
VkPipelineDynamicStateCreateInfo dynamicStateCI = vks : : initializers : : pipelineDynamicStateCreateInfo ( dynamicStateEnables . data ( ) , static_cast < uint32_t > ( dynamicStateEnables . size ( ) ) , 0 ) ;
// Vertex input bindings and attributes
const std : : vector < VkVertexInputBindingDescription > vertexInputBindings = {
2020-04-12 21:59:26 +02:00
vks : : initializers : : vertexInputBindingDescription ( 0 , sizeof ( VulkanglTFModel : : Vertex ) , VK_VERTEX_INPUT_RATE_VERTEX ) ,
2016-02-16 15:07:25 +01:00
} ;
2020-04-12 18:37:25 +02:00
const std : : vector < VkVertexInputAttributeDescription > vertexInputAttributes = {
2020-05-29 16:08:53 +01:00
vks : : initializers : : vertexInputAttributeDescription ( 0 , 0 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , pos ) ) , // Location 0: Position
2020-04-12 21:59:26 +02:00
vks : : initializers : : vertexInputAttributeDescription ( 0 , 1 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , normal ) ) , // Location 1: Normal
vks : : initializers : : vertexInputAttributeDescription ( 0 , 2 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , uv ) ) , // Location 2: Texture coordinates
vks : : initializers : : vertexInputAttributeDescription ( 0 , 3 , VK_FORMAT_R32G32B32_SFLOAT , offsetof ( VulkanglTFModel : : Vertex , color ) ) , // Location 3: Color
2020-04-12 18:37:25 +02:00
} ;
VkPipelineVertexInputStateCreateInfo vertexInputStateCI = vks : : initializers : : pipelineVertexInputStateCreateInfo ( ) ;
vertexInputStateCI . vertexBindingDescriptionCount = static_cast < uint32_t > ( vertexInputBindings . size ( ) ) ;
vertexInputStateCI . pVertexBindingDescriptions = vertexInputBindings . data ( ) ;
vertexInputStateCI . vertexAttributeDescriptionCount = static_cast < uint32_t > ( vertexInputAttributes . size ( ) ) ;
vertexInputStateCI . pVertexAttributeDescriptions = vertexInputAttributes . data ( ) ;
const std : : array < VkPipelineShaderStageCreateInfo , 2 > shaderStages = {
2020-07-04 14:20:45 +02:00
loadShader ( getShadersPath ( ) + " gltfloading/mesh.vert.spv " , VK_SHADER_STAGE_VERTEX_BIT ) ,
loadShader ( getShadersPath ( ) + " gltfloading/mesh.frag.spv " , VK_SHADER_STAGE_FRAGMENT_BIT )
2020-04-12 18:37:25 +02:00
} ;
VkGraphicsPipelineCreateInfo pipelineCI = vks : : initializers : : pipelineCreateInfo ( pipelineLayout , renderPass , 0 ) ;
pipelineCI . pVertexInputState = & vertexInputStateCI ;
pipelineCI . pInputAssemblyState = & inputAssemblyStateCI ;
pipelineCI . pRasterizationState = & rasterizationStateCI ;
pipelineCI . pColorBlendState = & colorBlendStateCI ;
pipelineCI . pMultisampleState = & multisampleStateCI ;
pipelineCI . pViewportState = & viewportStateCI ;
pipelineCI . pDepthStencilState = & depthStencilStateCI ;
pipelineCI . pDynamicState = & dynamicStateCI ;
pipelineCI . stageCount = static_cast < uint32_t > ( shaderStages . size ( ) ) ;
pipelineCI . pStages = shaderStages . data ( ) ;
2016-02-16 15:07:25 +01:00
// Solid rendering pipeline
2020-04-12 18:37:25 +02:00
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipelines . solid ) ) ;
2016-05-15 11:13:57 +02:00
// Wire frame rendering pipeline
2017-03-08 21:31:29 +01:00
if ( deviceFeatures . fillModeNonSolid ) {
2020-04-12 18:37:25 +02:00
rasterizationStateCI . polygonMode = VK_POLYGON_MODE_LINE ;
rasterizationStateCI . lineWidth = 1.0f ;
VK_CHECK_RESULT ( vkCreateGraphicsPipelines ( device , pipelineCache , 1 , & pipelineCI , nullptr , & pipelines . wireframe ) ) ;
2017-03-08 21:31:29 +01:00
}
2016-02-16 15:07:25 +01:00
}
// Prepare and initialize uniform buffer containing shader uniforms
void prepareUniformBuffers ( )
{
// Vertex shader uniform buffer block
2016-12-24 12:48:01 +01:00
VK_CHECK_RESULT ( vulkanDevice - > createBuffer (
2016-02-16 15:07:25 +01:00
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT ,
2016-06-05 20:28:39 +02:00
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ,
2020-04-19 10:59:16 +02:00
& shaderData . buffer ,
sizeof ( shaderData . values ) ) ) ;
2020-05-29 16:08:53 +01:00
2016-12-24 12:48:01 +01:00
// Map persistent
2020-04-19 10:59:16 +02:00
VK_CHECK_RESULT ( shaderData . buffer . map ( ) ) ;
2016-02-16 15:07:25 +01:00
updateUniformBuffers ( ) ;
}
void updateUniformBuffers ( )
{
2020-04-19 10:59:16 +02:00
shaderData . values . projection = camera . matrices . perspective ;
shaderData . values . model = camera . matrices . view ;
memcpy ( shaderData . buffer . mapped , & shaderData . values , sizeof ( shaderData . values ) ) ;
2016-02-16 15:07:25 +01:00
}
void prepare ( )
{
VulkanExampleBase : : prepare ( ) ;
2017-02-09 21:55:35 +01:00
loadAssets ( ) ;
2016-02-16 15:07:25 +01:00
prepareUniformBuffers ( ) ;
2020-04-12 21:24:33 +02:00
setupDescriptors ( ) ;
2016-02-16 15:07:25 +01:00
preparePipelines ( ) ;
buildCommandBuffers ( ) ;
prepared = true ;
}
virtual void render ( )
{
2020-04-19 10:59:16 +02:00
renderFrame ( ) ;
2020-04-19 09:18:48 +02:00
if ( camera . updated ) {
2019-02-20 20:03:12 +01:00
updateUniformBuffers ( ) ;
2020-04-19 09:18:48 +02:00
}
2016-02-16 15:07:25 +01:00
}
2016-05-15 11:13:57 +02:00
2017-11-01 14:22:10 +01:00
virtual void OnUpdateUIOverlay ( vks : : UIOverlay * overlay )
2016-05-15 11:13:57 +02:00
{
2017-11-01 14:22:10 +01:00
if ( overlay - > header ( " Settings " ) ) {
if ( overlay - > checkBox ( " Wireframe " , & wireframe ) ) {
buildCommandBuffers ( ) ;
2017-03-08 21:31:29 +01:00
}
}
2016-06-05 20:28:39 +02:00
}
2016-02-16 15:07:25 +01:00
} ;
2016-12-13 19:25:56 +01:00
VULKAN_EXAMPLE_MAIN ( )