UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
ImageOccupancyMap.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Templates/Tuple.h"
6#include "VectorTypes.h"
8#include "Image/ImageTile.h"
11#include "MathUtil.h"
12
13namespace UE
14{
15namespace Geometry
16{
17
34{
35public:
39
43
44 // texel types
45 static constexpr int8 EmptyTexel = 0;
46 static constexpr int8 InteriorTexel = 1;
47 static constexpr int8 BorderTexel = 2;
48 static constexpr int8 GutterTexel = 3;
49
55
61
67
73
79
85
91
94
95 bool bParallel = true;
96
97
98 void Initialize(FImageDimensions DimensionsIn, int32 SamplesPerPixel = 1)
99 {
100 check(DimensionsIn.IsSquare()); // are we sure it works otherwise?
103 InitializePixelSampler(SamplesPerPixel);
104 }
105
107 {
108 check(DimensionsIn.IsSquare());
110 Tile = TileIn;
111 InitializePixelSampler(SamplesPerPixel);
112 }
113
117 bool IsInterior(int64 LinearIndex) const
118 {
119 return TexelType[LinearIndex] == InteriorTexel;
120 }
121
123 int32 TexelNumSamples(int64 LinearIndex) const
124 {
125 return TexelInteriorSamples[LinearIndex];
126 }
127
129 //void SetTexelType(int64 X, int64 Y, int8 Type)
130 //{
131 // TexelType[Dimensions.GetIndex(X, Y)] = Type;
132 //}
133
134 template<typename MeshType, typename GetTriangleIDFuncType>
136 const MeshType& UVSpaceMesh,
137 GetTriangleIDFuncType GetTriangleIDFunc = [](int32 TriangleID) { return TriangleID; },
138 const TArray<int32>* UVSpaceMeshTriCharts = nullptr)
139 {
140 TRACE_CPUPROFILER_EVENT_SCOPE(FImageOccupancyMap::ClassifySamples_NoSpatial);
141
142 // make flat mesh
145 }
146
147 template<typename MeshType, typename GetTriangleIDFuncType>
149 const MeshType& UVSpaceMesh,
151 GetTriangleIDFuncType GetTriangleIDFunc = [](int32 TriangleID) { return TriangleID; },
152 const TArray<int32>* UVSpaceMeshTriCharts = nullptr)
153 {
154 TRACE_CPUPROFILER_EVENT_SCOPE(FImageOccupancyMap::ClassifySamples);
155
156 const int64 LinearImageSize = Tile.Num();
159
164
165 const FVector2d TexelSize = Dimensions.GetTexelSize();
166 const double TexelDiag = TexelSize.Length();
167
170
172
173 // Classify texel samples
176 (int32 ImgY)
177 {
178 for (int32 ImgX = 0; ImgX < Tile.GetWidth(); ++ImgX)
179 {
180 const FVector2i SourceCoords = Tile.GetSourceCoords(ImgX, ImgY);
181 const int64 SourceTexelLinearIdx = Dimensions.GetIndex(SourceCoords.X, SourceCoords.Y);
182 const int64 TexelLinearIdx = Tile.GetIndex(ImgX, ImgY);
183 const FVector2d SourceTexelCenterUV = Dimensions.GetTexelUV(SourceTexelLinearIdx);
184
185 for (int32 Sample = 0; Sample < PixelSampler.Num(); ++Sample)
186 {
187 const int64 SampleLinearIdx = TexelLinearIdx * PixelSampler.Num() + Sample;
188 const FVector2d SampleUV = PixelSampler.Sample(Sample);
189 const FVector2d UVPoint = SourceTexelCenterUV - 0.5 * TexelSize + SampleUV * TexelSize;
190 const FVector3d UVPoint3d(UVPoint.X, UVPoint.Y, 0);
191
192 double NearDistSqr;
193 const int32 NearestTriID = UVSpaceMeshSpatial.FindNearestTriangle(UVPoint3d, NearDistSqr, QueryOptions);
194 if (NearestTriID >= 0)
195 {
196 FVector3d A, B, C;
197 UVSpaceMesh.GetTriVertices(NearestTriID, A, B, C);
198 const FTriangle2d UVTriangle(GetXY(A), GetXY(B), GetXY(C));
199
200 const int32 TriId = GetTriangleIDFunc(NearestTriID);
201 if (UVTriangle.IsInsideOrOn(UVPoint))
202 {
203 TexelType[SampleLinearIdx] = InteriorTexel;
204 TexelQueryUV[SampleLinearIdx] = (FVector2f)UVPoint;
205 TexelQueryTriangle[SampleLinearIdx] = TriId;
206 ++TexelInteriorSamples[TexelLinearIdx];
207 }
208 else if (NearDistSqr < TexelDiag * TexelDiag)
209 {
210 const FDistPoint3Triangle3d DistQuery = TMeshQueries<MeshType>::TriangleDistance(UVSpaceMesh, NearestTriID, UVPoint3d);
211 FVector2d NearestUV = GetXY(DistQuery.ClosestTrianglePoint);
212
213 // nudge point into triangle to improve numerical behavior of things like barycentric coord calculation
214 // TODO Hmm this nudging could invalidate TriId? Maybe users should do it explicitly and then deal with/ignore this problem themselves
215 NearestUV += (10.0 * FMathf::ZeroTolerance) * Normalized(NearestUV - UVPoint);
216
217 // TODO Use BorderTexel here, and we should probably enable those
218 TexelType[SampleLinearIdx] = InteriorTexel;
219 TexelQueryUV[SampleLinearIdx] = (FVector2f)NearestUV;
220 TexelQueryTriangle[SampleLinearIdx] = TriId;
221 ++TexelInteriorSamples[TexelLinearIdx];
222 }
223 else
224 {
225 TexelType[SampleLinearIdx] = GutterTexel;
226 const FDistPoint3Triangle3d DistQuery = TMeshQueries<MeshType>::TriangleDistance(UVSpaceMesh, NearestTriID, UVPoint3d);
227 const FVector2d NearestUV = GetXY(DistQuery.ClosestTrianglePoint);
228
229 TexelQueryUV[SampleLinearIdx] = (FVector2f)NearestUV;
230 TexelQueryTriangle[SampleLinearIdx] = TriId;
231 }
232
233 if (TriId < NumUVSpaceMeshTriCharts && TexelQueryUVChart[TexelLinearIdx] == IndexConstants::InvalidID)
234 {
235 TexelQueryUVChart[TexelLinearIdx] = (*UVSpaceMeshTriCharts)[TriId];
236 }
237 }
238 } // end Sample loop
239 } // end scanline loop
241
242 return true;
243 }
244
246 {
250
252 (int32 ImgY)
253 {
254 for (int32 ImgX = 0; ImgX < Tile.GetWidth(); ++ImgX)
255 {
256 const FVector2i SourceCoords = Tile.GetSourceCoords(ImgX, ImgY);
257 const int64 SourceTexelLinearIdx = Dimensions.GetIndex(SourceCoords.X, SourceCoords.Y);
258 const int64 TexelLinearIdx = Tile.GetIndex(ImgX, ImgY);
259 const TTuple<int64, int64> InvalidGutterNearestTexel(-1, -1);
260
261 // With multiple samples, a texel may contain multiple gutter samples.
262 // Since we copy nearest interior texel over top our gutter texels, we
263 // should only consider a texel a gutter texel iff all samples in a
264 // texel are gutter texels.
265 TTuple<int64, int64> GutterNearestTexel = InvalidGutterNearestTexel;
266 for (int32 Sample = 0; Sample < PixelSampler.Num(); ++Sample)
267 {
268 const int64 SampleLinearIdx = TexelLinearIdx * PixelSampler.Num() + Sample;
269
270 if (TexelType[SampleLinearIdx] == InteriorTexel)
271 {
272 GutterNearestTexel = InvalidGutterNearestTexel;
273 break;
274 }
275
276 if (TexelType[SampleLinearIdx] == GutterTexel)
277 {
278 const FVector2d NearestUV = (FVector2d)TexelQueryUV[SampleLinearIdx];
279 const FVector2i NearestCoords = Dimensions.UVToCoords(NearestUV);
280
281 // To avoid artifacts with mipmapping the gutter texels store the nearest
282 // interior texel and a post pass copies those nearest interior texel values
283 // to each gutter pixel.
284 //
285 // TODO There can be interior texels closer to the gutter the texel than the one we find here.
286 // Search :NearestInteriorGutterTexel for a related problem in the MeshMapBaker.
287 //
288 const int64 NearestLinearIdx = Dimensions.GetIndex(NearestCoords);
289 GutterNearestTexel = TTuple<int64, int64>(SourceTexelLinearIdx, NearestLinearIdx);
290 }
291 } // end Sample loop
292
293 if (GutterNearestTexel != InvalidGutterNearestTexel)
294 {
295 GutterTexelsPerScanline[ImgY].Add(GutterNearestTexel);
296 }
297 } // end scanline loop
298
300
302
303 // Now build GutterTexels
304 GutterTexels.Reserve(TotalGutterCounter);
306 {
307 GutterTexels.Append(LineGutterTexels);
308 }
309
310 return true;
311 }
312
322 template<typename MeshType, typename GetTriangleIDFuncType>
324 const MeshType& UVSpaceMesh,
325 GetTriangleIDFuncType GetTriangleIDFunc = [](int32 TriangleID) { return TriangleID; },
326 const TArray<int32>* UVSpaceMeshTriCharts = nullptr)
327 {
328 ClassifySamplesFromUVSpaceMesh(UVSpaceMesh, GetTriangleIDFunc, UVSpaceMeshTriCharts);
329
330 ComputeGutterTexelsFromGutterSamples();
331
332 return true;
333 }
334
335
336
337
338 template<typename TexelValueType>
344 TFunctionRef<float(const FVector2i& TexelOffset)> WeightFunction,
345 int32 FilterWidth,
347 ) const
348 {
349 int64 N = Dimensions.Num();
350 checkSlow(N <= TMathUtilConstants<int32>::MaxReal); // TArray< , FDefaultAllocator>::SetNum(int32 ), so max Dimension ~ 65k x 65k
351 int32 N32 = int32(N);
352 PassBuffer.SetNum( N32 );
353
354 ParallelFor(Dimensions.GetHeight(),
355 [this, &BeginTexel, & AccumulateTexel, &CompleteTexel, &WeightFunction, FilterWidth, &PassBuffer]
356 (int32 ImgY)
357 {
358 for (int32 ImgX = 0; ImgX < Dimensions.GetWidth(); ++ImgX)
359 {
360 int32 LinearIdx = (int32)Dimensions.GetIndex(ImgX, ImgY);
361 if (TexelType[LinearIdx] != EmptyTexel)
362 {
363 TexelValueType AccumValue = BeginTexel(LinearIdx);
364 float WeightSum = 0;
365
366 FVector2i Coords(ImgX, ImgY);
367 FVector2i MaxNbr = Coords + FVector2i(FilterWidth, FilterWidth);
368 Dimensions.Clamp(MaxNbr);
369 FVector2i MinNbr = Coords - FVector2i(FilterWidth, FilterWidth);
370 Dimensions.Clamp(MinNbr);
371
372 for (int32 Y = MinNbr.Y; Y <= MaxNbr.Y; ++Y)
373 {
374 for (int32 X = MinNbr.X; X <= MaxNbr.X; ++X)
375 {
376 FVector2i NbrCoords(X, Y);
377 if (Dimensions.IsValidCoords(NbrCoords))
378 {
379 FVector2i Offset = NbrCoords - Coords;
380 int64 LinearNbrIndex = Dimensions.GetIndex(NbrCoords);
381 if (TexelType[LinearNbrIndex] != EmptyTexel)
382 {
383 float NbrWeight = WeightFunction(Offset);
384 AccumulateTexel(LinearNbrIndex, NbrWeight, AccumValue);
385 WeightSum += NbrWeight;
386 }
387 }
388 }
389 }
390
391 CompleteTexel(LinearIdx, WeightSum, AccumValue);
392 PassBuffer[LinearIdx] = AccumValue;
393 }
394 }
395 });
396
397 // write results
398 for (int32 k = 0; k < N32; ++k)
399 {
400 if (TexelType[k] != EmptyTexel)
401 {
402 WriteTexel(k, PassBuffer[k]);
403 }
404 }
405 }
406
407protected:
413 {
414 const float GridDimensionFloat = SamplesPerPixelIn > 0 ? static_cast<float>(SamplesPerPixelIn) : 1.0f;
416 PixelSampler = FGridSampler(GridDimension);
417 }
418
419};
420
421
422} // end namespace UE::Geometry
423} // end namespace UE
#define checkSlow(expr)
Definition AssertionMacros.h:332
#define check(expr)
Definition AssertionMacros.h:314
void ParallelFor(int32 Num, TFunctionRef< void(int32)> Body, bool bForceSingleThread, bool bPumpRenderingThread=false)
Definition ParallelFor.h:481
FPlatformTypes::int8 int8
An 8-bit signed integer.
Definition Platform.h:1121
FPlatformTypes::int64 int64
A 64-bit signed integer.
Definition Platform.h:1127
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
#define TRACE_CPUPROFILER_EVENT_SCOPE(Name)
Definition CpuProfilerTrace.h:528
Definition Array.h:670
void SetNum(SizeType NewNum, EAllowShrinking AllowShrinking=UE::Core::Private::AllowShrinkingByDefault< AllocatorType >())
Definition Array.h:2308
Definition Atomic.h:538
Definition AssetRegistryState.h:50
static RealType Clamp(const RealType Value, const RealType ClampMin, const RealType ClampMax)
Definition MathUtil.h:222
static RealType Sqrt(const RealType Value)
Definition MathUtil.h:342
Definition ImageDimensions.h:18
int32 GetHeight() const
Definition ImageDimensions.h:40
int64 Num() const
Definition ImageDimensions.h:42
FVector2d GetTexelSize() const
Definition ImageDimensions.h:97
int32 GetWidth() const
Definition ImageDimensions.h:38
Definition ImageOccupancyMap.h:34
TArray64< int32 > TexelInteriorSamples
Definition ImageOccupancyMap.h:60
TArray64< TTuple< int64, int64 > > BorderTexels
Definition ImageOccupancyMap.h:84
TArray64< int8 > TexelType
Definition ImageOccupancyMap.h:54
FGridSampler PixelSampler
Definition ImageOccupancyMap.h:93
bool ClassifySamplesFromUVSpaceMesh(const MeshType &UVSpaceMesh, GetTriangleIDFuncType GetTriangleIDFunc=[](int32 TriangleID) { return TriangleID;}, const TArray< int32 > *UVSpaceMeshTriCharts=nullptr)
Definition ImageOccupancyMap.h:135
TArray64< int32 > TexelQueryUVChart
Definition ImageOccupancyMap.h:78
static constexpr int8 BorderTexel
Definition ImageOccupancyMap.h:47
void InitializePixelSampler(const int32 SamplesPerPixelIn)
Definition ImageOccupancyMap.h:412
FImageDimensions Dimensions
Definition ImageOccupancyMap.h:37
TArray64< FVector2f > TexelQueryUV
Definition ImageOccupancyMap.h:66
bool ClassifySamplesFromUVSpaceMesh(const MeshType &UVSpaceMesh, const TMeshAABBTree3< MeshType > &UVSpaceMeshSpatial, GetTriangleIDFuncType GetTriangleIDFunc=[](int32 TriangleID) { return TriangleID;}, const TArray< int32 > *UVSpaceMeshTriCharts=nullptr)
Definition ImageOccupancyMap.h:148
static constexpr int8 EmptyTexel
Definition ImageOccupancyMap.h:45
bool IsInterior(int64 LinearIndex) const
Definition ImageOccupancyMap.h:117
int32 GutterSize
Definition ImageOccupancyMap.h:42
void Initialize(FImageDimensions DimensionsIn, const FImageTile &TileIn, int32 SamplesPerPixel=1)
Definition ImageOccupancyMap.h:106
int32 TexelNumSamples(int64 LinearIndex) const
Definition ImageOccupancyMap.h:123
void ParallelProcessingPass(TFunctionRef< TexelValueType(int64 LinearIdx)> BeginTexel, TFunctionRef< void(int64 LinearIdx, float Weight, TexelValueType &)> AccumulateTexel, TFunctionRef< void(int64 LinearIdx, float Weight, TexelValueType &)> CompleteTexel, TFunctionRef< void(int64 LinearIdx, TexelValueType &)> WriteTexel, TFunctionRef< float(const FVector2i &TexelOffset)> WeightFunction, int32 FilterWidth, TArray< TexelValueType > &PassBuffer) const
Definition ImageOccupancyMap.h:339
bool bParallel
Definition ImageOccupancyMap.h:95
TArray64< TTuple< int64, int64 > > GutterTexels
Definition ImageOccupancyMap.h:90
bool ComputeFromUVSpaceMesh(const MeshType &UVSpaceMesh, GetTriangleIDFuncType GetTriangleIDFunc=[](int32 TriangleID) { return TriangleID;}, const TArray< int32 > *UVSpaceMeshTriCharts=nullptr)
Definition ImageOccupancyMap.h:323
TGridSampler< double > FGridSampler
Definition ImageOccupancyMap.h:92
bool ComputeGutterTexelsFromGutterSamples()
Definition ImageOccupancyMap.h:245
TArray64< int32 > TexelQueryTriangle
Definition ImageOccupancyMap.h:72
void Initialize(FImageDimensions DimensionsIn, int32 SamplesPerPixel=1)
Definition ImageOccupancyMap.h:98
static constexpr int8 InteriorTexel
Definition ImageOccupancyMap.h:46
FImageTile Tile
Definition ImageOccupancyMap.h:38
static constexpr int8 GutterTexel
Definition ImageOccupancyMap.h:48
Definition ImageTile.h:14
int64 Num() const
Definition ImageTile.h:51
int32 GetHeight() const
Definition ImageTile.h:46
int32 Num() const
Definition GridSampler.h:32
Definition MeshAABBTree3.h:61
constexpr int InvalidID
Definition IndexTypes.h:13
Definition AdvancedWidgetsModule.cpp:13
Definition MathUtil.h:16
Definition Tuple.h:652
Definition IntVectorTypes.h:20
Definition SpatialInterfaces.h:57
double MaxDistance
Definition SpatialInterfaces.h:61
static TVector2< float > Zero()
Definition Vector2D.h:79