Model Vertices rendered.

This commit is contained in:
Anish Bhobe 2024-07-14 20:49:27 +02:00
parent 93981bca4c
commit 69aa72770f
14 changed files with 772 additions and 78 deletions

View File

@ -91,12 +91,20 @@ UniformBuffer::Init(const Device *device, const usize size, const cstr name)
} }
void void
UniformStorageBuffer::Init(const Device *device, usize size, cstr name) StorageBuffer::Init(const Device *device, usize size, bool hostVisible, cstr name)
{ {
Allocate(device, size, vk::BufferUsageFlagBits::eStorageBuffer, if (hostVisible)
VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT | {
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT, Allocate(device, size, vk::BufferUsageFlagBits::eStorageBuffer,
VMA_MEMORY_USAGE_AUTO, name); VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT,
VMA_MEMORY_USAGE_AUTO, name);
}
else
{
Allocate(device, size, vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eTransferDst,
VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, VMA_MEMORY_USAGE_AUTO, name);
}
} }
void void
@ -106,6 +114,13 @@ VertexBuffer::Init(const Device *device, usize size, cstr name)
VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, VMA_MEMORY_USAGE_AUTO, name); VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, VMA_MEMORY_USAGE_AUTO, name);
} }
void
IndexBuffer::Init(const Device *device, usize size, cstr name)
{
Allocate(device, size, vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eTransferDst,
VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, VMA_MEMORY_USAGE_AUTO, name);
}
void void
StagingBuffer::Init(const Device *device, usize size, cstr name) StagingBuffer::Init(const Device *device, usize size, cstr name)
{ {

View File

@ -41,9 +41,9 @@ struct UniformBuffer : Buffer
void Init(const Device *device, usize size, cstr name = nullptr); void Init(const Device *device, usize size, cstr name = nullptr);
}; };
struct UniformStorageBuffer : Buffer struct StorageBuffer : Buffer
{ {
void Init(const Device *device, usize size, cstr name = nullptr); void Init(const Device *device, usize size, bool hostVisible, cstr name = nullptr);
}; };
struct VertexBuffer : Buffer struct VertexBuffer : Buffer
@ -52,6 +52,12 @@ struct VertexBuffer : Buffer
void Write(const Device *device, void *data, usize size, usize offset) const = delete; void Write(const Device *device, void *data, usize size, usize offset) const = delete;
}; };
struct IndexBuffer : Buffer
{
void Init(const Device *device, usize size, cstr name = nullptr);
void Write(const Device *device, void *data, usize size, usize offset) const = delete;
};
struct StagingBuffer : Buffer struct StagingBuffer : Buffer
{ {
void Init(const Device *device, usize size, cstr name = nullptr); void Init(const Device *device, usize size, cstr name = nullptr);

View File

@ -40,6 +40,8 @@ constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
#define Take(ELEMENT) eastl::exchange(ELEMENT, {}) #define Take(ELEMENT) eastl::exchange(ELEMENT, {})
#define TODO(MSG) assert(false && ("Unimplemented: " MSG))
[[nodiscard]] inline bool [[nodiscard]] inline bool
Failed(const vk::Result result) Failed(const vk::Result result)
{ {

View File

@ -68,6 +68,7 @@ Texture::Init(const Device *device, const vk::Extent2D extent, vk::Format imageF
m_View = view; m_View = view;
m_Allocation = allocation; m_Allocation = allocation;
m_Extent = {extent.width, extent.height, 1}; m_Extent = {extent.width, extent.height, 1};
m_MipLevels = mipLevels;
device->SetName(m_Image, name); device->SetName(m_Image, name);
} }

View File

@ -15,6 +15,7 @@ struct Image
vk::ImageView m_View = nullptr; vk::ImageView m_View = nullptr;
VmaAllocation m_Allocation = nullptr; VmaAllocation m_Allocation = nullptr;
vk::Extent3D m_Extent; vk::Extent3D m_Extent;
u8 m_MipLevels = 1;
[[nodiscard]] bool IsValid() const; [[nodiscard]] bool IsValid() const;

View File

@ -11,7 +11,8 @@ add_executable(model_render model_render.cpp
render_resource_manager.cpp render_resource_manager.cpp
render_resource_manager.h render_resource_manager.h
model_loader.cpp model_loader.cpp
model_loader.h) model_loader.h
)
add_shader(model_render shader/model.vert.glsl) add_shader(model_render shader/model.vert.glsl)
add_shader(model_render shader/model.frag.glsl) add_shader(model_render shader/model.frag.glsl)

View File

@ -12,16 +12,183 @@
#include "model_loader.h" #include "model_loader.h"
#include "buffer.h"
#include "device.h"
#include "helpers.h"
#include "image.h"
#include "render_resource_manager.h"
#include <EASTL/array.h>
#include <EASTL/fixed_vector.h>
#include <EASTL/span.h>
vec4
VectorToVec4(const std::vector<double> &vec)
{
if (vec.empty())
{
return vec4{0.0f};
}
return {vec[0], vec[1], vec[2], vec[3]};
}
TextureHandle
ModelLoader::LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, StagingBuffer *stagingBuffer,
tinygltf::Image *image)
{
assert(image->component == 4);
texture->Init(m_ResourceManager->m_Device, {.width = Cast<u32>(image->width), .height = Cast<u32>(image->height)},
vk::Format::eR8G8B8A8Srgb, true, image->name.data());
// .srcAccessMask = ,
// .dstAccessMask = ,
// .oldLayout = ,
// .newLayout = ,
// .srcQueueFamilyIndex = ,
// .dstQueueFamilyIndex = ,
// .image = ,
// .subresourceRange =
vk::ImageMemoryBarrier imageStartBarrier = {
.srcAccessMask = vk::AccessFlagBits::eNone,
.dstAccessMask = vk::AccessFlagBits::eTransferWrite,
.oldLayout = vk::ImageLayout::eUndefined,
.newLayout = vk::ImageLayout::eTransferDstOptimal,
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
.image = texture->m_Image,
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = texture->m_MipLevels,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
vk::ImageMemoryBarrier nextMipBarrier = {
.srcAccessMask = vk::AccessFlagBits::eTransferWrite,
.dstAccessMask = vk::AccessFlagBits::eTransferRead,
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
.newLayout = vk::ImageLayout::eTransferSrcOptimal,
.srcQueueFamilyIndex = vk::QueueFamilyIgnored,
.dstQueueFamilyIndex = vk::QueueFamilyIgnored,
.image = texture->m_Image,
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
vk::ImageMemoryBarrier imageReadyBarrier = {
.srcAccessMask = vk::AccessFlagBits::eTransferRead,
.dstAccessMask = vk::AccessFlagBits::eShaderRead,
.oldLayout = vk::ImageLayout::eTransferSrcOptimal,
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
.srcQueueFamilyIndex = m_TransferQueueIndex,
.dstQueueFamilyIndex = m_GraphicsQueueIndex,
.image = texture->m_Image,
.subresourceRange =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.baseMipLevel = 0,
.levelCount = texture->m_MipLevels,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
vk::BufferImageCopy imageCopy = {
.bufferOffset = 0,
.bufferRowLength = Cast<u32>(image->width),
.bufferImageHeight = Cast<u32>(image->height),
.imageSubresource =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.imageOffset = {},
.imageExtent = texture->m_Extent,
};
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eTransfer, {}, 0,
nullptr, 0, nullptr, 1, &imageStartBarrier);
commandBuffer.copyBufferToImage(stagingBuffer->m_Buffer, texture->m_Image, vk::ImageLayout::eTransferDstOptimal, 1,
&imageCopy);
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0,
nullptr, 0, nullptr, 1, &nextMipBarrier);
auto calcNextMip = [](i32 prev) { return eastl::max(prev / 2, 1); };
i32 prevMipWidth = Cast<i32>(texture->m_Extent.width);
i32 prevMipHeight = Cast<i32>(texture->m_Extent.height);
for (u32 prevMipLevel = 1; prevMipLevel < texture->m_MipLevels; ++prevMipLevel)
{
i32 currentMipWidth = calcNextMip(prevMipWidth);
i32 currentMipHeight = calcNextMip(prevMipHeight);
u32 currentMipLevel = prevMipLevel + 1;
vk::ImageBlit blitRegion = {
.srcSubresource =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = prevMipLevel,
.baseArrayLayer = 0,
.layerCount = 1,
},
.srcOffsets =
std::array{
vk::Offset3D{0, 0, 0},
vk::Offset3D{prevMipWidth, prevMipHeight, 1},
},
.dstSubresource =
{
.aspectMask = vk::ImageAspectFlagBits::eColor,
.mipLevel = currentMipLevel,
.baseArrayLayer = 0,
.layerCount = 1,
},
.dstOffsets =
std::array{
vk::Offset3D{0, 0, 0},
vk::Offset3D{currentMipWidth, currentMipHeight, 1},
},
};
nextMipBarrier.subresourceRange.baseMipLevel = prevMipLevel;
commandBuffer.blitImage(texture->m_Image, vk::ImageLayout::eTransferSrcOptimal, texture->m_Image,
vk::ImageLayout::eTransferDstOptimal, 1, &blitRegion, vk::Filter::eLinear);
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTransfer, {}, 0,
nullptr, 0, nullptr, 1, &nextMipBarrier);
}
commandBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eTopOfPipe, {}, 0,
nullptr, 0, nullptr, 1, &imageReadyBarrier);
return m_ResourceManager->Commit(texture);
}
Model Model
LoadModel(RenderResourceManager *resourceManager, cstr path) ModelLoader::LoadModel(cstr path, cstr name)
{ {
namespace fs = std::filesystem; namespace fs = std::filesystem;
tinygltf::Model model; tinygltf::Model model;
tinygltf::TinyGLTF loader; tinygltf::TinyGLTF loader;
const Device *pDevice = m_ResourceManager->m_Device;
const auto fsPath = fs::absolute(path); const auto fsPath = fs::absolute(path);
const auto ext = fsPath.extension(); const auto ext = fsPath.extension();
if (ext.c_str() == GLTF_ASCII_FILE_EXTENSION) if (ext == GLTF_ASCII_FILE_EXTENSION)
{ {
std::string err; std::string err;
std::string warn; std::string warn;
@ -31,7 +198,7 @@ LoadModel(RenderResourceManager *resourceManager, cstr path)
ELSE_IF_WARN(!warn.empty(), "{}", warn); ELSE_IF_WARN(!warn.empty(), "{}", warn);
} }
} }
if (ext.c_str() == GLTF_BINARY_FILE_EXTENSION) if (ext == GLTF_BINARY_FILE_EXTENSION)
{ {
std::string err; std::string err;
std::string warn; std::string warn;
@ -41,4 +208,309 @@ LoadModel(RenderResourceManager *resourceManager, cstr path)
ELSE_IF_WARN(!warn.empty(), "{}", warn); ELSE_IF_WARN(!warn.empty(), "{}", warn);
} }
} }
vk::CommandBuffer commandBuffer;
{
vk::CommandBufferAllocateInfo commandBufferAllocateInfo = {
.commandPool = m_CommandPool,
.level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = 1,
};
AbortIfFailed(pDevice->m_Device.allocateCommandBuffers(&commandBufferAllocateInfo, &commandBuffer));
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
AbortIfFailed(commandBuffer.begin(&beginInfo));
}
eastl::vector<StagingBuffer> stagingBuffers;
eastl::vector<Texture> textures;
eastl::vector<TextureHandle> textureHandles;
if (!model.images.empty())
{
u32 numImages = model.images.size();
stagingBuffers.resize(numImages);
textures.resize(numImages);
textureHandles.resize(numImages);
auto stagingPtr = stagingBuffers.data();
auto texturePtr = textures.data();
auto imagePtr = model.images.data();
for (TextureHandle &handle : textureHandles)
{
handle = LoadImage(commandBuffer, texturePtr++, stagingPtr++, imagePtr++);
}
AbortIfFailed(commandBuffer.end());
}
eastl::vector<Material> materials;
StorageBuffer materialsBuffer;
BufferHandle materialsHandle;
if (!model.materials.empty())
{
auto getTextureHandle = [&textureHandles](i32 index) -> TextureHandle {
if (index >= 0)
{
return textureHandles[index];
}
return {};
};
materials.reserve(model.materials.size());
for (auto &material : model.materials)
{
materials.push_back({
.m_AlbedoFactor = VectorToVec4(material.pbrMetallicRoughness.baseColorFactor),
.m_EmissionFactor = VectorToVec4(material.emissiveFactor),
.m_MetalFactor = Cast<f32>(material.pbrMetallicRoughness.metallicFactor),
.m_RoughFactor = Cast<f32>(material.pbrMetallicRoughness.roughnessFactor),
.m_AlbedoTex = getTextureHandle(material.pbrMetallicRoughness.baseColorTexture.index),
.m_NormalTex = getTextureHandle(material.normalTexture.index),
.m_MetalRoughTex = getTextureHandle(material.pbrMetallicRoughness.metallicRoughnessTexture.index),
.m_OcclusionTex = getTextureHandle(material.occlusionTexture.index),
.m_EmissionTex = getTextureHandle(material.emissiveTexture.index),
});
}
usize materialsByteSize = materials.size() * sizeof materials[0];
materialsBuffer.Init(pDevice, materialsByteSize, false, name);
materialsHandle = m_ResourceManager->Commit(&materialsBuffer);
StagingBuffer &materialStaging = stagingBuffers.push_back();
materialStaging.Init(pDevice, materialsByteSize);
materialStaging.Write(pDevice, 0, materialsByteSize, materials.data());
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = materialsByteSize};
commandBuffer.copyBuffer(materialStaging.m_Buffer, materialsBuffer.m_Buffer, 1, &bufferCopy);
}
// TODO: Mesh reordering based on nodes AND OR meshoptimizer
// TODO: Support scenes
eastl::vector<vec4> vertexPositions;
eastl::vector<u32> indices;
eastl::vector<MeshPrimitive> meshPrimitives;
meshPrimitives.reserve(model.meshes.size());
for (auto &mesh : model.meshes)
{
for (auto &prim : mesh.primitives)
{
u32 vertexOffset = vertexPositions.size();
u32 vertexCount;
u32 indexOffset = indices.size();
u32 indexCount;
assert(prim.attributes.contains(APosition));
assert(prim.mode == TINYGLTF_MODE_TRIANGLES);
{
tinygltf::Accessor *posAccessor = &model.accessors[prim.attributes[APosition]];
assert(posAccessor->count <= MaxValue<u32>);
tinygltf::BufferView *posBufferView = &model.bufferViews[posAccessor->bufferView];
tinygltf::Buffer *posBuffer = &model.buffers[posBufferView->buffer];
usize byteOffset = (posAccessor->byteOffset + posBufferView->byteOffset);
vertexCount = posAccessor->count;
vertexPositions.reserve(vertexOffset + vertexCount);
if (posAccessor->type == TINYGLTF_TYPE_VEC4)
{
vec4 *data = Recast<vec4 *>(posBuffer->data.data() + byteOffset);
vertexPositions.insert(vertexPositions.end(), data, data + vertexCount);
}
else if (posAccessor->type == TINYGLTF_TYPE_VEC3)
{
vec3 *data = Recast<vec3 *>(posBuffer->data.data() + byteOffset);
for (u32 i = 0; i < vertexCount; ++i)
{
vertexPositions.push_back(vec4(data[i], 1.0f));
}
}
else if (posAccessor->type == TINYGLTF_TYPE_VEC2)
{
vec2 *data = Recast<vec2 *>(posBuffer->data.data() + byteOffset);
for (u32 i = 0; i < vertexCount; ++i)
{
vertexPositions.push_back(vec4(data[i], 0.0f, 1.0f));
}
}
}
if (prim.indices >= 0)
{
tinygltf::Accessor *indexAccessor = &model.accessors[prim.indices];
assert(indexAccessor->count <= MaxValue<u32>);
tinygltf::BufferView *indexBufferView = &model.bufferViews[indexAccessor->bufferView];
tinygltf::Buffer *indexBuffer = &model.buffers[indexBufferView->buffer];
usize byteOffset = (indexAccessor->byteOffset + indexBufferView->byteOffset);
indexCount = indexAccessor->count;
indices.reserve(indexOffset + indexCount);
if (indexAccessor->componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT)
{
u32 *data = Recast<u32 *>(indexBuffer->data.data() + byteOffset);
indices.insert(indices.end(), data, data + indexCount);
}
else if (indexAccessor->componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT)
{
u16 *data = Recast<u16 *>(indexBuffer->data.data() + byteOffset);
indices.insert(indices.end(), data, data + indexCount);
}
else if (indexAccessor->componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE)
{
u8 *data = Recast<u8 *>(indexBuffer->data.data() + byteOffset);
indices.insert(indices.end(), data, data + indexCount);
}
}
else
{
indexCount = vertexCount;
indices.reserve(indexOffset + vertexCount);
for (u32 i = 0; i < indexCount; ++i)
{
indices.push_back(i);
}
}
meshPrimitives.push_back({
.m_VertexOffset = vertexOffset,
.m_FirstIndex = indexOffset,
.m_IndexCount = indexCount,
.m_MaterialIdx = prim.material,
});
}
}
StorageBuffer positionBuffer;
positionBuffer.Init(pDevice, vertexPositions.size() * sizeof vertexPositions[0], false);
BufferHandle positionBufferHandle = m_ResourceManager->Commit(&positionBuffer);
IndexBuffer indexBuffer;
indexBuffer.Init(pDevice, indices.size() * sizeof indices[0]);
{
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0};
StagingBuffer &positionStaging = stagingBuffers.push_back();
positionStaging.Init(pDevice, positionBuffer.GetSize());
positionStaging.Write(pDevice, 0, positionBuffer.GetSize(), vertexPositions.data());
bufferCopy.size = positionBuffer.GetSize();
commandBuffer.copyBuffer(positionStaging.m_Buffer, positionBuffer.m_Buffer, 1, &bufferCopy);
StagingBuffer &indexStaging = stagingBuffers.push_back();
indexStaging.Init(pDevice, indexBuffer.GetSize());
indexStaging.Write(pDevice, 0, indexBuffer.GetSize(), indices.data());
bufferCopy.size = indexBuffer.GetSize();
commandBuffer.copyBuffer(indexStaging.m_Buffer, indexBuffer.m_Buffer, 1, &bufferCopy);
}
AbortIfFailed(commandBuffer.end());
vk::SubmitInfo submitInfo = {
.waitSemaphoreCount = 0,
.pWaitDstStageMask = 0,
.commandBufferCount = 1,
.pCommandBuffers = &commandBuffer,
};
vk::Fence fence;
vk::FenceCreateInfo fenceCreateInfo = {};
AbortIfFailed(pDevice->m_Device.createFence(&fenceCreateInfo, nullptr, &fence));
AbortIfFailed(m_TransferQueue.submit(1, &submitInfo, fence));
AbortIfFailed(pDevice->m_Device.waitForFences(1, &fence, true, MaxValue<u32>));
pDevice->m_Device.destroy(fence, nullptr);
for (auto &buffer : stagingBuffers)
{
buffer.Destroy(pDevice);
}
return Model{m_ResourceManager, std::move(textures), std::move(textureHandles),
materialsBuffer, materialsHandle, positionBuffer,
positionBufferHandle, indexBuffer, meshPrimitives};
}
Model::Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&textures,
eastl::vector<TextureHandle> &&textureHandles, const StorageBuffer &materialsBuffer,
BufferHandle materialsHandle, const StorageBuffer &vertexPosBuffer, BufferHandle vertexPosHandle,
const IndexBuffer &indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives)
: m_ResourceManager(resourceManager)
, m_Textures(textures)
, m_TextureHandles(textureHandles)
, m_MaterialsBuffer(materialsBuffer)
, m_MaterialsHandle(materialsHandle)
, m_VertexPositions(vertexPosBuffer)
, m_VertexPositionHandle(vertexPosHandle)
, m_IndexBuffer(indexBuffer)
, m_MeshPrimitives(meshPrimitives)
{
}
Model::Model(Model &&other) noexcept
: m_ResourceManager(Take(other.m_ResourceManager))
, m_Textures(std::move(other.m_Textures))
, m_TextureHandles(std::move(other.m_TextureHandles))
, m_MaterialsBuffer(other.m_MaterialsBuffer)
, m_MaterialsHandle(other.m_MaterialsHandle)
, m_VertexPositions(other.m_VertexPositions)
, m_VertexPositionHandle(other.m_VertexPositionHandle)
, m_IndexBuffer(other.m_IndexBuffer)
, m_MeshPrimitives(std::move(other.m_MeshPrimitives))
{
}
Model &
Model::operator=(Model &&other) noexcept
{
if (this == &other)
return *this;
m_ResourceManager = Take(other.m_ResourceManager);
m_Textures = std::move(other.m_Textures);
m_TextureHandles = std::move(other.m_TextureHandles);
m_MaterialsBuffer = other.m_MaterialsBuffer;
m_MaterialsHandle = other.m_MaterialsHandle;
m_VertexPositions = other.m_VertexPositions;
m_VertexPositionHandle = other.m_VertexPositionHandle;
m_IndexBuffer = other.m_IndexBuffer;
m_MeshPrimitives = std::move(other.m_MeshPrimitives);
return *this;
}
Model::~Model()
{
if (!m_ResourceManager)
return;
m_VertexPositions.Destroy(m_ResourceManager->m_Device);
m_IndexBuffer.Destroy(m_ResourceManager->m_Device);
m_ResourceManager->Release(m_VertexPositionHandle);
for (const TextureHandle &handle : m_TextureHandles)
{
m_ResourceManager->Release(handle);
}
m_ResourceManager->Release(m_MaterialsHandle);
for (Texture &texture : m_Textures)
{
texture.Destroy(m_ResourceManager->m_Device);
}
m_MaterialsBuffer.Destroy(m_ResourceManager->m_Device);
}
ModelLoader::ModelLoader(RenderResourceManager *resourceManager, vk::CommandPool commandPool, vk::Queue transferQueue,
u32 transferQueueIndex, u32 graphicsQueueIndex)
: m_ResourceManager(resourceManager)
, m_CommandPool(commandPool)
, m_TransferQueue(transferQueue)
, m_TransferQueueIndex(transferQueueIndex)
, m_GraphicsQueueIndex(graphicsQueueIndex)
{
} }

