Compare commits
5 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
6733eb3495 | |
|
|
2e7056c246 | |
|
|
ee3aa35567 | |
|
|
69efacc681 | |
|
|
0bf2e20d96 |
|
|
@ -11,6 +11,20 @@
|
||||||
"cppStandard": "gnu++17",
|
"cppStandard": "gnu++17",
|
||||||
"intelliSenseMode": "linux-gcc-x64",
|
"intelliSenseMode": "linux-gcc-x64",
|
||||||
"configurationProvider": "ms-vscode.makefile-tools"
|
"configurationProvider": "ms-vscode.makefile-tools"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mac",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**",
|
||||||
|
"/Users/wanghao/VulkanSDK/1.4.328.1/macOS/include",
|
||||||
|
"/opt/local/include",
|
||||||
|
"/usr/local/include"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"compilerPath": "/usr/bin/clang++",
|
||||||
|
"cStandard": "c17",
|
||||||
|
"cppStandard": "c++17",
|
||||||
|
"intelliSenseMode": "macos-clang-arm64"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"version": 4
|
"version": 4
|
||||||
|
|
|
||||||
1
Makefile
1
Makefile
|
|
@ -1,4 +1,5 @@
|
||||||
VULKAN_SDK_PATH = /Users/wanghao/VulkanSDK/1.4.328.1/macOS
|
VULKAN_SDK_PATH = /Users/wanghao/VulkanSDK/1.4.328.1/macOS
|
||||||
|
GLSLC = $(VULKAN_SDK_PATH)/bin/glslc
|
||||||
CFLAGS = -std=c++17 -o2 -I. -I$(VULKAN_SDK_PATH)/include -I/opt/local/include
|
CFLAGS = -std=c++17 -o2 -I. -I$(VULKAN_SDK_PATH)/include -I/opt/local/include
|
||||||
LDFLAGS = -L$(VULKAN_SDK_PATH)/lib -L/opt/local/lib `pkg-config --static --libs glfw3` -lvulkan -ldl -lpthread -lX11
|
LDFLAGS = -L$(VULKAN_SDK_PATH)/lib -L/opt/local/lib `pkg-config --static --libs glfw3` -lvulkan -ldl -lpthread -lX11
|
||||||
|
|
||||||
|
|
|
||||||
BIN
VulkanTest
BIN
VulkanTest
Binary file not shown.
168
first_app.cpp
168
first_app.cpp
|
|
@ -1,7 +1,9 @@
|
||||||
#include "first_app.hpp"
|
#include "first_app.hpp"
|
||||||
#include "simple_render_system.hpp"
|
#include "simple_render_system.hpp"
|
||||||
#include "rainbow_system.hpp"
|
#include "rainbow_system.hpp"
|
||||||
#include "gravity_physics_system.hpp"
|
|
||||||
|
#include "keyboard_movement_controller.hpp"
|
||||||
|
#include "hk_camera.hpp"
|
||||||
|
|
||||||
// libs
|
// libs
|
||||||
#define GLM_FORCE_RADIANS
|
#define GLM_FORCE_RADIANS
|
||||||
|
|
@ -11,6 +13,7 @@
|
||||||
|
|
||||||
// std
|
// std
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <chrono>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -25,88 +28,37 @@ namespace hk
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void FirstApp::runGravitySystem()
|
|
||||||
{
|
|
||||||
// Gravity Physics System
|
|
||||||
// Create some Models
|
|
||||||
std::shared_ptr<Model> squareModel = createSquareModel(m_device, {.5f, .0f});
|
|
||||||
std::shared_ptr<Model> circleModel = createCircleModel(m_device, 64);
|
|
||||||
// Create Physics Objects
|
|
||||||
std::vector<GameObject> physicsObjects{};
|
|
||||||
auto red = GameObject::createGameObject();
|
|
||||||
red.m_transform2d.scale = glm::vec2{.05f};
|
|
||||||
red.m_transform2d.translation = {.5f, .5f};
|
|
||||||
red.m_color = {1.f, 0.f, 0.f};
|
|
||||||
red.m_rigidBody2d.velocity = {-.5f, .0f};
|
|
||||||
red.m_model = circleModel;
|
|
||||||
physicsObjects.push_back(std::move(red));
|
|
||||||
auto blue = GameObject::createGameObject();
|
|
||||||
blue.m_transform2d.scale = glm::vec2{.05f};
|
|
||||||
blue.m_transform2d.translation = {-.45f, -.25f};
|
|
||||||
blue.m_color = {0.f, 0.f, 1.f};
|
|
||||||
blue.m_rigidBody2d.velocity = {.5f, .0f};
|
|
||||||
blue.m_model = circleModel;
|
|
||||||
physicsObjects.push_back(std::move(blue));
|
|
||||||
|
|
||||||
// Create Vector Field
|
|
||||||
std::vector<GameObject> vectorField{};
|
|
||||||
int gridCount = 40;
|
|
||||||
for (int i = 0; i < gridCount; i++)
|
|
||||||
{
|
|
||||||
for(int j = 0; j < gridCount; j ++)
|
|
||||||
{
|
|
||||||
auto vf = GameObject::createGameObject();
|
|
||||||
vf.m_transform2d.scale = glm::vec2{0.005f};
|
|
||||||
vf.m_transform2d.translation = {-1.0f + (i + 0.5f) * 2.0f / gridCount, -1.0f + (j + 0.5f) * 2.0f / gridCount};
|
|
||||||
vf.m_color = glm::vec3{1.0f};
|
|
||||||
vf.m_model = squareModel;
|
|
||||||
vectorField.push_back(std::move(vf));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GravityPhysicsSystem gravitySystem(0.81f);
|
|
||||||
Vec2FieldSystem vecFieldSystem{};
|
|
||||||
|
|
||||||
SimpleRenderSystem simpleRenderSystem{m_device, m_renderer.getSwapChainRenderPass()};
|
|
||||||
|
|
||||||
while(!m_window.shouldClose())
|
|
||||||
{
|
|
||||||
glfwPollEvents();
|
|
||||||
|
|
||||||
if (auto commandBuffer = m_renderer.beginFrame())
|
|
||||||
{
|
|
||||||
// update system
|
|
||||||
gravitySystem.update(physicsObjects, 1.f / 60, 5);
|
|
||||||
vecFieldSystem.update(gravitySystem, physicsObjects, vectorField);
|
|
||||||
|
|
||||||
// render system
|
|
||||||
m_renderer.beginSwapChainRenderPass(commandBuffer);
|
|
||||||
simpleRenderSystem.renderGameObjects(commandBuffer, physicsObjects);
|
|
||||||
simpleRenderSystem.renderGameObjects(commandBuffer, vectorField);
|
|
||||||
m_renderer.endSwapChainRenderPass(commandBuffer);
|
|
||||||
m_renderer.endFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
vkDeviceWaitIdle(m_device.device());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FirstApp::run()
|
void FirstApp::run()
|
||||||
{
|
{
|
||||||
SimpleRenderSystem simpleRenderSystem{m_device, m_renderer.getSwapChainRenderPass()};
|
SimpleRenderSystem simpleRenderSystem{m_device, m_renderer.getSwapChainRenderPass()};
|
||||||
RainbowSystem rainbowSystem(2000.0f);
|
RainbowSystem rainbowSystem(2000.0f);
|
||||||
|
Camera camera{};
|
||||||
|
|
||||||
|
auto viewerObject = GameObject::createGameObject();
|
||||||
|
KeyboardMovementController cameraController{};
|
||||||
|
|
||||||
|
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
while (!m_window.shouldClose())
|
while (!m_window.shouldClose())
|
||||||
{
|
{
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
||||||
|
auto newTime = std::chrono::high_resolution_clock::now();
|
||||||
|
float frameTime = std::chrono::duration<float, std::chrono::seconds::period>(newTime - currentTime).count();
|
||||||
|
currentTime = newTime;
|
||||||
|
|
||||||
|
cameraController.moveInPlaneXZ(m_window.getWindow(), frameTime, viewerObject);
|
||||||
|
camera.setViewYXZ(viewerObject.m_transform.translation, viewerObject.m_transform.rotation);
|
||||||
|
|
||||||
// update objects color
|
// update objects color
|
||||||
rainbowSystem.update(5.0f, m_gameObjects);
|
rainbowSystem.update(5.0f, m_gameObjects);
|
||||||
|
|
||||||
|
float aspect = m_renderer.getAspectRatio();
|
||||||
|
camera.setPerspectiveProjection(glm::radians(50.f), aspect, 0.1f, 10.f);
|
||||||
if (auto commandBuffer = m_renderer.beginFrame())
|
if (auto commandBuffer = m_renderer.beginFrame())
|
||||||
{
|
{
|
||||||
m_renderer.beginSwapChainRenderPass(commandBuffer);
|
m_renderer.beginSwapChainRenderPass(commandBuffer);
|
||||||
simpleRenderSystem.renderGameObjects(commandBuffer, m_gameObjects);
|
simpleRenderSystem.renderGameObjects(commandBuffer, m_gameObjects, camera);
|
||||||
m_renderer.endSwapChainRenderPass(commandBuffer);
|
m_renderer.endSwapChainRenderPass(commandBuffer);
|
||||||
m_renderer.endFrame();
|
m_renderer.endFrame();
|
||||||
}
|
}
|
||||||
|
|
@ -115,22 +67,74 @@ namespace hk
|
||||||
vkDeviceWaitIdle(m_device.device());
|
vkDeviceWaitIdle(m_device.device());
|
||||||
}
|
}
|
||||||
|
|
||||||
void FirstApp::loadGameObjects()
|
// temporary helper function, creates a 1x1x1 cube centered at offset
|
||||||
|
std::unique_ptr<Model> createCubeModel(hk::Device &device, glm::vec3 offset)
|
||||||
{
|
{
|
||||||
std::vector<Model::Vertex> vertices{
|
std::vector<Model::Vertex> vertices{
|
||||||
{{0.0f, -0.5f}, {1.0f, 0.0f, 0.0f}},
|
|
||||||
{{0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},
|
|
||||||
{{-0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}}
|
|
||||||
};
|
|
||||||
auto model = std::make_shared<Model>(m_device, vertices);
|
|
||||||
|
|
||||||
auto triangle = GameObject::createGameObject();
|
// left face (white)
|
||||||
triangle.m_model = model;
|
{{-.5f, -.5f, -.5f}, {.9f, .9f, .9f}},
|
||||||
triangle.m_color = {.1f, .8f, .1f};
|
{{-.5f, .5f, .5f}, {.9f, .9f, .9f}},
|
||||||
triangle.m_transform2d.translation.x = .2f;
|
{{-.5f, -.5f, .5f}, {.9f, .9f, .9f}},
|
||||||
triangle.m_transform2d.scale = {2.0f, .5f};
|
{{-.5f, -.5f, -.5f}, {.9f, .9f, .9f}},
|
||||||
triangle.m_transform2d.rotation = .25f * glm::two_pi<float>();
|
{{-.5f, .5f, -.5f}, {.9f, .9f, .9f}},
|
||||||
|
{{-.5f, .5f, .5f}, {.9f, .9f, .9f}},
|
||||||
m_gameObjects.push_back(std::move(triangle));
|
|
||||||
|
// right face (yellow)
|
||||||
|
{{.5f, -.5f, -.5f}, {.8f, .8f, .1f}},
|
||||||
|
{{.5f, .5f, .5f}, {.8f, .8f, .1f}},
|
||||||
|
{{.5f, -.5f, .5f}, {.8f, .8f, .1f}},
|
||||||
|
{{.5f, -.5f, -.5f}, {.8f, .8f, .1f}},
|
||||||
|
{{.5f, .5f, -.5f}, {.8f, .8f, .1f}},
|
||||||
|
{{.5f, .5f, .5f}, {.8f, .8f, .1f}},
|
||||||
|
|
||||||
|
// top face (orange, remember y axis points down)
|
||||||
|
{{-.5f, -.5f, -.5f}, {.9f, .6f, .1f}},
|
||||||
|
{{.5f, -.5f, .5f}, {.9f, .6f, .1f}},
|
||||||
|
{{-.5f, -.5f, .5f}, {.9f, .6f, .1f}},
|
||||||
|
{{-.5f, -.5f, -.5f}, {.9f, .6f, .1f}},
|
||||||
|
{{.5f, -.5f, -.5f}, {.9f, .6f, .1f}},
|
||||||
|
{{.5f, -.5f, .5f}, {.9f, .6f, .1f}},
|
||||||
|
|
||||||
|
// bottom face (red)
|
||||||
|
{{-.5f, .5f, -.5f}, {.8f, .1f, .1f}},
|
||||||
|
{{.5f, .5f, .5f}, {.8f, .1f, .1f}},
|
||||||
|
{{-.5f, .5f, .5f}, {.8f, .1f, .1f}},
|
||||||
|
{{-.5f, .5f, -.5f}, {.8f, .1f, .1f}},
|
||||||
|
{{.5f, .5f, -.5f}, {.8f, .1f, .1f}},
|
||||||
|
{{.5f, .5f, .5f}, {.8f, .1f, .1f}},
|
||||||
|
|
||||||
|
// nose face (blue)
|
||||||
|
{{-.5f, -.5f, 0.5f}, {.1f, .1f, .8f}},
|
||||||
|
{{.5f, .5f, 0.5f}, {.1f, .1f, .8f}},
|
||||||
|
{{-.5f, .5f, 0.5f}, {.1f, .1f, .8f}},
|
||||||
|
{{-.5f, -.5f, 0.5f}, {.1f, .1f, .8f}},
|
||||||
|
{{.5f, -.5f, 0.5f}, {.1f, .1f, .8f}},
|
||||||
|
{{.5f, .5f, 0.5f}, {.1f, .1f, .8f}},
|
||||||
|
|
||||||
|
// tail face (green)
|
||||||
|
{{-.5f, -.5f, -0.5f}, {.1f, .8f, .1f}},
|
||||||
|
{{.5f, .5f, -0.5f}, {.1f, .8f, .1f}},
|
||||||
|
{{-.5f, .5f, -0.5f}, {.1f, .8f, .1f}},
|
||||||
|
{{-.5f, -.5f, -0.5f}, {.1f, .8f, .1f}},
|
||||||
|
{{.5f, -.5f, -0.5f}, {.1f, .8f, .1f}},
|
||||||
|
{{.5f, .5f, -0.5f}, {.1f, .8f, .1f}},
|
||||||
|
|
||||||
|
};
|
||||||
|
for (auto &v : vertices)
|
||||||
|
{
|
||||||
|
v.position += offset;
|
||||||
|
}
|
||||||
|
return std::make_unique<Model>(device, vertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FirstApp::loadGameObjects()
|
||||||
|
{
|
||||||
|
std::shared_ptr<Model> cubeModel = createCubeModel(m_device, {0.f, 0.f, 0.f});
|
||||||
|
auto cube = GameObject::createGameObject();
|
||||||
|
cube.m_model = cubeModel;
|
||||||
|
cube.m_transform.translation = {0.f, 0.f, 2.5f};
|
||||||
|
cube.m_transform.scale = {.5f, .5f, .5f};
|
||||||
|
m_gameObjects.push_back(std::move(cube));
|
||||||
}
|
}
|
||||||
} // namespace hk
|
} // namespace hk
|
||||||
|
|
@ -24,7 +24,6 @@ namespace hk
|
||||||
FirstApp &operator=(const FirstApp &) = delete;
|
FirstApp &operator=(const FirstApp &) = delete;
|
||||||
|
|
||||||
void run();
|
void run();
|
||||||
void runGravitySystem();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadGameObjects();
|
void loadGameObjects();
|
||||||
|
|
|
||||||
|
|
@ -1,129 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <hk_game_object.hpp>
|
|
||||||
|
|
||||||
#define GLM_FORCE_RADIANS
|
|
||||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <glm/gtc/constants.hpp>
|
|
||||||
|
|
||||||
// std
|
|
||||||
#include <memory>
|
|
||||||
#include <random>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace hk
|
|
||||||
{
|
|
||||||
class GravityPhysicsSystem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GravityPhysicsSystem(float strength) :m_strengthGravity(strength) {}
|
|
||||||
|
|
||||||
void update(std::vector<GameObject> &objs, float dt, unsigned int substeps = 1)
|
|
||||||
{
|
|
||||||
const float stepDelta = dt / substeps;
|
|
||||||
|
|
||||||
for (int i = 0; i < substeps; i++)
|
|
||||||
{
|
|
||||||
stepSimulation(objs, stepDelta);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec2 computeForce(GameObject &fromObj, GameObject &toObj) const
|
|
||||||
{
|
|
||||||
auto offset = fromObj.m_transform2d.translation - toObj.m_transform2d.translation;
|
|
||||||
float distanceSquared = glm::dot(offset, offset);
|
|
||||||
|
|
||||||
if (glm::abs(distanceSquared < 1e-10f))
|
|
||||||
{
|
|
||||||
return {.0f, .0f};
|
|
||||||
}
|
|
||||||
float force = m_strengthGravity * toObj.m_rigidBody2d.mass * fromObj.m_rigidBody2d.mass / distanceSquared;
|
|
||||||
|
|
||||||
return force * offset / glm::sqrt(distanceSquared);
|
|
||||||
}
|
|
||||||
|
|
||||||
const float m_strengthGravity;
|
|
||||||
private:
|
|
||||||
void stepSimulation(std::vector<GameObject> &physicsObjs, float dt)
|
|
||||||
{
|
|
||||||
// Loops throught all pairs of objects and applies attractive force between them
|
|
||||||
for (auto iterA = physicsObjs.begin(); iterA != physicsObjs.end(); ++iterA)
|
|
||||||
{
|
|
||||||
auto &objA = *iterA;
|
|
||||||
for (auto iterB = iterA; iterB != physicsObjs.end(); ++iterB)
|
|
||||||
{
|
|
||||||
if (iterA == iterB) continue;
|
|
||||||
|
|
||||||
auto &objB = *iterB;
|
|
||||||
auto force = computeForce(objA, objB);
|
|
||||||
objA.m_rigidBody2d.velocity += dt * -force / objA.m_rigidBody2d.mass;
|
|
||||||
objB.m_rigidBody2d.velocity += dt * force / objB.m_rigidBody2d.mass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update each objects position based on its final velocity
|
|
||||||
for (auto &obj : physicsObjs)
|
|
||||||
{
|
|
||||||
obj.m_transform2d.translation += dt * obj.m_rigidBody2d.velocity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Vec2FieldSystem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void update(const GravityPhysicsSystem &physicsSystem, std::vector<GameObject> &physicsObjs, std::vector<GameObject> &vectorField)
|
|
||||||
{
|
|
||||||
for (auto &vf : vectorField)
|
|
||||||
{
|
|
||||||
glm::vec2 direction{};
|
|
||||||
for (auto &obj : physicsObjs)
|
|
||||||
{
|
|
||||||
direction += physicsSystem.computeForce(obj, vf);
|
|
||||||
}
|
|
||||||
|
|
||||||
vf.m_transform2d.scale.x = 0.005f + 0.045f * glm::clamp(glm::log(glm::length(direction) + 1) / 3.f, 0.f, 1.f);
|
|
||||||
vf.m_transform2d.rotation = atan2(direction.y, direction.x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<Model> createSquareModel(Device &device, glm::vec2 offset)
|
|
||||||
{
|
|
||||||
std::vector<Model::Vertex> vertices = {
|
|
||||||
{{-0.5f, -0.5f}}, {{0.5f, 0.5f}},
|
|
||||||
{{-0.5f, 0.5f}}, {{-0.5f, -0.5f}},
|
|
||||||
{{0.5f, -0.5f}}, {{0.5f, 0.5f}},
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto &v : vertices)
|
|
||||||
{
|
|
||||||
v.posision += offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_unique<Model>(device, vertices);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<Model> createCircleModel(Device &device, unsigned int numSides)
|
|
||||||
{
|
|
||||||
std::vector<Model::Vertex> uniqueVertices{};
|
|
||||||
for(int i = 0; i < numSides; i++)
|
|
||||||
{
|
|
||||||
float angle = i * glm::two_pi<float>() / numSides;
|
|
||||||
uniqueVertices.push_back({{glm::cos(angle), glm::sin(angle)}});
|
|
||||||
}
|
|
||||||
|
|
||||||
uniqueVertices.push_back({});
|
|
||||||
|
|
||||||
std::vector<Model::Vertex> vertices{};
|
|
||||||
for(int i = 0; i < numSides; i++)
|
|
||||||
{
|
|
||||||
vertices.push_back(uniqueVertices[i]);
|
|
||||||
vertices.push_back(uniqueVertices[(i+1) % numSides]);
|
|
||||||
vertices.push_back(uniqueVertices[numSides]);
|
|
||||||
}
|
|
||||||
return std::make_unique<Model>(device, vertices);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
#include "hk_camera.hpp"
|
||||||
|
|
||||||
|
namespace hk
|
||||||
|
{
|
||||||
|
void Camera::setOrthographicProjection(float left, float right, float top, float bottom, float near, float far)
|
||||||
|
{
|
||||||
|
m_projectionMatrix = glm::mat4{1.0f};
|
||||||
|
m_projectionMatrix[0][0] = 2.f / (right - left);
|
||||||
|
m_projectionMatrix[1][1] = 2.f / (bottom - top);
|
||||||
|
m_projectionMatrix[2][2] = 1.f / (far - near);
|
||||||
|
m_projectionMatrix[3][0] = -(right + left) / (right - left);
|
||||||
|
m_projectionMatrix[3][1] = -(bottom + top) / (bottom - top);
|
||||||
|
m_projectionMatrix[3][2] = -near / (far - near);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::setPerspectiveProjection(float fovY, float aspect, float near, float far)
|
||||||
|
{
|
||||||
|
assert(glm::abs(aspect - std::numeric_limits<float>::epsilon()) > 0.0f);
|
||||||
|
const float tanHalfFovy = tan(fovY / 2.f);
|
||||||
|
m_projectionMatrix = glm::mat4{0.0f};
|
||||||
|
m_projectionMatrix[0][0] = 1.f / (aspect * tanHalfFovy);
|
||||||
|
m_projectionMatrix[1][1] = 1.f / (tanHalfFovy);
|
||||||
|
m_projectionMatrix[2][2] = far / (far - near);
|
||||||
|
m_projectionMatrix[2][3] = 1.f;
|
||||||
|
m_projectionMatrix[3][2] = -(far * near) / (far - near);
|
||||||
|
}
|
||||||
|
void Camera::setViewDirection(glm::vec3 position, glm::vec3 direction, glm::vec3 up)
|
||||||
|
{
|
||||||
|
const glm::vec3 w = glm::normalize(direction);
|
||||||
|
const glm::vec3 u = glm::normalize(glm::cross(w, up));
|
||||||
|
const glm::vec3 v = glm::cross(w, u);
|
||||||
|
|
||||||
|
m_viewMatrix = glm::mat4{1.0f};
|
||||||
|
m_viewMatrix[0][0] = u.x;
|
||||||
|
m_viewMatrix[1][0] = u.y;
|
||||||
|
m_viewMatrix[2][0] = u.z;
|
||||||
|
m_viewMatrix[0][1] = v.x;
|
||||||
|
m_viewMatrix[1][1] = v.y;
|
||||||
|
m_viewMatrix[2][1] = v.z;
|
||||||
|
m_viewMatrix[0][2] = w.x;
|
||||||
|
m_viewMatrix[1][2] = w.y;
|
||||||
|
m_viewMatrix[2][2] = w.z;
|
||||||
|
m_viewMatrix[3][0] = -glm::dot(u, position);
|
||||||
|
m_viewMatrix[3][1] = -glm::dot(v, position);
|
||||||
|
m_viewMatrix[3][2] = -glm::dot(w, position);
|
||||||
|
|
||||||
|
m_inverseViewMatrix = glm::mat4{1.0f};
|
||||||
|
m_inverseViewMatrix[0][0] = u.x;
|
||||||
|
m_inverseViewMatrix[0][1] = u.y;
|
||||||
|
m_inverseViewMatrix[0][2] = u.z;
|
||||||
|
m_inverseViewMatrix[1][0] = v.x;
|
||||||
|
m_inverseViewMatrix[1][1] = v.y;
|
||||||
|
m_inverseViewMatrix[1][2] = v.z;
|
||||||
|
m_inverseViewMatrix[2][0] = w.x;
|
||||||
|
m_inverseViewMatrix[2][1] = w.y;
|
||||||
|
m_inverseViewMatrix[2][2] = w.z;
|
||||||
|
m_inverseViewMatrix[3][0] = position.x;
|
||||||
|
m_inverseViewMatrix[3][1] = position.y;
|
||||||
|
m_inverseViewMatrix[3][2] = position.z;
|
||||||
|
}
|
||||||
|
void Camera::setViewTarget(glm::vec3 position, glm::vec3 target, glm::vec3 up)
|
||||||
|
{
|
||||||
|
setViewDirection(position, target - position, up);
|
||||||
|
}
|
||||||
|
void Camera::setViewYXZ(glm::vec3 position, glm::vec3 rotation)
|
||||||
|
{
|
||||||
|
const float c3 = glm::cos(rotation.z);
|
||||||
|
const float s3 = glm::sin(rotation.z);
|
||||||
|
const float c2 = glm::cos(rotation.x);
|
||||||
|
const float s2 = glm::sin(rotation.x);
|
||||||
|
const float c1 = glm::cos(rotation.y);
|
||||||
|
const float s1 = glm::sin(rotation.y);
|
||||||
|
const glm::vec3 u{(c1 * c3 + s1 * s2 * s3), (c2 * s3), (c1 * s2 * s3 - c3 * s1)};
|
||||||
|
const glm::vec3 v{(c3 * s1 * s2 - c1 * s3), (c2 * c3), (c1 * c3 * s2 + s1 * s3)};
|
||||||
|
const glm::vec3 w{(c2 * s1), (-s2), (c1 * c2)};
|
||||||
|
|
||||||
|
m_viewMatrix = glm::mat4{1.0f};
|
||||||
|
m_viewMatrix[0][0] = u.x;
|
||||||
|
m_viewMatrix[1][0] = u.y;
|
||||||
|
m_viewMatrix[2][0] = u.z;
|
||||||
|
m_viewMatrix[0][1] = v.x;
|
||||||
|
m_viewMatrix[1][1] = v.y;
|
||||||
|
m_viewMatrix[2][1] = v.z;
|
||||||
|
m_viewMatrix[0][2] = w.x;
|
||||||
|
m_viewMatrix[1][2] = w.y;
|
||||||
|
m_viewMatrix[2][2] = w.z;
|
||||||
|
m_viewMatrix[3][0] = -glm::dot(u, position);
|
||||||
|
m_viewMatrix[3][1] = -glm::dot(v, position);
|
||||||
|
m_viewMatrix[3][2] = -glm::dot(w, position);
|
||||||
|
|
||||||
|
m_inverseViewMatrix = glm::mat4{1.0f};
|
||||||
|
m_inverseViewMatrix[0][0] = u.x;
|
||||||
|
m_inverseViewMatrix[0][1] = u.y;
|
||||||
|
m_inverseViewMatrix[0][2] = u.z;
|
||||||
|
m_inverseViewMatrix[1][0] = v.x;
|
||||||
|
m_inverseViewMatrix[1][1] = v.y;
|
||||||
|
m_inverseViewMatrix[1][2] = v.z;
|
||||||
|
m_inverseViewMatrix[2][0] = w.x;
|
||||||
|
m_inverseViewMatrix[2][1] = w.y;
|
||||||
|
m_inverseViewMatrix[2][2] = w.z;
|
||||||
|
m_inverseViewMatrix[3][0] = position.x;
|
||||||
|
m_inverseViewMatrix[3][1] = position.y;
|
||||||
|
m_inverseViewMatrix[3][2] = position.z;
|
||||||
|
}
|
||||||
|
} // namespace hk
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// libs
|
||||||
|
#define GLM_FORCE_RADIANS
|
||||||
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
namespace hk
|
||||||
|
{
|
||||||
|
class Camera
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Camera() = default;
|
||||||
|
~Camera() = default;
|
||||||
|
|
||||||
|
void setOrthographicProjection(float left, float right, float top, float bottom, float near, float far);
|
||||||
|
void setPerspectiveProjection(float fovY, float aspect, float near, float far);
|
||||||
|
|
||||||
|
void setViewDirection(glm::vec3 position, glm::vec3 direction, glm::vec3 up = glm::vec3{0.f, -1.f, 0.f});
|
||||||
|
void setViewTarget(glm::vec3 position, glm::vec3 target, glm::vec3 up = glm::vec3{0.f, -1.f, 0.f});
|
||||||
|
void setViewYXZ(glm::vec3 position, glm::vec3 rotation);
|
||||||
|
|
||||||
|
const glm::mat4& getProjection() const { return m_projectionMatrix; }
|
||||||
|
const glm::mat4& getView() const { return m_viewMatrix; }
|
||||||
|
const glm::mat4& getInverseView() const { return m_inverseViewMatrix; }
|
||||||
|
private:
|
||||||
|
glm::mat4 m_projectionMatrix{1.0f};
|
||||||
|
glm::mat4 m_viewMatrix{1.0f};
|
||||||
|
glm::mat4 m_inverseViewMatrix{1.0f};
|
||||||
|
};
|
||||||
|
} // namespace hk
|
||||||
|
|
@ -2,29 +2,51 @@
|
||||||
|
|
||||||
#include "hk_model.hpp"
|
#include "hk_model.hpp"
|
||||||
|
|
||||||
|
// libs
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
// std
|
// std
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace hk
|
namespace hk
|
||||||
{
|
{
|
||||||
struct Transform2dComponent
|
struct TransformComponent
|
||||||
{
|
{
|
||||||
glm::vec2 translation{};
|
glm::vec3 translation{};
|
||||||
glm::vec2 scale{1.0f, 1.0f};
|
glm::vec3 scale{1.0f, 1.0f, 1.0f};
|
||||||
float rotation;
|
glm::vec3 rotation{};
|
||||||
glm::mat2 mat2()
|
|
||||||
|
// Matrix corrsponds to Translate * Ry * Rx * Rz * Scale
|
||||||
|
// Rotations correspond to Tait-bryan angles of Y(1), X(2), Z(3)
|
||||||
|
// https://en.wikipedia.org/wiki/Euler_angles#Rotation_matrix
|
||||||
|
glm::mat4 mat4()
|
||||||
{
|
{
|
||||||
const float cos = glm::cos(rotation);
|
const float c3 = glm::cos(rotation.z);
|
||||||
const float sin = glm::sin(rotation);
|
const float s3 = glm::sin(rotation.z);
|
||||||
glm::mat2 rotationMat{
|
const float c2 = glm::cos(rotation.x);
|
||||||
{cos, sin},
|
const float s2 = glm::sin(rotation.x);
|
||||||
{-sin, cos}};
|
const float c1 = glm::cos(rotation.y);
|
||||||
|
const float s1 = glm::sin(rotation.y);
|
||||||
glm::mat2 scaleMat{
|
return glm::mat4{
|
||||||
{scale.x, .0f},
|
{
|
||||||
{.0f, scale.y}};
|
scale.x * (c1 * c3 + s1 * s2 * s3),
|
||||||
|
scale.x * (c2 * s3),
|
||||||
return rotationMat * scaleMat;
|
scale.x * (c1 * s2 * s3 - c3 * s1),
|
||||||
|
0.0f,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scale.y * (c3 * s1 * s2 - c1 * s3),
|
||||||
|
scale.y * (c2 * c3),
|
||||||
|
scale.y * (c1 * c3 * s2 + s1 * s3),
|
||||||
|
0.0f,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scale.z * (c2 * s1),
|
||||||
|
scale.z * (-s2),
|
||||||
|
scale.z * (c1 * c2),
|
||||||
|
0.0f,
|
||||||
|
},
|
||||||
|
{translation.x, translation.y, translation.z, 1.0f}};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -55,7 +77,7 @@ namespace hk
|
||||||
|
|
||||||
std::shared_ptr<Model> m_model{};
|
std::shared_ptr<Model> m_model{};
|
||||||
glm::vec3 m_color{};
|
glm::vec3 m_color{};
|
||||||
Transform2dComponent m_transform2d{};
|
TransformComponent m_transform{};
|
||||||
|
|
||||||
RigidBody2dComponent m_rigidBody2d{};
|
RigidBody2dComponent m_rigidBody2d{};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,8 +58,8 @@ namespace hk{
|
||||||
std::vector<VkVertexInputAttributeDescription> attributeDescriptions(2);
|
std::vector<VkVertexInputAttributeDescription> attributeDescriptions(2);
|
||||||
attributeDescriptions[0].binding = 0;
|
attributeDescriptions[0].binding = 0;
|
||||||
attributeDescriptions[0].location = 0;
|
attributeDescriptions[0].location = 0;
|
||||||
attributeDescriptions[0].format = VK_FORMAT_R32G32_SFLOAT;
|
attributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
attributeDescriptions[0].offset = offsetof(Vertex, posision);
|
attributeDescriptions[0].offset = offsetof(Vertex, position);
|
||||||
|
|
||||||
attributeDescriptions[1].binding = 0;
|
attributeDescriptions[1].binding = 0;
|
||||||
attributeDescriptions[1].location = 1;
|
attributeDescriptions[1].location = 1;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace hk{
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct Vertex {
|
struct Vertex {
|
||||||
glm::vec2 posision;
|
glm::vec3 position;
|
||||||
glm::vec3 color;
|
glm::vec3 color;
|
||||||
|
|
||||||
static std::vector<VkVertexInputBindingDescription> getBindingDescriptions();
|
static std::vector<VkVertexInputBindingDescription> getBindingDescriptions();
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
namespace hk
|
namespace hk
|
||||||
{
|
{
|
||||||
Renderer::Renderer(Window &window, Device &device) : m_window{window}, m_device{device}
|
Renderer::Renderer(Window &window, Device &device) : m_window{window}, m_device{device}, m_currentFrameIndex{0}, m_isFrameStarted{false}
|
||||||
{
|
{
|
||||||
recreateSwapChain();
|
recreateSwapChain();
|
||||||
createCommandBuffers();
|
createCommandBuffers();
|
||||||
|
|
@ -45,8 +45,9 @@ namespace hk
|
||||||
throw std::runtime_error("Swap chain image(or depth) format has changed!");
|
throw std::runtime_error("Swap chain image(or depth) format has changed!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: we'll come back to this in just a moment
|
// Reset currentFrameIndex when recreating swapchain
|
||||||
|
m_currentFrameIndex = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,8 +121,7 @@ namespace hk
|
||||||
m_window.resetWindowResizedFlag();
|
m_window.resetWindowResizedFlag();
|
||||||
recreateSwapChain();
|
recreateSwapChain();
|
||||||
}
|
}
|
||||||
|
else if (result != VK_SUCCESS)
|
||||||
if (result != VK_SUCCESS)
|
|
||||||
{
|
{
|
||||||
throw std::runtime_error("failed to present swap chain image!");
|
throw std::runtime_error("failed to present swap chain image!");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ namespace hk
|
||||||
Renderer &operator=(const Renderer &) = delete;
|
Renderer &operator=(const Renderer &) = delete;
|
||||||
|
|
||||||
VkRenderPass getSwapChainRenderPass() const { return m_swapChain->getRenderPass(); }
|
VkRenderPass getSwapChainRenderPass() const { return m_swapChain->getRenderPass(); }
|
||||||
|
float getAspectRatio() const { return m_swapChain->extentAspectRatio(); }
|
||||||
bool isFrameInProgress() const {return m_isFrameStarted;}
|
bool isFrameInProgress() const {return m_isFrameStarted;}
|
||||||
VkCommandBuffer getCurrentCommandBuffer() const {
|
VkCommandBuffer getCurrentCommandBuffer() const {
|
||||||
assert(m_isFrameStarted && "Cannot get command buffer when frame not in progress");
|
assert(m_isFrameStarted && "Cannot get command buffer when frame not in progress");
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ namespace hk
|
||||||
: device{deviceRef}, windowExtent{extent}, oldSwapChain{previous}
|
: device{deviceRef}, windowExtent{extent}, oldSwapChain{previous}
|
||||||
{
|
{
|
||||||
init();
|
init();
|
||||||
|
// Reset currentFrame to 0 when creating a new swap chain
|
||||||
|
currentFrame = 0;
|
||||||
|
|
||||||
// clean up old swap chain
|
// clean up old swap chain
|
||||||
oldSwapChain = nullptr;
|
oldSwapChain = nullptr;
|
||||||
|
|
@ -65,10 +67,13 @@ namespace hk
|
||||||
vkDestroyRenderPass(device.device(), renderPass, nullptr);
|
vkDestroyRenderPass(device.device(), renderPass, nullptr);
|
||||||
|
|
||||||
// cleanup synchronization objects
|
// cleanup synchronization objects
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
for (size_t i = 0; i < imageAvailableSemaphores.size(); i++)
|
||||||
{
|
{
|
||||||
vkDestroySemaphore(device.device(), renderFinishedSemaphores[i], nullptr);
|
vkDestroySemaphore(device.device(), renderFinishedSemaphores[i], nullptr);
|
||||||
vkDestroySemaphore(device.device(), imageAvailableSemaphores[i], nullptr);
|
vkDestroySemaphore(device.device(), imageAvailableSemaphores[i], nullptr);
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||||
|
{
|
||||||
vkDestroyFence(device.device(), inFlightFences[i], nullptr);
|
vkDestroyFence(device.device(), inFlightFences[i], nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -82,11 +87,12 @@ namespace hk
|
||||||
VK_TRUE,
|
VK_TRUE,
|
||||||
std::numeric_limits<uint64_t>::max());
|
std::numeric_limits<uint64_t>::max());
|
||||||
|
|
||||||
|
// Acquire with a temporary semaphore, we'll use the imageIndex-specific one later
|
||||||
VkResult result = vkAcquireNextImageKHR(
|
VkResult result = vkAcquireNextImageKHR(
|
||||||
device.device(),
|
device.device(),
|
||||||
swapChain,
|
swapChain,
|
||||||
std::numeric_limits<uint64_t>::max(),
|
std::numeric_limits<uint64_t>::max(),
|
||||||
imageAvailableSemaphores[currentFrame], // must be a not signaled semaphore
|
imageAvailableSemaphores[currentFrame % imageAvailableSemaphores.size()],
|
||||||
VK_NULL_HANDLE,
|
VK_NULL_HANDLE,
|
||||||
imageIndex);
|
imageIndex);
|
||||||
|
|
||||||
|
|
@ -105,7 +111,8 @@ namespace hk
|
||||||
VkSubmitInfo submitInfo = {};
|
VkSubmitInfo submitInfo = {};
|
||||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
|
||||||
VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
|
// Use the semaphore associated with the currentFrame for waiting (from acquireNextImage)
|
||||||
|
VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame % imageAvailableSemaphores.size()]};
|
||||||
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
|
||||||
submitInfo.waitSemaphoreCount = 1;
|
submitInfo.waitSemaphoreCount = 1;
|
||||||
submitInfo.pWaitSemaphores = waitSemaphores;
|
submitInfo.pWaitSemaphores = waitSemaphores;
|
||||||
|
|
@ -114,7 +121,8 @@ namespace hk
|
||||||
submitInfo.commandBufferCount = 1;
|
submitInfo.commandBufferCount = 1;
|
||||||
submitInfo.pCommandBuffers = buffers;
|
submitInfo.pCommandBuffers = buffers;
|
||||||
|
|
||||||
VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
|
// Use the semaphore associated with this specific image for signaling
|
||||||
|
VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[*imageIndex]};
|
||||||
submitInfo.signalSemaphoreCount = 1;
|
submitInfo.signalSemaphoreCount = 1;
|
||||||
submitInfo.pSignalSemaphores = signalSemaphores;
|
submitInfo.pSignalSemaphores = signalSemaphores;
|
||||||
|
|
||||||
|
|
@ -380,8 +388,9 @@ namespace hk
|
||||||
|
|
||||||
void SwapChain::createSyncObjects()
|
void SwapChain::createSyncObjects()
|
||||||
{
|
{
|
||||||
imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
// Create one set of semaphores for each swapchain image
|
||||||
renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
|
imageAvailableSemaphores.resize(imageCount());
|
||||||
|
renderFinishedSemaphores.resize(imageCount());
|
||||||
inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
|
inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
|
||||||
imagesInFlight.resize(imageCount(), VK_NULL_HANDLE);
|
imagesInFlight.resize(imageCount(), VK_NULL_HANDLE);
|
||||||
|
|
||||||
|
|
@ -392,13 +401,20 @@ namespace hk
|
||||||
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||||
|
|
||||||
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
for (size_t i = 0; i < imageCount(); i++)
|
||||||
{
|
{
|
||||||
if (vkCreateSemaphore(device.device(), &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) !=
|
if (vkCreateSemaphore(device.device(), &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) !=
|
||||||
VK_SUCCESS ||
|
VK_SUCCESS ||
|
||||||
vkCreateSemaphore(device.device(), &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) !=
|
vkCreateSemaphore(device.device(), &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) !=
|
||||||
VK_SUCCESS ||
|
VK_SUCCESS)
|
||||||
vkCreateFence(device.device(), &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS)
|
{
|
||||||
|
throw std::runtime_error("failed to create synchronization objects for a frame!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
|
||||||
|
{
|
||||||
|
if (vkCreateFence(device.device(), &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS)
|
||||||
{
|
{
|
||||||
throw std::runtime_error("failed to create synchronization objects for a frame!");
|
throw std::runtime_error("failed to create synchronization objects for a frame!");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ namespace hk
|
||||||
Window(const Window&) = delete;
|
Window(const Window&) = delete;
|
||||||
Window &operator=(const Window&) = delete;
|
Window &operator=(const Window&) = delete;
|
||||||
|
|
||||||
|
GLFWwindow* getWindow() { return m_window; }
|
||||||
|
|
||||||
bool shouldClose() { return glfwWindowShouldClose(m_window); }
|
bool shouldClose() { return glfwWindowShouldClose(m_window); }
|
||||||
VkExtent2D getExtend() { return {static_cast<uint32_t>(m_width), static_cast<uint32_t>(m_height)}; }
|
VkExtent2D getExtend() { return {static_cast<uint32_t>(m_width), static_cast<uint32_t>(m_height)}; }
|
||||||
bool wasWindowResized() { return m_framebufferResized; }
|
bool wasWindowResized() { return m_framebufferResized; }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include "keyboard_movement_controller.hpp"
|
||||||
|
|
||||||
|
namespace hk
|
||||||
|
{
|
||||||
|
void KeyboardMovementController::moveInPlaneXZ(GLFWwindow *window, float dt, GameObject &gameObject)
|
||||||
|
{
|
||||||
|
glm::vec3 rotate{0};
|
||||||
|
if (glfwGetKey(window, m_keys.lookRight) == GLFW_PRESS) rotate.y += 1.f;
|
||||||
|
if (glfwGetKey(window, m_keys.lookLeft) == GLFW_PRESS) rotate.y -= 1.f;
|
||||||
|
if (glfwGetKey(window, m_keys.lookUp) == GLFW_PRESS) rotate.x += 1.f;
|
||||||
|
if (glfwGetKey(window, m_keys.lookDown) == GLFW_PRESS) rotate.x -= 1.f;
|
||||||
|
|
||||||
|
if (glm::dot(rotate, rotate) > std::numeric_limits<float>::epsilon())
|
||||||
|
{
|
||||||
|
gameObject.m_transform.rotation += m_lookSpeed * dt * glm::normalize(rotate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// limit pitch values between about +/-85ish degrees
|
||||||
|
gameObject.m_transform.rotation.x = glm::clamp(gameObject.m_transform.rotation.x, -1.5f, 1.5f);
|
||||||
|
gameObject.m_transform.rotation.y = glm::mod(gameObject.m_transform.rotation.y, glm::two_pi<float>());
|
||||||
|
|
||||||
|
|
||||||
|
float yaw = gameObject.m_transform.rotation.y;
|
||||||
|
const glm::vec3 forwardDir{sin(yaw), 0.f, cos(yaw)};
|
||||||
|
const glm::vec3 rightDir{forwardDir.z, 0.f, -forwardDir.x};
|
||||||
|
const glm::vec3 upDir{0.f, -1.f, 0.f};
|
||||||
|
|
||||||
|
glm::vec3 moveDir{0.f};
|
||||||
|
if (glfwGetKey(window, m_keys.moveForward) == GLFW_PRESS) moveDir += forwardDir;
|
||||||
|
if (glfwGetKey(window, m_keys.moveBackward) == GLFW_PRESS) moveDir -= forwardDir;
|
||||||
|
if (glfwGetKey(window, m_keys.moveRight) == GLFW_PRESS) moveDir += rightDir;
|
||||||
|
if (glfwGetKey(window, m_keys.moveLeft) == GLFW_PRESS) moveDir -= rightDir;
|
||||||
|
if (glfwGetKey(window, m_keys.moveUp) == GLFW_PRESS) moveDir += upDir;
|
||||||
|
if (glfwGetKey(window, m_keys.moveDown) == GLFW_PRESS) moveDir -= upDir;
|
||||||
|
|
||||||
|
if (glm::dot(moveDir, moveDir) > std::numeric_limits<float>::epsilon())
|
||||||
|
{
|
||||||
|
gameObject.m_transform.translation += m_moveSpeed * dt * glm::normalize(moveDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hk_game_object.hpp>
|
||||||
|
#include <hk_window.hpp>
|
||||||
|
|
||||||
|
namespace hk
|
||||||
|
{
|
||||||
|
class KeyboardMovementController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct KeyMappings
|
||||||
|
{
|
||||||
|
int moveLeft{ GLFW_KEY_A };
|
||||||
|
int moveRight{ GLFW_KEY_D };
|
||||||
|
int moveForward{ GLFW_KEY_W };
|
||||||
|
int moveBackward{ GLFW_KEY_S };
|
||||||
|
int moveUp{ GLFW_KEY_E };
|
||||||
|
int moveDown{ GLFW_KEY_Q };
|
||||||
|
int lookLeft{ GLFW_KEY_LEFT };
|
||||||
|
int lookRight{ GLFW_KEY_RIGHT };
|
||||||
|
int lookUp{ GLFW_KEY_UP };
|
||||||
|
int lookDown{ GLFW_KEY_DOWN };
|
||||||
|
};
|
||||||
|
|
||||||
|
void moveInPlaneXZ(GLFWwindow *window, float dt, GameObject &gameObject);
|
||||||
|
|
||||||
|
KeyMappings m_keys{};
|
||||||
|
float m_moveSpeed{ 3.f };
|
||||||
|
float m_lookSpeed{ 1.5f };
|
||||||
|
};
|
||||||
|
}
|
||||||
6
main.cpp
6
main.cpp
|
|
@ -5,19 +5,13 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#define GRAVITY_SYSTEM 1
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
hk::FirstApp app{};
|
hk::FirstApp app{};
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if GRAVITY_SYSTEM == 1
|
|
||||||
app.runGravitySystem();
|
|
||||||
#else
|
|
||||||
app.run();
|
app.run();
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
catch(const std::exception& e)
|
catch(const std::exception& e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
|
layout (location = 0) in vec3 fragColor;
|
||||||
layout (location = 0) out vec4 outColor;
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
layout(push_constant) uniform Push{
|
layout(push_constant) uniform Push{
|
||||||
mat2 transform;
|
mat4 transform;
|
||||||
vec2 offset;
|
|
||||||
vec3 color;
|
vec3 color;
|
||||||
} push;
|
} push;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
outColor = vec4(push.color, 1.0);
|
outColor = vec4(fragColor, 1.0);
|
||||||
}
|
}
|
||||||
Binary file not shown.
|
|
@ -1,14 +1,16 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
layout(location = 0) in vec2 position;
|
layout(location = 0) in vec3 position;
|
||||||
layout(location = 1) in vec3 color;
|
layout(location = 1) in vec3 color;
|
||||||
|
|
||||||
|
layout(location = 0) out vec3 fragColor;
|
||||||
|
|
||||||
layout(push_constant) uniform Push{
|
layout(push_constant) uniform Push{
|
||||||
mat2 transform;
|
mat4 transform;
|
||||||
vec2 offset;
|
|
||||||
vec3 color;
|
vec3 color;
|
||||||
} push;
|
} push;
|
||||||
|
|
||||||
void main(){
|
void main(){
|
||||||
gl_Position = vec4(push.transform * position + push.offset, 0.0, 1.0);
|
gl_Position = push.transform * vec4(position, 1.0);
|
||||||
|
fragColor = color;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -14,8 +14,7 @@ namespace hk
|
||||||
{
|
{
|
||||||
struct SimplePushConstantData
|
struct SimplePushConstantData
|
||||||
{
|
{
|
||||||
glm::mat2 transform{1.0f};
|
glm::mat4 transform{1.0f};
|
||||||
glm::vec2 offset;
|
|
||||||
alignas(16) glm::vec3 color;
|
alignas(16) glm::vec3 color;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -67,17 +66,17 @@ namespace hk
|
||||||
pipelineConfig);
|
pipelineConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SimpleRenderSystem::renderGameObjects(VkCommandBuffer commandBuffer, std::vector<GameObject> &gameObjects)
|
void SimpleRenderSystem::renderGameObjects(VkCommandBuffer commandBuffer, std::vector<GameObject> &gameObjects, const Camera &camera)
|
||||||
{
|
{
|
||||||
m_pipeline->bind(commandBuffer);
|
m_pipeline->bind(commandBuffer);
|
||||||
|
|
||||||
|
auto projectionView = camera.getProjection() * camera.getInverseView();
|
||||||
|
|
||||||
for (auto &obj : gameObjects)
|
for (auto &obj : gameObjects)
|
||||||
{
|
{
|
||||||
obj.m_transform2d.rotation = glm::mod(obj.m_transform2d.rotation + 0.01f, glm::two_pi<float>());
|
|
||||||
|
|
||||||
SimplePushConstantData push{};
|
SimplePushConstantData push{};
|
||||||
push.offset = obj.m_transform2d.translation;
|
|
||||||
push.color = obj.m_color;
|
push.color = obj.m_color;
|
||||||
push.transform = obj.m_transform2d.mat2();
|
push.transform = projectionView * obj.m_transform.mat4();
|
||||||
|
|
||||||
vkCmdPushConstants(
|
vkCmdPushConstants(
|
||||||
commandBuffer,
|
commandBuffer,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "hk_camera.hpp"
|
||||||
#include "hk_device.hpp"
|
#include "hk_device.hpp"
|
||||||
#include "hk_game_object.hpp"
|
#include "hk_game_object.hpp"
|
||||||
#include "hk_pipeline.hpp"
|
#include "hk_pipeline.hpp"
|
||||||
|
|
@ -20,7 +21,7 @@ namespace hk
|
||||||
SimpleRenderSystem(const SimpleRenderSystem &) = delete;
|
SimpleRenderSystem(const SimpleRenderSystem &) = delete;
|
||||||
SimpleRenderSystem &operator=(const SimpleRenderSystem &) = delete;
|
SimpleRenderSystem &operator=(const SimpleRenderSystem &) = delete;
|
||||||
|
|
||||||
void renderGameObjects(VkCommandBuffer commandBuffer, std::vector<GameObject> &gameObjects);
|
void renderGameObjects(VkCommandBuffer commandBuffer, std::vector<GameObject> &gameObjects, const Camera &camera);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createPipelineLayout();
|
void createPipelineLayout();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue