1#include "TrajectorySystem.h"
5#include "Components/Core/LodComponent.h"
6#include "Components/Data/TrajectoryComponent.h"
8#include "Systems/Core/CameraSystem.h"
9#include "Systems/Core/TransformSystem.h"
10#include "Systems/Core/LodSystem.h"
12#include "Utilities/Math.h"
13#include "Utilities/TransformVertices.h"
15#include "Foundation/ComponentModel/Entity.h"
16#include "Foundation/Logging/Logger.h"
18#define _USE_MATH_DEFINES
26 glm::vec3 removeLinearDepenence(
const glm::vec3& vec,
const glm::vec3& normalizedRef)
28 return vec - glm::dot(vec, normalizedRef)*normalizedRef;
31 glm::vec3 pickAnyDirectionBut(
const glm::vec3& but)
33 glm::vec3 t = glm::abs(but);
35 if ((t.x > t.y) && (t.x > t.z)) {
36 r = glm::vec3(0.f, 0.f, 1.f);
39 r = glm::vec3(0.f, 1.f, 0.f);
42 r = glm::vec3(1.f, 0.f, 0.f);
44 return glm::normalize(removeLinearDepenence(r, but));
49 template<GeometricErrorKind K>
struct GeometricErrorKindTraits;
53 inline static float bakedTolerance(
float sourceTolerance) {
return sourceTolerance; }
54 inline static float error(
const glm::vec2& ,
const glm::vec2&ac,
const glm::vec2&n)
55 {
return glm::abs(glm::dot(ac, n));}
60 inline static float bakedTolerance(
float sourceTolerance) {
return sourceTolerance*sourceTolerance; }
61 inline static float error(
const glm::vec2&ab,
const glm::vec2&ac,
const glm::vec2& )
62 {
return 0.5f*glm::abs(ab.x*ac.y - ac.x*ab.y); }
66template<GeometricErrorKind K>
67void selectLodSubset(std::vector<bool>& currInclude,
68 const std::vector<bool>& prevInclude,
69 const std::vector<glm::vec4> positions,
70 const glm::vec2& viewportSize,
71 const float distanceTolerance,
72 const float previousFrameStickyness)
74 float tolerance = GeometricErrorKindTraits<K>::bakedTolerance(distanceTolerance);
75 float unstickyness = glm::clamp(1.f - previousFrameStickyness, 0.001f, 0.999f);
77 const size_t N = positions.size();
78 std::vector<glm::vec2> screenPosition(N);
79 std::vector<std::pair<size_t,size_t>> ranges;
82 currInclude.resize(N);
84 bool prevInsideState =
false;
85 size_t rangeStart = 0;
86 for(
size_t i=0; i<=N; i++) {
90 bool currInsideState = i < N ? positions[i].z >= -positions[i].w :
false;
92 if (prevInsideState != currInsideState) {
93 prevInsideState = currInsideState;
94 currInclude[i == 0 ? 0 : i - 1] =
true;
95 currInclude[i < N ? i : N - 1] =
true;
97 if (currInsideState) {
101 ranges.emplace_back(rangeStart, i - 1);
106 if(currInsideState) {
107 const glm::vec4& p = positions[i];
108 screenPosition[i] = (0.5f / p.w)* viewportSize * glm::vec2(p.x, p.y);
118 while (!ranges.empty()) {
120 const std::pair<size_t, size_t> r = ranges.back();
126 if (r.first + 1 < r.second) {
127 size_t prevSplit = 0;
128 size_t currSplit = 0;
129 float prevError = -std::numeric_limits<float>::max();
130 float currError = -std::numeric_limits<float>::max();
132 glm::vec2 ab = screenPosition[r.second] - screenPosition[r.first];
133 glm::vec2 n = glm::normalize(glm::vec2(-ab.y, ab.x));
134 for (
size_t i = r.first + 1; i < r.second; i++) {
135 glm::vec2 ac = screenPosition[i] - screenPosition[r.first];
137 float error = GeometricErrorKindTraits<K>::error(ab, ac, n);
139 if (currError < error) {
144 if ((prevError < error) && prevInclude[i]) {
150 if (tolerance < currError) {
155 if (unstickyness*currError < prevError) {
156 currSplit = prevSplit;
160 currInclude[currSplit] =
true;
161 if (r.first + 1 < currSplit) {
162 ranges.emplace_back(r.first, currSplit);
164 if (currSplit + 1 < r.second) {
165 ranges.emplace_back(currSplit, r.second);
173void Cogs::Core::TrajectorySystem::generateAnchoredFramesOfReference(std::vector<glm::quat>& orientations,
174 const std::vector<float>& indices,
175 const std::vector<glm::vec3>& positions,
176 const glm::vec3& startAnchor,
177 const glm::vec3& stopAnchor,
178 const float anchorStickyness)
180 const size_t N = positions.size();
181 orientations.resize(N);
187 std::vector<glm::vec3> directions(N);
188 for (
size_t i = 0; i < N - 1; i++) {
189 directions[i] = positions[i + 1] - positions[i];
191 directions[N - 1] = directions[N - 2];
192 for (
size_t i = N - 2; i > 0; i--) {
193 directions[i] = glm::normalize(directions[i] + directions[i - 1]);
195 directions[0] = glm::normalize(directions[0]);
196 directions[N - 1] = glm::normalize(directions[N - 1]);
198 std::vector<float> debug(N, -43.f);
199 std::vector<glm::vec3> anchors(N);
200 anchors[0] = glm::normalize(removeLinearDepenence(startAnchor, directions[0]));
201 anchors[N-1] = glm::normalize(removeLinearDepenence(stopAnchor, directions[N - 1]));
203 float to = indices[0];
204 float ts = 1.f / (indices[N - 1] - indices[0]);
205 float linearDepenenceTolerance = glm::clamp(1.f - anchorStickyness, 0.01f, 1.f);
207 size_t prevIndependent = 0;
208 for (
size_t i = 1; i < N; ) {
209 glm::vec3 interpolatedAnchor = glm::mix(startAnchor, stopAnchor, ts*(indices[i] - to));
210 glm::vec3 orthogonalAnchor = removeLinearDepenence(interpolatedAnchor, directions[i]);
212 if (linearDepenenceTolerance < glm::length(orthogonalAnchor)) {
214 anchors[i] = glm::normalize(orthogonalAnchor);
223 size_t nextIndependent = N - 1;
224 for (
size_t k = i + 1; k < N - 1; k++) {
225 glm::vec3 interpolatedAnchor_ = glm::mix(startAnchor, stopAnchor, ts*(indices[k] - to));
226 glm::vec3 orthogonalAnchor_ = removeLinearDepenence(interpolatedAnchor_, directions[k]);
227 if (linearDepenenceTolerance < glm::length(orthogonalAnchor_)) {
228 anchors[k] = glm::normalize(orthogonalAnchor_);
238 size_t halfWay = (prevIndependent + nextIndependent) / 2;
239 glm::vec3 va = glm::normalize(positions[nextIndependent] - positions[prevIndependent]);
240 glm::vec3 detour = glm::cross(positions[halfWay] - positions[prevIndependent], va);
241 if (glm::length(detour) < std::numeric_limits<float>::epsilon()) {
243 detour = pickAnyDirectionBut(directions[halfWay]);
247 detour = glm::normalize(detour);
251 glm::quat unconstrainedRotation = Cogs::Core::getRotation(directions[prevIndependent], directions[halfWay]);
252 if (glm::dot(unconstrainedRotation * anchors[prevIndependent], detour) < 0.f) {
258 for (
size_t k = prevIndependent+1; k < nextIndependent; k++) {
259 float t_k = ts*(indices[k] - indices[prevIndependent]) / (indices[nextIndependent] - indices[prevIndependent]);
260 glm::vec3 twistAnchor = ((1.f - t_k)*(1.f - t_k)*anchors[prevIndependent] +
261 2.f*(1.f - t_k)*t_k*detour +
262 t_k*t_k*anchors[nextIndependent]);
263 anchors[k] = glm::normalize(removeLinearDepenence(twistAnchor, directions[k]));
268 prevIndependent = nextIndependent;
269 i = nextIndependent+1;
274 for (
size_t i = 0; i < N; i++) {
279 alignZ = Cogs::Core::getRotation(glm::vec3(0.f, 0.f, 1.f), directions[0]);
282 alignZ = Cogs::Core::getRotation(directions[i - 1], directions[i])*orientations[i - 1];
286 glm::quat alignY = Cogs::Core::getRotation(alignZ * glm::vec3(0.f, 1.f, 0.f), anchors[i]);
288 orientations[i] = alignY*alignZ;
294 const std::vector<glm::vec3>& positions)
296 const size_t N = positions.size();
297 orientations.resize(N);
304 std::vector<glm::vec3> directions(N);
305 for (
size_t i = 0; i < N - 1; i++) {
306 directions[i] = positions[i + 1] - positions[i];
308 directions[N - 1] = directions[N - 2];
309 for (
size_t i = N - 2; i > 0; i--) {
310 directions[i] = glm::normalize(directions[i] + directions[i - 1]);
312 directions[0] = glm::normalize(directions[0]);
313 directions[N - 1] = glm::normalize(directions[N - 1]);
316 orientations[0] = Cogs::Core::getRotation(glm::vec3(0.f, 0.f, 1.f), directions[0]);
317 for (
size_t i = 1; i < N; i++) {
318 orientations[i] = Cogs::Core::getRotation(directions[i - 1], directions[i])*orientations[i - 1];
324 const auto & cameraComponent = context->cameraSystem->getMainCamera();
329 if (trajComp.hasChanged()) {
331 float l2a = glm::dot(trajComp.startRadialAnchor, trajComp.startRadialAnchor);
332 float l2b = glm::dot(trajComp.startRadialAnchor, trajComp.stopRadialAnchor);
333 if (std::isnormal(l2a) && std::isnormal(l2b)) {
334 generateAnchoredFramesOfReference(trajData.
frames, trajComp.indexes, trajComp.positions,
335 trajComp.startRadialAnchor, trajComp.stopRadialAnchor,
336 trajComp.anchorStickyness);
339 generateFramesOfReference(trajData.
frames, trajComp.positions);
348 const LodData & lodData = context->lodSystem->getData<
LodData>(lodComp);
351 trajData.
clipSpacePos.resize(trajComp.positions.size());
352 Cogs::Core::transformVertices(context,
357 bool hasChanged =
false;
358 std::vector<bool> lodSelection(trajComp.positions.size(),
false);
359 if (trajComp.hasChanged() || (trajData.
lodSelection.size() != trajComp.positions.size())) {
361 trajData.
lodSelection.resize(trajComp.positions.size());
367 switch (context->lodSystem->geometricErrorKind) {
368 case GeometricErrorKind::AreaBased:
371 context->lodSystem->previousFrameStickyness);
373 case GeometricErrorKind::DistanceBased:
376 context->lodSystem->previousFrameStickyness);
381 hasChanged = !std::equal(lodSelection.begin(), lodSelection.end(),
387 trajComp.setChangedTransient();
395 trajComp.setChangedTransient();
ComponentType * getComponent() const
void update()
Updates the system state to that of the current frame.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
Contains data describing level of detail behavior for the entity the component belongs to.
LodPolicy policy
The policy used for determining the level of detail for this entity.
float geometricTolerance
Geometric tolerance value applied when the lodPolicy field is set to LodPolicy::GeometricTolerance.
static void generateFramesOfReference(std::vector< glm::quat > &orientations, const std::vector< glm::vec3 > &positions)
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
GeometricErrorKind
Defines kinds of geometric error calculations.
@ GeometricTolerance
Use a geometric error bound to determine how refined geometry needs to be at its current position.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Defines level of detail data calculated by the LodSystem.
Data component defining a 3D trajectory, for example a Well trajectory.
std::vector< glm::quat > frames
Frames of reference along trajectory with minimal torsion.
std::vector< glm::vec4 > clipSpacePos
Clip space position of trajectory stations.
std::vector< bool > lodSelection
Set of trajectory stations that should be included in current lod-situation.