View File

@ -5,26 +5,86 @@
#pragma once #pragma once
#include "constants.h" #include "buffer.h"
#include "global.h"
#include "image.h"
#include "render_resource_manager.h"
#include <EASTL/vector.h>
#include <tiny_gltf.h> #include <tiny_gltf.h>
struct RenderResourceManager; struct TextureHandle;
struct Texture; struct Texture;
constexpr auto GLTF_ASCII_FILE_EXTENSION = ".gltf"; constexpr auto GLTF_ASCII_FILE_EXTENSION = ".gltf";
constexpr auto GLTF_BINARY_FILE_EXTENSION = ".glb"; constexpr auto GLTF_BINARY_FILE_EXTENSION = ".glb";
constexpr static auto NORMAL = "NORMAL"; struct MeshPrimitive
constexpr static auto POSITION = "POSITION"; {
constexpr static auto TANGENT = "TANGENT"; u32 m_VertexOffset;
constexpr static auto TEXCOORD_0 = "TEXCOORD_0"; u32 m_FirstIndex;
constexpr static auto TEXCOORD_1 = "TEXCOORD_1"; u32 m_IndexCount;
constexpr static auto JOINTS_0 = "JOINTS_0"; i32 m_MaterialIdx; // -1 for invalid
constexpr static auto WEIGHTS_0 = "WEIGHTS_0"; };
struct Material
{
vec4 m_AlbedoFactor;
vec4 m_EmissionFactor;
f32 m_MetalFactor;
f32 m_RoughFactor;
TextureHandle m_AlbedoTex;
TextureHandle m_NormalTex;
TextureHandle m_MetalRoughTex;
TextureHandle m_OcclusionTex;
TextureHandle m_EmissionTex;
};
struct Model struct Model
{ {
RenderResourceManager *m_ResourceManager;
eastl::vector<Texture> m_Textures;
eastl::vector<TextureHandle> m_TextureHandles;
StorageBuffer m_MaterialsBuffer;
BufferHandle m_MaterialsHandle;
StorageBuffer m_VertexPositions;
BufferHandle m_VertexPositionHandle;
IndexBuffer m_IndexBuffer;
eastl::vector<MeshPrimitive> m_MeshPrimitives;
Model(RenderResourceManager *resourceManager, eastl::vector<Texture> &&textures,
eastl::vector<TextureHandle> &&textureHandles, const StorageBuffer &materialsBuffer,
BufferHandle materialsHandle, const StorageBuffer &vertexPosBuffer, BufferHandle vertexPosHandle,
const IndexBuffer &indexBuffer, const eastl::vector<MeshPrimitive> &meshPrimitives);
Model(Model &&other) noexcept;
Model &operator=(Model &&other) noexcept;
~Model();
DISALLOW_COPY_AND_ASSIGN(Model);
}; };
Model LoadModel(RenderResourceManager *resourceManager, cstr path); struct ModelLoader
{
RenderResourceManager *const m_ResourceManager;
vk::CommandPool m_CommandPool;
vk::Queue m_TransferQueue;
u32 m_TransferQueueIndex;
u32 m_GraphicsQueueIndex;
ModelLoader(RenderResourceManager *resourceManager, vk::CommandPool commandPool, vk::Queue transferQueue,
u32 transferQueueIndex, u32 graphicsQueueIndex);
TextureHandle
LoadImage(vk::CommandBuffer commandBuffer, Texture *texture, StagingBuffer *stagingBuffer, tinygltf::Image *image);
Model LoadModel(cstr path, cstr name = nullptr);
constexpr static auto ANormal = "NORMAL";
constexpr static auto APosition = "POSITION";
constexpr static auto ATangent = "TANGENT";
constexpr static auto ATexCoord0 = "TEXCOORD_0";
constexpr static auto ATexCoord1 = "TEXCOORD_1";
constexpr static auto AJoints0 = "JOINTS_0";
constexpr static auto AWeights0 = "WEIGHTS_0";
};

View File

@ -31,7 +31,7 @@ constexpr auto MODEL_FILE = "model/Box.glb";
struct ImageFile struct ImageFile
{ {
void *m_Data = nullptr; u8 *m_Data = nullptr;
u32 m_Width = 0; u32 m_Width = 0;
u32 m_Height = 0; u32 m_Height = 0;
u32 m_NumChannels = 0; u32 m_NumChannels = 0;
@ -85,7 +85,31 @@ main(int, char **)
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"}; Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0); vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
Swapchain swapchain = {&window, &device, "Primary Chain"}; Swapchain swapchain = {&window, &device, "Primary Chain"};
RenderResourceManager resourceManager(&device, 10); RenderResourceManager resourceManager = {&device, 1000};
vk::CommandPool copyPool;
vk::CommandBuffer copyBuffer;
{
vk::CommandPoolCreateInfo poolCreateInfo = {
.flags = vk::CommandPoolCreateFlagBits::eTransient,
.queueFamilyIndex = queueAllocation.m_Family,
};
AbortIfFailedM(device.m_Device.createCommandPool(&poolCreateInfo, nullptr, &copyPool),
"Copy command pool creation failed.");
vk::CommandBufferAllocateInfo bufferAllocateInfo = {
.commandPool = copyPool,
.level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = 1,
};
AbortIfFailedM(device.m_Device.allocateCommandBuffers(&bufferAllocateInfo, &copyBuffer),
"Copy command buffer allocation failed.");
}
ModelLoader modelLoader = {&resourceManager, copyPool, commandQueue, queueAllocation.m_Family,
queueAllocation.m_Family};
auto model = modelLoader.LoadModel(MODEL_FILE);
Pipeline pipeline = CreatePipeline(&device, &swapchain, &resourceManager); Pipeline pipeline = CreatePipeline(&device, &swapchain, &resourceManager);
@ -123,25 +147,6 @@ main(int, char **)
AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &descriptorSet)); AbortIfFailed(device.m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &descriptorSet));
} }
vk::CommandPool copyPool;
vk::CommandBuffer copyBuffer;
{
vk::CommandPoolCreateInfo poolCreateInfo = {
.flags = vk::CommandPoolCreateFlagBits::eTransient,
.queueFamilyIndex = queueAllocation.m_Family,
};
AbortIfFailedM(device.m_Device.createCommandPool(&poolCreateInfo, nullptr, &copyPool),
"Copy command pool creation failed.");
vk::CommandBufferAllocateInfo bufferAllocateInfo = {
.commandPool = copyPool,
.level = vk::CommandBufferLevel::ePrimary,
.commandBufferCount = 1,
};
AbortIfFailedM(device.m_Device.allocateCommandBuffers(&bufferAllocateInfo, &copyBuffer),
"Copy command buffer allocation failed.");
}
eastl::array vertices = { eastl::array vertices = {
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)}, Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 1.0f)},
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)}, Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_TexCoord0 = vec2(1.0f, 0.0f)},
@ -192,14 +197,14 @@ main(int, char **)
INFO("Image {}x{} : {} channels", crateImageFile.m_Width, crateImageFile.m_Height, crateImageFile.m_NumChannels); INFO("Image {}x{} : {} channels", crateImageFile.m_Width, crateImageFile.m_Height, crateImageFile.m_NumChannels);
assert(plainImageFile.Load({0.7f, 0.4f, 0.1f, 1.0f})); assert(plainImageFile.Load({0.7f, 0.4f, 0.1f, 1.0f}));
UniformStorageBuffer pvbo; StorageBuffer pvbo;
Texture crateTexture; Texture crateTexture;
Texture plainTexture; Texture plainTexture;
crateTexture.Init(&device, {crateImageFile.m_Width, crateImageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false, crateTexture.Init(&device, {crateImageFile.m_Width, crateImageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false,
"Crate Texture"); "Crate Texture");
plainTexture.Init(&device, {crateImageFile.m_Width, crateImageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false, plainTexture.Init(&device, {crateImageFile.m_Width, crateImageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false,
"Plain Texture"); "Plain Texture");
pvbo.Init(&device, vertices.size() * sizeof vertices[0], "Pull VBO"); pvbo.Init(&device, vertices.size() * sizeof vertices[0], true, "Pull VBO");
pvbo.Write(&device, 0, pvbo.GetSize(), vertices.data()); pvbo.Write(&device, 0, pvbo.GetSize(), vertices.data());
auto crateTextureId = resourceManager.Commit(&crateTexture); auto crateTextureId = resourceManager.Commit(&crateTexture);
@ -308,7 +313,6 @@ main(int, char **)
1, &imageCopy); 1, &imageCopy);
copyBuffer.copyBufferToImage(imageStaging2.m_Buffer, plainTexture.m_Image, vk::ImageLayout::eTransferDstOptimal, copyBuffer.copyBufferToImage(imageStaging2.m_Buffer, plainTexture.m_Image, vk::ImageLayout::eTransferDstOptimal,
1, &imageCopy); 1, &imageCopy);
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {}, copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
0, nullptr, 0, nullptr, Cast<u32>(imageReadyToRead.size()), imageReadyToRead.data()); 0, nullptr, 0, nullptr, Cast<u32>(imageReadyToRead.size()), imageReadyToRead.data());
@ -423,8 +427,8 @@ main(int, char **)
Time::Init(); Time::Init();
Handle *pushData = &crateTextureId; GpuResourceHandle *pushData = &crateTextureId;
Handle *otherPushData = &plainTextureId; GpuResourceHandle *otherPushData = &plainTextureId;
bool prevPressed = false; bool prevPressed = false;
auto isSpaceJustPressed = [&prevPressed, &window] { auto isSpaceJustPressed = [&prevPressed, &window] {
@ -434,6 +438,17 @@ main(int, char **)
return justPressed; return justPressed;
}; };
struct ModelData
{
BufferHandle m_VertexBuffer;
BufferHandle m_Materials;
};
ModelData modelData = {
.m_VertexBuffer = model.m_VertexPositionHandle,
.m_Materials = model.m_MaterialsHandle,
};
INFO("Starting loop"); INFO("Starting loop");
while (window.Poll()) while (window.Poll())
{ {
@ -498,13 +513,23 @@ main(int, char **)
cmd.setViewport(0, 1, &viewport); cmd.setViewport(0, 1, &viewport);
cmd.setScissor(0, 1, &scissor); cmd.setScissor(0, 1, &scissor);
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline); cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, 0, sizeof *pushData, pushData); // cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, 0, sizeof *pushData, pushData);
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof *pushData, sizeof pvboBufferId, // cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof *pushData, sizeof pvboBufferId,
&pvboBufferId); // &pvboBufferId);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1, cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1,
&resourceManager.m_DescriptorSet, 0, nullptr); &resourceManager.m_DescriptorSet, 0, nullptr);
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 1, 1, &descriptorSet, 0, nullptr); cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 1, 1, &descriptorSet, 0, nullptr);
cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0); // cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0);
cmd.bindIndexBuffer(model.m_IndexBuffer.m_Buffer, 0, vk::IndexType::eUint32);
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, 0, sizeof modelData, &modelData);
for (auto &prim : model.m_MeshPrimitives)
{
cmd.pushConstants(pipeline.m_Layout, vk::ShaderStageFlagBits::eAll, sizeof modelData,
sizeof prim.m_MaterialIdx, &prim.m_MaterialIdx);
cmd.drawIndexed(prim.m_IndexCount, 1, prim.m_FirstIndex, Cast<i32>(prim.m_VertexOffset), 0);
}
cmd.endRendering(); cmd.endRendering();

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include "global.h"
#include "pipeline.h" #include "pipeline.h"
#include <EASTL/array.h> #include <EASTL/array.h>

