@@ -46,6 +46,90 @@ namespace
4646 throw GLTFException (" Invalid packing." );
4747 }
4848 }
49+
50+
51+ void Renormalize (std::unique_ptr<DirectX::ScratchImage> &normalImage, DirectX::ScratchImage &renormalizedImage)
52+ {
53+ auto image = normalImage->GetImage (0 , 0 , 0 );
54+ if (FAILED (renormalizedImage.Initialize2D (image->format , image->width , image->height , 1 , 1 )))
55+ {
56+ throw GLTFException (" Failed to initialize from texture." );
57+ }
58+
59+ uint8_t *normalPixels = normalImage->GetPixels ();
60+ auto metadata = normalImage->GetMetadata ();
61+
62+ auto renormalizedPixels = renormalizedImage.GetPixels ();
63+
64+ const auto two = DirectX::XMVectorReplicate (2 .0f );
65+ const auto minusOne = DirectX::XMVectorReplicate (-1 .0f );
66+ const auto half = DirectX::XMVectorReplicate (0 .5f );
67+
68+ for (size_t i = 0 ; i < metadata.width * metadata.height ; i += 1 )
69+ {
70+ // renormalizedPixels = 0.5 * normalize(normalPixel * 2 - 1) + 0.5
71+ const auto value = DirectX::XMVectorSet (
72+ *GLTFTextureUtils::GetChannelValue (normalPixels, i, Channel::Red),
73+ *GLTFTextureUtils::GetChannelValue (normalPixels, i, Channel::Green),
74+ *GLTFTextureUtils::GetChannelValue (normalPixels, i, Channel::Blue),
75+ 0 .0f );
76+
77+ auto normal = DirectX::XMVectorMultiplyAdd (value, two, minusOne);
78+ normal = DirectX::XMVector3Normalize (normal);
79+ const auto result = DirectX::XMVectorMultiplyAdd (half, normal, half);
80+
81+ *GLTFTextureUtils::GetChannelValue (renormalizedPixels, i, Channel::Red) = DirectX::XMVectorGetX (result);
82+ *GLTFTextureUtils::GetChannelValue (renormalizedPixels, i, Channel::Green) = DirectX::XMVectorGetY (result);
83+ *GLTFTextureUtils::GetChannelValue (renormalizedPixels, i, Channel::Blue) = DirectX::XMVectorGetZ (result);
84+ }
85+ }
86+
87+ void AdjustRoughness (std::unique_ptr<DirectX::ScratchImage> &roughnessImage, std::unique_ptr<DirectX::ScratchImage> &normalImage, DirectX::ScratchImage &adjustedImage)
88+ {
89+ auto image = roughnessImage->GetImage (0 , 0 , 0 );
90+ if (FAILED (adjustedImage.Initialize2D (image->format , image->width , image->height , 1 , 1 )))
91+ {
92+ throw GLTFException (" Failed to initialize from texture." );
93+ }
94+
95+ const auto two = DirectX::XMVectorReplicate (2 .0f );
96+ const auto minusOne = DirectX::XMVectorReplicate (-1 .0f );
97+
98+ uint8_t *normalPixels = normalImage->GetPixels ();
99+ auto metadata = normalImage->GetMetadata ();
100+
101+ auto adjustedPixels = adjustedImage.GetPixels ();
102+ uint8_t *roughnessPixels = roughnessImage->GetPixels ();
103+
104+ for (size_t i = 0 ; i < metadata.width * metadata.height ; i += 1 )
105+ {
106+ auto normal = DirectX::XMVectorSet (
107+ *GLTFTextureUtils::GetChannelValue (normalPixels, i, Channel::Red),
108+ *GLTFTextureUtils::GetChannelValue (normalPixels, i, Channel::Green),
109+ *GLTFTextureUtils::GetChannelValue (normalPixels, i, Channel::Blue),
110+ 0 .0f );
111+ normal = DirectX::XMVectorMultiplyAdd (normal, two, minusOne);
112+ auto avgNormalLengthSquare = DirectX::XMVector3LengthSq (normal);
113+ float avgNormalLengthSquareF = DirectX::XMVectorGetX (avgNormalLengthSquare);
114+
115+ float oldRoughness = *GLTFTextureUtils::GetChannelValue (roughnessPixels, i, Channel::Green);
116+ if (avgNormalLengthSquareF < 1 .0f )
117+ {
118+ auto avgNormalLength = DirectX::XMVectorSqrt (avgNormalLengthSquare);
119+ float avgNormalLengthF = DirectX::XMVectorGetX (avgNormalLength);
120+ float kappa = (3 .0f * avgNormalLengthF - avgNormalLengthF * avgNormalLengthSquareF) / (1 .0f - avgNormalLengthSquareF);
121+ float variance = 1 .0f / (2 .0f * kappa);
122+
123+ float newRoughness = sqrt (oldRoughness * oldRoughness + variance);
124+
125+ *GLTFTextureUtils::GetChannelValue (adjustedPixels, i, Channel::Green) = newRoughness;
126+ }
127+ else
128+ {
129+ *GLTFTextureUtils::GetChannelValue (adjustedPixels, i, Channel::Green) = oldRoughness;
130+ }
131+ }
132+ }
49133}
50134
51135std::unordered_set<int > GLTFTexturePackingUtils::GetTextureIndicesFromMsftExtensions (const Material& material)
@@ -273,6 +357,24 @@ Document GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::shared_ptr<IStre
273357
274358 if (packingIncludesNrm && (hasMR || hasNormal))
275359 {
360+ uint8_t *renormalPixels = normalPixels;
361+ DirectX::ScratchImage renormalizedImage;
362+ uint8_t *roughnessPixels = mrPixels;
363+ DirectX::ScratchImage adjustRoughnessImage;
364+
365+ if (hasNormal)
366+ {
367+ Renormalize (normalImage, renormalizedImage);
368+ renormalPixels = renormalizedImage.GetPixels ();
369+
370+ if (hasMR)
371+ {
372+ AdjustRoughness (metallicRoughnessImage, normalImage, adjustRoughnessImage);
373+ roughnessPixels = adjustRoughnessImage.GetPixels ();
374+ }
375+ }
376+
377+
276378 DirectX::ScratchImage nrm;
277379
278380 auto sourceImage = hasMR ? *metallicRoughnessImage->GetImage (0 , 0 , 0 ) : *normalImage->GetImage (0 , 0 , 0 );
@@ -287,15 +389,15 @@ Document GLTFTexturePackingUtils::PackMaterialForWindowsMR(std::shared_ptr<IStre
287389 for (size_t i = 0 ; i < metadata.width * metadata.height ; i += 1 )
288390 {
289391 // Normal: N [RG] -> NRM [RG]
290- *GLTFTextureUtils::GetChannelValue (nrmPixels, i, Channel::Red) = hasNormal ? *GLTFTextureUtils::GetChannelValue (normalPixels , i, Channel::Red) : 255 .0f ;
291- *GLTFTextureUtils::GetChannelValue (nrmPixels, i, Channel::Green) = hasNormal ? *GLTFTextureUtils::GetChannelValue (normalPixels , i, Channel::Green) : 255 .0f ;
392+ *GLTFTextureUtils::GetChannelValue (nrmPixels, i, Channel::Red) = hasNormal ? *GLTFTextureUtils::GetChannelValue (renormalPixels , i, Channel::Red) : 255 .0f ;
393+ *GLTFTextureUtils::GetChannelValue (nrmPixels, i, Channel::Green) = hasNormal ? *GLTFTextureUtils::GetChannelValue (renormalPixels , i, Channel::Green) : 255 .0f ;
292394 // Roughness: MR [G] -> NRM [B]
293- *GLTFTextureUtils::GetChannelValue (nrmPixels, i, Channel::Blue) = hasMR ? *GLTFTextureUtils::GetChannelValue (mrPixels , i, Channel::Green) : 255 .0f ;
395+ *GLTFTextureUtils::GetChannelValue (nrmPixels, i, Channel::Blue) = hasMR ? *GLTFTextureUtils::GetChannelValue (roughnessPixels , i, Channel::Green) : 255 .0f ;
294396 // Metalness: MR [B] -> NRM [A]
295397 *GLTFTextureUtils::GetChannelValue (nrmPixels, i, Channel::Alpha) = hasMR ? *GLTFTextureUtils::GetChannelValue (mrPixels, i, Channel::Blue) : 255 .0f ;
296398 }
297399
298- // sRGB conversion not needed for PNG in BGRA
400+ // Assumed sRGB because PNG defaults to that color space.
299401 auto imagePath = GLTFTextureUtils::SaveAsPng (&nrm, " packing_nrm_" + material.id + " .png" , outputDirectory, &GUID_WICPixelFormat32bppBGRA);
300402
301403 // Add back to GLTF
0 commit comments