DRAGON TIME MF'ERS (glTF loaded)

This commit is contained in:
Conál 2024-01-29 11:23:12 -05:00
parent ef1bceb388
commit c0d6d07e7e
19 changed files with 37522 additions and 30 deletions

View File

@ -3,7 +3,7 @@
#include <util/log.hpp> #include <util/log.hpp>
Buffer::Buffer(vk::PhysicalDevice phys_dev, vk::Device dev, vk::DeviceSize sz, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags mem_flags, vk::SharingMode sharing) : dev(dev), size(sz) { Buffer::Buffer(vk::PhysicalDevice phys_dev, vk::Device dev, vk::DeviceSize sz, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags mem_flags, vk::SharingMode sharing) : phys_dev(phys_dev), dev(dev), size(sz) {
auto info = vk::BufferCreateInfo { auto info = vk::BufferCreateInfo {
.size = sz, .size = sz,
.usage = usage, .usage = usage,
@ -23,6 +23,8 @@ Buffer::Buffer(vk::PhysicalDevice phys_dev, vk::Device dev, vk::DeviceSize sz, v
dev.bindBufferMemory(buffer, memory, 0); dev.bindBufferMemory(buffer, memory, 0);
p = dev.mapMemory(memory, 0, size); p = dev.mapMemory(memory, 0, size);
Log::debug("Buffer %p allocated\n", buffer);
} }
void Buffer::upload(const uint8_t* data, vk::DeviceSize size) { void Buffer::upload(const uint8_t* data, vk::DeviceSize size) {

View File

@ -6,6 +6,7 @@
struct Buffer { struct Buffer {
Buffer(vk::PhysicalDevice phys_dev, vk::Device dev, vk::DeviceSize sz, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags mem_flags, vk::SharingMode sharing = vk::SharingMode::eExclusive); Buffer(vk::PhysicalDevice phys_dev, vk::Device dev, vk::DeviceSize sz, vk::BufferUsageFlags usage, vk::MemoryPropertyFlags mem_flags, vk::SharingMode sharing = vk::SharingMode::eExclusive);
vk::PhysicalDevice phys_dev;
vk::Device dev; vk::Device dev;
vk::DeviceSize size; vk::DeviceSize size;
vk::DeviceMemory memory; vk::DeviceMemory memory;

161
Model/Model.cpp Normal file
View File

@ -0,0 +1,161 @@
#include <Model/Model.hpp>
#include <util/log.hpp>
#include <util/file.hpp>
#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include <tinygltf/tiny_gltf.h>
#include <glm/gtc/type_ptr.hpp>
Model::Model(vk::PhysicalDevice phys_dev, vk::Device dev, const std::string& fname) {
Log::debug("Loading model " + fname + "\n");
tinygltf::TinyGLTF loader;
std::string err, warn;
model = std::make_shared<tinygltf::Model>();
auto ret = loader.LoadASCIIFromFile(model.get(), &err, &warn, fname);
if(!warn.empty()) {
Log::debug(fname + ": " + warn);
}
if(!err.empty()) {
Log::debug(fname + ": " + err);
}
if(!ret) {
Log::error("Failed to pase glTF model\n");
}
for(auto& node: model->nodes)
initNode(node, nullptr);
/* vertex, index buffer should be populated now */
Log::debug("%zu vertices loaded from model " + fname + "\n", vertices.size());
vertex_buffer = std::make_unique<VertexBuffer>(phys_dev, dev, vertices.size());
vertex_buffer->upload(vertices);
index_buffer = std::make_unique<Buffer>(phys_dev, dev, indices.size()*sizeof(uint16_t),
vk::BufferUsageFlagBits::eIndexBuffer, vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostVisible);
index_buffer->upload(reinterpret_cast<uint8_t*>(indices.data()), static_cast<vk::DeviceSize>(indices.size()*sizeof(uint16_t)));
}
void Model::initVertices(Node* node, const tinygltf::Primitive& prim) {
Log::debug("Loading vertices\n");
uint32_t first_idx = indices.size();
uint32_t vert_start = vertices.size();
uint32_t idx_count = 0;
const float* pos_buff = nullptr;
const float* norm_buff = nullptr;
const float* uv_buff = nullptr;
size_t vertex_count = 0;
auto loc = prim.attributes.find("POSITION");
if(loc != prim.attributes.end()) {
auto accessor = model->accessors[loc->second];
const auto& view = model->bufferViews[accessor.bufferView];
pos_buff = reinterpret_cast<const float*>(&model->buffers[view.buffer].data[accessor.byteOffset+view.byteOffset]);
vertex_count = accessor.count;
}
loc = prim.attributes.find("NORMAL");
if(loc != prim.attributes.end()) {
auto accessor = model->accessors[loc->second];
const auto& view = model->bufferViews[accessor.bufferView];
norm_buff = reinterpret_cast<const float*>(&model->buffers[view.buffer].data[accessor.byteOffset+view.byteOffset]);
}
loc = prim.attributes.find("TEXCOORD_0");
if(loc != prim.attributes.end()) {
auto accessor = model->accessors[loc->second];
const auto& view = model->bufferViews[accessor.bufferView];
norm_buff = reinterpret_cast<const float*>(&model->buffers[view.buffer].data[accessor.byteOffset+view.byteOffset]);
}
for(size_t i = 0; i < vertex_count; i++) {
vertices.push_back(Vertex {
.pos = pos_buff? glm::make_vec3(pos_buff+i*3) : glm::vec3(0.0),
.norm = norm_buff? glm::normalize(glm::make_vec3(norm_buff+i*3)) : glm::vec3(0.0),
.uv = uv_buff? glm::make_vec2(uv_buff+i*2) : glm::vec2(0.0),
.color = glm::vec3(0.0),
});
}
Log::debug("Finished loading %zu vertices\n", vertex_count);
const auto& accessor = model->accessors[prim.indices];
const auto& view = model->bufferViews[accessor.bufferView];
const auto& buffer = model->buffers[view.buffer];
idx_count += accessor.count;
switch(accessor.componentType) {
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT:
for(size_t i = 0; i < accessor.count; i++)
indices.push_back(
reinterpret_cast<const uint32_t*>(
&buffer.data[accessor.byteOffset+view.byteOffset
])[i]
+ vert_start
);
break;
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT:
for(size_t i = 0; i < accessor.count; i++)
indices.push_back(
reinterpret_cast<const uint16_t*>(
&buffer.data[accessor.byteOffset+view.byteOffset
])[i]
+ vert_start
);
break;
case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE:
for(size_t i = 0; i < accessor.count; i++)
indices.push_back(
reinterpret_cast<const uint8_t*>(
&buffer.data[accessor.byteOffset+view.byteOffset
])[i]
+ vert_start
);
break;
default:
Log::error("Unrecognized index type in model\n");
break;
}
Log::debug("Loaded %zu indices of type %d\n", accessor.count, (accessor.componentType-TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE)/2+1);
node->mesh.push_back(Primitive {
.first_idx = first_idx,
.idx_count = idx_count,
});
}
void Model::initNode(const tinygltf::Node& node, Node* parent, int level) {
Log::debug("%*sNode:"+node.name+"\n", level*4, " ");
Node* ret = new Node;
ret->parent = parent;
/* load kids */
for(auto& child_idx : node.children) {
initNode(model->nodes[child_idx], ret, level+1);
}
if(node.mesh >= 0) {
const auto& mesh = model->meshes[node.mesh];
for(auto& prim : mesh.primitives) {
initVertices(ret, prim);
}
}
if(ret->parent)
ret->parent->children.push_back(ret);
else
nodes.push_back(ret);
}

54
Model/Model.hpp Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include <Memory/Buffer.hpp>
#include <Renderer/VertexBuffer.hpp>
#include <memory>
#include <glm/glm.hpp>
#include <tinygltf/tiny_gltf.h>
struct Model {
struct Primitive {
uint32_t first_idx;
uint32_t idx_count;
uint32_t mat_idx;
};
using Mesh = std::vector<Primitive>;
struct Node {
Node* parent;
std::vector<Node*> children;
Mesh mesh;
glm::mat4 mat;
~Node() {
for(auto& n : children)
delete n;
}
};
Model(vk::PhysicalDevice phys_dev, vk::Device dev, const std::string& fname);
std::shared_ptr<tinygltf::Model> model;
void initVertices(Node*, const tinygltf::Primitive&);
std::unique_ptr<VertexBuffer> vertex_buffer;
std::unique_ptr<Buffer> index_buffer;
std::vector<Vertex> vertices;
std::vector<uint16_t> indices;
/* recusively initialize nodes with an accumulative vertex and index buffer collector */
void initNode(const tinygltf::Node& node, Node* parent, int level = 0);
std::vector<Node*> nodes;
~Model() {
for(auto& n : nodes)
delete n;
vertex_buffer.reset();
index_buffer.reset();
}
};

View File

@ -1,5 +1,9 @@
# Pléascach # Pléascach
## Short Term Changes
- Make index buffer device-local instead of host-coherent
- Possibly restructure Buffer class to use templates to change
constructor and functions to use staging buffers if needed.
## Constant Improvements ## Constant Improvements
- Add more comments - Add more comments
## Long Term Improvements ## Long Term Improvements
@ -7,3 +11,5 @@
- Fix all this cleanup vs destructor NONSENSE (inconsistency) - Fix all this cleanup vs destructor NONSENSE (inconsistency)
- Add pipeline caching - Add pipeline caching
- Make more robust solution to window minimization (flushing out Input system should provide candidates) - Make more robust solution to window minimization (flushing out Input system should provide candidates)
- Command buffer per swapchain image
- Make smaller memory allocation object to pass around instead of directly passing physical device to everything

View File

@ -17,14 +17,14 @@
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
const static std::vector<Vertex> triangle = { // const static std::vector<Vertex> triangle = {
{{ 1.0, -1.0, -1.0 }, { 1.0, 0.0 }}, // {{ 1.0, -1.0, -1.0 }, {}, { 1.0, 0.0 }},
{{ 1.0, 1.0, -1.0 }, { 1.0, 1.0 }}, // {{ 1.0, 1.0, -1.0 }, {}, { 1.0, 1.0 }},
{{-1.0, 1.0, -1.0 }, { 0.0, 1.0 }}, // {{-1.0, 1.0, -1.0 }, {}, { 0.0, 1.0 }},
{{-1.0, 1.0, -1.0 }, { 0.0, 1.0 }}, // {{-1.0, 1.0, -1.0 }, {}, { 0.0, 1.0 }},
{{-1.0, -1.0, -1.0 }, { 0.0, 0.0 }}, // {{-1.0, -1.0, -1.0 }, {}, { 0.0, 0.0 }},
{{ 1.0, -1.0, -1.0 }, { 1.0, 0.0 }}, // {{ 1.0, -1.0, -1.0 }, {}, { 1.0, 0.0 }},
}; // };
using namespace std::string_literals; using namespace std::string_literals;
@ -181,11 +181,8 @@ Renderer::Renderer(Window& win) : win(win) {
command_buffer = std::make_unique<CommandBuffer>(dev, queue_family); command_buffer = std::make_unique<CommandBuffer>(dev, queue_family);
vertex_buffer = std::make_unique<VertexBuffer>(phys_dev, dev, triangle.size());
uniform_buffer = std::make_unique<UniformBuffer>(phys_dev, dev); uniform_buffer = std::make_unique<UniformBuffer>(phys_dev, dev);
vertex_buffer->upload(triangle);
textures = createTextures({ textures = createTextures({
"assets/textures/oil.jpg", "assets/textures/oil.jpg",
}); });
@ -200,7 +197,12 @@ Renderer::Renderer(Window& win) : win(win) {
textures[0].binding(1), textures[0].binding(1),
}; };
pipeline = std::make_unique<GraphicsPipeline>(dev, shaders, swapchain->extent, *render_pass, bindings, *vertex_buffer); /* initialize models */
models.push_back(std::make_shared<Model>(phys_dev, dev, "assets/models/dragon.gltf"));
Log::debug("#%zu vertex indices\n", models[0]->indices.size());
pipeline = std::make_unique<GraphicsPipeline>(dev, shaders, swapchain->extent, *render_pass, bindings, *models[0]->vertex_buffer);
pipeline->update(0, *uniform_buffer); pipeline->update(0, *uniform_buffer);
pipeline->update(1, textures[0]); pipeline->update(1, textures[0]);
@ -217,7 +219,7 @@ std::vector<Texture> Renderer::createTextures(const std::vector<std::string>& na
texture_cmd.begin(); texture_cmd.begin();
for (const auto& name : names) { for (const auto& name : names) {
ret.push_back({phys_dev, dev, texture_cmd, "assets/textures/oil.jpg"}); ret.push_back({phys_dev, dev, texture_cmd, name});
} }
texture_cmd.end(); texture_cmd.end();
@ -306,21 +308,23 @@ void Renderer::draw() {
command_buffer->command_buffer.setScissor(0, scissor); command_buffer->command_buffer.setScissor(0, scissor);
command_buffer->bind(*vertex_buffer); command_buffer->bind(*models[0]->vertex_buffer);
command_buffer->command_buffer.bindIndexBuffer(*models[0]->index_buffer, 0, vk::IndexType::eUint16);
command_buffer->bind(pipeline->layout, pipeline->desc_set); command_buffer->bind(pipeline->layout, pipeline->desc_set);
auto sz = win.getDimensions(); auto sz = win.getDimensions();
const auto p = glm::perspective(glm::radians(90.0f), static_cast<float>(sz.width) / static_cast<float>(sz.height), 0.01f, 50.0f); const auto p = glm::perspective(glm::radians(90.0f), static_cast<float>(sz.width) / static_cast<float>(sz.height), 0.01f, 2000.0f);
uniform_buffer->upload(UniformData{ uniform_buffer->upload(UniformData{
.mvp = p * glm::rotate(glm::mat4(1.0), glm::radians(static_cast<float>(frame)), glm::vec3(1.0, 1.0, 1.0)), .mvp = p,
.time = static_cast<float>(frame) * 0.0167f, .time = static_cast<float>(frame) * 0.0167f,
.aspect_ratio = static_cast<float>(sz.width)/static_cast<float>(sz.height), .aspect_ratio = static_cast<float>(sz.width)/static_cast<float>(sz.height),
}); });
command_buffer->draw(std::size(triangle), 1, 0, 0); //command_buffer->draw(std::size(triangle), 1, 0, 0);
command_buffer->command_buffer.drawIndexed(models[0]->indices.size(), 1, 0, 0, 0);
command_buffer->command_buffer.endRenderPass(); command_buffer->command_buffer.endRenderPass();
@ -371,6 +375,9 @@ void Renderer::present() {
Renderer::~Renderer() { Renderer::~Renderer() {
dev.waitIdle(); dev.waitIdle();
for(auto& model : models)
model.reset();
uniform_buffer.reset(); uniform_buffer.reset();
vertex_buffer.reset(); vertex_buffer.reset();
pipeline.reset(); pipeline.reset();

View File

@ -9,6 +9,8 @@
#include <Renderer/CommandBuffer.hpp> #include <Renderer/CommandBuffer.hpp>
#include <Renderer/RenderPass.hpp> #include <Renderer/RenderPass.hpp>
#include <Model/Model.hpp>
struct Window; struct Window;
struct UniformBuffer; struct UniformBuffer;
struct VertexBuffer; struct VertexBuffer;
@ -50,4 +52,6 @@ struct Renderer {
uint32_t current_image_idx; uint32_t current_image_idx;
uint64_t frame = 0; uint64_t frame = 0;
std::vector<std::shared_ptr<Model>> models;
}; };

View File

@ -60,7 +60,8 @@ void Swapchain::create(vk::SwapchainKHR old_swapchain) {
/* see if this allows see through windows on Wayland */ /* see if this allows see through windows on Wayland */
.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque, .compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque,
/* waits for refresh (V-Sync), consider playing with relaxed fifo later on*/ /* waits for refresh (V-Sync), consider playing with relaxed fifo later on*/
.presentMode = vk::PresentModeKHR::eFifo, // .presentMode = vk::PresentModeKHR::eFifo,
.presentMode = vk::PresentModeKHR::eMailbox,
.clipped = VK_TRUE, .clipped = VK_TRUE,
.oldSwapchain = old_swapchain, .oldSwapchain = old_swapchain,
}; };

View File

@ -1,5 +1,8 @@
#include <Renderer/VertexBuffer.hpp> #include <Renderer/VertexBuffer.hpp>
#include <Memory/Buffer.hpp>
#include <tinygltf/tiny_gltf.h>
VertexBuffer::VertexBuffer(vk::PhysicalDevice phys_dev, vk::Device dev, size_t n_vertices) { VertexBuffer::VertexBuffer(vk::PhysicalDevice phys_dev, vk::Device dev, size_t n_vertices) {
buffer = std::make_unique<Buffer>(phys_dev, dev, n_vertices * sizeof(Vertex), buffer = std::make_unique<Buffer>(phys_dev, dev, n_vertices * sizeof(Vertex),
@ -10,3 +13,7 @@ VertexBuffer::VertexBuffer(vk::PhysicalDevice phys_dev, vk::Device dev, size_t n
void VertexBuffer::upload(const std::vector<Vertex>& data) { void VertexBuffer::upload(const std::vector<Vertex>& data) {
buffer->upload(reinterpret_cast<const uint8_t*>(data.data()), sizeof(Vertex)*data.size()); buffer->upload(reinterpret_cast<const uint8_t*>(data.data()), sizeof(Vertex)*data.size());
} }
void VertexBuffer::upload(const tinygltf::Buffer& buff, const tinygltf::BufferView& view) {
std::memcpy(buffer->p, buff.data.data() + view.byteOffset, view.byteLength);
}

View File

@ -1,20 +1,28 @@
#pragma once
#include <Memory/Buffer.hpp> #include <Memory/Buffer.hpp>
#include <memory> #include <memory>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <tinygltf/tiny_gltf.h>
struct Vertex { struct Vertex {
glm::vec3 coord; glm::vec3 pos;
glm::vec2 tex_coord; glm::vec3 norm;
glm::vec2 uv;
glm::vec3 color;
}; };
struct VertexBuffer { struct VertexBuffer {
std::unique_ptr<Buffer> buffer; std::unique_ptr<Buffer> buffer;
VertexBuffer(vk::PhysicalDevice phys_dev, vk::Device dev, size_t n_vertices); VertexBuffer(vk::PhysicalDevice phys_dev, vk::Device dev, size_t n_vertices);
void upload(const std::vector<Vertex>& data); void upload(const std::vector<Vertex>& data);
void upload(const tinygltf::Buffer& buff, const tinygltf::BufferView& view);
inline vk::VertexInputBindingDescription binding(uint32_t binding, vk::ShaderStageFlags stages = vk::ShaderStageFlagBits::eVertex) const { inline vk::VertexInputBindingDescription binding(uint32_t binding, vk::ShaderStageFlags stages = vk::ShaderStageFlagBits::eVertex) const {
return vk::VertexInputBindingDescription { return vk::VertexInputBindingDescription {
@ -30,12 +38,22 @@ struct VertexBuffer {
.location = 0, .location = 0,
.binding = binding, .binding = binding,
.format = vk::Format::eR32G32B32Sfloat, .format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(Vertex, coord), .offset = offsetof(Vertex, pos),
}, { }, {
.location = 1, .location = 1,
.binding = binding, .binding = binding,
.format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(Vertex, norm),
},{
.location = 2,
.binding = binding,
.format = vk::Format::eR32G32Sfloat, .format = vk::Format::eR32G32Sfloat,
.offset = offsetof(Vertex, tex_coord), .offset = offsetof(Vertex, uv),
},{
.location = 3,
.binding = binding,
.format = vk::Format::eR32G32B32Sfloat,
.offset = offsetof(Vertex, color),
} }
}; };
} }

224
assets/models/dragon.gltf Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,7 @@
#version 460 core #version 460 core
layout (location = 0) in vec2 texCoord; layout (location = 0) in vec3 norm;
layout (location = 1) in vec2 texCoord;
layout (location = 0) out vec4 FragColor; layout (location = 0) out vec4 FragColor;
layout (set = 0, binding = 0) uniform Matrices { layout (set = 0, binding = 0) uniform Matrices {
@ -11,5 +12,6 @@ layout (set = 0, binding = 0) uniform Matrices {
layout (set = 0, binding = 1) uniform sampler2D tex; layout (set = 0, binding = 1) uniform sampler2D tex;
void main() { void main() {
FragColor = texture(tex, texCoord); //FragColor = vec4(1.0);
FragColor = vec4(norm, 1.0);
} }

Binary file not shown.

View File

@ -1,8 +1,10 @@
#version 460 core #version 460 core
layout (location = 0) in vec3 aPos; layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord; layout (location = 1) in vec3 aNorm;
layout (location = 2) in vec2 aTexCoord;
layout (location = 0) out vec2 texCoord; layout (location = 0) out vec3 norm;
layout (location = 1) out vec2 texCoord;
layout (set = 0, binding = 0) uniform Matrices { layout (set = 0, binding = 0) uniform Matrices {
mat4 mpv; mat4 mpv;
@ -10,6 +12,7 @@ layout (set = 0, binding = 0) uniform Matrices {
}; };
void main() { void main() {
gl_Position = mpv*vec4(aPos, 1.0); gl_Position = mpv * vec4(aPos - vec3(0.0, 0.0, 3.0) * time/3.0, 1.0);
texCoord = aTexCoord; texCoord = aTexCoord;
norm = aNorm;
} }

Binary file not shown.

View File

@ -23,7 +23,6 @@ vec3 ray_color(vec3 ray) {
return vec3(1.0-a) + a*vec3(0.5, 0.7, 1.0); return vec3(1.0-a) + a*vec3(0.5, 0.7, 1.0);
} }
/* returns float of where you hit, or -1.0 */ /* returns float of where you hit, or -1.0 */
float sphere(vec3 center, float r, Ray ray) { float sphere(vec3 center, float r, Ray ray) {
vec3 p = ray.orig-center; vec3 p = ray.orig-center;

1724
include/stb_image_write.h Normal file

File diff suppressed because it is too large Load Diff

26753
include/tinygltf/json.hpp Normal file

File diff suppressed because it is too large Load Diff

8526
include/tinygltf/tiny_gltf.h Normal file

File diff suppressed because it is too large Load Diff