View File

@ -28,7 +28,7 @@ RenderResourceManager::WriteInfo::WriteInfo(vk::BufferView info)
} }
BufferHandle BufferHandle
RenderResourceManager::Commit(const UniformStorageBuffer *storageBuffer) RenderResourceManager::Commit(const StorageBuffer *storageBuffer)
{ {
const u32 handle = m_BufferFreeList.Alloc(); const u32 handle = m_BufferFreeList.Alloc();
@ -47,18 +47,53 @@ RenderResourceManager::Commit(const UniformStorageBuffer *storageBuffer)
.pBufferInfo = &m_WriteInfos.back().uBufferInfo, .pBufferInfo = &m_WriteInfos.back().uBufferInfo,
}); });
m_WriteOwner.emplace_back(HandleType::eBuffer, handle);
return {handle}; return {handle};
} }
void
RenderResourceManager::EraseWrites(u32 handleIndex, HandleType handleType)
{
auto writeIter = m_Writes.begin();
auto ownerIter = m_WriteOwner.begin();
const auto ownerEnd = m_WriteOwner.end();
while (ownerIter != ownerEnd)
{
if (ownerIter->first == handleType && ownerIter->second == handleIndex)
{
*writeIter = m_Writes.back();
*ownerIter = m_WriteOwner.back();
m_Writes.pop_back();
m_WriteOwner.pop_back();
return;
}
++ownerIter;
++writeIter;
}
}
void void
RenderResourceManager::Release(BufferHandle handle) RenderResourceManager::Release(BufferHandle handle)
{ {
if (handle.IsInvalid())
return;
EraseWrites(handle.m_Index, HandleType::eBuffer);
m_BufferFreeList.Free(handle.m_Index); m_BufferFreeList.Free(handle.m_Index);
} }
void void
RenderResourceManager::Release(TextureHandle handle) RenderResourceManager::Release(TextureHandle handle)
{ {
if (handle.IsInvalid())
return;
EraseWrites(handle.m_Index, HandleType::eTexture);
m_TextureFreeList.Free(handle.m_Index); m_TextureFreeList.Free(handle.m_Index);
} }
@ -82,13 +117,15 @@ RenderResourceManager::Commit(const Texture *texture)
.pImageInfo = &m_WriteInfos.back().uImageInfo, .pImageInfo = &m_WriteInfos.back().uImageInfo,
}); });
m_WriteOwner.emplace_back(HandleType::eBuffer, handle);
return {handle}; return {handle};
} }
void void
RenderResourceManager::Update() RenderResourceManager::Update()
{ {
if (m_Writes.empty()) if (m_Writes.empty() || m_WriteInfos.empty())
return; return;
m_Device->m_Device.updateDescriptorSets(m_Writes.size(), m_Writes.data(), 0, nullptr); m_Device->m_Device.updateDescriptorSets(m_Writes.size(), m_Writes.data(), 0, nullptr);
@ -180,6 +217,10 @@ RenderResourceManager::RenderResourceManager(const Device *device, u16 maxSize)
.pSetLayouts = &m_SetLayout, .pSetLayouts = &m_SetLayout,
}; };
AbortIfFailed(device->m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &m_DescriptorSet)); AbortIfFailed(device->m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &m_DescriptorSet));
m_Device->SetName(m_SetLayout, "Bindless Layout");
m_Device->SetName(m_DescriptorPool, "Bindless Pool");
m_Device->SetName(m_DescriptorSet, "Bindless Set");
} }
RenderResourceManager::~RenderResourceManager() RenderResourceManager::~RenderResourceManager()

