diff --git a/res/dpr/mesh_data.inc b/res/dpr/mesh_data.inc new file mode 100644 index 0000000000000000000000000000000000000000..13e2785abd3f8863dbdfeec532213d491666eeb8 --- /dev/null +++ b/res/dpr/mesh_data.inc @@ -0,0 +1,3 @@ +struct MeshData { + mat4 localToWorldSpace; +}; diff --git a/src/scene.cpp b/src/scene.cpp index 6bc21b7f5863084bd97147656f3f01a9509c7913..93376797361500d3f87848cc1bf0e589bb44588f 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -4,6 +4,7 @@ #include <assimp/scene.h> #include <filesystem> #include <glm/gtc/type_ptr.hpp> +#include <glm/gtx/quaternion.hpp> using namespace lava; @@ -18,6 +19,44 @@ void scene::set_vertex_input(lava::graphics_pipeline* pipeline) { } void scene::update(float delta_time) { + current_time += delta_time * animations[active_animation].ticks_per_second; + + for (const auto& channel : animations[active_animation].channels) { + glm::vec3 position(0.0f); + glm::quat rotation(1.0f, 0.0f, 0.0f, 0.0f); + glm::vec3 scaling(1.0f); + + std::pair<float, glm::vec3> last_position_frame = channel.position_frames.front(); + for (const auto& position_frame : channel.position_frames) { + if (position_frame.first > current_time) { + const float t = (current_time - last_position_frame.first) / (position_frame.first - last_position_frame.first); + position = glm::mix(last_position_frame.second, position_frame.second, t); + break; + } + last_position_frame = position_frame; + } + std::pair<float, glm::quat> last_rotation_frame = channel.rotation_frames.front(); + for (const auto& rotation_frame : channel.rotation_frames) { + if (rotation_frame.first > current_time) { + const float t = (current_time - last_rotation_frame.first) / (rotation_frame.first - last_rotation_frame.first); + rotation = glm::mix(last_rotation_frame.second, rotation_frame.second, t); + break; + } + last_rotation_frame = rotation_frame; + } + std::pair<float, glm::vec3> last_scaling_frame = channel.scaling_frames.front(); + for (const auto& scaling_frame : channel.scaling_frames) { + if (scaling_frame.first > current_time) { + const float t = (current_time - last_scaling_frame.first) / (scaling_frame.first - last_scaling_frame.first); + scaling = glm::mix(last_scaling_frame.second, scaling_frame.second, t); + break; + } + last_scaling_frame = scaling_frame; + } + + nodes[channel.node_index].local_transform = + glm::translate(glm::toMat4(rotation) * glm::scale(glm::mat4(1.0f), scaling), position); + } for (auto& node : nodes) { if (node.parent_index != std::numeric_limits<size_t>::max()) { @@ -28,6 +67,7 @@ void scene::update(float delta_time) { } for (size_t i = 0; i < meshes.size(); ++i) { mesh_data[i].localToWorldSpace = nodes[meshes[i].node_index].global_transform; + // mesh_data[i].localToWorldSpace = glm::mat4(1.0f); } std::memcpy(mesh_data_buffer->get_mapped_data(), mesh_data.data(), sizeof(glsl::MeshData) * meshes.size()); } @@ -45,21 +85,23 @@ void print_node(const aiScene* scene, aiNode* node, std::string prefix = "") { } } -void insert_node(scene* scene, aiNode* assimp_node, size_t parent_index) { +void insert_node(scene* scene, aiNode* assimp_node, size_t parent_index, std::map<std::string, std::size_t>* node_indices) { ::scene::node node { .global_transform = glm::mat4(1.0f), .parent_index = parent_index, }; std::memcpy(glm::value_ptr(node.local_transform), &assimp_node->mTransformation.a1, sizeof(glm::mat4)); + node.local_transform = glm::transpose(node.local_transform); const size_t node_index = scene->nodes.size(); scene->nodes.push_back(node); + node_indices->insert(std::make_pair(assimp_node->mName.C_Str(), node_index)); for (unsigned int i = 0; i < assimp_node->mNumMeshes; ++i) { const size_t mesh_index = assimp_node->mMeshes[i]; scene->meshes[mesh_index].node_index = node_index; } for (unsigned int i = 0; i < assimp_node->mNumChildren; ++i) { - insert_node(scene, assimp_node->mChildren[i], node_index); + insert_node(scene, assimp_node->mChildren[i], node_index, node_indices); } } @@ -103,7 +145,77 @@ scene::ptr load_scene(lava::device_ptr device, lava::name filename) { return {}; } scene->meshes.resize(assimp_scene->mNumMeshes); - insert_node(scene.get(), assimp_scene->mRootNode, std::numeric_limits<size_t>::max()); + + std::map<std::string, size_t> node_indices; + insert_node(scene.get(), assimp_scene->mRootNode, std::numeric_limits<size_t>::max(), &node_indices); + + for (unsigned int i = 0; i < assimp_scene->mNumCameras; ++i) { + const auto assimp_camera = assimp_scene->mCameras[i]; + + if (!node_indices.contains(assimp_camera->mName.C_Str())) { + log()->warn("Unknown node: {}", assimp_camera->mName.C_Str()); + continue; + } + + scene_camera camera; + camera.node_index = node_indices[assimp_camera->mName.C_Str()]; + // camera.projection_matrix = ; + scene->cameras.push_back(std::move(camera)); + } + + log()->info("{} lights", assimp_scene->mNumLights); + log()->info("{} cameras", assimp_scene->mNumCameras); + + auto assimp_vector3_to_glm = [](aiVector3D v) { + return glm::vec3(v.x, v.y, v.z); + }; + auto assimp_quaternion_to_glm = [](aiQuaternion v) { + return glm::quat(v.w, v.x, v.y, v.z); + }; + + for (unsigned int i = 0; i < assimp_scene->mNumAnimations; ++i) { + const auto assimp_animation = assimp_scene->mAnimations[i]; + scene_animation animation; + + animation.duration = assimp_animation->mDuration; + animation.ticks_per_second = assimp_animation->mTicksPerSecond; + + for (unsigned int j = 0; j < assimp_animation->mNumChannels; ++j) { + const auto assimp_channel = assimp_animation->mChannels[j]; + + scene_animation_channel channel; + + if (!node_indices.contains(assimp_channel->mNodeName.C_Str())) { + log()->warn("Unknown node: {}", assimp_channel->mNodeName.C_Str()); + continue; + } + + channel.node_index = node_indices[assimp_channel->mNodeName.C_Str()]; + + channel.position_frames.reserve(assimp_channel->mNumPositionKeys); + for (unsigned int k = 0; k < assimp_channel->mNumPositionKeys; ++k) { + const auto key = assimp_channel->mPositionKeys[k]; + channel.position_frames.push_back(std::make_pair(key.mTime, assimp_vector3_to_glm(key.mValue))); + } + + channel.rotation_frames.reserve(assimp_channel->mNumRotationKeys); + for (unsigned int k = 0; k < assimp_channel->mNumRotationKeys; ++k) { + const auto key = assimp_channel->mRotationKeys[k]; + channel.rotation_frames.push_back(std::make_pair(key.mTime, assimp_quaternion_to_glm(key.mValue))); + } + + channel.scaling_frames.reserve(assimp_channel->mNumScalingKeys); + for (unsigned int k = 0; k < assimp_channel->mNumScalingKeys; ++k) { + const auto key = assimp_channel->mScalingKeys[k]; + channel.scaling_frames.push_back(std::make_pair(key.mTime, assimp_vector3_to_glm(key.mValue))); + } + + animation.channels.push_back(std::move(channel)); + } + + scene->animations.push_back(std::move(animation)); + } + scene->active_animation = 0; scene->mesh_data.resize(assimp_scene->mNumMeshes, glsl::MeshData { .localToWorldSpace = glm::mat4(1.0f) }); @@ -112,9 +224,6 @@ scene::ptr load_scene(lava::device_ptr device, lava::name filename) { throw std::runtime_error("Failed to create mesh data buffer"); } - auto assimp_vector3_to_glm = [](aiVector3D v) { - return glm::vec3(v.x, v.y, v.z); - }; std::vector<VkWriteDescriptorSet> descriptor_set_writes; for (unsigned int i = 0; i < assimp_scene->mNumMeshes; ++i) { @@ -124,14 +233,11 @@ scene::ptr load_scene(lava::device_ptr device, lava::name filename) { data.vertices.resize(assimp_mesh->mNumVertices); for (unsigned int vertex_index = 0; vertex_index < assimp_mesh->mNumVertices; ++vertex_index) { data.vertices[vertex_index].position = assimp_vector3_to_glm(assimp_mesh->mVertices[vertex_index]); - data.vertices[vertex_index].position.y *= -1; if (assimp_mesh->HasNormals()) { data.vertices[vertex_index].normal = assimp_vector3_to_glm(assimp_mesh->mNormals[vertex_index]); - data.vertices[vertex_index].normal.y *= -1; } if (assimp_mesh->HasTangentsAndBitangents()) { data.vertices[vertex_index].color = glm::vec4(assimp_vector3_to_glm(assimp_mesh->mTangents[vertex_index]), 0.0f); - data.vertices[vertex_index].color.y *= -1; } if (assimp_mesh->HasTextureCoords(0)) { data.vertices[vertex_index].uv = glm::vec2(assimp_vector3_to_glm(assimp_mesh->mTextureCoords[0][vertex_index])); diff --git a/src/scene.hpp b/src/scene.hpp index 51b9a597074eed0764a11cb5ec1bc8e38578a00e..7a90c6d6dadbd4bc05af28cb271548fa6dc99818 100644 --- a/src/scene.hpp +++ b/src/scene.hpp @@ -25,11 +25,23 @@ struct scene_mesh { size_t material_index; }; -struct animation_channel { +struct scene_animation_channel { + size_t node_index; + std::vector<std::pair<float, glm::vec3>> position_frames; + std::vector<std::pair<float, glm::quat>> rotation_frames; + std::vector<std::pair<float, glm::vec3>> scaling_frames; }; struct scene_animation { + float duration; + float ticks_per_second; + std::vector<scene_animation_channel> channels; +}; +struct scene_camera { + size_t node_index; + glm::mat4 projection_matrix; + glm::mat4 view_matrix; }; class scene { @@ -62,6 +74,10 @@ public: lava::texture::ptr dummy_texture; float current_time = 0.0f; + std::vector<scene_animation> animations; + size_t active_animation; + + std::vector<scene_camera> cameras; }; scene::ptr load_scene(lava::device_ptr device, lava::name filename); diff --git a/src/vr_app.cpp b/src/vr_app.cpp index c4cd355d66bd92aa3d3794850471c4dd62f8dfd0..8d6b494a33a629b52a29343e16fb76263e56f7ef 100644 --- a/src/vr_app.cpp +++ b/src/vr_app.cpp @@ -86,8 +86,8 @@ vr_app::vr_app(name name, argh::parser cmd_line) { throw std::runtime_error("Failed to create vulkan device"); } } - app_->camera.position = glm::vec3(0.0f, 0.0f, -0.5f); - app_->camera.movement_speed = 100.0f; + // app_->camera.position = glm::vec3(0.0f, 0.0f, -0.5f); + app_->camera.movement_speed = 10.0f; app_->on_process = [this](VkCommandBuffer command_buffer, lava::index frame) { VkImageSubresourceRange const image_range{ @@ -128,8 +128,10 @@ vr_app::vr_app(name name, argh::parser cmd_line) { app_->camera.update_view(dt, app_->input.get_mouse_position()); scene()->update(dt); + const glm::mat4 scene_view_matrix = glm::inverse(scene()->nodes[scene()->cameras[0].node_index].global_transform); + for (auto& framebuffer : framebuffers_) { - framebuffer->per_frame_data.view = framebuffer->per_frame_data.headToEye * camera().view; + framebuffer->per_frame_data.view = framebuffer->per_frame_data.headToEye * scene_view_matrix; framebuffer->per_frame_data.viewProjection = framebuffer->per_frame_data.projection * framebuffer->per_frame_data.view; std::memcpy(framebuffer->per_frame_ubo->get_mapped_data(), &framebuffer->per_frame_data, sizeof(framebuffer->per_frame_data)); } @@ -261,6 +263,8 @@ bool vr_app::setup() { ImGui::InputFloat("Z-far", &app_->camera.z_far)) { app_->camera.update_projection(); } + + ImGui::DragFloat("Scene Time", &scene()->current_time); std::array<const char*, 2> strategy_names = { "Naive Stereo", "Depth Peeling Reprojection" }; @@ -446,7 +450,7 @@ stereo_framebuffer::ptr vr_app::create_framebuffer(glm::uvec2 size, vr::EVREye e framebuffer->per_frame_data.projection = glm::transpose(framebuffer->per_frame_data.projection); } else { framebuffer->per_frame_data.projection = glm::perspective(M_PI / 2, 16.0/9.0, 0.1, 1000000.0); - framebuffer->per_frame_data.headToEye = glm::translate(glm::mat4(1.0f), glm::vec3(10.0f, 0.0, 0.0f) * (eye == vr::Eye_Left ? 1.0f : -1.0f)); + framebuffer->per_frame_data.headToEye = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f, 0.0, 0.0f) * (eye == vr::Eye_Left ? 1.0f : -1.0f)); } framebuffer->per_frame_data.view = glm::identity<glm::mat4>();