Gjk, FPS view.
This commit is contained in:
141
src/Simplex.cpp
Normal file
141
src/Simplex.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
|
||||
#include <Simplex.h>
|
||||
|
||||
|
||||
Vector3 polyhedron_support(Vector3AV polyhedron, const Vector3& direction) {
|
||||
assert(polyhedron.size() > 0);
|
||||
|
||||
Index best = 0;
|
||||
Real best_dot = polyhedron[0].dot(direction);
|
||||
|
||||
for (Index index = 1; index < polyhedron.size(); index += 1) {
|
||||
Real dot = polyhedron[index].dot(direction);
|
||||
if (dot > best_dot) {
|
||||
best = index;
|
||||
best_dot = dot;
|
||||
}
|
||||
}
|
||||
|
||||
return polyhedron[best];
|
||||
}
|
||||
|
||||
|
||||
Simplex::Simplex() = default;
|
||||
Simplex::Simplex(const Vector3& point)
|
||||
: m_points{ point, Vector3{}, Vector3{}, Vector3{} }
|
||||
, m_point_count(1)
|
||||
{}
|
||||
|
||||
|
||||
Gjk::Gjk(Vector3AV polyhedron0, Vector3AV polyhedron1, const Vector3& direction)
|
||||
: m_polyhedron0(polyhedron0)
|
||||
, m_polyhedron1(polyhedron1)
|
||||
, m_direction(direction)
|
||||
{}
|
||||
|
||||
Gjk::~Gjk() = default;
|
||||
|
||||
const Vector3& Gjk::direction() const {
|
||||
return m_direction;
|
||||
}
|
||||
|
||||
bool Gjk::operator()() {
|
||||
while (true) {
|
||||
m_simplex.push(support(m_direction));
|
||||
|
||||
if (m_simplex.last().dot(m_direction) < Real(0))
|
||||
return false;
|
||||
|
||||
if (nextSimplex())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Gjk::nextSimplex() {
|
||||
switch(m_simplex.point_count()) {
|
||||
case 1: return nextFromPoint();
|
||||
case 2: return nextFromLine();
|
||||
case 3: return nextFromTriangle();
|
||||
case 4: return nextFromTetrahedron();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Gjk::nextFromPoint() {
|
||||
m_direction = -m_simplex.last();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Gjk::nextFromLine() {
|
||||
Vector3 v01 = m_simplex.point(1) - m_simplex.point(0);
|
||||
Vector3 v1o = -m_simplex.point(1);
|
||||
|
||||
m_direction = v01.cross(v1o).cross(v01);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Gjk::nextFromTriangle() {
|
||||
Vector3 v20 = m_simplex.point(0) - m_simplex.point(2);
|
||||
Vector3 v21 = m_simplex.point(1) - m_simplex.point(2);
|
||||
Vector3 v2o = -m_simplex.point(2);
|
||||
|
||||
Vector3 n = v20.cross(v21);
|
||||
Vector3 n0 = n.cross(v21);
|
||||
Vector3 n1 = v20.cross(n);
|
||||
|
||||
if(n0.dot(v2o) > Real(0)) {
|
||||
m_simplex.pop(0);
|
||||
m_direction = n0;
|
||||
}
|
||||
else if(n1.dot(v2o) > Real(0)) {
|
||||
m_simplex.pop(1);
|
||||
m_direction = n1;
|
||||
}
|
||||
else if(n.dot(v2o) > Real(0)) {
|
||||
m_direction = n;
|
||||
}
|
||||
else {
|
||||
m_simplex.swap(0, 1);
|
||||
m_direction = -n;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Gjk::nextFromTetrahedron() {
|
||||
Vector3 v30 = m_simplex.point(0) - m_simplex.point(3);
|
||||
Vector3 v31 = m_simplex.point(1) - m_simplex.point(3);
|
||||
Vector3 v32 = m_simplex.point(2) - m_simplex.point(3);
|
||||
Vector3 v3o = -m_simplex.point(3);
|
||||
|
||||
Vector3 n[3] = {
|
||||
v31.cross(v32),
|
||||
v32.cross(v30),
|
||||
v30.cross(v31),
|
||||
};
|
||||
|
||||
Real d[3] = {
|
||||
n[0].dot(v3o),
|
||||
n[1].dot(v3o),
|
||||
n[2].dot(v3o),
|
||||
};
|
||||
|
||||
Index best = (d[0] > d[1])? ((d[0] > d[2])? 0: 2):
|
||||
((d[1] > d[2])? 1: 2);
|
||||
|
||||
if(d[best] <= Real(0))
|
||||
return true;
|
||||
|
||||
m_simplex.pop(best);
|
||||
m_direction = n[best];
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3 Gjk::support(const Vector3& direction) const
|
||||
{
|
||||
return polyhedron_support(m_polyhedron0, direction)
|
||||
- polyhedron_support(m_polyhedron1, -direction);
|
||||
}
|
||||
75
src/Simplex.h
Normal file
75
src/Simplex.h
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include <core.h>
|
||||
|
||||
|
||||
class Simplex {
|
||||
public:
|
||||
Simplex();
|
||||
Simplex(const Vector3& point);
|
||||
|
||||
inline Index point_count() const {
|
||||
return m_point_count;
|
||||
}
|
||||
|
||||
inline const Vector3& point(Index index) const {
|
||||
assert(index < m_point_count);
|
||||
return m_points[index];
|
||||
}
|
||||
|
||||
inline const Vector3& last() const {
|
||||
assert(m_point_count > 0);
|
||||
return point(m_point_count - 1);
|
||||
}
|
||||
|
||||
inline void push(const Vector3& point) {
|
||||
assert(m_point_count < MaxPointCount);
|
||||
m_points[m_point_count] = point;
|
||||
m_point_count += 1;
|
||||
}
|
||||
|
||||
inline void pop(Index index) {
|
||||
assert(index < m_point_count);
|
||||
for(Index i = index; i + 1 < m_point_count; i += 1)
|
||||
m_points[i] = m_points[i + 1];
|
||||
m_point_count -= 1;
|
||||
}
|
||||
|
||||
inline void swap(Index index0, Index index1) {
|
||||
using std::swap;
|
||||
swap(m_points[index0], m_points[index1]);
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr Index MaxPointCount = 4;
|
||||
|
||||
private:
|
||||
Vector3 m_points[MaxPointCount];
|
||||
Index m_point_count = 0;
|
||||
};
|
||||
|
||||
|
||||
class Gjk {
|
||||
public:
|
||||
Gjk(Vector3AV polyhedron0, Vector3AV polyhedron1, const Vector3& direction=Vector3::UnitX());
|
||||
~Gjk();
|
||||
|
||||
const Vector3& direction() const;
|
||||
|
||||
bool operator()();
|
||||
|
||||
private:
|
||||
bool nextSimplex();
|
||||
bool nextFromPoint();
|
||||
bool nextFromLine();
|
||||
bool nextFromTriangle();
|
||||
bool nextFromTetrahedron();
|
||||
|
||||
Vector3 support(const Vector3& direction) const;
|
||||
|
||||
private:
|
||||
Vector3AV m_polyhedron0;
|
||||
Vector3AV m_polyhedron1;
|
||||
Simplex m_simplex;
|
||||
Vector3 m_direction;
|
||||
};
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
|
||||
|
||||
void SdlWindowDeleter::operator()(SDL_Window* window) const {
|
||||
@@ -25,7 +26,7 @@ void VkExpe::initialize() {
|
||||
auto const window = SDL_CreateWindow(
|
||||
"vk_expe",
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
800, 600,
|
||||
1920, 1080,
|
||||
SDL_WINDOW_VULKAN
|
||||
| SDL_WINDOW_ALLOW_HIGHDPI
|
||||
| SDL_WINDOW_SHOWN
|
||||
@@ -60,6 +61,8 @@ void VkExpe::run() {
|
||||
m_running = false;
|
||||
});
|
||||
|
||||
auto last_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
SDL_Event event;
|
||||
while(m_running) {
|
||||
while(SDL_PollEvent(&event)) {
|
||||
@@ -72,17 +75,88 @@ void VkExpe::run() {
|
||||
m_running = false;
|
||||
break;
|
||||
}
|
||||
case SDL_MOUSEMOTION: {
|
||||
m_mouse_offset += Vector2(
|
||||
event.motion.xrel,
|
||||
event.motion.yrel
|
||||
);
|
||||
break;
|
||||
}
|
||||
case SDL_WINDOWEVENT: {
|
||||
switch(event.window.event) {
|
||||
case SDL_WINDOWEVENT_RESIZED: {
|
||||
m_vulkan.invalidate_swapchain();
|
||||
break;
|
||||
}
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED: {
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
break;
|
||||
}
|
||||
case SDL_WINDOWEVENT_FOCUS_LOST: {
|
||||
SDL_SetRelativeMouseMode(SDL_FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto new_time = std::chrono::high_resolution_clock::now();
|
||||
const auto elapsed = new_time - last_time;
|
||||
last_time = new_time;
|
||||
|
||||
update(std::chrono::duration<double>(elapsed).count());
|
||||
|
||||
m_vulkan.set_camera(m_camera_position, m_camera_z, m_camera_y);
|
||||
m_vulkan.draw_frame();
|
||||
// m_running = false;
|
||||
|
||||
m_mouse_offset = Vector2::Zero();
|
||||
}
|
||||
}
|
||||
|
||||
void VkExpe::update(double elapsed) {
|
||||
int key_count = 0;
|
||||
const auto keys = SDL_GetKeyboardState(&key_count);
|
||||
|
||||
const auto test_key = [key_count, keys](int scan_code) {
|
||||
return scan_code < key_count && keys[scan_code];
|
||||
};
|
||||
|
||||
if (!m_mouse_offset.isZero()) {
|
||||
const Real x_sensi = 0.001;
|
||||
const Real y_sensi = -0.001;
|
||||
|
||||
const Vector3 camera_x = m_camera_y.cross(m_camera_z);
|
||||
Vector3 axis =
|
||||
x_sensi * m_mouse_offset[0] * m_camera_y +
|
||||
y_sensi * m_mouse_offset[1] * camera_x;
|
||||
Real rot_norm = axis.norm();
|
||||
AngleAxis rot(rot_norm, axis / rot_norm);
|
||||
m_camera_y = rot * m_camera_y;
|
||||
m_camera_z = rot * m_camera_z;
|
||||
}
|
||||
|
||||
Vector3 walk_direction = Vector3::Zero();
|
||||
if(test_key(SDL_SCANCODE_W))
|
||||
walk_direction += Vector3::UnitZ();
|
||||
if(test_key(SDL_SCANCODE_S))
|
||||
walk_direction -= Vector3::UnitZ();
|
||||
if(test_key(SDL_SCANCODE_A))
|
||||
walk_direction -= Vector3::UnitX();
|
||||
if(test_key(SDL_SCANCODE_D))
|
||||
walk_direction += Vector3::UnitX();
|
||||
if(test_key(SDL_SCANCODE_SPACE))
|
||||
walk_direction -= Vector3::UnitY();
|
||||
if(test_key(SDL_SCANCODE_LCTRL))
|
||||
walk_direction += Vector3::UnitY();
|
||||
|
||||
if(!walk_direction.isZero()) {
|
||||
walk_direction.normalize();
|
||||
const Real base_velocity = 1;
|
||||
|
||||
Matrix3 camera_basis;
|
||||
camera_basis << m_camera_y.cross(m_camera_z), m_camera_y, m_camera_z;
|
||||
m_camera_position += elapsed * base_velocity * (camera_basis * walk_direction);
|
||||
}
|
||||
}
|
||||
|
||||
10
src/VkExpe.h
10
src/VkExpe.h
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <core.h>
|
||||
#include <VulkanTutorial.h>
|
||||
|
||||
#include <SDL2/SDL.h>
|
||||
@@ -26,8 +27,17 @@ public:
|
||||
|
||||
void run();
|
||||
|
||||
void update(double elapsed);
|
||||
|
||||
private:
|
||||
VulkanTutorial m_vulkan;
|
||||
|
||||
Vector3 m_camera_position = Vector3(0.0f, 0.0f, -3.0f);
|
||||
Vector3 m_camera_z = Vector3(0.0f, 0.0f, 1.0f);
|
||||
Vector3 m_camera_y = Vector3(0.0f, 1.0f, 0.0f);
|
||||
|
||||
WindowUP m_window;
|
||||
bool m_running = false;
|
||||
|
||||
Vector2 m_mouse_offset = Vector2::Zero();
|
||||
};
|
||||
|
||||
@@ -196,6 +196,12 @@ void VulkanTutorial::shutdown() {
|
||||
m_context.shutdown();
|
||||
}
|
||||
|
||||
void VulkanTutorial::set_camera(const Vector3& camera_position, const Vector3& camera_z, const Vector3& camera_y) {
|
||||
m_camera_position = camera_position;
|
||||
m_camera_z = camera_z;
|
||||
m_camera_y = camera_y;
|
||||
}
|
||||
|
||||
void VulkanTutorial::draw_frame() {
|
||||
m_swapchain.begin_frame();
|
||||
auto const image_index = m_swapchain.current_image_index();
|
||||
@@ -206,15 +212,14 @@ void VulkanTutorial::draw_frame() {
|
||||
}
|
||||
m_last_frame_time = now;
|
||||
|
||||
const float alpha = SecondsD(m_time).count() * (2.0 * M_PI) / 10.0;
|
||||
const float dist = 2.0f;
|
||||
const Eigen::Matrix4f view = look_at_matrix(
|
||||
// Eigen::Vector3f(0.0f, 0.0f, -dist),
|
||||
Eigen::Vector3f(0.0f, -dist, -dist),
|
||||
// dist * Eigen::Vector3f(std::cos(alpha), std::sin(alpha), -1.0),
|
||||
Eigen::Vector3f::Zero(),
|
||||
-Eigen::Vector3f::UnitY()
|
||||
);
|
||||
Matrix3 linear_view;
|
||||
linear_view <<
|
||||
m_camera_y.cross(m_camera_z).transpose(),
|
||||
m_camera_y.transpose(),
|
||||
m_camera_z.transpose();
|
||||
Matrix4 view;
|
||||
view << linear_view, linear_view * -m_camera_position,
|
||||
Vector4::UnitW().transpose();
|
||||
|
||||
const float fov = M_PI / 3.0f;
|
||||
const float near = 0.1f;
|
||||
@@ -227,12 +232,7 @@ void VulkanTutorial::draw_frame() {
|
||||
near, far
|
||||
);
|
||||
|
||||
using Transform = Eigen::Transform<float, 3, Eigen::Affine>;
|
||||
Transform model = Transform::Identity();
|
||||
model.rotate(Eigen::AngleAxisf(
|
||||
alpha,
|
||||
Eigen::Vector3f::UnitY()
|
||||
));
|
||||
|
||||
const Uniforms uniforms = {
|
||||
.scene_from_model = model.matrix(),
|
||||
@@ -241,7 +241,7 @@ void VulkanTutorial::draw_frame() {
|
||||
0.5 * m_swapchain.extent().width,
|
||||
0.5 * m_swapchain.extent().height,
|
||||
},
|
||||
.lod = std::cos(alpha) * 0.5f + 0.5f,
|
||||
// .lod = std::cos(alpha) * 0.5f + 0.5f,
|
||||
};
|
||||
|
||||
void* uniform_buffer;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <core.h>
|
||||
|
||||
#include <Vulkan/Context.h>
|
||||
#include <Vulkan/Swapchain.h>
|
||||
|
||||
@@ -35,6 +37,8 @@ public:
|
||||
void initialize(SDL_Window* window);
|
||||
void shutdown();
|
||||
|
||||
void set_camera(const Vector3& camera_position, const Vector3& camera_z, const Vector3& camera_y);
|
||||
|
||||
void draw_frame();
|
||||
void invalidate_swapchain();
|
||||
|
||||
@@ -78,6 +82,10 @@ private:
|
||||
std::vector<VkCommandBuffer> m_command_buffers;
|
||||
std::vector<VkSemaphore> m_render_done;
|
||||
|
||||
Vector3 m_camera_position = Vector3(0.0f, 0.0f, -3.0f);
|
||||
Vector3 m_camera_z = Vector3(0.0f, 0.0f, 1.0f);
|
||||
Vector3 m_camera_y = Vector3(0.0f, 1.0f, 0.0f);
|
||||
|
||||
TimePoint m_last_frame_time;
|
||||
Duration m_time = Duration(0);
|
||||
};
|
||||
|
||||
13
src/core.h
13
src/core.h
@@ -8,8 +8,21 @@
|
||||
|
||||
using Byte = unsigned char;
|
||||
using Index = uint32_t;
|
||||
|
||||
using Real = float;
|
||||
|
||||
using Vector2 = Eigen::Matrix<Real, 2, 1>;
|
||||
using Vector3 = Eigen::Matrix<Real, 3, 1>;
|
||||
using Vector4 = Eigen::Matrix<Real, 4, 1>;
|
||||
|
||||
using Matrix2 = Eigen::Matrix<Real, 2, 2>;
|
||||
using Matrix3 = Eigen::Matrix<Real, 3, 3>;
|
||||
using Matrix4 = Eigen::Matrix<Real, 4, 4>;
|
||||
|
||||
using Transform = Eigen::Transform<Real, 3, Eigen::Affine>;
|
||||
using AngleAxis = Eigen::AngleAxis<Real>;
|
||||
using Quaternion = Eigen::Quaternion<Real>;
|
||||
|
||||
using Triangle = Eigen::Array<Index, 3, 1>;
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user