fixing stroke direction

This commit is contained in:
2019-11-25 00:47:20 +01:00
parent b26a814208
commit 423df3b92d
2 changed files with 181 additions and 4 deletions

View File

@@ -52,6 +52,62 @@ void Stroke::randomize_prng()
} }
std::vector<StrokeSample> Stroke::compute_samples() std::vector<StrokeSample> Stroke::compute_samples()
{
std::vector<StrokeSample> samples;
auto dirs = m_interp_dir.compute();
m_dirs_cache.insert(m_dirs_cache.end(), dirs.begin(), dirs.end());
auto points = m_interp_main.compute();
//if (!dirs.empty() && !points.empty())
{
LOG("dirs %f - points %f", m_interp_dir.dist, m_interp_main.dist);
}
for (const auto& kp : points)
{
for (; m_dir_i < m_dirs_cache.size() && (kp.dist >= m_dirs_cache[m_dir_i].dist || !m_dir_valid); m_dir_i++)
{
m_dir_angle = -glm::orientedAngle(-m_dirs_cache[m_dir_i].dir, m_dir_ref);
if (m_dir_angle > glm::radians(120.f) || !m_dir_valid)
{
auto old_dir = m_dir_ref;
m_dir_ref = -m_dirs_cache[m_dir_i].dir;
m_dir_ref_angle = -glm::orientedAngle(m_dir_ref, { 1, 0 });
m_dir_angle = -glm::orientedAngle(-m_dirs_cache[m_dir_i].dir, m_dir_ref);
auto angle_diff = -glm::orientedAngle(m_dir_ref, old_dir);
for (int i = 0; i < m_direction.m_count; i++)
m_direction.m_vec[i] -= angle_diff;
}
if (glm::abs(m_direction.average() - m_dir_angle) > glm::radians(120.f))
m_direction.clear();
m_dir_valid = true;
}
auto s = randomize_sample(kp.pos, kp.pressure, m_dir_angle);
if (s.valid())
{
if (m_brush->m_tip_angle_follow)
{
m_direction.add(m_dir_angle);
s.angle += m_direction.average() + m_dir_ref_angle;
}
m_prev_sample = s;
samples.push_back(s);
}
else
{
static bool invalid_logged = false;
if (!invalid_logged)
{
for (auto const& p : m_keypoints)
LOG("point dist %f pos %f %f %f", p.dist, p.pos.x, p.pos.y, p.pos.z);
invalid_logged = true;
}
LOG("Invalid sample");
}
}
return samples;
}
std::vector<StrokeSample> Stroke::compute_samples_old()
{ {
if (m_keypoints.size() < 2) return {}; if (m_keypoints.size() < 2) return {};
int nsamples = (int)glm::floor((m_keypoints.back().dist - m_dist) / m_step); int nsamples = (int)glm::floor((m_keypoints.back().dist - m_dist) / m_step);
@@ -75,11 +131,14 @@ std::vector<StrokeSample> Stroke::compute_samples()
int next_kp = m_last_kp == m_dir_kp ? m_last_kp + 1 : m_dir_kp; int next_kp = m_last_kp == m_dir_kp ? m_last_kp + 1 : m_dir_kp;
glm::vec2 v = glm::normalize(m_keypoints[m_last_kp].pos - m_keypoints[next_kp].pos); glm::vec2 v = glm::normalize(m_keypoints[m_last_kp].pos - m_keypoints[next_kp].pos);
m_dir_angle = -glm::orientedAngle(v, m_dir_ref); m_dir_angle = -glm::orientedAngle(v, m_dir_ref);
LOG("DIR ANGLE %f PT (%f,%f)(%f,%f)", m_dir_angle,
m_keypoints[m_last_kp].pos.x, m_keypoints[m_last_kp].pos.y,
m_keypoints[next_kp].pos.x, m_keypoints[next_kp].pos.y);
if (m_brush->m_tip_angle_smooth > 0 && (glm::abs(m_dir_angle) > glm::radians(30.f) || !m_dir_valid)) if (m_brush->m_tip_angle_smooth > 0 && (glm::abs(m_dir_angle) > glm::radians(30.f) || !m_dir_valid))
{ {
if (glm::abs(m_dir_angle) > glm::radians(100.f)) if (glm::abs(m_dir_angle) > glm::radians(100.f))
{ {
//LOG("BIG ANGLE"); LOG("BIG ANGLE");
m_direction.clear(); m_direction.clear();
} }
@@ -90,6 +149,7 @@ std::vector<StrokeSample> Stroke::compute_samples()
auto angle_diff = -glm::orientedAngle(m_dir_ref, old_dir); auto angle_diff = -glm::orientedAngle(m_dir_ref, old_dir);
for (int i = 0; i < m_direction.m_count; i++) for (int i = 0; i < m_direction.m_count; i++)
m_direction.m_vec[i] -= angle_diff; m_direction.m_vec[i] -= angle_diff;
LOG("REF ANGLE %f", m_dir_ref_angle);
} }
m_dir_kp = m_last_kp; m_dir_kp = m_last_kp;
m_dir_dist = 0; m_dir_dist = 0;
@@ -97,6 +157,7 @@ std::vector<StrokeSample> Stroke::compute_samples()
{ {
m_dir_init = m_dir_angle + m_dir_ref_angle; m_dir_init = m_dir_angle + m_dir_ref_angle;
m_dir_valid = true; m_dir_valid = true;
LOG("DIR INVALID");
} }
} }
@@ -115,12 +176,13 @@ std::vector<StrokeSample> Stroke::compute_samples()
if (m_brush->m_tip_angle_follow) if (m_brush->m_tip_angle_follow)
{ {
m_direction.add(m_dir_angle); m_direction.add(m_dir_angle);
s.angle += m_direction.average() + m_dir_ref_angle; s.angle += m_dir_angle /*m_direction.average()*/ + m_dir_ref_angle;
} }
else if (m_brush->m_tip_angle_init) else if (m_brush->m_tip_angle_init)
{ {
s.angle += m_dir_init; s.angle += m_dir_init;
} }
LOG("angle %f", s.angle);
m_prev_sample = s; m_prev_sample = s;
samples.push_back(s); samples.push_back(s);
@@ -142,9 +204,11 @@ std::vector<StrokeSample> Stroke::compute_samples()
} }
bool Stroke::has_sample() bool Stroke::has_sample()
{ {
return m_keypoints.size() < 2 ? false : // no keypoints //return m_keypoints.size() < 2 ? false : // no keypoints
(m_keypoints.back().dist > (m_dist + m_step)); // check if next kp is closer than spacing // (m_keypoints.back().dist > (m_dist + m_step)); // check if next kp is closer than spacing
return m_interp_main.ready() && m_interp_dir.ready_first;
} }
void Stroke::reset(bool clear_keypoints /*= false*/) void Stroke::reset(bool clear_keypoints /*= false*/)
{ {
m_dir_kp = 0; m_dir_kp = 0;
@@ -153,8 +217,12 @@ void Stroke::reset(bool clear_keypoints /*= false*/)
m_dir_dist = 0; m_dir_dist = 0;
m_last_kp = 0; m_last_kp = 0;
m_dist = 0.f; m_dist = 0.f;
m_dir_i = 0;
m_dirs_cache.clear();
if (clear_keypoints) if (clear_keypoints)
m_keypoints.clear(); m_keypoints.clear();
m_interp_main.reset(clear_keypoints);
m_interp_dir.reset(clear_keypoints);
} }
void Stroke::add_point(glm::vec3 pos, float pressure) void Stroke::add_point(glm::vec3 pos, float pressure)
{ {
@@ -189,9 +257,14 @@ void Stroke::add_point(glm::vec3 pos, float pressure)
kp.pressure = pressure; kp.pressure = pressure;
kp.dist = dist; kp.dist = dist;
m_keypoints.push_back(kp); m_keypoints.push_back(kp);
m_interp_main.add(kp);
m_interp_dir.add(kp);
} }
void Stroke::start(const std::shared_ptr<Brush>& brush) void Stroke::start(const std::shared_ptr<Brush>& brush)
{ {
m_dir_i = 0;
m_dirs_cache.clear();
m_hold_points.clear(); m_hold_points.clear();
m_curve = 0.f; m_curve = 0.f;
m_direction.clear(); m_direction.clear();
@@ -221,6 +294,9 @@ void Stroke::start(const std::shared_ptr<Brush>& brush)
m_direction.resize(std::max<int>(1, m_brush->m_tip_angle_smooth * 200.f / m_step)); m_direction.resize(std::max<int>(1, m_brush->m_tip_angle_smooth * 200.f / m_step));
prng.seed(0); prng.seed(0);
m_interp_main = SamplesInterpolator(m_step);
m_interp_dir = SamplesInterpolator(std::max(4.f, m_step));
} }
bool Brush::load_tip(const std::string& path, const std::string& thumb) bool Brush::load_tip(const std::string& path, const std::string& thumb)
@@ -579,3 +655,83 @@ void Brush::write(BinaryStreamWriter& w) const
w << d; w << d;
} }
//////////////////////////////////////////////////////////////////////////
Stroke::SamplesInterpolator::SamplesInterpolator(float sp) noexcept
{
spacing = sp;
dist = 0;
first = true;
ready_first = false;
}
Stroke::SamplesInterpolator::SamplesInterpolator() noexcept
{
spacing = 1.f;
dist = 0;
first = true;
ready_first = false;
}
void Stroke::SamplesInterpolator::add(const Keypoint& p) noexcept
{
keypoints.push_back(p);
if (first)
{
last = p;
first = false;
}
if (!ready_first)
ready_first = ready();
}
bool Stroke::SamplesInterpolator::ready() const noexcept
{
return keypoints.size() > 1 &&
glm::distance(last.pos, keypoints.back().pos) > spacing;
}
void Stroke::SamplesInterpolator::reset(bool clear_keypoints) noexcept
{
dist = 0;
if (clear_keypoints || keypoints.empty())
{
ready_first = false;
first = true;
keypoints.clear();
}
else
{
last = keypoints[0];
}
}
std::vector<Stroke::Keypoint> Stroke::SamplesInterpolator::compute() noexcept
{
std::vector<Stroke::Keypoint> ret;
for (const auto& kp : keypoints)
{
float d = glm::distance(last.pos, kp.pos);
if (d < spacing)
continue;
int n = glm::floor(d / spacing);
float t_step = spacing / d;
for (int i = 0; i < n; i++)
{
float t = (float)(i + 1) * t_step;
dist += spacing;
Keypoint p;
p.pos = glm::lerp(last.pos, kp.pos, t);
p.dir = glm::normalize(last.pos - p.pos);
p.pressure = glm::lerp(last.pressure, kp.pressure, t);
p.dist = dist;
ret.push_back(p);
}
if (!ret.empty())
last = ret.back();
}
if (!ret.empty())
keypoints.clear();
return ret;
}

