From 947bccf35f32bde09567bd06cfe79cec3cbcdf95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tur=C3=A1nszki=20J=C3=A1nos?= Date: Mon, 30 Dec 2024 12:13:17 +0100 Subject: [PATCH] fix: fall back to full precision UVs when the model has a very large UV layout --- WickedEngine/wiScene_Components.cpp | 44 ++++++++++++++++++++++------- WickedEngine/wiScene_Components.h | 18 ++++++++++++ WickedEngine/wiVersion.cpp | 2 +- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/WickedEngine/wiScene_Components.cpp b/WickedEngine/wiScene_Components.cpp index 30a09bbde..32e2b449d 100644 --- a/WickedEngine/wiScene_Components.cpp +++ b/WickedEngine/wiScene_Components.cpp @@ -769,6 +769,8 @@ namespace wi::scene } // Determine UV range for normalization: + size_t uv_stride = sizeof(Vertex_UVS); + Format uv_format = Vertex_UVS::FORMAT; if (!vertex_uvset_0.empty() || !vertex_uvset_1.empty()) { const XMFLOAT2* uv0_stream = vertex_uvset_0.empty() ? vertex_uvset_1.data() : vertex_uvset_0.data(); @@ -783,6 +785,13 @@ namespace wi::scene uv_range_min = wi::math::Min(uv_range_min, uv0_stream[i]); uv_range_min = wi::math::Min(uv_range_min, uv1_stream[i]); } + + if (std::abs(uv_range_max.x - uv_range_min.x) > 65536 || std::abs(uv_range_max.y - uv_range_min.y) > 65536) + { + // The bounding box of UVs is too large, fall back to full precision UVs: + uv_stride = sizeof(Vertex_UVS32); + uv_format = Vertex_UVS32::FORMAT; + } } const size_t position_stride = GetFormatStride(position_format); @@ -809,7 +818,7 @@ namespace wi::scene AlignTo(indices.size() * GetIndexStride(), alignment) + AlignTo(vertex_normals.size() * sizeof(Vertex_NOR), alignment) + AlignTo(vertex_tangents.size() * sizeof(Vertex_TAN), alignment) + - AlignTo(uv_count * sizeof(Vertex_UVS), alignment) + + AlignTo(uv_count * uv_stride, alignment) + AlignTo(vertex_atlas.size() * sizeof(Vertex_TEX), alignment) + AlignTo(vertex_colors.size() * sizeof(Vertex_COL), alignment) + AlignTo(vertex_boneindices.size() * sizeof(Vertex_BON), alignment) + @@ -1058,15 +1067,30 @@ namespace wi::scene const XMFLOAT2* uv1_stream = vertex_uvset_1.empty() ? vertex_uvset_0.data() : vertex_uvset_1.data(); vb_uvs.offset = buffer_offset; - vb_uvs.size = uv_count * sizeof(Vertex_UVS); - Vertex_UVS* vertices = (Vertex_UVS*)(buffer_data + buffer_offset); - buffer_offset += AlignTo(vb_uvs.size, alignment); - for (size_t i = 0; i < uv_count; ++i) + vb_uvs.size = uv_count * uv_stride; + if (uv_stride == sizeof(Vertex_UVS)) { - Vertex_UVS vert; - vert.uv0.FromFULL(uv0_stream[i], uv_range_min, uv_range_max); - vert.uv1.FromFULL(uv1_stream[i], uv_range_min, uv_range_max); - std::memcpy(vertices + i, &vert, sizeof(vert)); + Vertex_UVS* vertices = (Vertex_UVS*)(buffer_data + buffer_offset); + buffer_offset += AlignTo(vb_uvs.size, alignment); + for (size_t i = 0; i < uv_count; ++i) + { + Vertex_UVS vert; + vert.uv0.FromFULL(uv0_stream[i], uv_range_min, uv_range_max); + vert.uv1.FromFULL(uv1_stream[i], uv_range_min, uv_range_max); + std::memcpy(vertices + i, &vert, sizeof(vert)); + } + } + else + { + Vertex_UVS32* vertices = (Vertex_UVS32*)(buffer_data + buffer_offset); + buffer_offset += AlignTo(vb_uvs.size, alignment); + for (size_t i = 0; i < uv_count; ++i) + { + Vertex_UVS32 vert; + vert.uv0.FromFULL(uv0_stream[i], uv_range_min, uv_range_max); + vert.uv1.FromFULL(uv1_stream[i], uv_range_min, uv_range_max); + std::memcpy(vertices + i, &vert, sizeof(vert)); + } } } @@ -1267,7 +1291,7 @@ namespace wi::scene } if (vb_uvs.IsValid()) { - vb_uvs.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_uvs.offset, vb_uvs.size, &Vertex_UVS::FORMAT); + vb_uvs.subresource_srv = device->CreateSubresource(&generalBuffer, SubresourceType::SRV, vb_uvs.offset, vb_uvs.size, &uv_format); vb_uvs.descriptor_srv = device->GetDescriptorIndex(&generalBuffer, SubresourceType::SRV, vb_uvs.subresource_srv); } if (vb_atl.IsValid()) diff --git a/WickedEngine/wiScene_Components.h b/WickedEngine/wiScene_Components.h index 03f6dbe91..82dc09e97 100644 --- a/WickedEngine/wiScene_Components.h +++ b/WickedEngine/wiScene_Components.h @@ -674,12 +674,30 @@ namespace wi::scene } static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R16G16_UNORM; }; + struct Vertex_TEX32 + { + float x = 0; + float y = 0; + + constexpr void FromFULL(const XMFLOAT2& uv, const XMFLOAT2& uv_range_min = XMFLOAT2(0, 0), const XMFLOAT2& uv_range_max = XMFLOAT2(1, 1)) + { + x = wi::math::InverseLerp(uv_range_min.x, uv_range_max.x, uv.x); + y = wi::math::InverseLerp(uv_range_min.y, uv_range_max.y, uv.y); + } + static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R32G32_FLOAT; + }; struct Vertex_UVS { Vertex_TEX uv0; Vertex_TEX uv1; static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R16G16B16A16_UNORM; }; + struct Vertex_UVS32 + { + Vertex_TEX32 uv0; + Vertex_TEX32 uv1; + static constexpr wi::graphics::Format FORMAT = wi::graphics::Format::R32G32B32A32_FLOAT; + }; struct Vertex_BON { XMUINT4 packed = XMUINT4(0, 0, 0, 0); diff --git a/WickedEngine/wiVersion.cpp b/WickedEngine/wiVersion.cpp index 0ca6aceb5..180e3c2fc 100644 --- a/WickedEngine/wiVersion.cpp +++ b/WickedEngine/wiVersion.cpp @@ -9,7 +9,7 @@ namespace wi::version // minor features, major updates, breaking compatibility changes const int minor = 71; // minor bug fixes, alterations, refactors, updates - const int revision = 642; + const int revision = 643; const std::string version_string = std::to_string(major) + "." + std::to_string(minor) + "." + std::to_string(revision);