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_stencil.create(GL_LINEAR, GL_REPEAT);
sampler_linear.create(GL_LINEAR); sampler_linear.create(GL_LINEAR);
m_face_plane.create<1>(2, 2); 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 load uvs texture");
LOG("initializing assets completed"); LOG("initializing assets completed");
} }

View File

@@ -53,7 +53,7 @@ public:
Sampler sampler_stencil; Sampler sampler_stencil;
Sampler sampler_linear; Sampler sampler_linear;
Plane m_face_plane; Plane m_face_plane;
//Sphere sphere; Sphere sphere;
LayoutManager layout; LayoutManager layout;
NodeMessageBox* msgbox; NodeMessageBox* msgbox;
NodeSettings* settings; 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 // draw the motion controller sphere
/*
{ {
auto mvp = proj * camera * glm::translate(glm::normalize(vr_controller_pos)); auto mvp = proj * camera * glm::translate(glm::normalize(vr_controller_pos));
ShaderManager::use(kShader::Color); 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))); ShaderManager::u_mat4(kShaderUniform::MVP, mvp * glm::scale(glm::vec3(.025)));
sphere.draw_fill(); sphere.draw_fill();
} }
*/
// draw the motion controller brush // draw the motion controller brush
{ {

View File

@@ -277,7 +277,7 @@ void Canvas::stroke_draw_mix(const glm::vec2& bb_min, const glm::vec2& bb_sz)
gl.restore(); 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 // intersect P with the current face to clip diverging points from the plane
const auto unp_vp = zw(m_box); const auto unp_vp = zw(m_box);
@@ -285,59 +285,69 @@ std::array<std::vector<vertex_t>, 6> Canvas::stroke_draw_project(std::array<vert
std::array<std::vector<vertex_t>, 6> ret; std::array<std::vector<vertex_t>, 6> ret;
for (int i = 0; i < 6; i++) for (int i = 0; i < 6; i++)
{ {
auto P = poly_intersect(B.data(), B.data() + 4, m_plane_shape[i]); struct ray_t {
glm::mat4 plane_camera = glm::lookAt(m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i]); glm::vec3 o;
int intersections = 0; glm::vec3 d;
for (int j = 0; j < P.size(); j++) 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)
{ {
glm::vec3 ray_origin, ray_dir; rays.reserve(B.size());
//if (s.pos.z == 0) 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]);
rays.reserve(P.size());
for (auto const& p : P)
{ {
//point_unproject(P[j].pos, { 0, 0, zw(m_box) }, m_mv, m_proj, ray_origin, ray_dir); glm::vec3 ray_origin, ray_dir;
auto clip_space = glm::vec2(p.pos.x, unp_vp.y - p.pos.y - 1.f) / unp_vp * 2.f - 1.f;
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 wp0 = unp_inv * glm::vec4(clip_space, 0, 1); auto wp0 = unp_inv * glm::vec4(clip_space, 0, 1);
auto wp1 = unp_inv * glm::vec4(clip_space, .5, 1); auto wp1 = unp_inv * glm::vec4(clip_space, .5, 1);
ray_origin = xyz(wp0 / wp0.w); ray_origin = xyz(wp0 / wp0.w);
ray_dir = glm::normalize(xyz(wp1 / wp1.w) - ray_origin); ray_dir = glm::normalize(xyz(wp1 / wp1.w) - ray_origin);
rays.emplace_back(ray_origin, ray_dir, p);
} }
//else }
//{ glm::mat4 plane_camera = glm::lookAt(m_plane_origin[i], m_plane_normal[i], m_plane_tangent[i]);
// auto m = glm::inverse(glm::lookAt({ 0, 0, 0 }, s.pos, { 0, 1, 0 })); std::vector<vertex_t> face_ret;
// glm::vec3 off_3d = m * glm::vec4(off[j], 0, 1); face_ret.reserve(rays.size());
// ray_origin = glm::vec3(0); for (auto const& r : rays)
// ray_dir = s.pos + off_3d; {
//}
glm::vec3 hit; glm::vec3 hit;
float hit_t; 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); 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].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; vertex_t v;
P[j].pos.y = (plane_local.y * 0.5f + 0.5f) * m_height; 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! // Black magic - BEWARE!
// interpolation perspective correction, use the current camera projection to correct the interpolation // 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 // 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 // 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 // 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); auto hit_cam = mv * glm::vec4(hit, 1);
P[j].pos.z = 0; v.pos.z = 0;
P[j].pos.w = hit_cam.z; v.pos.w = hit_cam.z;
P[j].uvs *= hit_cam.z; v.uvs = r.v.uvs * hit_cam.z;
P[j].uvs2 *= hit_cam.z; v.uvs2 = r.v.uvs2 * hit_cam.z;
intersections++; face_ret.emplace_back(v);
} }
else else
{ {
break; break;
} }
} }
if (intersections >= 3) if (face_ret.size() >= 3)
ret[i] = P; ret[i] = std::move(face_ret);
} }
return 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_min = glm::max({ 0, 0 }, glm::min(mixer_bb_min, p));
mixer_bb_max = glm::min(mixer_sz, glm::max(mixer_bb_max, p)); mixer_bb_max = glm::min(mixer_sz, glm::max(mixer_bb_max, p));
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); 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; 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.col = glm::vec4(s.col, 1);
f.flow = s.flow; f.flow = s.flow;
f.opacity = s.opacity; 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; prev = s;
} }

