1#define _USE_MATH_DEFINES
5#include "Resources/MeshManager.h"
7#include "Components/Core/MeshComponent.h"
8#include "Components/Core/MeshRenderComponent.h"
9#include "Components/Data/TrajectoryComponent.h"
10#include "Components/Core/SceneComponent.h"
11#include "Components/Core/LodComponent.h"
13#include "Systems/Core/LodSystem.h"
14#include "Systems/Core/CameraSystem.h"
15#include "Systems/Core/TransformSystem.h"
16#include "Systems/Data/TrajectorySystem.h"
18#include "Utilities/FrustumClassification.h"
19#include "Utilities/TransformVertices.h"
20#include "Utilities/TessellationPredicates.h"
22#include "LoftedCrossSectionsComponent.h"
23#include "TrajectoryCrossSectionsSystem.h"
24#include "LoftedCrossSectionsSystem.h"
26#include "Foundation/ComponentModel/Entity.h"
27#include "Foundation/Logging/Logger.h"
35 template<
typename Store>
struct StoreTraits;
38 struct StoreTraits <
std::vector<Cogs::Core::PositionNormalVertex> >
40 typedef std::vector<Cogs::Core::PositionNormalVertex>
Storage;
41 typedef glm::vec3 Pos;
42 typedef glm::vec2 Tex;
43 typedef glm::vec3 Nrm;
45 inline static void set(
Storage& V,
int i,
const Pos& p,
const Tex& ,
const Nrm& n)
53 struct StoreTraits <
std::vector<Cogs::Core::PositionNormalTexVertex> >
55 typedef std::vector<Cogs::Core::PositionNormalTexVertex>
Storage;
56 typedef glm::vec3 Pos;
57 typedef glm::vec2 Tex;
58 typedef glm::vec3 Nrm;
60 inline static void set(
Storage& V,
int i,
const Pos& p,
const Tex& t,
const Nrm& n)
68 template<TrajectoryCrossSectionsComponent::Parameterization type>
struct ParameterizationTraits;
73 typedef std::vector<Cogs::Core::PositionNormalVertex> Store;
75 static StoreTraits<Store>::Tex map(
float ,
float ,
float ,
float )
77 return StoreTraits<Store>::Tex(0.f);
80 static const bool doubleSeam =
false;
86 typedef std::vector<Cogs::Core::PositionNormalTexVertex> Store;
88 static StoreTraits<Store>::Tex map(
float u,
float v,
float ,
float )
90 return StoreTraits<Store>::Tex(u, v);
93 static const bool doubleSeam =
true;
99 typedef std::vector<Cogs::Core::PositionNormalTexVertex> Store;
101 static StoreTraits<Store>::Tex map(
float u,
float ,
float circumference,
float acc_coordlen)
103 return StoreTraits<Store>::Tex(u, acc_coordlen / circumference);
106 static const bool doubleSeam =
true;
109 template<
bool hollow,
bool caps, TrajectoryCrossSectionsComponent::Parameterization ParamType>
110 int sampleShape(
typename ParameterizationTraits<ParamType>::Store& vertices,
111 std::vector<glm::vec3>& spine,
112 const std::vector<float>& depths,
113 const std::vector<glm::vec3>& positions,
114 const std::vector<glm::quat>& orientations,
115 const std::vector<bool>& include,
116 const float inner_radius,
117 const float outer_radius,
118 const float start_depth,
119 const float end_depth,
120 const int trajectory_offset,
124 typedef typename ParameterizationTraits<ParamType>::Store Store;
125 const bool doubleSeam = ParameterizationTraits<ParamType>::doubleSeam;
127 std::vector<glm::vec2> profile(samples);
128 for (
int i = 0; i < samples; i++) {
129 float t =
static_cast<float>(2.0*M_PI)*(
static_cast<float>(i) /
static_cast<float>(samples - (doubleSeam ? 1 : 0)));
130 profile[i].x = cos(t);
131 profile[i].y = sin(t);
134 int actualSlices = caps ? 4 : 2;
135 for (
int i = 1; i + 1 < slices; i++) {
136 actualSlices += include[trajectory_offset + i] ? 1 : 0;
139 float circumference = 2.f*float(M_PI)*outer_radius;
140 float coord_length = 0.f;
141 const int f_h = hollow ? 2 : 1;
142 const int f_c = caps ? 1 : 0;
144 vertices.resize((hollow ? 2 : 1) * samples * actualSlices);
145 spine.resize(actualSlices);
149 size_t o = trajectory_offset;
150 float t = (start_depth - depths[o]) / (depths[o + 1] - depths[o]);
151 glm::quat q = glm::mix(orientations[o], orientations[o + 1], t);
152 glm::vec3 u = q*glm::vec3(1.f, 0.f, 0.f);
153 glm::vec3 v = q*glm::vec3(0.f, 1.f, 0.f);
154 glm::vec3 w = q*glm::vec3(0.f, 0.f, 1.f);
155 glm::vec3 p = glm::mix(positions[o], positions[o + 1], t);
160 for (
int i = 0; i < samples; i++) {
161 float unit_u =
static_cast<float>(i) / (samples - (doubleSeam ? 1 : 0));
162 typename StoreTraits<Store>::Tex tex = ParameterizationTraits<ParamType>::map(unit_u, 0.f, circumference, 0.f);
163 typename StoreTraits<Store>::Nrm n = u * profile[i].x + v * profile[i].y;
165 StoreTraits<Store>::set(vertices, f_h * (samples * 0 + i) + 0, p + outer_radius*n, tex, -w);
167 StoreTraits<Store>::set(vertices, f_h * (samples * f_c + i) + 0, p + outer_radius*n, tex, n);
170 StoreTraits<Store>::set(vertices, f_h * (samples * 0 + i) + 1, p + inner_radius*n, tex, -w);
172 StoreTraits<Store>::set(vertices, f_h * (samples * f_c + i) + 1, p + inner_radius*n, tex, -n);
175 coord_length += (1.f - t)*glm::distance(positions[o], positions[o + 1]);
178 int slice = caps ? 2 : 1;
179 for (
int j = 1; j < slices - 1; j++) {
180 int k = j + trajectory_offset;
182 coord_length += glm::distance(positions[k - 1], positions[k]);
185 glm::vec3 u = orientations[k] * glm::vec3(1.f, 0.f, 0.f);
186 glm::vec3 v = orientations[k] * glm::vec3(0.f, 1.f, 0.f);
187 typename StoreTraits<Store>::Pos p = positions[k];
188 float unit_v = ((depths[k] - start_depth) / (end_depth - start_depth));
191 for (
int i = 0; i < samples; i++) {
192 float unit_u =
static_cast<float>(i) / (samples - (doubleSeam ? 1 : 0));
193 typename StoreTraits<Store>::Tex tex = ParameterizationTraits<ParamType>::map(unit_u, unit_v, circumference, coord_length);
195 typename StoreTraits<Store>::Nrm n = u * profile[i].x + v * profile[i].y;
196 StoreTraits<Store>::set(vertices, 2 * (samples * slice + i) + 0, p + outer_radius*n, tex, n);
197 StoreTraits<Store>::set(vertices, 2 * (samples * slice + i) + 1, p + inner_radius*n, tex, -n);
200 typename StoreTraits<Store>::Nrm n = u * profile[i].x + v * profile[i].y;
201 StoreTraits<Store>::set(vertices, samples * slice + i + 0, p + outer_radius*n, tex, n);
209 size_t o = trajectory_offset + slices - 2;
210 float t = (end_depth - depths[o]) / (depths[o + 1] - depths[o]);
211 glm::quat q = glm::mix(orientations[o], orientations[o + 1], t);
212 glm::vec3 u = q*glm::vec3(1.f, 0.f, 0.f);
213 glm::vec3 v = q*glm::vec3(0.f, 1.f, 0.f);
214 glm::vec3 w = q*glm::vec3(0.f, 0.f, 1.f);
215 glm::vec3 p = glm::mix(positions[o], positions[o + 1], t);
216 coord_length += t*glm::distance(positions[o], positions[o + 1]);
217 spine[slice + 0] = p;
219 spine[slice + 1] = p;
221 for (
int i = 0; i < samples; i++) {
222 float unit_u =
static_cast<float>(i) / (samples - (doubleSeam ? 1 : 0));
223 typename StoreTraits<Store>::Tex tex = ParameterizationTraits<ParamType>::map(unit_u, 1.f, circumference, coord_length);
224 typename StoreTraits<Store>::Nrm n = u * profile[i].x + v * profile[i].y;
225 StoreTraits<Store>::set(vertices, f_h * (samples * (slice + 0) + i) + 0, p + outer_radius*n, tex, n);
227 StoreTraits<Store>::set(vertices, f_h * (samples * (slice + 1) + i) + 0, p + outer_radius*n, tex, w);
230 StoreTraits<Store>::set(vertices, f_h * (samples * (slice + 0) + i) + 1, p + inner_radius*n, tex, -n);
232 StoreTraits<Store>::set(vertices, f_h * (samples * (slice + 1) + i) + 1, p + inner_radius*n, tex, w);
242 template<TrajectoryCrossSectionsComponent::Parameterization ParamType>
249 typedef typename ParameterizationTraits<ParamType>::Store Store;
251 std::vector<glm::vec3> spine;
253 const bool doubleSeam = ParameterizationTraits<ParamType>::doubleSeam;
254 const int samples = cSectData.
samples + (doubleSeam ? 1 : 0);
255 const float startMeasuredDepth = cSectData.startMeasuredDepth;
256 const float stopMeasuredDepth = cSectData.stopMeasuredDepth;
259 int rings = cSectData.
rings;
261 switch (cSectComp.shape) {
263 case LoftedCrossSectionsComponent::Shape::Hollow:
264 rings = sampleShape<true, true, ParamType>(vertices, spine,
266 innerRadius, outerRadius, startMeasuredDepth, stopMeasuredDepth,
267 cSectData.
index0, rings, samples);
269 loftComp->set(std::move(vertices), std::move(spine), LoftedCrossSectionsComponent::Shape::Hollow, samples, rings, doubleSeam);
272 case LoftedCrossSectionsComponent::Shape::Solid:
273 rings = sampleShape<false, true, ParamType>(vertices, spine,
275 innerRadius, outerRadius, startMeasuredDepth, stopMeasuredDepth,
276 cSectData.
index0, rings, samples);
278 loftComp->set(std::move(vertices), std::move(spine), LoftedCrossSectionsComponent::Shape::Solid, samples, rings, doubleSeam);
281 case LoftedCrossSectionsComponent::Shape::Shell:
282 rings = sampleShape<false, false, ParamType>(vertices, spine,
284 innerRadius, outerRadius, startMeasuredDepth, stopMeasuredDepth,
285 cSectData.
index0, rings, samples);
287 loftComp->set(std::move(vertices), std::move(spine), LoftedCrossSectionsComponent::Shape::Shell, samples, rings, doubleSeam);
292 void minMaxFromVertices3(
Context* ,
296 const size_t src_stride,
298 const size_t src_count)
300 if (src_count == 0) {
304 glm::vec3& min = *
reinterpret_cast<glm::vec3*
>(min_v3);
305 glm::vec3& max = *
reinterpret_cast<glm::vec3*
>(max_v3);
307 min = max = *
reinterpret_cast<const glm::vec3*
>(src);
309 for (
size_t i = 1; i < src_count; i++) {
310 const glm::vec3& s = *
reinterpret_cast<const glm::vec3*
>(src + src_stride * i);
311 min = glm::min(min, s);
312 max = glm::max(max, s);
317 inline void minMaxFromVertices(
Context* context,
320 const std::vector<glm::vec3>& src,
324 assert(offset + count <= src.size());
325 minMaxFromVertices3(context, glm::value_ptr(min), glm::value_ptr(max),
326 reinterpret_cast<const uint8_t*
>(src.data() + offset),
327 sizeof(glm::vec3),
sizeof(glm::vec3)*(src.size() - offset), count);
337 for (
const auto & cSectComp :
pool) {
338 if (!cSectComp.trajectory) {
347 auto& cSectData = getData(&cSectComp);
348 auto& trajData =
context->trajectorySystem->getData(trajComp);
355 LOG_WARNING(logger,
"trajectory must have at least two samples, skipping.");
356 loftComp->visibility =
false;
357 loftComp->setChanged();
362 LOG_WARNING(logger,
"trajectory has mismatching position and index counts, skipping.");
363 loftComp->visibility =
false;
364 loftComp->setChanged();
369 LOG_WARNING(logger,
"trajectory subset has illegal measured depth extent, skipping.");
370 loftComp->visibility =
false;
371 loftComp->setChanged();
380 trajComp->
determineindices(cSectData.index0, cSectData.index1, cSectData.rings,
381 cSectData.startMeasuredDepth, cSectData.stopMeasuredDepth);
383 if (cSectData.rings < 2) {
384 LOG_ERROR(logger,
"Less than two slices will be produced, skipping.");
385 loftComp->visibility =
false;
386 loftComp->setChanged();
392 cSectData.trajectoryBoundingBox.min,
393 cSectData.trajectoryBoundingBox.max,
396 cSectData.boundingBox.min = cSectData.trajectoryBoundingBox.min - glm::vec3(cSectComp.
radiusScale*cSectComp.
outerRadius);
397 cSectData.boundingBox.max = cSectData.trajectoryBoundingBox.max + glm::vec3(cSectComp.
radiusScale*cSectComp.
outerRadius);
402 cSectData.generate =
true;
407 FrustumPlanes frustumCheck = frustumClassifyBoundingBox(lodData.localToClip,
408 cSectData.boundingBox.min,
409 cSectData.boundingBox.max);
410 if ((frustumCheck&FrustumPlanes::InsideAllButFar) != FrustumPlanes::InsideAllButFar) {
412 if (loftComp->visibility) {
413 loftComp->visibility =
false;
414 loftComp->setChanged();
418 else if (loftComp->visibility ==
false) {
420 loftComp->visibility =
true;
421 loftComp->setChanged();
422 cSectData.generate =
true;
432 bool inFrontOfNear =
false;
433 glm::vec4 screenReferencePoint = lodData.localToClip * glm::vec4(cSectData.trajectoryBoundingBox.min, 1.f);
434 for (
int i = 0; i < 8; i++) {
435 glm::vec3 p((i & 1) ? cSectData.trajectoryBoundingBox.min.x : cSectData.trajectoryBoundingBox.max.x,
436 (i & 2) ? cSectData.trajectoryBoundingBox.min.y : cSectData.trajectoryBoundingBox.max.y,
437 (i & 4) ? cSectData.trajectoryBoundingBox.min.z : cSectData.trajectoryBoundingBox.max.z);
438 glm::vec4 h = lodData.localToClip * glm::vec4(p, 1.f);
439 if (h.z / h.w < screenReferencePoint.z / screenReferencePoint.w) {
440 screenReferencePoint = h;
443 inFrontOfNear =
true;
447 screenReferencePoint = glm::vec4(0.f, 0.f, -1.f, 1.f);
451 float minSamples = 3.f;
452 float maxSamples = 4.f * float(cSectComp.
samples);
453 float epsilon = lodComp->geometricTolerance;
455 screenReferencePoint,
457 float nonIntegerSamples = 0.0f;
458 switch (
context->lodSystem->geometricErrorKind)
460 case GeometricErrorKind::AreaBased:
461 nonIntegerSamples = sphereSectorGeometricAreaPredicate(rr, camComp->
viewportSize,
462 epsilon*epsilon, minSamples, maxSamples);
464 case GeometricErrorKind::DistanceBased:
465 nonIntegerSamples = sphereSectorGeometricDistancePredicate(rr, camComp->
viewportSize,
466 epsilon, minSamples, maxSamples);
471 int samples = int(std::ceil(nonIntegerSamples));
472 bool change = samples != cSectData.
samples;
475 cSectData.generate =
true;
483 if (cSectData.generate) {
485 switch (cSectComp.parameterization)
488 process<TrajectoryCrossSectionsComponent::Parameterization::None>(cSectComp, cSectData, trajComp, trajData, loftComp);
491 process<TrajectoryCrossSectionsComponent::Parameterization::UnitSquare>(cSectComp, cSectData, trajComp, trajData, loftComp);
494 process<TrajectoryCrossSectionsComponent::Parameterization::CoordLengthOverCircumference>(cSectComp, cSectData, trajComp, trajData, loftComp);
497 cSectData.generate =
false;
ComponentType * getComponent() const
glm::vec2 viewportSize
Size of the viewport covered by this instance, given in pixels.
Context * context
Pointer to the Context instance the system lives in.
void update()
Updates the system state to that of the current frame.
ComponentPool< ComponentType > pool
Pool of components managed by the system.
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.
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
COGSCORE_DLL_API glm::vec2 localSphereRadiusInScreenSpace(const glm::mat4 &localToClip, const glm::mat4 &clipToLocal, const glm::vec4 &clipPosition, const float localRadius)
Given a screen space reference position and a local space radius, find the corresponding screen space...
@ GeometricTolerance
Use a geometric error bound to determine how refined geometry needs to be at its current position.
Contains geometry calculations and generation.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Defines level of detail data calculated by the LodSystem.
int samples
Number of sample points in each of the cross sections.
Data component defining a 3D trajectory, for example a Well trajectory.
std::vector< float > indexes
Positive distances along trajectory. For wells Measured Depth (MD). Set same length of indexes and po...
COGSCORE_DLL_API void determineindices(int &ix0, int &ix1, int &slices, const float startDepth, const float stopDepth)
std::vector< glm::vec3 > positions
Trajectory positions. For wells the Z component is a measurement of True Vertical Depth (TVD)....
float startMeasuredDepth
Spine of the tubular shape.
int samples
Number of samples around the circumference.
@ CoordLengthOverCircumference
U maps to [0,1) around circumference, V is coordlength divided by circumference.
@ None
No texture coordinates are generated.
@ UnitSquare
Unit square mapped over shape.
float outerRadius
The outer radius of the tubular shape, used for all shapes.
float stopMeasuredDepth
Measured depth along trajectory where casing stops.
float innerRadius
The inner radius of the tubular shape, only used for Hollow shape.
float radiusScale
Factor by which to scale the inner and outer radius.
int index0
Start index along trajectory.
int samples
Number of perimeter samples used when cross sections were created.
int rings
Number of rings around trajectory in tessellation.
std::vector< glm::quat > frames
Frames of reference along trajectory with minimal torsion.
std::vector< bool > lodSelection
Set of trajectory stations that should be included in current lod-situation.