Cogs.Core
ExtrusionSystem.cpp
1#include "ExtrusionSystem.h"
2
3#include "Components/Data/TrajectoryComponent.h"
4#include "Components/Core/TransformComponent.h"
5#include "Components/Core/MeshComponent.h"
6#include "Components/Core/MeshRenderComponent.h"
7#include "Components/Data/DataSetComponent.h"
8#include "Components/Appearance/MaterialComponent.h"
9
10#include "Systems/Core/TransformSystem.h"
11
12#include "Context.h"
13
14#include "Resources/Mesh.h"
15#include "Resources/VertexFormats.h"
16#include "Resources/MeshManager.h"
17#include "Resources/MaterialManager.h"
18#include "Resources/DefaultMaterial.h"
19
20#include "Utilities/Math.h"
21
22#include "Math/CrossSectionGenerator.h"
23#include "Math/ExtrusionGenerator.h"
24
25#include "Foundation/ComponentModel/Entity.h"
26#include "Foundation/Geometry/Glm.hpp"
27#include "Foundation/Geometry/SampleListGenerator.hpp"
28#include "Foundation/Geometry/ValueQuery.hpp"
29#include "Foundation/Geometry/PathGenerator.hpp"
30
31using namespace Cogs::Geometry;
32
33static void generateExtrusionVertices(float radius, const size_t numSegments, const std::vector<glm::vec3> & positions, std::vector<Cogs::Core::PositionNormalTexVertex> & vertices)
34{
35 std::vector<glm::vec3> crossection(numSegments);
36
37 CrossSectionGenerator::generateCircularCrossection(crossection.data(), static_cast<int>(numSegments), radius, 0, glm::pi<float>() * 2.0f, false);
38
39 vertices.resize(numSegments * positions.size());
40
41 glm::vec3 direction = positions[1] - positions[0];
42
43 for (size_t i = 0; i < positions.size(); ++i) {
44 if (i > 0 && i < (positions.size() - 2)) {
45 direction = positions[i + 1] - positions[i - 1];
46 direction = glm::normalize(direction);
47 }
48
49 glm::quat rotation = Cogs::Core::getRotation(glm::vec3(0, 0, -1), direction);
50
51 for (size_t j = 0; j < crossection.size(); ++j) {
52 const size_t index = (i * numSegments) + j;
53
54 glm::vec3 position = rotation * crossection[j];
55 position = glm::normalize(position);
56 glm::vec3 normal = position;
57 position *= radius;
58 position += positions[i];
59
60 Cogs::Core::PositionNormalTexVertex vertex = { position, normal, glm::vec2(static_cast<float>(j) / static_cast<float>(crossection.size()), 0) };
61
62 vertices[index] = vertex;
63 }
64 }
65}
66
67template<class IndexType>
68static void generateExtrusionIndices(const unsigned int numSections, const unsigned int numSegments, std::vector<IndexType> & indices)
69{
70 const unsigned int numFaces = numSegments * (numSections - 1) * 2;
71 const unsigned int numIndices = numFaces * 3;
72
73 indices.resize(numIndices);
74
75 ExtrusionGenerator::generateTriangleIndices(indices.data(), numSections, numSegments, true, false, 0);
76}
77
79{
80 auto & meshManager = context->meshManager;
81
82 for (const auto & component : pool) {
83 if (!component.active) continue;
84
85 auto meshComponent = component.getComponent<MeshComponent>();
86
87 if (meshComponent->meshHandle == MeshHandle::NoHandle) {
88 meshComponent->meshHandle = context->meshManager->create();
89 }
90
91 auto mesh = meshManager->get(meshComponent->meshHandle);
92
93 if (component.trajectory) {
94 updateExtrusion(component, mesh);
95 } else if (component.extrusion && component.dataSet) {
96 updateLogExtrusion(component, context, mesh);
97 } else if (component.highlightTarget) {
98 updateHighlightExtrusion(component, context, mesh);
99 } else {
100 mesh->clear();
101 }
102 }
103}
104
105void Cogs::Core::ExtrusionSystem::updateExtrusion(const ExtrusionComponent & component, Mesh * mesh)
106{
107 const auto trajectoryData = component.trajectory->getComponent<TrajectoryComponent>();
108
109 if (!trajectoryData || !trajectoryData->positions.size()) return;
110
111 auto & data = getData<ExtrusionData>(&component);
112
113 if (component.hasChanged() || trajectoryData->hasChanged()) {
114 std::vector<PositionNormalTexVertex> extrusionVertices;
115
116 if (component.coverEntireTrajectory) {
117 generateExtrusionVertices(component.radius * component.diameterScale, component.numSegments, trajectoryData->positions, extrusionVertices);
118
119 for (size_t i = 0; i < trajectoryData->indexes.size(); ++i) {
120 for (size_t j = 0; j < component.numSegments; ++j) {
121 extrusionVertices[i * component.numSegments + j].tex.y = trajectoryData->indexes[i];
122 }
123 }
124 } else {
125 auto & depthList = data.depthList;
126 depthList.clear();
127
128 SampleListGenerator::generateIndexedSamples(
129 component.startDepth,
130 component.endDepth,
131 trajectoryData->indexes.data(),
132 static_cast<int>(trajectoryData->indexes.size()),
133 depthList);
134
135 data.basePositions.resize(depthList.size());
136 data.baseDirections.resize(depthList.size());
137
138 PathGenerator::generateLinearPath(depthList.data(),
139 static_cast<int>(depthList.size()),
140 trajectoryData->indexes.data(),
141 trajectoryData->positions.data(),
142 static_cast<int>(trajectoryData->indexes.size()),
143 data.basePositions.data(),
144 data.baseDirections.data());
145
146 generateExtrusionVertices(component.radius * component.diameterScale, component.numSegments, data.basePositions, extrusionVertices);
147 }
148
149 mesh->setVertexData(extrusionVertices.data(), extrusionVertices.size());
150
151 std::vector<unsigned int> extrusionIndices;
152
153 generateExtrusionIndices(static_cast<unsigned int>(component.coverEntireTrajectory ? trajectoryData->positions.size() : data.basePositions.size()), component.numSegments, extrusionIndices);
154
155 mesh->setIndexes(std::move(extrusionIndices));
156
158 }
159}
160
161void Cogs::Core::ExtrusionSystem::updateLogExtrusion(const ExtrusionComponent & component, Context * context, Mesh * mesh)
162{
163 const auto transform = component.getComponent<TransformComponent>();
164 const auto extrusion = component.extrusion->getComponent<ExtrusionComponent>();
165 const auto extrusionTransform = extrusion->getComponent<TransformComponent>();
166 const auto trajectory = extrusion->trajectory->getComponent<TrajectoryComponent>();
167 const auto dataSet = component.dataSet->getComponent<DataSetComponent>();
168
169 context->transformSystem->copyTransform(extrusionTransform, transform);
170
171 auto material = component.getComponent<MaterialComponent>();
172
173 auto colorMap = component.colorMap;
174
175 if (colorMap) {
176 auto colorMapMaterial = colorMap->getComponent<MaterialComponent>();
177
178 if (material->diffuseMap != colorMapMaterial->diffuseMap) {
179 material->diffuseMap = colorMapMaterial->diffuseMap;
180 material->diffuseColor = glm::vec4(1, 1, 1, 1);
181 material->setChanged();
182 }
183 }
184
185 if (extrusion->hasChanged() ||
186 trajectory->hasChanged() ||
187 dataSet->hasChanged() ||
188 component.hasChanged()) {
189 auto & data = getData<ExtrusionData>(&component);
190 auto & logData = getData<ExtrusionLogData>(&component);
191
192 const float endDepth = component.coverEntireTrajectory ? std::min(dataSet->indexes[dataSet->indexes.size() - 1], trajectory->indexes[trajectory->indexes.size() - 1]) : component.startDepth;
193 const float startDepth = component.coverEntireTrajectory ? std::max(dataSet->indexes[0], trajectory->indexes[0]) : component.endDepth;
194
195 std::vector<float> & depthList = data.depthList;
196 depthList.clear();
197
198 SampleListGenerator::generateIndexedSamples<float>(
199 startDepth,
200 endDepth,
201 trajectory->indexes.data(),
202 static_cast<int>(trajectory->indexes.size()),
203 depthList);
204
205 std::vector<float> & samples = data.samples;
206 samples.clear();
207
208 SampleListGenerator::createUniqueVector(
209 depthList.data(),
210 depthList.size(),
211 dataSet->indexes.data(),
212 static_cast<int>(dataSet->indexes.size()),
213 startDepth,
214 endDepth,
215 samples);
216
217 std::vector<glm::vec3> & basePositions = data.basePositions;
218 basePositions.resize(samples.size());
219
220 std::vector<glm::vec3> & baseDirections = data.baseDirections;
221 baseDirections.resize(samples.size());
222
223 std::vector<float> & values = logData.values;
224 logData.values.resize(samples.size());
225
226 ValueQuery::getValuesAtDepths(samples.data(), static_cast<int>(samples.size()), dataSet->indexes.data(), dataSet->values.data(), static_cast<int>(dataSet->values.size()), values.data());
227
228 auto minMax = std::minmax_element(dataSet->values.begin(), dataSet->values.end());
229
230 SampleListGenerator::normalizeValues<float, true>(values.data(), values.data(), static_cast<int>(values.size()), *minMax.first, *minMax.second);
231
232 PathGenerator::generateLinearPath(samples.data(), static_cast<int>(samples.size()), trajectory->indexes.data(), trajectory->positions.data(), static_cast<int>(trajectory->positions.size()), basePositions.data(), baseDirections.data());
233
234 logData.radius = extrusion->radius * extrusion->diameterScale * 1.05f;
235
236 std::vector<PositionNormalTexVertex> extrusionVertices;
237
238 generateExtrusionVertices(logData.radius, component.numSegments, data.basePositions, extrusionVertices);
239
240 const size_t numSamples = data.samples.size();
241
242 size_t texIdx = 0;
243 for (size_t s = 0; s < numSamples; ++s) {
244 for (size_t ss = 0; ss < component.numSegments; ++ss) {
245 extrusionVertices[texIdx++].tex = glm::vec2(logData.values[s], 0);
246 }
247 }
248
249 mesh->setVertexData(extrusionVertices.data(), extrusionVertices.size());
250
251 std::vector<unsigned int> extrusionIndices;
252
253 generateExtrusionIndices(static_cast<unsigned int>(data.basePositions.size()), component.numSegments, extrusionIndices);
254
255 mesh->setIndexData(extrusionIndices.data(), extrusionIndices.size());
256
257 mesh->setMeshFlag(MeshFlags::ClockwiseWinding);
258 }
259}
260
261void Cogs::Core::ExtrusionSystem::updateHighlightExtrusion(const ExtrusionComponent & component, Context * context, Mesh * mesh)
262{
263 const auto transform = component.getComponent<TransformComponent>();
264 const auto extrusionComponent = component.highlightTarget->getComponent<ExtrusionComponent>();
265 const auto extrusionTransform = extrusionComponent->getComponent<TransformComponent>();
266
267 if (!extrusionComponent->active) return;
268
269 context->transformSystem->copyTransform(extrusionTransform, transform);
270
271 TrajectoryComponent * trajectory;
272
273 if (extrusionComponent->extrusion) {
274 // Log
275 auto well = extrusionComponent->extrusion->getComponent<ExtrusionComponent>();
276 trajectory = well->trajectory->getComponent<TrajectoryComponent>();
277 } else {
278 // Wellbore
279 trajectory = extrusionComponent->trajectory->getComponent<TrajectoryComponent>();
280 }
281
282 const auto & targetData = getData<ExtrusionData>(extrusionComponent);
283 const auto & targetLogData = getData<ExtrusionLogData>(extrusionComponent);
284 auto & data = getData<ExtrusionData>(&component);
285
286 if (extrusionComponent->hasChanged() ||
287 trajectory->hasChanged() ||
288 component.hasChanged()) {
289 const float startDepth = std::max(component.highlightStart, trajectory->indexes[0]);
290 const float endDepth = std::min(component.highlightEnd, trajectory->indexes[trajectory->indexes.size() - 1]);
291 data.samples.clear();
292
293 SampleListGenerator::generateIndexedSamples<float>(
294 startDepth,
295 endDepth,
296 extrusionComponent->extrusion ? targetData.depthList.data() : trajectory->indexes.data(),
297 static_cast<int>(extrusionComponent->extrusion ? targetData.depthList.size() : trajectory->indexes.size()),
298 data.samples);
299
300 data.basePositions.resize(data.samples.size());
301 data.baseDirections.resize(data.samples.size());
302
303 PathGenerator::generateLinearPath(data.samples.data(), static_cast<int>(data.samples.size()), trajectory->indexes.data(), trajectory->positions.data(), static_cast<int>(trajectory->positions.size()), data.basePositions.data(), data.baseDirections.data());
304
305 if (data.samples.size() > 1) {
306 std::vector<PositionNormalTexVertex> extrusionVertices;
307
308 generateExtrusionVertices(extrusionComponent->extrusion ? targetLogData.radius * 1.05f : extrusionComponent->radius * 1.05f, component.numSegments, data.basePositions, extrusionVertices);
309
310 mesh->setVertexData(extrusionVertices.data(), extrusionVertices.size());
311
312 std::vector<unsigned int> extrusionIndices;
313
314 generateExtrusionIndices((unsigned int) data.basePositions.size(), component.numSegments, extrusionIndices);
315
316 mesh->setIndexes(std::move(extrusionIndices));
317
318 auto materialComponent = component.getComponent<MaterialComponent>();
319 materialComponent->blendMode = BlendMode::Add;
320 materialComponent->setChanged();
321
322 if (true) {
323 /*if (renderComponent->materialHandles[1] == MaterialInstanceHandle::NoHandle) {
324 renderComponent->materialHandles[1] = context->materialInstanceManager->createMaterialInstance(context->materialManager->getDefaultMaterial());
325 }
326
327 auto material = context->materialInstanceManager->get(renderComponent->materialHandles[1]);
328 material->setVec4Property(DefaultMaterial::DiffuseColor, glm::vec4(0, 0, 0, 1));
329
330 std::vector<uint32_t> outlineIndexes(component.numSegments * 4);
331 size_t index = 0;
332
333 for (uint32_t i = 0; i < component.numSegments; ++i) {
334 outlineIndexes[index++] = i;
335 outlineIndexes[index++] = (i < static_cast<size_t>(component.numSegments - 1)) ? i + 1 : 0;
336 }
337
338 const uint32_t baseOffset = static_cast<uint32_t>(data.basePositions.size() - 1) * component.numSegments;
339
340 for (uint32_t i = 0; i < component.numSegments; ++i) {
341 outlineIndexes[index++] = baseOffset + i;
342 outlineIndexes[index++] = baseOffset + ((i < static_cast<size_t>(component.numSegments - 1)) ? i + 1 : 0);
343 }
344
345 mesh->addSubMesh(outlineIndexes, PrimitiveType::LineList);*/
346 }
347
348 mesh->setMeshFlag(MeshFlags::ClockwiseWinding);
349 } else {
350 mesh->clear();
351 }
352 }
353}
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.
Definition: Context.h:83
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
Definition: MeshComponent.h:15
MeshHandle meshHandle
Handle to a Mesh resource to use when rendering.
Definition: MeshComponent.h:29
@ Add
Render with additive blending.
Contains geometry calculations and generation.
@ ClockwiseWinding
The mesh uses clockwise winding order for it's triangles as opposed to the counter-clockwise default.
Definition: Mesh.h:63
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
void setIndexes(std::span< const uint32_t > collection)
Set the index data to the collection given.
Definition: Mesh.h:596
void setMeshFlag(MeshFlags::EMeshFlags flag)
Set the given mesh flag.
Definition: Mesh.h:659
void setVertexData(Element *elements, size_t count)
Set vertex data.
Definition: Mesh.h:754
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
Data component defining a 3D trajectory, for example a Well trajectory.
static void generateTriangleIndices(int32_t *indices, int numSections, int numSegments, bool closed, bool useTexture, int32_t offset=0)
Generate legacy triangle extrusion indices.