View File

@ -5,10 +5,12 @@
#pragma once #pragma once
#include "buffer.h"
#include "global.h" #include "global.h"
#include <EASTL/deque.h> #include <EASTL/deque.h>
#include <EASTL/stack.h> #include <EASTL/stack.h>
#include <EASTL/vector_map.h>
struct Device; struct Device;
struct Texture; struct Texture;
@ -16,16 +18,23 @@ struct UniformStorageBuffer;
struct RenderResourceManager; struct RenderResourceManager;
struct Handle struct GpuResourceHandle
{ {
u32 m_Index; constexpr static u32 INVALID_HANDLE = MaxValue<u32>;
u32 m_Index = INVALID_HANDLE; // Default = invalid
[[nodiscard]] bool
IsInvalid() const
{
return m_Index == INVALID_HANDLE;
}
}; };
struct BufferHandle : Handle struct BufferHandle : GpuResourceHandle
{ {
}; };
struct TextureHandle : Handle struct TextureHandle : GpuResourceHandle
{ {
}; };
@ -38,6 +47,8 @@ struct FreeList
void void
Init(u32 maxCapacity) Init(u32 maxCapacity)
{ {
// MaxValue<u32> is 'invalid-handle' so you can't use it as a handle.
assert(maxCapacity < GpuResourceHandle::INVALID_HANDLE);
m_MaxCapacity = maxCapacity; m_MaxCapacity = maxCapacity;
} }
@ -80,14 +91,25 @@ struct RenderResourceManager
explicit WriteInfo(vk::BufferView info); explicit WriteInfo(vk::BufferView info);
}; };
enum class HandleType
{
eBuffer,
eTexture,
};
using WriteOwner = eastl::pair<HandleType, u32>;
eastl::deque<WriteInfo> m_WriteInfos; eastl::deque<WriteInfo> m_WriteInfos;
eastl::vector<vk::WriteDescriptorSet> m_Writes; eastl::vector<vk::WriteDescriptorSet> m_Writes;
eastl::vector<WriteOwner> m_WriteOwner;
vk::Sampler m_Sampler; vk::Sampler m_Sampler;
FreeList m_BufferFreeList; FreeList m_BufferFreeList;
FreeList m_TextureFreeList; FreeList m_TextureFreeList;
void EraseWrites(u32 handleIndex, HandleType handleType);
public: public:
const Device *m_Device; const Device *m_Device;
@ -98,7 +120,7 @@ struct RenderResourceManager
vk::DescriptorSetLayout m_SetLayout; vk::DescriptorSetLayout m_SetLayout;
vk::DescriptorSet m_DescriptorSet; vk::DescriptorSet m_DescriptorSet;
BufferHandle Commit(const UniformStorageBuffer *storageBuffer); BufferHandle Commit(const StorageBuffer *storageBuffer);
void Release(BufferHandle handle); void Release(BufferHandle handle);
TextureHandle Commit(const Texture *texture); TextureHandle Commit(const Texture *texture);
void Release(TextureHandle handle); void Release(TextureHandle handle);
@ -106,6 +128,8 @@ struct RenderResourceManager
void Update(); void Update();
// Ctor/Dtor // Ctor/Dtor
explicit RenderResourceManager(const Device *device, u16 maxSize); RenderResourceManager(const Device *device, u16 maxSize);
~RenderResourceManager(); ~RenderResourceManager();
DISALLOW_COPY_AND_ASSIGN(RenderResourceManager);
}; };

