Unity 3 d二重線形補間テクスチャピクチャスケーリングの実現
最近Unityで2 Dゲームをしていたとき、Unity 3.5が低級なバグを導入していることに気づきました.Unity 3.5の前に、Texture 2 D.PackTexturesを使用してTexture Atlasを生成し、元のピクチャが大きすぎて大きなピクチャにヒットできない場合、自動的に元のピクチャを縮小して適応します.Unity 3.5にアップグレードすると、この動作が変更されます.スケールではなく、大きな画像が直接切り取られて適応されます.これはEZGUIユーザーにとって深刻な問題で、1枚の材質で多くの画像を縮小して1枚のマップに打つことを望むと、EZGUIは自動的にこの仕事を完成させてくれるが、このバグは原図を不完全に裁断し、この道は通じない.Unityフォーラムで他のユーザーもこの問題に直面していることがわかりましたが、うまく解決できず、マテリアルを再設定し、大きなマップがすべての元の画像を収容できるようにするしかありません.
その後、PackTexturesが元の画像を切り取ることができない場合、私たちは自発的に切り取った画像の大きさに従って元の画像をスケールすることができて、元の画像を切り取った画像と同じ大きさにして、それから再びPackTextuesを呼び出して、このように今回の大きな図がすべての元の画像を収容することができることを保証して、完璧にUnityのこのバグを迂回しました.次に、私が実装した二重線形補間でスケールを実現するコードを添付します.
次にEZGUIのBuildAtlas関数を少し修正します.最終的な大きな図が元の図を収容できない場合は、私たちの関数を使用して元の図を先にスケールし、PackTexturesを再び呼び出すことで、BuildAtlasをUnity 3.5にアップグレードする前と同じ効果を得ることができます.
その後、PackTexturesが元の画像を切り取ることができない場合、私たちは自発的に切り取った画像の大きさに従って元の画像をスケールすることができて、元の画像を切り取った画像と同じ大きさにして、それから再びPackTextuesを呼び出して、このように今回の大きな図がすべての元の画像を収容することができることを保証して、完璧にUnityのこのバグを迂回しました.次に、私が実装した二重線形補間でスケールを実現するコードを添付します.
Texture2D ScaleTextureBilinear(Texture2D originalTexture, float scaleFactor)
{
Texture2D newTexture = new Texture2D(Mathf.CeilToInt (originalTexture.width * scaleFactor), Mathf.CeilToInt (originalTexture.height * scaleFactor));
float scale = 1.0f / scaleFactor;
int maxX = originalTexture.width - 1;
int maxY = originalTexture.height - 1;
for (int y = 0; y < newTexture.height; y++)
{
for (int x = 0; x < newTexture.width; x++)
{
// Bilinear Interpolation
float targetX = x * scale;
float targetY = y * scale;
int x1 = Mathf.Min(maxX, Mathf.FloorToInt(targetX));
int y1 = Mathf.Min(maxY, Mathf.FloorToInt(targetY));
int x2 = Mathf.Min(maxX, x1 + 1);
int y2 = Mathf.Min(maxY, y1 + 1);
float u = targetX - x1;
float v = targetY - y1 ;
float w1 = (1 - u) * (1 - v);
float w2 = u * (1 - v);
float w3 = (1 - u) * v;
float w4 = u * v;
Color color1 = originalTexture.GetPixel(x1, y1);
Color color2 = originalTexture.GetPixel(x2, y1);
Color color3 = originalTexture.GetPixel(x1, y2);
Color color4 = originalTexture.GetPixel(x2, y2);
Color color = new Color(Mathf.Clamp01(color1.r * w1 + color2.r * w2 + color3.r * w3+ color4.r * w4),
Mathf.Clamp01(color1.g * w1 + color2.g * w2 + color3.g * w3 + color4.g * w4),
Mathf.Clamp01(color1.b * w1 + color2.b * w2 + color3.b * w3 + color4.b * w4),
Mathf.Clamp01(color1.a * w1 + color2.a * w2 + color3.a * w3 + color4.a * w4)
);
newTexture.SetPixel(x, y, color);
}
}
return newTexture;
}
この関数はscaleFactorに従って入力テクスチャピクチャを二重線形補間スケーリングして新しいテクスチャを出力します.次にEZGUIのBuildAtlas関数を少し修正します.最終的な大きな図が元の図を収容できない場合は、私たちの関数を使用して元の図を先にスケールし、PackTexturesを再び呼び出すことで、BuildAtlasをUnity 3.5にアップグレードする前と同じ効果を得ることができます.
// Pack the textures to the atlas:
texList.uvs = atlas.PackTextures((Texture2D[])texList.trimmedTextures.ToArray(typeof(Texture2D)), padding, maxAtlasSize);
// Check to see if the texture had to be resized to fit:
if (texList.uvs[0].width * atlas.width != ((Texture2D)texList.trimmedTextures[0]).width ||
texList.uvs[0].height * atlas.height != ((Texture2D)texList.trimmedTextures[0]).height)
{
Debug.LogWarning("WARNING: Not all textures were able to fit on atlas \"" + atlas.name + "\" at their original sizes. These textures were scaled down to fit. To resolve this, assign some of your sprites to use a different material, or if possible, use a larger maximum texture size.");
Debug.LogWarning("WARNING: Textures were resized to fit onto atlas \"" + atlas.name + "\"! To resolve this, assign some of your sprites a different material, or if possible, use a larger maximum texture size.");
float scaleRateX = texList.uvs[0].width * atlas.width / ((Texture2D)texList.trimmedTextures[0]).width;
float scaleRateY = texList.uvs[0].height * atlas.height /((Texture2D)texList.trimmedTextures[0]).height;
float scaleRate = scaleRateX <= scaleRateY ? scaleRateX : scaleRateY;
while (true)
{
Debug.Log("Scale Rate = " + scaleRate);
Texture2D[] texArray = (Texture2D[])texList.trimmedTextures.ToArray(typeof(Texture2D));
Texture2D[] newArray = new Texture2D[texArray.Length];
for (int i = 0; i < newArray.Length; i++)
{
newArray[i] = ScaleTextureBilinear(texArray[i], scaleRate);
}
texList.uvs = atlas.PackTextures(newArray, padding, maxAtlasSize);
if (texList.uvs[0].width * atlas.width == newArray[0].width &&
texList.uvs[0].height * atlas.height == newArray[0].height)
{
break;
}
scaleRate *= 0.9f;
}
}