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