Unity3d 双线性插值纹理图片缩放的实现

        原文地址:http://blog.youkuaiyun.com/ring0hx/article/details/7676295

        最近用Unity做一个2D游戏的时候发现了Unity3.5引入了一个很低级的bug。在Unity3.5之前,使用Texture2D.PackTextures生成Texture Atlas,当原始图片太大无法打在一张大图上时会自动对原始图片进行缩小适应。在升级到Unity3.5后这一行为发生了改变:太大的图片会被直接裁剪适应,而不是缩放适应。这对于使用EZGUI用户来说是个很严重的问题,如果希望使用一张材质把很多图片缩小后打到一张贴图上,原来EZGUI会自动帮我们完成这个工作,但这个bug使原图被裁剪得不完整了,这条路就行不通了。在Unity论坛上发现其他用户也遇到了这个问题,但是没有很好的解决方法,只能重新设置材质,确保大贴图能容纳下所有的原始图片。

         后来我想了个解决办法,当PackTextures无法容下原始图片发生裁剪后,我们可以主动按照裁剪后的图片大小缩放原始图片,使原始图片和裁剪后的图片一样大,然后再次调用PackTextues,这样就保证了这次大图可以容纳下所有原始图片了,完美地绕过了Unity的这个bug。下面附上我实现的一个双线性插值实现缩放的代码:

[csharp]  view plain  copy
  1. Texture2D ScaleTextureBilinear(Texture2D originalTexture, float scaleFactor)  
  2.     {  
  3.         Texture2D newTexture = new Texture2D(Mathf.CeilToInt (originalTexture.width * scaleFactor), Mathf.CeilToInt (originalTexture.height * scaleFactor));  
  4.         float scale = 1.0f / scaleFactor;  
  5.         int maxX = originalTexture.width - 1;  
  6.         int maxY = originalTexture.height - 1;  
  7.         for (int y = 0; y < newTexture.height; y++)  
  8.         {  
  9.             for (int x = 0; x < newTexture.width; x++)  
  10.             {  
  11.                 // Bilinear Interpolation  
  12.                 float targetX = x * scale;  
  13.                 float targetY = y * scale;  
  14.                 int x1 = Mathf.Min(maxX, Mathf.FloorToInt(targetX));  
  15.                 int y1 = Mathf.Min(maxY, Mathf.FloorToInt(targetY));  
  16.                 int x2 = Mathf.Min(maxX, x1 + 1);  
  17.                 int y2 = Mathf.Min(maxY, y1 + 1);  
  18.   
  19.                 float u = targetX - x1;  
  20.                 float v = targetY - y1 ;  
  21.                 float w1 = (1 - u) * (1 - v);  
  22.                 float w2 = u * (1 - v);  
  23.                 float w3 = (1 - u) * v;  
  24.                 float w4 = u * v;  
  25.                 Color color1 = originalTexture.GetPixel(x1, y1);  
  26.                 Color color2 = originalTexture.GetPixel(x2, y1);  
  27.                 Color color3 = originalTexture.GetPixel(x1, y2);  
  28.                 Color color4 = originalTexture.GetPixel(x2,  y2);  
  29.                 Color color = new Color(Mathf.Clamp01(color1.r * w1 + color2.r * w2 + color3.r * w3+ color4.r * w4),  
  30.                     Mathf.Clamp01(color1.g * w1 + color2.g * w2 + color3.g * w3 + color4.g * w4),  
  31.                     Mathf.Clamp01(color1.b * w1 + color2.b * w2 + color3.b * w3 + color4.b * w4),  
  32.                     Mathf.Clamp01(color1.a * w1 + color2.a * w2 + color3.a * w3 + color4.a * w4)  
  33.                     );  
  34.                 newTexture.SetPixel(x, y, color);  
  35.             }  
  36.         }  
  37.   
  38.         return newTexture;  
  39.     }  
这个函数会根据scaleFactor对输入纹理图片进行双线性插值缩放后输出新纹理。

然后对EZGUI的BuildAtlas函数稍作修改:如果最终的大图容纳不下原图,则使用我们自己的函数先对原图进行缩放,然后再次调用PackTextures,这样就可以使BuildAtlas和升级到Unity3.5之前有一样的效果了。

[csharp]  view plain  copy
  1. // Pack the textures to the atlas:  
  2.         texList.uvs = atlas.PackTextures((Texture2D[])texList.trimmedTextures.ToArray(typeof(Texture2D)), padding, maxAtlasSize);  
  3.   
  4.         // Check to see if the texture had to be resized to fit:  
  5.         if (texList.uvs[0].width * atlas.width != ((Texture2D)texList.trimmedTextures[0]).width ||  
  6.            texList.uvs[0].height * atlas.height != ((Texture2D)texList.trimmedTextures[0]).height)  
  7.         {  
  8.             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.");  
  9.             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.");  
  10.             float scaleRateX =  texList.uvs[0].width * atlas.width / ((Texture2D)texList.trimmedTextures[0]).width;  
  11.             float scaleRateY = texList.uvs[0].height * atlas.height /((Texture2D)texList.trimmedTextures[0]).height;  
  12.             float scaleRate = scaleRateX <= scaleRateY ? scaleRateX : scaleRateY;  
  13.             while (true)  
  14.             {  
  15.                 Debug.Log("Scale Rate = " + scaleRate);  
  16.                 Texture2D[] texArray = (Texture2D[])texList.trimmedTextures.ToArray(typeof(Texture2D));  
  17.                 Texture2D[] newArray = new Texture2D[texArray.Length];  
  18.                 for (int i = 0; i < newArray.Length; i++)  
  19.                 {  
  20.                     newArray[i] = ScaleTextureBilinear(texArray[i], scaleRate);  
  21.                 }  
  22.                 texList.uvs = atlas.PackTextures(newArray, padding, maxAtlasSize);  
  23.                 if (texList.uvs[0].width * atlas.width == newArray[0].width &&  
  24.                     texList.uvs[0].height * atlas.height == newArray[0].height)  
  25.                 {  
  26.                     break;  
  27.                 }  
  28.                 scaleRate *= 0.9f;  
  29.             }  
  30.         }  

QQ交流群:162136059
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值