UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
GridBoxMeshGenerator.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
6#include "OrientedBoxTypes.h"
7#include "Util/IndexUtil.h"
8
9namespace UE
10{
11namespace Geometry
12{
13
18class /*GEOMETRYCORE_API*/ FGridBoxMeshGenerator : public FMeshShapeGenerator
19{
20public:
23
25
28
30 bool bPolygroupPerQuad = false;
31
32public:
33
35 virtual FMeshShapeGenerator& Generate() override
36 {
38 N.A = FMath::Max(2, N.A);
39 N.B = FMath::Max(2, N.B);
40 N.C = FMath::Max(2, N.C);
41
42 FVector3d Nscale(1.0 / (N.A-1), 1.0 / (N.B-1), 1.0 / (N.C-1));
43
45 NInternal.A -= 2; NInternal.B -= 2; NInternal.C -= 2;
46
47 FIndex3i NTri = N;
48 NTri.A--; NTri.B--; NTri.C--;
49 int NumUVsAndNormals = 2 * (N.A * N.B + N.B * N.C + N.C * N.A);
50 int NumVertices = 8 + (NInternal.A + NInternal.B + NInternal.C) * 4 + (NInternal.A*NInternal.B + NInternal.B*NInternal.C + NInternal.C*NInternal.A) * 2;
51 int NumTriangles = 4 * (NTri.A * NTri.B + NTri.B * NTri.C + NTri.C * NTri.A);
52 SetBufferSizes(NumVertices, NumTriangles, NumUVsAndNormals, NumUVsAndNormals);
53
54 int FaceDimOrder[3]{ 1, 2, 0 }; // ordering from IndexUtil.cpp
55 int D[2][3]{ { 1,2,0 }, { 2,0,1 } }; // helper mapping to go from major dimension to the two canonical sub-dimensions in order; is just D[i][j] -> (j+i+1)%3 (TODO: replace with the modulus version?)
56
57 // allocate a big mapping from faces to vertices, to make life easier when creating triangles later
58 FIndex3i VerticesPerFace(N.B * N.C, N.A * N.C, N.A * N.B);
61 for (int Dim = 0; Dim < 3; Dim++)
62 {
63 int FaceIdxForDim = FaceDimOrder[Dim] * 2;
64 int VertexNum = VerticesPerFace[Dim];
67 }
68
69 auto ToFaceV = [&N, &D](int Dim, int D0, int D1)
70 {
71 return D0 + N[D[0][Dim]] * D1;
72 };
73
74 // create the corners and distribute them into the face mapping
75 for (int i = 0; i < 8; ++i)
76 {
77 Vertices[i] = Box.GetCorner(i);
79 for (int Dim = 0; Dim < 3; Dim++)
80 {
81 int FaceIdx = FaceDimOrder[Dim]*2 + CornerSides[Dim];
82 int D0Ind = CornerSides[D[0][Dim]] * (N[D[0][Dim]] - 1);
83 int D1Ind = CornerSides[D[1][Dim]] * (N[D[1][Dim]] - 1);
84 int CornerVInd = ToFaceV(Dim, D0Ind, D1Ind);
85 FaceVertIndices[FaceIdx][CornerVInd] = i;
86 }
87 }
88
89 // create the internal (non-corner) edge vertices and distribute them into the face mapping
90 int CurrentVertIndex = 8;
91 for (int Dim = 0; Dim < 3; Dim++)
92 {
93 int EdgeLen = N[Dim];
94 if (EdgeLen <= 2)
95 {
96 continue; // no internal edge vertices on this dimension
97 }
98 int MajorFaceInd = FaceDimOrder[Dim] * 2;
99 int FaceInds[2]{ -1,-1 };
100 int DSides[2]{ 0,0 };
101 for (DSides[0] = 0; DSides[0] < 2; DSides[0]++)
102 {
103 FaceInds[0] = FaceDimOrder[D[0][Dim]] * 2 + DSides[0];
104 for (DSides[1] = 0; DSides[1] < 2; DSides[1]++)
105 {
106 FaceInds[1] = FaceDimOrder[D[1][Dim]] * 2 + DSides[1];
107 int MajorCornerInd = ToFaceV(Dim, DSides[0] * (N[D[0][Dim]] - 1), DSides[1] * (N[D[1][Dim]] - 1));
108 FVector3d Corners[2]
109 {
112 };
113
114 for (int EdgeVert = 1; EdgeVert + 1 < EdgeLen; EdgeVert++)
115 {
116 Vertices[CurrentVertIndex] = Lerp(Corners[0], Corners[1], EdgeVert * Nscale[Dim]);
117 for (int WhichFace = 0; WhichFace < 2; WhichFace++) // each edge is shared by two faces (w/ major axes of subdim 0 and subdim 1 respectively)
118 {
120
121 int FaceDim = D[WhichFace][Dim];
122 int SubDims[2];
125 int FaceV = ToFaceV(FaceDim, SubDims[0], SubDims[1]); //-V614
127 }
129 }
130 }
131 }
132 }
133
134 // create the internal (non-corner, non-edge) face vertices and distribute them into the face mapping
135 for (int Dim = 0; Dim < 3; Dim++)
136 {
137 int FaceIdxBase = FaceDimOrder[Dim]*2;
138 int FaceInternalVNum = NInternal[D[0][Dim]] * NInternal[D[1][Dim]];
139 if (FaceInternalVNum <= 0)
140 {
141 continue;
142 }
143
144 for (int Side = 0; Side < 2; Side++)
145 {
146 int MajorFaceInd = FaceIdxBase + Side;
147 for (int D0 = 1; D0 + 1 < N[D[0][Dim]]; D0++)
148 {
149 int BotInd = ToFaceV(Dim, D0, 0);
150 int TopInd = ToFaceV(Dim, D0, N[D[1][Dim]] - 1);
151
152 FVector3d Edges[2]
153 {
156 };
157 for (int D1 = 1; D1 + 1 < N[D[1][Dim]]; D1++)
158 {
159 Vertices[CurrentVertIndex] = Lerp(Edges[0], Edges[1], D1 * Nscale[D[1][Dim]]);
162 }
163 }
164 }
165 }
166
167 double MaxDimension = MaxAbsElement(2.0*Box.Extents);
168 float UVScale = (bScaleUVByAspectRatio) ? (1.0f / (float)MaxDimension) : 1.0f;
169
170 // create the face triangles and UVs+normals
171 int CurrentTriIdx = 0;
172 int CurrentUVIdx = 0;
173 int CurrentQuadIdx = 0;
174 for (int Dim = 0; Dim < 3; Dim++)
175 {
176 int FaceIdxBase = FaceDimOrder[Dim]*2;
177
178 // UV-specific minor axes + flips; manually set to match default UnrealEngine cube texture arrangement
179 int Minor1Flip[3] = { -1, 1, 1 };
180 int Minor2Flip[3] = { -1, -1, 1 };
181
182 // UV scales for D0, D1
183 double FaceWidth = FMathd::Abs(Box.Extents[D[0][Dim]]) * 2.0;
184 double FaceHeight = FMathd::Abs(Box.Extents[D[1][Dim]]) * 2.0;
185 double WidthUVScale = FaceWidth * UVScale;
186 double HeightUVScale = FaceHeight * UVScale;
187
188
189 for (int Side = 0; Side < 2; Side++)
190 {
191 int SideOpp = 1 - Side;
192 int SideSign = Side * 2 - 1;
193
194 FVector3f Normal(0, 0, 0);
195 Normal[Dim] = float(2 * Side - 1);
197
198 int MajorFaceInd = FaceIdxBase + Side;
199
201 // set all the UVs and normals
203 int UVXDim = Dim == 1 ? 1 : 0; // which dim (of D0,D1) follows the horizontal UV coordinate
204 int UVYDim = 1 - UVXDim; // which dim (of D0,D1) follows the vertical UV coordinate
205 for (int D0 = 0; D0 < N[D[0][Dim]]; D0++)
206 {
207 for (int D1 = 0; D1 < N[D[1][Dim]]; D1++)
208 {
209 // put the grid coordinates (centered at 0,0) into the UVs
210 UV[UVXDim] = float (D0 * Nscale[D[0][Dim]] - .5);
211 UV[UVYDim] = float (D1 * Nscale[D[1][Dim]] - .5);
212 // invert axes to match the desired UV patterns & so the opp faces are not backwards
213 UV.X *= float(SideSign * Minor1Flip[Dim]);
214 UV.Y *= float(Minor2Flip[Dim]);
215 // recenter and scale up
216 UV[UVXDim] = float ( (UV[UVXDim] + .5f) * WidthUVScale);
217 UV[UVYDim] = float ( (UV[UVYDim] + .5f) * HeightUVScale);
222 CurrentUVIdx++;
223 }
224 }
225
226 // set all the triangles
227 for (int D0 = 0; D0 + 1 < N[D[0][Dim]]; D0++)
228 {
229 for (int D1 = 0; D1 + 1 < N[D[1][Dim]]; D1++)
230 {
232 FaceVertIndices[MajorFaceInd][ToFaceV(Dim, D0, D1)],
233 FaceVertIndices[MajorFaceInd][ToFaceV(Dim, D0+SideOpp, D1+Side)],
234 FaceVertIndices[MajorFaceInd][ToFaceV(Dim, D0+1, D1+1)]
235 );
236
238 FaceUVStartInd + D1 + (D0) * N[D[1][Dim]],
239 FaceUVStartInd + D1+Side + (D0+SideOpp) * N[D[1][Dim]],
240 FaceUVStartInd + D1+1 + (D0+1) * N[D[1][Dim]]
241 );
243 FaceUVStartInd + D1 + (D0) * N[D[1][Dim]],
244 FaceUVStartInd + D1+Side + (D0+SideOpp) * N[D[1][Dim]],
245 FaceUVStartInd + D1+1 + (D0+1) * N[D[1][Dim]]
246 );
249
251 FaceVertIndices[MajorFaceInd][ToFaceV(Dim, D0, D1)],
252 FaceVertIndices[MajorFaceInd][ToFaceV(Dim, D0+1, D1+1)],
253 FaceVertIndices[MajorFaceInd][ToFaceV(Dim, D0+Side, D1+SideOpp)]
254 );
256 FaceUVStartInd + D1 + (D0) * N[D[1][Dim]],
257 FaceUVStartInd + D1+1 + (D0+1) * N[D[1][Dim]],
258 FaceUVStartInd + D1+SideOpp + (D0+Side) * N[D[1][Dim]]
259 );
261 FaceUVStartInd + D1 + (D0) * N[D[1][Dim]],
262 FaceUVStartInd + D1+1 + (D0+1) * N[D[1][Dim]],
263 FaceUVStartInd + D1+SideOpp + (D0+Side) * N[D[1][Dim]]
264 );
268 }
269 }
270 }
271 }
272
273
274 return *this;
275 }
276
277};
278
279
280
281} // end namespace UE::Geometry
282} // end namespace UE
@ Normal
Definition AndroidInputInterface.h:116
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
UE::Math::TVector< float > FVector3f
Definition MathFwd.h:73
USkinnedMeshComponent float
Definition SkinnedMeshComponent.h:60
Definition Array.h:670
void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2308
static RealType Abs(const RealType Value)
Definition MathUtil.h:215
Definition GridBoxMeshGenerator.h:19
FIndex3i EdgeVertices
Definition GridBoxMeshGenerator.h:24
FOrientedBox3d Box
Definition GridBoxMeshGenerator.h:22
virtual FMeshShapeGenerator & Generate() override
Definition GridBoxMeshGenerator.h:35
bool bScaleUVByAspectRatio
Definition GridBoxMeshGenerator.h:27
bool bPolygroupPerQuad
Definition GridBoxMeshGenerator.h:30
Definition MeshShapeGenerator.h:19
TArray< FVector2f > UVs
Definition MeshShapeGenerator.h:25
TArray< int > UVParentVertex
Definition MeshShapeGenerator.h:27
TArray< FVector3d > Vertices
Definition MeshShapeGenerator.h:22
TArray< FVector3f > Normals
Definition MeshShapeGenerator.h:30
void SetTriangle(int Index, const FIndex3i &Tri)
Definition MeshShapeGenerator.h:193
void SetTriangleUVs(int Index, const FIndex3i &Tri)
Definition MeshShapeGenerator.h:217
TArray< int > NormalParentVertex
Definition MeshShapeGenerator.h:32
void SetTrianglePolygon(int Index, int PolygonID)
Definition MeshShapeGenerator.h:244
void SetTriangleNormals(int Index, const FIndex3i &Tri)
Definition MeshShapeGenerator.h:231
void SetBufferSizes(int NumVertices, int NumTriangles, int NumUVs, int NumNormals)
Definition MeshShapeGenerator.h:97
constexpr T MaxAbsElement(const UE::Math::TVector< T > &Vector)
Definition VectorTypes.h:324
Definition AdvancedWidgetsModule.cpp:13
Definition IndexTypes.h:158
int B
Definition IndexTypes.h:164
int A
Definition IndexTypes.h:163
int C
Definition IndexTypes.h:165
TVector< RealType > FromFrameVector(const TVector< RealType > &Vector) const
Definition FrameTypes.h:229
TVector< RealType > GetCorner(int Index) const
Definition OrientedBoxTypes.h:156
TVector< RealType > Extents
Definition OrientedBoxTypes.h:32
static FIndex3i GetCornerSide(int Index)
Definition OrientedBoxTypes.h:211
TFrame3< RealType > Frame
Definition OrientedBoxTypes.h:30