Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions engine/includes/components/spline.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,15 @@ class ENGINE_EXPORT Spline : public Component {
void insertPoint(int index, const Point &point);
void removePoint(int index);

Vector3 value(float position) const;
Vector3 value(float position);

private:
void normalizePath();

float arcLengthFactor(int start, int end, float factor) const;
float computeArcLength(int start, int end, float t) const;
Vector3 bezierDerivative(int start, int end, float t) const;

void composeComponent() override;

void loadUserData(const VariantMap& data) override;
Expand All @@ -58,7 +62,11 @@ class ENGINE_EXPORT Spline : public Component {

IndexVector m_indices;

bool m_closed;
float m_fullLength = 0.0f;

bool m_closed = false;

bool m_cacheDirty = true;

};

Expand Down
4 changes: 0 additions & 4 deletions engine/src/components/actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@

#include "resources/prefab.h"

#include "systems/resourcesystem.h"

#include "commandbuffer.h"

#include <cstring>

namespace {
Expand Down
169 changes: 128 additions & 41 deletions engine/src/components/spline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ namespace {
\inmodule Components
*/

Spline::Spline() :
m_closed(false) {
Spline::Spline() {

}
/*!
Expand All @@ -29,8 +28,7 @@ bool Spline::closed() const {
*/
void Spline::setClosed(bool closed) {
m_closed = closed;

normalizePath();
m_cacheDirty = true;
}
/*!
Returns the number of points in the spline.
Expand All @@ -57,63 +55,74 @@ void Spline::setPoint(int index, const Point &point) {
m_points.push_back(point);
}

normalizePath();
m_cacheDirty = true;
}
/*!
Inserts a \a point at the given \a index.
*/
void Spline::insertPoint(int index, const Point &point) {
m_points.insert(std::next(m_points.begin(), index), point);

normalizePath();
m_cacheDirty = true;
}
/*!
Removes the point at the given \a index.
*/
void Spline::removePoint(int index) {
m_points.erase(std::next(m_points.begin(), index));

normalizePath();
m_cacheDirty = true;
}
/*!
Returns the value of the spline at the given normalized \a position.
*/
Vector3 Spline::value(float position) const {
Vector3 Spline::value(float position) {
normalizePath();

position = CLAMP(position, 0.0f, 1.0f);

Vector3 result = (m_points.empty()) ? 0.0f : m_points.front().position;
if(m_points.size() >= 2) {
int begin = 0;
int end = 0;
if(m_points.size() < 2) {
return (m_points.empty()) ? Vector3(0.0f) : m_points.front().position;
}

for(; end < m_points.size() - 1; end++) {
if(position == m_points[end].normDistance) {
return m_points[end].position;
}
if(position > m_points[end].normDistance) {
begin = end;
} else if(position < m_points[end].normDistance) {
break;
}
}
int begin = 0;
int end = 0;

float dist = 1.0f;
if(m_closed && end == m_points.size()) {
end = 0;
} else {
dist = m_points[end].normDistance;
for(; end < m_points.size() - 1; end++) {
if(position == m_points[end].normDistance) {
return m_points[end].position;
}
if(position > m_points[end].normDistance) {
begin = end;
} else if(position < m_points[end].normDistance) {
break;
}
}

float factor = (position - m_points[begin].normDistance) / (dist - m_points[begin].normDistance);
return CMIX(m_points[begin].position, m_points[begin].tangentOut, m_points[end].tangentIn, m_points[end].position, factor);
if(m_closed && end == m_points.size()) {
end = 0;
}

return result;
float segmentStart = m_points[begin].normDistance;
float segmentEnd = (end == 0 && m_closed) ? 1.0f : m_points[end].normDistance;
float segmentLength = segmentEnd - segmentStart;

if(segmentLength < 0.0001f) {
return m_points[begin].position;
}

float factor = (position - segmentStart) / segmentLength;
factor = arcLengthFactor(begin, end, factor);

return CMIX(m_points[begin].position, m_points[begin].tangentOut,
m_points[end].tangentIn, m_points[end].position, factor);
}
/*!
\internal
*/
void Spline::normalizePath() {
if(!m_cacheDirty) return;

if(m_points.empty()) {
return;
}
Expand All @@ -129,7 +138,7 @@ void Spline::normalizePath() {

std::vector<float> paths(m_points.size(), 0.0f);

float fullLength = 0.0f;
m_fullLength = 0.0f;

int vertexIndex = 0;
for(int i = 0; i < segments; i++) {
Expand All @@ -146,7 +155,7 @@ void Spline::normalizePath() {
if(step != 0 || i != 0) {
float length = (m_vertices[index] - m_vertices[index - 1]).length();
paths[i] += length;
fullLength += length;
m_fullLength += length;
}

if(step != steps) {
Expand All @@ -157,13 +166,87 @@ void Spline::normalizePath() {
}
}

float lastLength = 0.0f;
float dist = 0.0f;
float accumulated = 0.0f;
for(int i = 0; i < m_points.size(); i++) {
dist += lastLength / fullLength;
m_points[i].normDistance = dist;
lastLength = paths[i];
m_points[i].normDistance = accumulated / m_fullLength;
accumulated += paths[i];
}

m_cacheDirty = false;
}
/*!
\internal
*/
float Spline::arcLengthFactor(int start, int end, float factor) const {
float totalSegmentLength = computeArcLength(start, end, 1.0f);
float targetLength = factor * totalSegmentLength;

float low = 0.0f;
float high = 1.0f;
float epsilon = 0.001f * totalSegmentLength;

for(int i = 0; i < 12; i++) {
float t = (low + high) * 0.5f;
float currentLength = computeArcLength(start, end, t);

if(fabs(currentLength - targetLength) < epsilon) {
return t;
}

if(currentLength < targetLength) {
low = t;
} else {
high = t;
}
}

return (low + high) * 0.5f;
}
/*!
\internal
*/
float Spline::computeArcLength(int start, int end, float t) const {
const int gaussPoints = 5;
static const float gaussWeights[] = {
0.236926885056189, 0.478628670499366, 0.568888888888889,
0.478628670499366, 0.236926885056189
};
static const float gaussAbscissas[] = {
-0.906179845938664, -0.538469310105683, 0.0,
0.538469310105683, 0.906179845938664
};

float length = 0.0f;
float halfT = t * 0.5f;

for(int i = 0; i < gaussPoints; i++) {
float u = halfT * (1.0f + gaussAbscissas[i]);
Vector3 derivative = bezierDerivative(start, end, u);
length += gaussWeights[i] * derivative.length();
}

return length * halfT;
}
/*!
\internal
*/
Vector3 Spline::bezierDerivative(int start, int end, float t) const {
// P'(t) = 3(1-t)²(P1-P0) + 6(1-t)t(P2-P1) + 3t²(P3-P2)

const Vector3 &p0 = m_points[start].position;
const Vector3 &p1 = m_points[start].tangentOut;
const Vector3 &p3 = m_points[end].position;
const Vector3 &p2 = m_points[end].tangentIn;

float t2 = t * t;
float mt = 1.0f - t;
float mt2 = mt * mt;

Vector3 dp0 = (p1 - p0) * 3.0f * mt2;
Vector3 dp1 = (p2 - p1) * 6.0f * mt * t;
Vector3 dp2 = (p3 - p2) * 3.0f * t2;

return dp0 + dp1 + dp2;
}
/*!
\internal
Expand All @@ -175,7 +258,7 @@ void Spline::loadUserData(const VariantMap& data) {
if(it != data.end()) {
m_points.clear();
VariantList knots = it->second.value<VariantList>();
for(auto k : knots) {
for(auto &k : knots) {
Point point;

VariantList fields = k.value<VariantList>();
Expand All @@ -191,7 +274,7 @@ void Spline::loadUserData(const VariantMap& data) {
m_points.push_back(point);
}

normalizePath();
m_cacheDirty = true;
}
}
/*!
Expand All @@ -201,7 +284,7 @@ VariantMap Spline::saveUserData() const {
VariantMap result = Component::saveUserData();

VariantList points;
for(auto knot : m_points) {
for(auto &knot : m_points) {
VariantList fields;
fields.push_back(knot.position);
fields.push_back(knot.tangentIn);
Expand All @@ -223,12 +306,14 @@ void Spline::composeComponent() {
{Vector3( 1.0f, 0.0f, 0.0f), Vector3( 0.0f, 0.0f, 0.0f), Vector3( 2.0f, 0.0f, 0.0f)}
};

normalizePath();
m_cacheDirty = true;
}
/*!
\internal
*/
void Spline::drawGizmos() {
normalizePath();

if(!m_vertices.empty()) {
Transform *t = transform();
Gizmos::drawLines(m_vertices, m_indices, Vector4(0.0f, 0.0f, 0.0f, 1.0f), t->worldTransform());
Expand All @@ -238,6 +323,8 @@ void Spline::drawGizmos() {
\internal
*/
void Spline::drawGizmosSelected() {
normalizePath();

if(!m_vertices.empty()) {
Transform *t = transform();
Gizmos::drawLines(m_vertices, m_indices, Vector4(1.0f, 1.0f, 0.0f, 1.0f), t->worldTransform());
Expand Down
10 changes: 5 additions & 5 deletions thirdparty/next/inc/math/amath.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@ static std::uniform_int_distribution<uint32_t> dist(0, UINT32_MAX);
#define DEG2RAD (PI / 180.0f)
#define RAD2DEG (180.0f / PI)

#define SQR(a) (a * a)
#define QUAD(a) (a * a * a)
#define SQR(a) ((a) * (a))
#define CUBE(a) ((a) * (a) * (a))

#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))

#define CLAMP(x, min, max) ((x < min) ? min : (x > max) ? max : x)
#define MIX(a, b, f) (a * (1 - f) + b * f)
#define QMIX(a, b, c, f) (a * SQR((1 - f)) + b * 2 * f * (1 - f) + c * SQR(f))
#define CMIX(a, b, c, d, f) (a * QUAD((1 - f)) + b * 3 * f * SQR((1 - f)) + c * 3 * SQR(f) * (1 - f) + d * QUAD(f))
#define MIX(a, b, f) ((a) * (1 - (f)) + (b) * (f))
#define QMIX(a, b, c, f) ((a) * SQR(1 - (f)) + (b) * 2 * (f) * (1 - (f)) + (c) * SQR(f))
#define CMIX(a, b, c, d, f) ((a) * CUBE(1 - (f)) + (b) * 3 * (f) * SQR(1 - (f)) + (c) * 3 * SQR(f) * (1 - (f)) + (d) * CUBE(f))

#define RANGE(min, max) (min + ((max - min) * (static_cast<areal>(dist(mt)) / static_cast<areal>(UINT32_MAX))))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ void SplinePanel::setTool(SplineTool *tool) {
}

void SplinePanel::update() {
int index = m_tool->point();
int index = m_tool->pointIndex();
Spline *spline = m_tool->spline();
if(spline && index > -1) {
Spline::Point p = spline->point(index);

QRegularExpression reg("\\.?0+$");
static const QRegularExpression reg("\\.?0+$");
ui->xEdit->setText(QString::number(p.position.x, 'f', 4).remove(reg));
ui->yEdit->setText(QString::number(p.position.y, 'f', 4).remove(reg));
ui->zEdit->setText(QString::number(p.position.z, 'f', 4).remove(reg));
Expand All @@ -53,7 +53,7 @@ void SplinePanel::update() {
}

void SplinePanel::onEditFinished() {
int index = m_tool->point();
int index = m_tool->pointIndex();
Spline *spline = m_tool->spline();
if(spline && index > -1) {
Spline::Point p = spline->point(index);
Expand Down
Loading
Loading