View File

@@ -146,15 +146,33 @@ public:
glm::vec3 pos = { 0, 0, 0 }; glm::vec3 pos = { 0, 0, 0 };
float pressure = 0; float pressure = 0;
float dist = 0; float dist = 0;
glm::vec2 dir = { 0, 0 };
}; };
struct Camera struct Camera
{ {
glm::mat4 rot; glm::mat4 rot;
float fov = 0; float fov = 0;
}; };
struct SamplesInterpolator
{
Keypoint last;
std::vector<Keypoint> keypoints;
bool ready_first;
bool first;
float spacing;
float dist;
SamplesInterpolator() noexcept;
SamplesInterpolator(float sp) noexcept;
void add(const Keypoint& p) noexcept;
bool ready() const noexcept;
void reset(bool clear_keypoints) noexcept;
std::vector<Keypoint> compute() noexcept;
};
int m_layer = 0; int m_layer = 0;
int m_dir_kp = 0; int m_dir_kp = 0;
bool m_dir_valid = false; bool m_dir_valid = false;
std::vector<Keypoint> m_dirs_cache;
int m_dir_i = 0;
glm::vec2 m_dir_ref = { 1, 0 }; glm::vec2 m_dir_ref = { 1, 0 };
float m_dir_ref_angle = 0; float m_dir_ref_angle = 0;
float m_dir_dist = 0; float m_dir_dist = 0;
@@ -183,7 +201,10 @@ public:
void reset(bool clear_keypoints = false); void reset(bool clear_keypoints = false);
bool has_sample(); bool has_sample();
std::vector<StrokeSample> compute_samples(); std::vector<StrokeSample> compute_samples();
std::vector<StrokeSample> compute_samples_old();
StrokeSample randomize_sample(const glm::vec3& pos, float pressure, float curve_angle); StrokeSample randomize_sample(const glm::vec3& pos, float pressure, float curve_angle);
SamplesInterpolator m_interp_main;
SamplesInterpolator m_interp_dir;
void randomize_prng(); void randomize_prng();
float rnd_nor() { return float((double)prng() / (double)prng.max()); }; // normalized [0, +1] float rnd_nor() { return float((double)prng() / (double)prng.max()); }; // normalized [0, +1]