| 240 | }; |
| 241 | |
| 242 | bool ModelTool::GenerateModelSDF(Model* inputModel, const ModelData* modelData, float resolutionScale, int32 lodIndex, ModelBase::SDFData* outputSDF, MemoryWriteStream* outputStream, const StringView& assetName, float backfacesThreshold, bool useGPU) |
| 243 | { |
| 244 | PROFILE_CPU(); |
| 245 | auto startTime = Platform::GetTimeSeconds(); |
| 246 | |
| 247 | // Setup SDF texture properties |
| 248 | BoundingBox bounds; |
| 249 | if (inputModel) |
| 250 | bounds = inputModel->LODs[lodIndex].GetBox(); |
| 251 | else if (modelData) |
| 252 | bounds = modelData->LODs[lodIndex].GetBox(); |
| 253 | else |
| 254 | return true; |
| 255 | ModelBase::SDFData sdf; |
| 256 | sdf.WorldUnitsPerVoxel = METERS_TO_UNITS(0.1f) / Math::Max(resolutionScale, 0.0001f); // 1 voxel per 10 centimeters |
| 257 | #if 0 |
| 258 | const float boundsMargin = sdf.WorldUnitsPerVoxel * 0.5f; // Add half-texel margin around the mesh |
| 259 | bounds.Minimum -= boundsMargin; |
| 260 | bounds.Maximum += boundsMargin; |
| 261 | #endif |
| 262 | const Float3 size = bounds.GetSize(); |
| 263 | Int3 resolution(Float3::Ceil(Float3::Clamp(size / sdf.WorldUnitsPerVoxel, 4, 256))); |
| 264 | Float3 uvwToLocalMul = size; |
| 265 | Float3 uvwToLocalAdd = bounds.Minimum; |
| 266 | sdf.LocalToUVWMul = Float3::One / uvwToLocalMul; |
| 267 | sdf.LocalToUVWAdd = -uvwToLocalAdd / uvwToLocalMul; |
| 268 | sdf.MaxDistance = size.MaxValue(); |
| 269 | sdf.LocalBoundsMin = bounds.Minimum; |
| 270 | sdf.LocalBoundsMax = bounds.Maximum; |
| 271 | sdf.ResolutionScale = resolutionScale; |
| 272 | sdf.LOD = lodIndex; |
| 273 | const int32 maxMips = 3; |
| 274 | const int32 mipCount = Math::Min(MipLevelsCount(resolution.X, resolution.Y, resolution.Z), maxMips); |
| 275 | PixelFormat format = PixelFormat::R16_UNorm; |
| 276 | int32 formatStride = 2; |
| 277 | float formatMaxValue = MAX_uint16; |
| 278 | typedef float (*FormatRead)(void* ptr); |
| 279 | typedef void (*FormatWrite)(void* ptr, float v); |
| 280 | FormatRead formatRead = [](void* ptr) |
| 281 | { |
| 282 | return (float)*(uint16*)ptr; |
| 283 | }; |
| 284 | FormatWrite formatWrite = [](void* ptr, float v) |
| 285 | { |
| 286 | *(uint16*)ptr = (uint16)v; |
| 287 | }; |
| 288 | if (resolution.MaxValue() < 8) |
| 289 | { |
| 290 | // For smaller meshes use more optimized format (gives small perf and memory gain but introduces artifacts on larger meshes) |
| 291 | format = PixelFormat::R8_UNorm; |
| 292 | formatStride = 1; |
| 293 | formatMaxValue = MAX_uint8; |
| 294 | formatRead = [](void* ptr) |
| 295 | { |
| 296 | return (float)*(uint8*)ptr; |
| 297 | }; |
| 298 | formatWrite = [](void* ptr, float v) |
| 299 | { |
nothing calls this directly
no test coverage detected