This commit is contained in:
2019-05-06 21:03:22 +02:00
parent ea2cf73bdb
commit 898afe9052
8 changed files with 216 additions and 36 deletions

View File

@@ -127,7 +127,7 @@ void App::initAssets()
sampler_stencil.create(GL_LINEAR, GL_REPEAT);
sampler_linear.create(GL_LINEAR);
m_face_plane.create<1>(2, 2);
//sphere.create<8, 8>(1);
sphere.create<8, 8>(1);
LOG("initializing assets load uvs texture");
LOG("initializing assets completed");
}

View File

@@ -53,7 +53,7 @@ public:
Sampler sampler_stencil;
Sampler sampler_linear;
Plane m_face_plane;
//Sphere sphere;
Sphere sphere;
LayoutManager layout;
NodeMessageBox* msgbox;
NodeSettings* settings;

View File

@@ -261,7 +261,6 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
}
// draw the motion controller sphere
/*
{
auto mvp = proj * camera * glm::translate(glm::normalize(vr_controller_pos));
ShaderManager::use(kShader::Color);
@@ -269,7 +268,6 @@ void App::vr_draw(const glm::mat4& proj, const glm::mat4& camera, const glm::mat
ShaderManager::u_mat4(kShaderUniform::MVP, mvp * glm::scale(glm::vec3(.025)));
sphere.draw_fill();
}
*/
// draw the motion controller brush
{

View File

@@ -277,67 +277,77 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
gl.restore();
}
std::array<std::vector<vertex_t>, 6> Canvas::stroke_draw_project(std::array<vertex_t, 4>& B) const
std::array<std::vector<vertex_t>, 6> Canvas::stroke_draw_project(std::array<vertex_t, 4>& B, bool project_3d /*= false*/, glm::mat4 mv /*= glm::mat4(1)*/) const
{
// intersect P with the current face to clip diverging points from the plane
const auto unp_vp = zw(m_box);
const auto unp_inv = glm::inverse(m_proj * m_mv);
std::array<std::vector<vertex_t>, 6> ret;
for (int i = 0; i < 6; i++)
{
struct ray_t {
glm::vec3 o;
glm::vec3 d;
vertex_t v;
ray_t(glm::vec3 o, glm::vec3 d, vertex_t v) : o(o), d(d), v(v) { }
};
std::vector<ray_t> rays;
if (project_3d)
{
rays.reserve(B.size());
for (auto const& b : B)
rays.emplace_back(glm::vec3(0), b.pos, b);
}
else
{
auto P = poly_intersect(B.data(), B.data() + 4, m_plane_shape[i]);
glm::mat4 plane_camera = glm::lookAt(m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i]);
int intersections = 0;
for (int j = 0; j < P.size(); j++)
rays.reserve(P.size());
for (auto const& p : P)
{
glm::vec3 ray_origin, ray_dir;
//if (s.pos.z == 0)
{
//point_unproject(P[j].pos, { 0, 0, zw(m_box) }, m_mv, m_proj, ray_origin, ray_dir);
auto clip_space = glm::vec2(P[j].pos.x, unp_vp.y - P[j].pos.y - 1.f) / unp_vp * 2.f - 1.f;
auto clip_space = glm::vec2(p.pos.x, unp_vp.y - p.pos.y - 1.f) / unp_vp * 2.f - 1.f;
auto wp0 = unp_inv * glm::vec4(clip_space, 0, 1);
auto wp1 = unp_inv * glm::vec4(clip_space, .5, 1);
ray_origin = xyz(wp0 / wp0.w);
ray_dir = glm::normalize(xyz(wp1 / wp1.w) - ray_origin);
rays.emplace_back(ray_origin, ray_dir, p);
}
//else
//{
// auto m = glm::inverse(glm::lookAt({ 0, 0, 0 }, s.pos, { 0, 1, 0 }));
// glm::vec3 off_3d = m * glm::vec4(off[j], 0, 1);
// ray_origin = glm::vec3(0);
// ray_dir = s.pos + off_3d;
//}
}
glm::mat4 plane_camera = glm::lookAt(m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i]);
std::vector<vertex_t> face_ret;
face_ret.reserve(rays.size());
for (auto const& r : rays)
{
glm::vec3 hit;
float hit_t;
if (ray_intersect(ray_origin, ray_dir, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit, hit_t))
if (ray_intersect(r.o, r.d, m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i], hit, hit_t))
{
glm::vec4 plane_local = plane_camera * glm::vec4(hit, 1);
//P[j].uvs2 = xy(P[j].pos) / glm::vec2(App::I.width, App::I.height);
P[j].pos.x = -(plane_local.x * 0.5f - 0.5f) * m_width;
P[j].pos.y = (plane_local.y * 0.5f + 0.5f) * m_height;
vertex_t v;
v.pos.x = -(plane_local.x * 0.5f - 0.5f) * m_width;
v.pos.y = (plane_local.y * 0.5f + 0.5f) * m_height;
// Black magic - BEWARE!
// interpolation perspective correction, use the current camera projection to correct the interpolation
// because the new shape will have z fixed with an ortho projection when drawn to the face
// we need to imitate the same perspective as the once in the camera
// see: https://www.scratchapixel.com/lessons/3d-basic-rendering/rasterization-practical-implementation/perspective-correct-interpolation-vertex-attributes
auto hit_cam = m_mv * glm::vec4(hit, 1);
P[j].pos.z = 0;
P[j].pos.w = hit_cam.z;
P[j].uvs *= hit_cam.z;
P[j].uvs2 *= hit_cam.z;
intersections++;
auto hit_cam = mv * glm::vec4(hit, 1);
v.pos.z = 0;
v.pos.w = hit_cam.z;
v.uvs = r.v.uvs * hit_cam.z;
v.uvs2 = r.v.uvs2 * hit_cam.z;
face_ret.emplace_back(v);
}
else
{
break;
}
}
if (intersections >= 3)
ret[i] = P;
if (face_ret.size() >= 3)
ret[i] = std::move(face_ret);
}
return ret;
}
@@ -443,7 +453,16 @@ std::vector<Canvas::StrokeFrame> Canvas::stroke_draw_compute(Stroke& stroke) con
mixer_bb_min = glm::max({ 0, 0 }, glm::min(mixer_bb_min, p));
mixer_bb_max = glm::min(mixer_sz, glm::max(mixer_bb_max, p));
if (s.pos.z == 0.f)
{
B[j].pos = glm::vec4(xy(s.pos) + App::I.zoom * s.scale * off[j] * glm::orientate2(-s.angle) - glm::vec2(0, 1), 1, 1);
}
else
{
auto m = glm::inverse(glm::lookAt({ 0, 0, 0 }, s.pos, { 0, 1, 0 }));
glm::vec3 off_3d = m * glm::vec4(off[j], 0, 1);
B[j].pos = glm::vec4(s.pos + off_3d, 1.f);
}
B[j].uvs2 = p / mixer_sz;
}
@@ -451,7 +470,15 @@ std::vector<Canvas::StrokeFrame> Canvas::stroke_draw_compute(Stroke& stroke) con
f.col = glm::vec4(s.col, 1);
f.flow = s.flow;
f.opacity = s.opacity;
f.shapes = stroke_draw_project(B);
if (s.pos.z == 0.f)
{
f.shapes = stroke_draw_project(B, false, m_mv);
}
else
{
auto m = glm::lookAt({ 0, 0, 0 }, s.pos, { 0, 1, 0 });
f.shapes = stroke_draw_project(B, true, m);
}
prev = s;
}