View File

@ -2,16 +2,45 @@
#pragma shader_stage(fragment) #pragma shader_stage(fragment)
#extension GL_EXT_nonuniform_qualifier : enable #extension GL_EXT_nonuniform_qualifier : enable
layout (location = 0) in vec2 inUV; //layout (location = 0) in vec2 inUV;
layout (location = 0) out vec4 outColor; layout (location = 0) out vec4 outColor;
layout(set = 0, binding = 1) uniform sampler2D textures[]; struct VertexData {
float position[4];
layout(push_constant) uniform Block { // float uv[2];
uint textureHandle;
uint vertexBufferHandle;
}; };
struct MaterialData {
float m_AlbedoFactor[4];
float m_EmissionFactor[4];
float m_MetalFactor;
float m_RoughFactor;
uint m_AlbedoTex;
uint m_NormalTex;
uint m_MetalRoughTex;
uint m_OcclusionTex;
uint m_EmissionTex;
};
layout(set = 0, binding = 1) uniform sampler2D textures[];
layout(std430, set = 0, binding = 0) readonly buffer Vertices {
VertexData data[];
} vertexBuffer[];
layout(std430, set = 0, binding = 0) readonly buffer Materials {
MaterialData data[];
} materialsBuffer[];
layout(push_constant) uniform Block {
uint vertexBufferHandle;
uint materialBufferHandle;
uint materialIdx;
};
vec4 ToVec4(float array[4]) {
return vec4(array[0],array[1],array[2],array[3]);
}
void main() { void main() {
outColor = vec4(texture(textures[textureHandle], inUV).rgb, 1.0f); outColor = ToVec4(materialsBuffer[materialBufferHandle].data[materialIdx].m_AlbedoFactor); // vec4(texture(textures[textureHandle], inUV).rgb, 1.0f);
} }

