1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "mesh_util.h"
17
18 #include <algorithm>
19
20 #include <3d/ecs/components/material_component.h>
21 #include <3d/ecs/components/name_component.h>
22 #include <3d/ecs/components/render_mesh_component.h>
23 #include <3d/ecs/components/uri_component.h>
24 #include <3d/ecs/systems/intf_node_system.h>
25 #include <3d/implementation_uids.h>
26 #include <3d/render/default_material_constants.h>
27 #include <3d/util/intf_mesh_builder.h>
28 #include <base/containers/vector.h>
29 #include <base/math/quaternion_util.h>
30 #include <base/math/vector.h>
31 #include <core/ecs/intf_ecs.h>
32 #include <core/intf_engine.h>
33 #include <core/log.h>
34 #include <core/namespace.h>
35 #include <core/plugin/intf_class_factory.h>
36 #include <render/device/intf_shader_manager.h>
37 #include <render/implementation_uids.h>
38 #include <render/intf_render_context.h>
39
40 #include "util/uri_lookup.h"
41
42 CORE3D_BEGIN_NAMESPACE()
43 using namespace BASE_NS;
44 using namespace CORE_NS;
45 using namespace RENDER_NS;
46
47 namespace {
48 constexpr Math::Vec3 PLANE_NORM[6u] = {
49 Math::Vec3(0.0f, 1.0f, 0.0f),
50 Math::Vec3(0.0f, 1.0f, 0.0f),
51 Math::Vec3(0.0f, 1.0f, 0.0f),
52
53 Math::Vec3(0.0f, 1.0f, 0.0f),
54 Math::Vec3(0.0f, 1.0f, 0.0f),
55 Math::Vec3(0.0f, 1.0f, 0.0f),
56 };
57
58 constexpr Math::Vec2 PLANE_UV[6u] = {
59 Math::Vec2(1.0f, 1.0f),
60 Math::Vec2(1.0f, 0.0f),
61 Math::Vec2(0.0f, 1.0f),
62
63 Math::Vec2(1.0f, 0.0f),
64 Math::Vec2(0.0f, 0.0f),
65 Math::Vec2(0.0f, 1.0f),
66 };
67
68 constexpr uint16_t PLANE_IND[] = { 0u, 1u, 2u, 3u, 4u, 5u };
69
70 constexpr Math::Vec3 CUBE_POS[8u] = {
71 Math::Vec3(-0.5f, -0.5f, -0.5f), //
72 Math::Vec3(0.5f, -0.5f, -0.5f), //
73 Math::Vec3(0.5f, 0.5f, -0.5f), //
74 Math::Vec3(-0.5f, 0.5f, -0.5f), //
75 Math::Vec3(-0.5f, -0.5f, 0.5f), //
76 Math::Vec3(0.5f, -0.5f, 0.5f), //
77 Math::Vec3(0.5f, 0.5f, 0.5f), //
78 Math::Vec3(-0.5f, 0.5f, 0.5f) //
79 };
80
81 constexpr Math::Vec2 CUBE_UV[4u] = { Math::Vec2(1.0f, 1.0f), Math::Vec2(0.0f, 1.0f), Math::Vec2(0.0f, 0.0f),
82 Math::Vec2(1.0f, 0.0f) };
83
84 constexpr uint16_t CUBE_INDICES[6u * 6u] = {
85 0, 3, 1, 3, 2, 1, //
86 1, 2, 5, 2, 6, 5, //
87 5, 6, 4, 6, 7, 4, //
88 4, 7, 0, 7, 3, 0, //
89 3, 7, 2, 7, 6, 2, //
90 4, 0, 5, 0, 1, 5 //
91 };
92
93 constexpr uint32_t CUBE_UV_INDICES[6u] = { 0, 3, 1, 3, 2, 1 };
94
95 constexpr float TWO_PI = Math::PI * 2.0f;
96
97 template<typename IndexType>
98 struct Geometry {
99 vector<Math::Vec3>& vertices;
100 vector<Math::Vec3>& normals;
101 vector<Math::Vec2>& uvs;
102 vector<IndexType>& indices;
103 };
104
GenerateCubeGeometry(float width,float height,float depth,Geometry<uint16_t> geometry)105 void GenerateCubeGeometry(float width, float height, float depth, Geometry<uint16_t> geometry)
106 {
107 vector<Math::Vec3>& vertices = geometry.vertices;
108 vector<Math::Vec3>& normals = geometry.normals;
109 vector<Math::Vec2>& uvs = geometry.uvs;
110 vector<uint16_t>& indices = geometry.indices;
111
112 vertices.reserve(countof(CUBE_INDICES));
113 normals.reserve(countof(CUBE_INDICES));
114 uvs.reserve(countof(CUBE_INDICES));
115 indices.reserve(countof(CUBE_INDICES));
116
117 constexpr size_t triangleCount = countof(CUBE_INDICES) / 3u;
118 for (size_t i = 0; i < triangleCount; ++i) {
119 const size_t vertexIndex = i * 3u;
120
121 const Math::Vec3 v0 = CUBE_POS[CUBE_INDICES[vertexIndex + 0u]];
122 const Math::Vec3 v1 = CUBE_POS[CUBE_INDICES[vertexIndex + 1u]];
123 const Math::Vec3 v2 = CUBE_POS[CUBE_INDICES[vertexIndex + 2u]];
124
125 vertices.emplace_back(v0.x * width, v0.y * height, v0.z * depth);
126 vertices.emplace_back(v1.x * width, v1.y * height, v1.z * depth);
127 vertices.emplace_back(v2.x * width, v2.y * height, v2.z * depth);
128
129 const Math::Vec3 normal = Math::Normalize(Math::Cross((v1 - v0), (v2 - v0)));
130 normals.insert(normals.end(), 3u, normal);
131
132 uvs.emplace_back(
133 CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 0u) % 6u]].x, CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 0u) % 6u]].y);
134 uvs.emplace_back(
135 CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 1u) % 6u]].x, CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 1u) % 6u]].y);
136 uvs.emplace_back(
137 CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 2u) % 6u]].x, CUBE_UV[CUBE_UV_INDICES[(vertexIndex + 2u) % 6u]].y);
138 }
139
140 for (uint16_t i = 0u; i < countof(CUBE_INDICES); ++i) {
141 indices.push_back(i);
142 }
143 }
144
GenerateSphereGeometry(float radius,uint32_t rings,uint32_t sectors,Geometry<uint32_t> geometry)145 void GenerateSphereGeometry(float radius, uint32_t rings, uint32_t sectors, Geometry<uint32_t> geometry)
146 {
147 vector<Math::Vec3>& vertices = geometry.vertices;
148 vector<Math::Vec3>& normals = geometry.normals;
149 vector<Math::Vec2>& uvs = geometry.uvs;
150 vector<uint32_t>& indices = geometry.indices;
151
152 const size_t maxVertexCount = rings * sectors;
153 const size_t maxIndexCount = (rings - 1) * sectors * 6u;
154
155 vertices.reserve(maxVertexCount);
156 normals.reserve(maxVertexCount);
157 uvs.reserve(maxVertexCount);
158 indices.reserve(maxIndexCount);
159
160 const float r = 1.0f / static_cast<float>(rings - 1);
161 const float s = 1.0f / static_cast<float>(sectors - 1);
162
163 constexpr float pi = Math::PI;
164 constexpr float halfPi = Math::PI * 0.5f;
165
166 for (uint32_t ring = 0; ring < rings; ++ring) {
167 const auto ringF = static_cast<float>(ring);
168 for (uint32_t sector = 0; sector < sectors; ++sector) {
169 const auto sectorF = static_cast<float>(sector);
170 const float y = Math::sin(-halfPi + pi * ringF * r);
171 const float x = Math::cos(TWO_PI * sectorF * s) * Math::sin(pi * ringF * r);
172 const float z = Math::sin(TWO_PI * sectorF * s) * Math::sin(pi * ringF * r);
173
174 vertices.emplace_back(x * radius, y * radius, z * radius);
175 normals.emplace_back(x, y, z);
176 uvs.emplace_back(sectorF * s, ringF * r);
177
178 if (ring < rings - 1) {
179 const uint32_t curRow = ring * sectors;
180 const uint32_t nextRow = (ring + 1) * sectors;
181 const uint32_t nextS = (sector + 1) % sectors;
182
183 indices.push_back(curRow + sector);
184 indices.push_back(nextRow + sector);
185 indices.push_back(nextRow + nextS);
186
187 indices.push_back(curRow + sector);
188 indices.push_back(nextRow + nextS);
189 indices.push_back(curRow + nextS);
190 }
191 }
192 }
193 }
194
GenerateConeCap(float radius,float length,uint32_t sectors,Geometry<uint32_t> geometry,const vector<Math::Vec2> & unitCoords)195 void GenerateConeCap(
196 float radius, float length, uint32_t sectors, Geometry<uint32_t> geometry, const vector<Math::Vec2>& unitCoords)
197 {
198 vector<Math::Vec3>& vertices = geometry.vertices;
199 vector<Math::Vec3>& normals = geometry.normals;
200 vector<Math::Vec2>& uvs = geometry.uvs;
201 vector<uint32_t>& indices = geometry.indices;
202
203 // Already generated vertices: tip + sectors
204 uint32_t startVertex = 1U + sectors;
205
206 // Cap center vert.
207 const uint32_t bottomIndex = startVertex;
208 vertices.emplace_back(0.0f, 0.0f, length);
209 normals.emplace_back(0.0f, 0.0f, 1.0f);
210 uvs.emplace_back(0.5f, 0.5f);
211
212 ++startVertex;
213
214 // Cap ring and triangles.
215 for (uint32_t idx = 0; idx < sectors; ++idx) {
216 const uint32_t vertexIndex = startVertex + idx;
217
218 const Math::Vec2& coords = unitCoords[idx];
219
220 vertices.emplace_back(coords.x * radius, coords.y * radius, length);
221 normals.emplace_back(0.0f, 0.0f, 1.0f);
222
223 float uvx = (coords.x + 1.0f) * 0.5f;
224 float uvy = 1.0f - (coords.y + 1.0f) * 0.5f;
225 uvs.emplace_back(uvx, uvy);
226
227 const uint32_t nextVertexIndex = startVertex + ((idx + 1) % sectors);
228
229 indices.push_back(vertexIndex);
230 indices.push_back(nextVertexIndex);
231 indices.push_back(bottomIndex);
232 }
233 }
234
GenerateConeGeometry(float radius,float length,uint32_t sectors,Geometry<uint32_t> geometry)235 void GenerateConeGeometry(float radius, float length, uint32_t sectors, Geometry<uint32_t> geometry)
236 {
237 vector<Math::Vec3>& vertices = geometry.vertices;
238 vector<Math::Vec3>& normals = geometry.normals;
239 vector<Math::Vec2>& uvs = geometry.uvs;
240 vector<uint32_t>& indices = geometry.indices;
241
242 const float s = (sectors > 0U) ? (1.0f / static_cast<float>(sectors)) : 1.0f;
243
244 const size_t maxVertexCount = (2 * static_cast<size_t>(sectors)) + 2u;
245 const size_t maxIndexCount = static_cast<size_t>(sectors) * 6u;
246
247 vertices.reserve(maxVertexCount);
248 normals.reserve(maxVertexCount);
249 uvs.reserve(maxVertexCount);
250 indices.reserve(maxIndexCount);
251
252 vector<Math::Vec2> unitCoords;
253 unitCoords.reserve(sectors);
254
255 vertices.emplace_back(0.0f, 0.0f, 0.0f);
256 normals.emplace_back(0.0f, 0.0f, -1.0f);
257 uvs.emplace_back(0.5f, 0.5f);
258
259 // Bottom ring vertices and side triangles, with given radius
260 const uint32_t startVertex = 1U;
261 for (uint32_t idx = 0; idx < sectors; ++idx) {
262 const auto idxF = static_cast<float>(idx);
263 const float x = Math::cos(idxF * s * TWO_PI);
264 const float y = Math::sin(idxF * s * TWO_PI);
265 unitCoords.emplace_back(x, y);
266
267 vertices.emplace_back(x * radius, y * radius, length);
268 normals.emplace_back(x, y, 0.f);
269
270 float uvx = (x + 1.0f) * 0.5f;
271 float uvy = 1.0f - (y + 1.0f) * 0.5f;
272 uvs.emplace_back(uvx, uvy);
273
274 const uint32_t v0 = 0;
275 const uint32_t v1 = startVertex + idx;
276 if (sectors == 0) {
277 return;
278 }
279 const uint32_t v2 = startVertex + ((idx + 1) % sectors);
280
281 indices.push_back(v0);
282 indices.push_back(v2);
283 indices.push_back(v1);
284 }
285
286 constexpr bool generateCapping = true;
287 if constexpr (generateCapping) {
288 GenerateConeCap(radius, length, sectors, geometry, unitCoords);
289 }
290 }
291
GenerateTorusSlices(float minorRadius,uint32_t minorSectors,float minorStep)292 vector<Math::Vec3> GenerateTorusSlices(float minorRadius, uint32_t minorSectors, float minorStep)
293 {
294 vector<Math::Vec3> tubeSlice;
295 tubeSlice.reserve(minorSectors);
296 for (uint32_t tube = 0; tube < minorSectors; tube++) {
297 const float minorRadians = static_cast<float>(tube) * minorStep;
298 const float x = 0.0f;
299 const float y = Math::cos(minorRadians) * minorRadius;
300 const float z = Math::sin(minorRadians) * minorRadius;
301 tubeSlice.emplace_back(x, y, z);
302 }
303 return tubeSlice;
304 }
305
GenerateTorusGeometry(float majorRadius,float minorRadius,uint32_t majorSectors,uint32_t minorSectors,Geometry<uint32_t> geometry)306 void GenerateTorusGeometry(
307 float majorRadius, float minorRadius, uint32_t majorSectors, uint32_t minorSectors, Geometry<uint32_t> geometry)
308 {
309 vector<Math::Vec3>& vertices = geometry.vertices;
310 vector<Math::Vec3>& normals = geometry.normals;
311 vector<Math::Vec2>& uvs = geometry.uvs;
312 vector<uint32_t>& indices = geometry.indices;
313
314 const float majorStep = TWO_PI / static_cast<float>(majorSectors);
315 const float minorStep = TWO_PI / static_cast<float>(minorSectors);
316
317 const size_t maxVertexCount = static_cast<size_t>(majorSectors) * static_cast<size_t>(minorSectors);
318 const size_t maxIndexCount = maxVertexCount * 6u;
319
320 vertices.reserve(maxVertexCount);
321 normals.reserve(maxVertexCount);
322 uvs.reserve(maxVertexCount);
323 indices.reserve(maxIndexCount);
324
325 const vector<Math::Vec3> tubeSlice = GenerateTorusSlices(minorRadius, minorSectors, minorStep);
326
327 uint32_t currentVertexIndex = 0;
328 for (uint32_t ring = 0; ring < majorSectors; ring++) {
329 const float majorRadians = static_cast<float>(ring) * majorStep;
330 const auto rotation = Math::AngleAxis(majorRadians, { 0.0f, 1.0f, 0.0f });
331 const auto translation = Math::Vec3(0.0f, 0.0f, 1.0f) * majorRadius;
332
333 for (uint32_t vertexIndex = 0; vertexIndex < minorSectors; vertexIndex++) {
334 const auto& ringVertex = tubeSlice[vertexIndex];
335
336 const auto tubeCenter = rotation * translation;
337
338 vertices.push_back(rotation * ringVertex + tubeCenter);
339
340 normals.push_back(Math::Normalize(rotation * ringVertex));
341
342 const float minorRadians = static_cast<float>(vertexIndex) * minorStep;
343 const float tx = 1.0f - Math::abs(majorRadians / TWO_PI * 2.0f - 1.0f);
344 const float ty = 1.0f - Math::abs(minorRadians / TWO_PI * 2.0f - 1.0f);
345 uvs.emplace_back(tx, ty);
346
347 const uint32_t i0 = currentVertexIndex;
348 const uint32_t i1 = (i0 + 1) % maxVertexCount;
349 const uint32_t i2 = (i0 + minorSectors) % maxVertexCount;
350 const uint32_t i3 = (i2 + 1) % maxVertexCount;
351
352 indices.push_back(i0);
353 indices.push_back(i1);
354 indices.push_back(i2);
355
356 indices.push_back(i1);
357 indices.push_back(i3);
358 indices.push_back(i2);
359
360 currentVertexIndex++;
361 }
362 }
363 }
364 } // namespace
365
366 template<typename IndexType>
CalculateTangentImpl(const array_view<const IndexType> & indices,const array_view<const Math::Vec3> & positions,const array_view<const Math::Vec3> & normals,const array_view<const Math::Vec2> & uvs,array_view<Math::Vec4> & outTangents)367 void CalculateTangentImpl(const array_view<const IndexType>& indices, const array_view<const Math::Vec3>& positions,
368 const array_view<const Math::Vec3>& normals, const array_view<const Math::Vec2>& uvs,
369 array_view<Math::Vec4>& outTangents)
370 {
371 // http://www.terathon.com/code/tangent.html
372 vector<Math::Vec3> tan(positions.size(), { 0, 0, 0 });
373 vector<Math::Vec3> bitan(positions.size(), { 0, 0, 0 });
374
375 for (size_t i = 0; i < indices.size(); i += 3u) {
376 const IndexType aa = indices[i + 0u];
377 const IndexType bb = indices[i + 1u];
378 const IndexType cc = indices[i + 2u];
379
380 const Math::Vec2& uv1 = uvs[aa];
381 const Math::Vec2& uv2 = uvs[bb];
382 const Math::Vec2& uv3 = uvs[cc];
383
384 const auto st1 = uv2 - uv1;
385 const auto st2 = uv3 - uv1;
386
387 auto d = Math::Cross(st1, st2);
388 if (Math::abs(d) < Math::EPSILON) {
389 d = Math::EPSILON;
390 }
391 const float r = 1.0f / d;
392
393 const Math::Vec3& v1 = positions[aa];
394 const Math::Vec3& v2 = positions[bb];
395 const Math::Vec3& v3 = positions[cc];
396
397 const auto e1 = v2 - v1;
398 const auto e2 = v3 - v1;
399
400 const Math::Vec3 sdir { (e1 * st2.y - e2 * st1.y) * r };
401 tan[aa] += sdir;
402 tan[bb] += sdir;
403 tan[cc] += sdir;
404
405 const Math::Vec3 tdir { (e2 * st1.x - e1 * st2.x) * r };
406
407 bitan[aa] += tdir;
408 bitan[bb] += tdir;
409 bitan[cc] += tdir;
410 }
411
412 for (size_t i = 0; i < positions.size(); i++) {
413 const Math::Vec3& n = normals[i];
414 const Math::Vec3& t = tan[i];
415
416 // Gram-Schmidt orthogonalize
417 const Math::Vec3 tmp = Math::Normalize(t - n * Math::Dot(n, t));
418
419 // Calculate handedness
420 const float w = (Math::Dot(Math::Cross(n, t), bitan[i]) < 0.0F) ? 1.0F : -1.0F;
421
422 outTangents[i] = Math::Vec4(tmp.x, tmp.y, tmp.z, w);
423 }
424 }
425
CalculateTangents(const array_view<const uint32_t> & indices,const array_view<const Math::Vec3> & positions,const array_view<const Math::Vec3> & normals,const array_view<const Math::Vec2> & uvs,array_view<Math::Vec4> outTangents)426 void MeshUtil::CalculateTangents(const array_view<const uint32_t>& indices,
427 const array_view<const Math::Vec3>& positions, const array_view<const Math::Vec3>& normals,
428 const array_view<const Math::Vec2>& uvs, array_view<Math::Vec4> outTangents)
429 {
430 CalculateTangentImpl<uint32_t>(indices, positions, normals, uvs, outTangents);
431 }
432
CalculateTangents(const array_view<const uint16_t> & indices,const array_view<const Math::Vec3> & positions,const array_view<const Math::Vec3> & normals,const array_view<const Math::Vec2> & uvs,array_view<Math::Vec4> outTangents)433 void MeshUtil::CalculateTangents(const array_view<const uint16_t>& indices,
434 const array_view<const Math::Vec3>& positions, const array_view<const Math::Vec3>& normals,
435 const array_view<const Math::Vec2>& uvs, array_view<Math::Vec4> outTangents)
436 {
437 CalculateTangentImpl<uint16_t>(indices, positions, normals, uvs, outTangents);
438 }
439
CalculateTangents(const array_view<const uint8_t> & indices,const array_view<const Math::Vec3> & positions,const array_view<const Math::Vec3> & normals,const array_view<const Math::Vec2> & uvs,array_view<Math::Vec4> outTangents)440 void MeshUtil::CalculateTangents(const array_view<const uint8_t>& indices,
441 const array_view<const Math::Vec3>& positions, const array_view<const Math::Vec3>& normals,
442 const array_view<const Math::Vec2>& uvs, array_view<Math::Vec4> outTangents)
443 {
444 CalculateTangentImpl<uint8_t>(indices, positions, normals, uvs, outTangents);
445 }
446
447 template<typename T>
FillData(array_view<const T> c)448 constexpr inline IMeshBuilder::DataBuffer FillData(array_view<const T> c) noexcept
449 {
450 Format format = BASE_FORMAT_UNDEFINED;
451 if constexpr (is_same_v<T, Math::Vec2>) {
452 format = BASE_FORMAT_R32G32_SFLOAT;
453 } else if constexpr (is_same_v<T, Math::Vec3>) {
454 format = BASE_FORMAT_R32G32B32_SFLOAT;
455 } else if constexpr (is_same_v<T, Math::Vec4>) {
456 format = BASE_FORMAT_R32G32B32A32_SFLOAT;
457 } else if constexpr (is_same_v<T, uint16_t>) {
458 format = BASE_FORMAT_R16_UINT;
459 } else if constexpr (is_same_v<T, uint32_t>) {
460 format = BASE_FORMAT_R32_UINT;
461 }
462 return IMeshBuilder::DataBuffer { format, sizeof(T),
463 { reinterpret_cast<const uint8_t*>(c.data()), c.size() * sizeof(T) } };
464 }
465
466 template<typename T, size_t N>
FillData(const T (& c)[N])467 constexpr inline IMeshBuilder::DataBuffer FillData(const T (&c)[N]) noexcept
468 {
469 return FillData(array_view(c, N));
470 }
471
472 template<typename T>
FillData(const vector<T> & c)473 constexpr inline IMeshBuilder::DataBuffer FillData(const vector<T>& c) noexcept
474 {
475 return FillData(array_view<const T> { c });
476 }
477
GeneratePlaneMesh(const IEcs & ecs,const string_view name,Entity material,float width,float depth)478 Entity MeshUtil::GeneratePlaneMesh(const IEcs& ecs, const string_view name, Entity material, float width, float depth)
479 {
480 const float extentX = width * 0.5f;
481 const float extentZ = depth * 0.5f;
482
483 const Math::Vec3 pos[6u] = {
484 Math::Vec3(-extentX, 0.0f, -extentZ),
485 Math::Vec3(-extentX, 0.0f, extentZ),
486 Math::Vec3(extentX, 0.0f, -extentZ),
487
488 Math::Vec3(-extentX, 0.0f, extentZ),
489 Math::Vec3(extentX, 0.0f, extentZ),
490 Math::Vec3(extentX, 0.0f, -extentZ),
491 };
492 vector<Math::Vec4> tangents(countof(pos));
493 {
494 constexpr auto indicesView = array_view(PLANE_IND);
495 const auto positionsView = array_view(pos);
496 constexpr auto normalsView = array_view(PLANE_NORM);
497 constexpr auto uvsView = array_view(PLANE_UV);
498
499 CalculateTangents(indicesView, positionsView, normalsView, uvsView, tangents);
500 }
501
502 IMeshBuilder::Submesh submesh;
503 submesh.material = material;
504 submesh.vertexCount = 6u;
505 submesh.indexCount = 6u;
506 submesh.indexType = CORE_INDEX_TYPE_UINT16;
507 submesh.tangents = true;
508
509 auto builder = InitializeBuilder(submesh);
510
511 auto positionData = FillData(pos);
512 auto normalData = FillData(PLANE_NORM);
513 auto uvData = FillData(PLANE_UV);
514 auto tangentData = FillData(tangents);
515 IMeshBuilder::DataBuffer dummy {};
516 builder->SetVertexData(0, positionData, normalData, uvData, dummy, tangentData, dummy);
517
518 builder->CalculateAABB(0, positionData);
519
520 auto indices = FillData(PLANE_IND);
521 builder->SetIndexData(0, indices);
522
523 return CreateMesh(ecs, *builder, name);
524 }
525
GenerateSphereMesh(const IEcs & ecs,const string_view name,Entity material,float radius,uint32_t rings,uint32_t sectors)526 Entity MeshUtil::GenerateSphereMesh(
527 const IEcs& ecs, const string_view name, Entity material, float radius, uint32_t rings, uint32_t sectors)
528 {
529 vector<Math::Vec3> vertices;
530 vector<Math::Vec3> normals;
531 vector<Math::Vec2> uvs;
532 vector<uint32_t> indices;
533 GenerateSphereGeometry(radius, rings, sectors, { vertices, normals, uvs, indices });
534
535 vector<Math::Vec4> tangents(vertices.size());
536 CalculateTangents(indices, vertices, normals, uvs, tangents);
537
538 IMeshBuilder::Submesh submesh;
539 submesh.material = material;
540 submesh.vertexCount = static_cast<uint32_t>(vertices.size());
541 submesh.indexCount = static_cast<uint32_t>(indices.size());
542 submesh.indexType = submesh.vertexCount <= UINT16_MAX ? CORE_INDEX_TYPE_UINT16 : CORE_INDEX_TYPE_UINT32;
543 submesh.tangents = true;
544
545 auto builder = InitializeBuilder(submesh);
546
547 auto positionData = FillData(vertices);
548 auto normalData = FillData(normals);
549 auto uvData = FillData(uvs);
550 auto tangentData = FillData(tangents);
551 IMeshBuilder::DataBuffer dummy {};
552 builder->SetVertexData(0, positionData, normalData, uvData, dummy, tangentData, dummy);
553
554 builder->CalculateAABB(0, positionData);
555
556 auto indexData = FillData(indices);
557 builder->SetIndexData(0, indexData);
558
559 return CreateMesh(ecs, *builder, name);
560 }
561
GenerateConeMesh(const IEcs & ecs,const string_view name,Entity material,float radius,float length,uint32_t sectors)562 Entity MeshUtil::GenerateConeMesh(
563 const IEcs& ecs, const string_view name, Entity material, float radius, float length, uint32_t sectors)
564 {
565 vector<Math::Vec3> vertices;
566 vector<Math::Vec3> normals;
567 vector<Math::Vec2> uvs;
568 vector<uint32_t> indices;
569 GenerateConeGeometry(radius, length, sectors, { vertices, normals, uvs, indices });
570
571 IMeshBuilder::Submesh submesh;
572 submesh.material = material;
573 submesh.vertexCount = static_cast<uint32_t>(vertices.size());
574 submesh.indexCount = static_cast<uint32_t>(indices.size());
575 submesh.indexType = submesh.vertexCount <= UINT16_MAX ? CORE_INDEX_TYPE_UINT16 : CORE_INDEX_TYPE_UINT32;
576 submesh.tangents = true;
577
578 vector<Math::Vec4> tangents(vertices.size());
579 CalculateTangents(indices, vertices, normals, uvs, tangents);
580
581 auto builder = InitializeBuilder(submesh);
582
583 auto positionData = FillData(vertices);
584 auto normalData = FillData(normals);
585 auto uvData = FillData(uvs);
586 auto tangentData = FillData(tangents);
587 IMeshBuilder::DataBuffer dummy {};
588 builder->SetVertexData(0, positionData, normalData, uvData, dummy, tangentData, dummy);
589
590 builder->CalculateAABB(0, positionData);
591
592 auto indexData = FillData(indices);
593 builder->SetIndexData(0, indexData);
594
595 return CreateMesh(ecs, *builder, name);
596 }
597
GenerateTorusMesh(const IEcs & ecs,const string_view name,Entity material,float majorRadius,float minorRadius,uint32_t majorSectors,uint32_t minorSectors)598 Entity MeshUtil::GenerateTorusMesh(const IEcs& ecs, const string_view name, Entity material, float majorRadius,
599 float minorRadius, uint32_t majorSectors, uint32_t minorSectors)
600 {
601 vector<Math::Vec3> vertices;
602 vector<Math::Vec3> normals;
603 vector<Math::Vec2> uvs;
604 vector<uint32_t> indices;
605 GenerateTorusGeometry(majorRadius, minorRadius, majorSectors, minorSectors, { vertices, normals, uvs, indices });
606
607 vector<Math::Vec4> tangents(vertices.size());
608 CalculateTangents(indices, vertices, normals, uvs, tangents);
609
610 IMeshBuilder::Submesh submesh;
611 submesh.material = material;
612 submesh.vertexCount = static_cast<uint32_t>(vertices.size());
613 submesh.indexCount = static_cast<uint32_t>(indices.size());
614 submesh.indexType = submesh.vertexCount <= UINT16_MAX ? CORE_INDEX_TYPE_UINT16 : CORE_INDEX_TYPE_UINT32;
615 submesh.tangents = true;
616
617 auto builder = InitializeBuilder(submesh);
618
619 auto positionData = FillData(vertices);
620 auto normalData = FillData(normals);
621 auto uvData = FillData(uvs);
622 auto tangentData = FillData(tangents);
623 IMeshBuilder::DataBuffer dummy {};
624 builder->SetVertexData(0, positionData, normalData, uvData, dummy, tangentData, dummy);
625
626 builder->CalculateAABB(0, positionData);
627
628 auto indexData = FillData(indices);
629 builder->SetIndexData(0, indexData);
630
631 return CreateMesh(ecs, *builder, name);
632 }
633
GenerateCubeMesh(const IEcs & ecs,const string_view name,Entity material,float width,float height,float depth)634 Entity MeshUtil::GenerateCubeMesh(
635 const IEcs& ecs, const string_view name, Entity material, float width, float height, float depth)
636 {
637 vector<Math::Vec3> positions;
638 vector<Math::Vec3> normals;
639 vector<Math::Vec2> uvs;
640 vector<uint16_t> indices;
641 GenerateCubeGeometry(width, height, depth, { positions, normals, uvs, indices });
642
643 vector<Math::Vec4> tangents(positions.size());
644 CalculateTangents(indices, positions, normals, uvs, tangents);
645
646 IMeshBuilder::Submesh submesh;
647 submesh.material = material;
648 submesh.vertexCount = static_cast<uint32_t>(countof(CUBE_INDICES));
649 submesh.indexCount = static_cast<uint32_t>(countof(CUBE_INDICES));
650 submesh.indexType = CORE_INDEX_TYPE_UINT16;
651 submesh.tangents = true;
652
653 auto builder = InitializeBuilder(submesh);
654
655 auto positionData = FillData(positions);
656 auto normalData = FillData(normals);
657 auto uvData = FillData(uvs);
658 auto tangentData = FillData(tangents);
659 IMeshBuilder::DataBuffer dummy {};
660 builder->SetVertexData(0, positionData, normalData, uvData, dummy, tangentData, dummy);
661
662 builder->CalculateAABB(0, positionData);
663
664 auto indexData = FillData(indices);
665 builder->SetIndexData(0, indexData);
666
667 return CreateMesh(ecs, *builder, name);
668 }
669
GenerateEntity(const IEcs & ecs,const string_view name,Entity meshHandle)670 Entity MeshUtil::GenerateEntity(const IEcs& ecs, const string_view name, Entity meshHandle)
671 {
672 INodeSystem* nodesystem = GetSystem<INodeSystem>(ecs);
673 CORE_ASSERT(nodesystem);
674
675 // Create node to scene.
676 ISceneNode* node = nodesystem->CreateNode();
677 if (!node) {
678 return Entity {};
679 }
680
681 node->SetName(name);
682
683 // Add render mesh component.
684 IRenderMeshComponentManager* renderMeshManager = GetManager<IRenderMeshComponentManager>(ecs);
685 CORE_ASSERT(renderMeshManager);
686
687 RenderMeshComponent component = CreateComponent(*renderMeshManager, node->GetEntity());
688 component.mesh = meshHandle;
689 renderMeshManager->Set(node->GetEntity(), component);
690
691 return node->GetEntity();
692 }
693
GenerateCube(const IEcs & ecs,const string_view name,Entity material,float width,float height,float depth)694 Entity MeshUtil::GenerateCube(
695 const IEcs& ecs, const string_view name, Entity material, float width, float height, float depth)
696 {
697 const Entity meshHandle = GenerateCubeMesh(ecs, name, material, width, height, depth);
698 return GenerateEntity(ecs, name, meshHandle);
699 }
700
GeneratePlane(const IEcs & ecs,const string_view name,Entity material,float width,float depth)701 Entity MeshUtil::GeneratePlane(const IEcs& ecs, const string_view name, Entity material, float width, float depth)
702 {
703 const Entity meshHandle = GeneratePlaneMesh(ecs, name, material, width, depth);
704 return GenerateEntity(ecs, name, meshHandle);
705 }
706
GenerateSphere(const IEcs & ecs,const string_view name,Entity material,float radius,uint32_t rings,uint32_t sectors)707 Entity MeshUtil::GenerateSphere(
708 const IEcs& ecs, const string_view name, Entity material, float radius, uint32_t rings, uint32_t sectors)
709 {
710 const Entity meshHandle = GenerateSphereMesh(ecs, name, material, radius, rings, sectors);
711 return GenerateEntity(ecs, name, meshHandle);
712 }
713
GenerateCone(const IEcs & ecs,const string_view name,Entity material,float radius,float length,uint32_t sectors)714 Entity MeshUtil::GenerateCone(
715 const IEcs& ecs, const string_view name, Entity material, float radius, float length, uint32_t sectors)
716 {
717 const Entity meshHandle = GenerateConeMesh(ecs, name, material, radius, length, sectors);
718 return GenerateEntity(ecs, name, meshHandle);
719 }
720
GenerateTorus(const IEcs & ecs,const string_view name,Entity material,float majorRadius,float minorRadius,uint32_t majorSectors,uint32_t minorSectors)721 Entity MeshUtil::GenerateTorus(const IEcs& ecs, const string_view name, Entity material, float majorRadius,
722 float minorRadius, uint32_t majorSectors, uint32_t minorSectors)
723 {
724 const Entity meshHandle =
725 GenerateTorusMesh(ecs, name, material, majorRadius, minorRadius, majorSectors, minorSectors);
726 return GenerateEntity(ecs, name, meshHandle);
727 }
728
InitializeBuilder(const IMeshBuilder::Submesh & submesh) const729 IMeshBuilder::Ptr MeshUtil::InitializeBuilder(const IMeshBuilder::Submesh& submesh) const
730 {
731 IMeshBuilder::Ptr builder;
732 if (IClassRegister* classRegister = factory_.GetInterface<IClassRegister>(); classRegister) {
733 auto renderContext = GetInstance<IRenderContext>(*classRegister, UID_RENDER_CONTEXT);
734 IShaderManager& shaderManager = renderContext->GetDevice().GetShaderManager();
735 const VertexInputDeclarationView vertexInputDeclaration =
736 shaderManager.GetVertexInputDeclarationView(shaderManager.GetVertexInputDeclarationHandle(
737 DefaultMaterialShaderConstants::VERTEX_INPUT_DECLARATION_FORWARD));
738 builder = CreateInstance<IMeshBuilder>(*renderContext, UID_MESH_BUILDER);
739 builder->Initialize(vertexInputDeclaration, 1);
740
741 builder->AddSubmesh(submesh);
742 builder->Allocate();
743 }
744
745 return builder;
746 }
747
CreateMesh(const IEcs & ecs,const IMeshBuilder & builder,const string_view name) const748 Entity MeshUtil::CreateMesh(const IEcs& ecs, const IMeshBuilder& builder, const string_view name) const
749 {
750 auto meshEntity = builder.CreateMesh(const_cast<IEcs&>(ecs));
751 if (!name.empty()) {
752 GetManager<IUriComponentManager>(ecs)->Set(meshEntity, { string(name) });
753 GetManager<INameComponentManager>(ecs)->Set(meshEntity, { string(name) });
754 }
755 return meshEntity;
756 }
757
MeshUtil(IClassFactory & factory)758 MeshUtil::MeshUtil(IClassFactory& factory) : factory_(factory) {}
759 CORE3D_END_NAMESPACE()
760