37 void SampleEquirect(
const float* RGBA, int32 W, int32 H,
float u,
float v,
float Out[4])
45 v0 = FMath::Clamp(v0, 0, H - 1); v1 = FMath::Clamp(v1, 0, H - 1);
58 const float* RGBA, int32 Width, int32 Height, int32 FaceSize)
60 if (RGBA ==
nullptr || Width < 2 || Height < 2 || FaceSize < 4)
62 UE_LOG(LogCarla, Error, TEXT(
"SkyLightMap: invalid panorama %dx%d face %d"), Width, Height, FaceSize);
69 UTextureCube* Cube = UTextureCube::CreateTransient(FaceSize, FaceSize, PF_FloatRGBA,
70 MakeUniqueObjectName(GetTransientPackage(), UTextureCube::StaticClass(), TEXT(
"CarlaSkyLightMap")));
76 Cube->CompressionSettings = TC_HDR;
77 Cube->NeverStream =
true;
78 Cube->Filter = TF_Bilinear;
80 FTexture2DMipMap& Mip = Cube->GetPlatformData()->Mips[0];
81 FFloat16Color* Dst =
static_cast<FFloat16Color*
>(Mip.BulkData.Lock(LOCK_READ_WRITE));
82 const float TwoPi = 2.0f * PI;
83 for (int32 Face = 0; Face < 6; ++Face)
85 FFloat16Color* FaceDst = Dst + int64(Face) * FaceSize * FaceSize;
86 for (int32 j = 0; j < FaceSize; ++j)
88 const float sv = (j + 0.5f) / FaceSize * 2.0f - 1.0f;
89 for (int32 i = 0; i < FaceSize; ++i)
91 const float su = (i + 0.5f) / FaceSize * 2.0f - 1.0f;
92 const FVector d = FaceDirection(Face, su, sv).GetSafeNormal();
93 float phi = std::atan2(d.Y, d.X);
94 if (phi < 0.0f) phi += TwoPi;
95 const float theta = std::asin(FMath::Clamp(
float(d.Z), -1.0f, 1.0f));
96 const float u = phi / TwoPi * Width;
97 const float v = (0.5f - theta / PI) * Height;
99 SampleEquirect(RGBA, Width, Height, u, v, Px);
100 FaceDst[j * FaceSize + i] = FFloat16Color(FLinearColor(Px[0], Px[1], Px[2], 1.0f));
104 Mip.BulkData.Unlock();
105 Cube->UpdateResource();
106 UE_LOG(LogCarla, Log, TEXT(
"SkyLightMap: built %dx%d cubemap from %dx%d panorama"), FaceSize, FaceSize, Width, Height);
CARLA_API UTextureCube * CreateCubemapFromEquirect(const float *RGBA, int32 Width, int32 Height, int32 FaceSize=512)
Resamples the panorama into a transient 6-face HDR cubemap (PF_FloatRGBA, FaceSize x FaceSize per fac...