View File

@ -2,16 +2,31 @@
#pragma shader_stage(vertex) #pragma shader_stage(vertex)
#extension GL_EXT_nonuniform_qualifier : enable #extension GL_EXT_nonuniform_qualifier : enable
layout(location = 0) out vec2 outUV; //layout(location = 0) out vec2 outUV;
struct VertexData { struct VertexData {
float position[3]; float position[4];
float uv[2]; // float uv[2];
};
struct MaterialData {
float m_AlbedoFactor[4];
float m_EmissionFactor[4];
float m_MetalFactor;
float m_RoughFactor;
uint m_AlbedoTex;
uint m_NormalTex;
uint m_MetalRoughTex;
uint m_OcclusionTex;
uint m_EmissionTex;
}; };
layout(std430, set = 0, binding = 0) readonly buffer Vertices { layout(std430, set = 0, binding = 0) readonly buffer Vertices {
VertexData data[]; VertexData data[];
} vertexBuffer[]; } vertexBuffer[];
layout(std430, set = 0, binding = 0) readonly buffer Materials {
MaterialData data[];
} materialsBuffer[];
vec3 GetPosition(uint bufferId, uint vertexIdx) { vec3 GetPosition(uint bufferId, uint vertexIdx) {
return vec3( return vec3(
@ -21,12 +36,12 @@ vec3 GetPosition(uint bufferId, uint vertexIdx) {
); );
} }
vec2 GetUV(uint bufferId, uint vertexIdx) { //vec2 GetUV(uint bufferId, uint vertexIdx) {
return vec2( // return vec2(
vertexBuffer[bufferId].data[vertexIdx].uv[0], // vertexBuffer[bufferId].data[vertexIdx].uv[0],
vertexBuffer[bufferId].data[vertexIdx].uv[1] // vertexBuffer[bufferId].data[vertexIdx].uv[1]
); // );
} //}
layout(set = 1, binding = 0) uniform Camera { layout(set = 1, binding = 0) uniform Camera {
mat4 model; mat4 model;
@ -35,11 +50,12 @@ layout(set = 1, binding = 0) uniform Camera {
} ubo; } ubo;
layout(push_constant) uniform Block { layout(push_constant) uniform Block {
uint textureHandle;
uint vertexBufferHandle; uint vertexBufferHandle;
uint materialBufferHandle;
uint materialIdx;
}; };
void main() { void main() {
outUV = GetUV(vertexBufferHandle, gl_VertexIndex); // outUV = GetUV(vertexBufferHandle, gl_VertexIndex);
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(GetPosition(vertexBufferHandle, gl_VertexIndex), 1.0f); gl_Position = ubo.proj * ubo.view * ubo.model * vec4(GetPosition(vertexBufferHandle, gl_VertexIndex), 1.0f);
} }