View File

@@ -242,7 +242,7 @@ public:
void stroke_start(glm::vec3 point, float pressure);
void stroke_update(glm::vec3 point, float pressure);
void stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz);
std::array<std::vector<vertex_t>, 6> stroke_draw_project(std::array<vertex_t, 4>& B) const;
std::array<std::vector<vertex_t>, 6> stroke_draw_project(std::array<vertex_t, 4>& B, bool project_3d = false, glm::mat4 mv = glm::mat4(1)) const;
// return rect {origin, size}
glm::vec4 stroke_draw_samples(int i, std::vector<vertex_t>& P);
std::vector<StrokeFrame> stroke_draw_compute(Stroke& stroke) const;

View File

@@ -3,6 +3,10 @@
#include "log.h"
#include <array>
std::map<ViveController::kButton, ViveController::kButtonMask> ViveController::m_mask{
{ ViveController::kButton::Trigger, ViveController::kButtonMask::TriggerBit },
};
bool Vive::Initialize()
{
vr::EVRInitError error;
@@ -79,18 +83,78 @@ void Vive::Update()
auto mat_proj = glm::make_mat4(data_eye_proj);
auto mat_pose = glm::inverse(glm::make_mat4(data_hmd_pose));
auto mat_eye = glm::inverse(glm::make_mat4(data_eye_pose));
glm::vec3 head_position(h.m[0][3], h.m[1][3], h.m[2][3]);
m_proj[eye] = mat_proj;
m_view[eye] = mat_eye * mat_pose;
m_pose = mat_pose;
// invalidate controller state
std::for_each(m_controllers, m_controllers + 1, [&](ViveController& c) { c.m_valid = false; });
int controller_index = 0;
auto pose_inv = glm::inverse(m_pose);
for (int id = 0; id < vr::k_unMaxTrackedDeviceCount; id++)
{
// device not tracking
if (!poses[id].bPoseIsValid)
continue;
switch (m_hmd->GetTrackedDeviceClass(id))
{
case vr::TrackedDeviceClass_HMD:
m_active = (m_hmd->GetTrackedDeviceActivityLevel(id) == vr::k_EDeviceActivityLevel_UserInteraction);
break;
case vr::TrackedDeviceClass_Controller:
{
m_controllers[controller_index].m_valid = true;
m_hmd->GetControllerState(id, &m_controllers[controller_index].m_state, sizeof(vr::VRControllerState_t));
m_controllers[controller_index].m_mat = glm::translate(-head_position) * Pose2Mat(poses[id].mDeviceToAbsoluteTracking);
std::array<ViveController::kButton, 4> button_ids{
ViveController::kButton::Trigger,
//ViveController::kButton::Pad, // unused
//ViveController::kButton::Menu, // unused
//ViveController::kButton::Grip, // unused
};
for (auto b : button_ids)
{
glm::vec2 force = { m_controllers[controller_index].m_state.rAxis[(int)b].x,
m_controllers[controller_index].m_state.rAxis[(int)b].y };
if (glm::compMax(glm::abs(force)) > 0.f && !m_controllers[controller_index].m_analog_buttons[(uint8_t)b])
{
m_controllers[controller_index].m_analog_buttons[(uint8_t)b] = true;
if (on_analog_button)
on_analog_button(m_controllers[controller_index], b, ViveController::kAction::Press);
}
if (glm::compMax(glm::abs(force)) == 0.f && m_controllers[controller_index].m_analog_buttons[(uint64_t)b])
{
m_controllers[controller_index].m_analog_buttons[(uint8_t)b] = false;
if (on_analog_button)
on_analog_button(m_controllers[controller_index], b, ViveController::kAction::Release);
}
}
auto pressed_mask = m_controllers[controller_index].m_state.ulButtonPressed;
for (auto b : button_ids)
{
bool b_pressed = pressed_mask & (uint64_t)m_controllers[controller_index].m_mask[b];
if (b_pressed == true && !m_controllers[controller_index].m_buttons[(uint64_t)b])
{
m_controllers[controller_index].m_buttons[(uint64_t)b] = true;
if (on_button)
on_button(m_controllers[controller_index], b, ViveController::kAction::Press);
}
if (b_pressed == false && m_controllers[controller_index].m_buttons[(uint64_t)b])
{
m_controllers[controller_index].m_buttons[(uint64_t)b] = false;
if (on_button)
on_button(m_controllers[controller_index], b, ViveController::kAction::Release);
}
}
controller_index++;
}
default:
break;
}
@@ -138,3 +202,14 @@ bool Vive::Valid()
{
return m_hmd && m_comp && comp_attempts < 10;
}
glm::mat4 Vive::Pose2Mat(vr::HmdMatrix34_t const& m)
{
float data[16] = {
m.m[0][0], m.m[1][0], m.m[2][0], 0,
m.m[0][1], m.m[1][1], m.m[2][1], 0,
m.m[0][2], m.m[1][2], m.m[2][2], 0,
m.m[0][3], m.m[1][3], m.m[2][3], 1,
};
return glm::make_mat4(data);
}

View File

@@ -1,6 +1,39 @@
#pragma once
#include "rtt.h"
struct ViveController
{
enum class kButton : uint8_t
{
Pad,
Trigger,
Menu,
Grip,
COUNT,
};
enum class kButtonMask : uint64_t
{
TriggerBit = 0x200000000,
PadBit = 0x100000000,
MenuBit = 0x000000002,
GripBit = 0x000000004,
};
enum class kAction
{
Press,
Release,
};
static std::map<kButton, kButtonMask> m_mask;
std::array<bool, (int)kButton::COUNT> m_buttons;
std::array<bool, (int)kButton::COUNT> m_analog_buttons;
glm::mat4 m_mat;
vr::VRControllerState_t m_state{ 0 };
bool m_valid = false;
glm::vec2 axis(kButton button) const {
return { m_state.rAxis[(int)button].x, m_state.rAxis[(int)button].y };
}
};
struct Vive
{
int comp_attempts = 0;
@@ -9,15 +42,19 @@ struct Vive
vr::IVRSystem* m_hmd = nullptr;
vr::IVRCompositor* m_comp = nullptr;
vr::IVRSettings* m_settings = nullptr;
ViveController m_controllers[2];
glm::mat4 m_view[2];
glm::mat4 m_proj[2];
glm::mat4 m_pose;
bool m_active = false;
std::function<void(const glm::mat4& m_proj, const glm::mat4& m_view, const glm::mat4& m_pose)> on_draw = nullptr;
std::function<void(const ViveController&, ViveController::kButton, ViveController::kAction)> on_button = nullptr;
std::function<void(const ViveController&, ViveController::kButton, ViveController::kAction)> on_analog_button = nullptr;
bool Initialize();
void Terminate();
void Update();
void Draw();
bool Valid();
glm::mat4 Pose2Mat(vr::HmdMatrix34_t const& m);
};

View File

@@ -478,6 +478,33 @@ bool win32_vr_start()
App::I.has_vr = true;
vr_running = true;
bool trigger_down = false;
cbuffer<glm::vec3> controller_points(10);
glm::vec3 controller_last_point;
vive->on_analog_button = [&](const ViveController& c, ViveController::kButton b, ViveController::kAction a) {
if (b == ViveController::kButton::Trigger)
{
if (a == ViveController::kAction::Press)
{
glm::vec3 pos = glm::normalize(xyz(vive->m_controllers[0].m_mat[3])) * 800.f;
float force = vive->m_controllers[0].axis(b).x;
async_lock();
Canvas::I->stroke_start(pos, force);
async_unlock();
controller_last_point = pos;
controller_points.clear();
trigger_down = true;
}
if (a == ViveController::kAction::Release)
{
trigger_down = false;
async_lock();
Canvas::I->stroke_end();
async_unlock();
}
}
};
const float target_tick_rate = 90;
unsigned long t0 = GetTickCount();
while (vr_running && running == 1 && vive->Valid())
@@ -488,6 +515,22 @@ bool win32_vr_start()
vive->Update();
App::I.vr_active = vive->m_active;
App::I.vr_controller = vive->m_controllers[0].m_mat;
App::I.vr_controller_pos = glm::normalize(xyz(vive->m_controllers[0].m_mat[3]));
if (trigger_down)
{
controller_points.add(App::I.vr_controller_pos * 800.f);
auto p = controller_points.average();
if (glm::distance(p, controller_last_point) > 1)
{
async_lock();
Canvas::I->stroke_update(p, vive->m_controllers[0].axis(ViveController::kButton::Trigger).x);
async_unlock();
controller_last_point = p;
App::I.redraw = true;
}
}
if (vr_running && vive->m_active)
{