View File

@@ -242,7 +242,7 @@ public:
void stroke_start(glm::vec3 point, float pressure); void stroke_start(glm::vec3 point, float pressure);
void stroke_update(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); 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} // return rect {origin, size}
glm::vec4 stroke_draw_samples(int i, std::vector<vertex_t>& P); glm::vec4 stroke_draw_samples(int i, std::vector<vertex_t>& P);
std::vector<StrokeFrame> stroke_draw_compute(Stroke& stroke) const; std::vector<StrokeFrame> stroke_draw_compute(Stroke& stroke) const;

View File

@@ -3,6 +3,10 @@
#include "log.h" #include "log.h"
#include <array> #include <array>
std::map<ViveController::kButton, ViveController::kButtonMask> ViveController::m_mask{
{ ViveController::kButton::Trigger, ViveController::kButtonMask::TriggerBit },
};
bool Vive::Initialize() bool Vive::Initialize()
{ {
vr::EVRInitError error; vr::EVRInitError error;
@@ -79,18 +83,78 @@ void Vive::Update()
auto mat_proj = glm::make_mat4(data_eye_proj); auto mat_proj = glm::make_mat4(data_eye_proj);
auto mat_pose = glm::inverse(glm::make_mat4(data_hmd_pose)); auto mat_pose = glm::inverse(glm::make_mat4(data_hmd_pose));
auto mat_eye = glm::inverse(glm::make_mat4(data_eye_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_proj[eye] = mat_proj;
m_view[eye] = mat_eye * mat_pose; m_view[eye] = mat_eye * mat_pose;
m_pose = 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++) for (int id = 0; id < vr::k_unMaxTrackedDeviceCount; id++)
{ {
// device not tracking
if (!poses[id].bPoseIsValid)
continue;
switch (m_hmd->GetTrackedDeviceClass(id)) switch (m_hmd->GetTrackedDeviceClass(id))
{ {
case vr::TrackedDeviceClass_HMD: case vr::TrackedDeviceClass_HMD:
m_active = (m_hmd->GetTrackedDeviceActivityLevel(id) == vr::k_EDeviceActivityLevel_UserInteraction); m_active = (m_hmd->GetTrackedDeviceActivityLevel(id) == vr::k_EDeviceActivityLevel_UserInteraction);
break; 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: default:
break; break;
} }
@@ -138,3 +202,14 @@ bool Vive::Valid()
{ {
return m_hmd && m_comp && comp_attempts < 10; 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 #pragma once
#include "rtt.h" #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 struct Vive
{ {
int comp_attempts = 0; int comp_attempts = 0;
@@ -9,15 +42,19 @@ struct Vive
vr::IVRSystem* m_hmd = nullptr; vr::IVRSystem* m_hmd = nullptr;
vr::IVRCompositor* m_comp = nullptr; vr::IVRCompositor* m_comp = nullptr;
vr::IVRSettings* m_settings = nullptr; vr::IVRSettings* m_settings = nullptr;
ViveController m_controllers[2];
glm::mat4 m_view[2]; glm::mat4 m_view[2];
glm::mat4 m_proj[2]; glm::mat4 m_proj[2];
glm::mat4 m_pose; glm::mat4 m_pose;
bool m_active = false; 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 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(); bool Initialize();
void Terminate(); void Terminate();
void Update(); void Update();
void Draw(); void Draw();
bool Valid(); 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; App::I.has_vr = true;
vr_running = 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; const float target_tick_rate = 90;
unsigned long t0 = GetTickCount(); unsigned long t0 = GetTickCount();
while (vr_running && running == 1 && vive->Valid()) while (vr_running && running == 1 && vive->Valid())
@@ -488,6 +515,22 @@ bool win32_vr_start()
vive->Update(); vive->Update();
App::I.vr_active = vive->m_active; 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) if (vr_running && vive->m_active)
{ {