3#include "Resources/Mesh.h"
4#include "Resources/MeshManager.h"
5#include "Resources/MaterialManager.h"
6#include "Resources/VertexFormats.h"
7#include "DataSet2DComponent.h"
8#include "Components/Core/MeshComponent.h"
9#include "Components/Appearance/MaterialComponent.h"
11#include "HeightMapSystem.h"
16 void updateVertices(std::vector<Cogs::Core::PositionNormalTexVertex>& V,
17 const std::vector<float>& values,
int Ni,
int Nj,
float minVal,
float maxVal,
18 float si,
float sj,
float sk,
19 bool gridLines,
const glm::vec3& gridLinesOffset,
22 V.resize((gridLines?2:1)*Ni*Nj);
27 float ukk = 1.f / std::max(std::numeric_limits<float>::epsilon(), maxVal - minVal);
29 float shiftX = 0.5f*si*(Ni - 1);
30 float shiftY = 0.5f*sj*(Nj - 1);
33 for (
int j = 0; j < Nj; j++) {
34 for (
int i = 0; i < Ni; i++) {
38 int jm = (j > 0 && std::isfinite(values[Ni*(j - 1) + i])) ? j - 1 : j;
39 int jp = (j < (Nj - 1) && std::isfinite(values[Ni *(j + 1) + i])) ? j + 1 : j;
41 int im = (i > 0 && std::isfinite(values[Ni*j + (i - 1)])) ? i - 1 : i;
42 int ip = (i < (Ni - 1) && std::isfinite(values[Ni*j + (i + 1)])) ? i + 1 : i;
44 float v = values[Ni*j + i]-minVal;
45 float di = (ip == im) ? 0 : (skk / (si*(ip - im)))*(values[Ni*j + ip] - values[Ni*j + im]);
46 float dj = (jp == jm) ? 0 : (skk / (sj*(jp - jm)))*(values[Ni*jp + i] - values[Ni*jm + i]);
47 glm::vec3 p(si*i-shiftX, sj*j-shiftY, skk*v);
48 glm::vec3 n = glm::normalize(glm::vec3(-di, -dj, 1.f));
50 glm::vec2 textureCoords;
51 if (textureDomain == Cogs::Core::HeightMapComponent::TextureDomain::Height) {
52 textureCoords = glm::vec2(ukk*v, 0.f);
55 textureCoords = glm::vec2(
static_cast<float>(i) / std::max(Ni - 1, 1),
56 static_cast<float>(j) / std::max(Nj - 1, 1));
59 *Vp++ = { p, n, textureCoords};
65 for (
int j = 0; j < Nj; j++) {
66 for (
int i = 0; i < Ni; i++) {
67 float v = values[Ni*j + i] - minVal;
68 glm::vec3 p(si*i - shiftX, sj*j - shiftY, skk*v);
69 *Vp++ = { p + gridLinesOffset, glm::vec3(0.f), glm::vec2(0.f) };
78 } isoLineCases[16] = {
80 { 1, { ((0 << 4) | 3) } },
81 { 1, { ((0 << 4) | 1) } },
82 { 1, { ((1 << 4) | 3) } },
83 { 1, { ((1 << 4) | 2) } },
84 { 2, { ((1 << 4) | 2), ((0 << 4) | 3) } },
85 { 1, { ((0 << 4) | 2) } },
86 { 1, { ((2 << 4) | 3) } },
87 { 1, { ((2 << 4) | 3) } },
88 { 1, { ((0 << 4) | 2) } },
89 { 2, { ((1 << 4) | 2), ((0 << 4) | 3) } },
90 { 1, { ((1 << 4) | 2) } },
91 { 1, { ((1 << 4) | 3) } },
92 { 1, { ((0 << 4) | 1) } },
93 { 1, { ((0 << 4) | 3) } },
97 void extractIsoLines(std::vector<Cogs::Core::PositionNormalTexVertex>& V,
98 std::vector<unsigned int>& lines,
99 const std::vector<float>& values,
int Ni,
int Nj,
100 float minValue,
float maxValue,
101 float isoOffset,
float isoDistance,
102 float zScale,
float zShift )
104 static const int maxIsoLevels = 1000;
105 float isoLevelsf = (maxValue - minValue) / isoDistance;
106 int isoLevels = int(std::floor( isoLevelsf )) + 1;
107 float scaleToInt = 1.f / isoDistance;
108 float minIsoLevel = isoOffset - std::floor(isoOffset - minValue);
111 if (!std::isfinite(scaleToInt) ||
112 !std::isfinite(minIsoLevel) ||
113 !std::isfinite(isoLevelsf) ||
114 (maxIsoLevels < isoLevels))
119 int Mi = std::max(0, Ni - 1);
120 int Mj = std::max(0, Nj - 1);
121 for (
int j = 0; j < Mj; j++) {
122 for (
int i = 0; i < Mi; i++) {
123 glm::ivec4 ix(Ni*j + i, Ni*(j + 1) + i, Ni*(j + 1) + i + 1, Ni*j + i + 1);
124 glm::vec4 _v(values[ix.x], values[ix.y], values[ix.z], values[ix.w]);
125 glm::vec4 v = scaleToInt*(_v - glm::vec4(minIsoLevel));
128 float vmin = glm::min(glm::min(v.x, v.y), glm::min(v.z, v.w));
129 float vmax = glm::max(glm::max(v.x, v.y), glm::max(v.z, v.w));
130 int l = glm::max(0,
int(glm::ceil(vmin)));
131 int h = glm::min(isoLevels,
int(glm::floor(vmax)));
134 for (
int k = l; k <= h; k++) {
137 float threshold = float(k);
138 glm::bvec4 m = glm::lessThan(v, glm::vec4(threshold));
142 for (
int o = 0; o < 4; o++) {
143 int op = (o + 1) & 3;
145 vix[o] = int(V.size());
146 float f0 = v[o] - threshold;
147 float f1 = v[op] - threshold;
153 t = glm::abs(f0) < glm::abs(f1) ? 0.f : 1.f;
155 glm::vec3 p = glm::mix(V[ix[o]].position, V[ix[op]].position, t);
156 p.z = zScale*p.z + zShift;
157 V.push_back({ p, glm::vec3(0.f), glm::vec2(threshold, 0.f) });
162 int code = (m.x ? 1 : 0) | (m.y ? 2 : 0) | (m.z ? 4 : 0) | (m.w ? 8 : 0);
163 for (
int o = 0; o <isoLineCases[code].n; o++) {
164 lines.push_back(vix[isoLineCases[code].e[o] >> 4]);
165 lines.push_back(vix[isoLineCases[code].e[o] & 3]);
172 void surfaceIndices(std::vector<unsigned int>& surface,
173 const std::vector<Cogs::Core::PositionNormalTexVertex>& V,
176 int Mi = std::max(0, Ni - 1);
177 int Mj = std::max(0, Nj - 1);
179 surface.reserve(6 * Mi*Mj);
180 for (
int j = 0; j < Mj; j++) {
181 for (
int i = 0; i < Mi; i++) {
183 float d0 = glm::dot(V[vo].normal, V[vo + Ni + 1].normal);
184 float d1 = glm::dot(V[vo+1].normal, V[vo + Ni].normal);
186 surface.push_back(vo);
187 surface.push_back(vo + 1);
188 surface.push_back(vo + Ni);
190 surface.push_back(vo + 1);
191 surface.push_back(vo + Ni + 1);
192 surface.push_back(vo + Ni);
195 surface.push_back(vo);
196 surface.push_back(vo + 1);
197 surface.push_back(vo + Ni + 1 );
199 surface.push_back(vo + Ni + 1);
200 surface.push_back(vo + Ni );
201 surface.push_back(vo);
209 void gridLineIndices(std::vector<unsigned int>& gridLines,
int Ni,
int Nj)
211 int Mi = std::max(0, Ni - 1);
212 int Mj = std::max(0, Nj - 1);
213 for (
int j = 0; j < Mj; j++) {
214 for (
int i = 0; i < Mi; i++) {
215 int vo = Ni*j + i + Ni*Nj;
216 gridLines.push_back(vo);
217 gridLines.push_back(vo + 1);
218 gridLines.push_back(vo);
219 gridLines.push_back(vo + Ni);
233 for (
auto & hmapComp :
pool) {
234 if (!hmapComp.dataSet) {
243 if (!dataSetComp || !meshComp || !matComp) {
247 if ((hmapComp.hasChanged() || dataSetComp->hasChanged()) && dataSetComp->hasData) {
249 meshComp->meshHandle =
context->meshManager->create();
251 auto mesh =
context->meshManager->get(meshComp->meshHandle);
253 float minValue = dataSetComp->minValue;
254 float maxValue = dataSetComp->maxValue;
255 if (std::isfinite(hmapComp.minValue) &&
256 std::isfinite(hmapComp.maxValue) &&
257 (hmapComp.minValue < hmapComp.maxValue))
259 minValue = hmapComp.minValue;
260 maxValue = hmapComp.maxValue;
263 std::vector<Cogs::Core::PositionNormalTexVertex> V;
264 updateVertices(V, dataSetComp->data, dataSetComp->sizeI, dataSetComp->sizeJ, minValue, maxValue,
265 hmapComp.xIncrement, hmapComp.yIncrement, hmapComp.height,
266 hmapComp.gridLines, hmapComp.gridLineOffset, hmapComp.textureDomain );
268 std::vector<unsigned int> surface;
269 surfaceIndices(surface, V, dataSetComp->sizeI, dataSetComp->sizeJ);
271 std::vector<unsigned int> gridLines;
272 if (hmapComp.gridLines) {
273 gridLineIndices(gridLines, dataSetComp->sizeI, dataSetComp->sizeJ);
276 std::vector<unsigned int> isoLines;
277 float isoLineOrigin = hmapComp.isoLineOrigin;
278 float isoLineDistance = hmapComp.isoLineDistance;
279 if (!std::isfinite(isoLineOrigin) || !std::isfinite(isoLineDistance)) {
280 isoLineOrigin = minValue;
281 isoLineDistance = (maxValue - minValue) / 10.f;
283 switch (hmapComp.isoLine)
288 extractIsoLines(V, isoLines,
289 dataSetComp->data, dataSetComp->sizeI, dataSetComp->sizeJ,
291 isoLineOrigin, isoLineDistance,
292 1.f, hmapComp.gridLineOffset.z );
295 extractIsoLines(V, isoLines,
296 dataSetComp->data, dataSetComp->sizeI, dataSetComp->sizeJ,
298 isoLineOrigin, isoLineDistance,
299 0.f, (maxValue-minValue)*hmapComp.height);
302 extractIsoLines(V, isoLines,
303 dataSetComp->data, dataSetComp->sizeI, dataSetComp->sizeJ,
305 isoLineOrigin, isoLineDistance,
310 glm::vec3 extent(dataSetComp->sizeI*hmapComp.xIncrement,
311 dataSetComp->sizeJ*hmapComp.yIncrement,
312 hmapComp.height*(maxValue-minValue));
314 mesh->setBounds({ glm::vec3(-0.5f*extent.x, -0.5f*extent.y, glm::min(extent.z, 0.f)),
315 glm::vec3(0.5f*extent.x, 0.5*extent.y, glm::max(extent.z, 0.f)) });
316 mesh->setVertexData(V.data(), V.size());
318 mesh->clearIndexes();
324 matComp->depthBiasConstant = 1.0f;
325 matComp->depthBiasSlope = 1.0f;
327 matComp->depthBiasConstant = 0.0f;
328 matComp->depthBiasSlope = 0.0f;
334 if (hmapComp.colorMap) {
338 matComp->diffuseMap = cmapComp->diffuseMap;
void setChanged()
Sets the component to the ComponentFlags::Changed state with carry.
ComponentType * getComponent() const
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 a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
Contains all Cogs related functionality.
@ Bottom
Iso-line on bottom of bounding box.
@ Top
Iso-line on top of bounding box.
@ XY
compute texture coordinates based on the height of the points
Exposes material properties for legacy entities and code.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
@ TriangleList
List of triangles.