版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pz789as/article/details/89949056
之前一直想使用Shader去做高斯模糊特效,后面发现图片过大的话,效率真的是相当的不理想。
后来在网上看到说iOS本身是有将图片处理成高斯模糊的功能的,想想也确实,苹果设备的背景经常会出现模糊特效,那他们的算法应该很快速的,于是突发奇想,如果将要做模糊处理的图片,传到原生端然后处理成模糊图片之后,再传回来使用,不就可以达到这个目的了么!
首先要知道这个的局限性,不能实时的去做,这是什么意思呢,如果截图这一下也是会有一点卡的,如果实时处理的话,肯定会不流畅。
还有一个,图片的格式,不能是Unity的压缩格式,因为我没法解压缩图片,那穿过去的图片就没法生成正常图片了。
最后,图片要是可读写的,否则拿不到图片的二进制数据,也没法做;
那么怎么做呢,关于Unity桥接原生的我在之前的文章说过了,可以参考这里:Unity和iOS互通
原生代码:
- (void) imageToBlurImage:(NSString *)media radius:(float)radius {
if(media.length != 0) {// 1、创建输入图像,CIImage类型,这里使用从外部传过来的图片。
NSData *imageData = [[NSData alloc]initWithBase64EncodedString:media options:0];
CIImage* inputImage = [CIImage imageWithData:imageData];
// 2、构建一个滤镜图表
// CIColor* sepiaColor = [CIColor colorWithRed:0.76 green:0.65 blue:0.54];
// // 2.1 先构建一个 CIColorMonochrome 滤镜,并配置输入图像与滤镜参数
// CIFilter* monochromeFilter = [CIFilter filterWithName:@"CIColorMonochrome" withInputParameters:@{@"inputColor":sepiaColor,@"inputIntensity":@1.0}];
// [monochromeFilter setValue:inputImage forKey:@"inputImage"];
// // 2.2 先构建一个 CIVignette 滤镜
// CIFilter* vignetteFilter = [CIFilter filterWithName:@"CIVignette" withInputParameters:@{@"inputRadius":@1.0, @"inputIntensity":@1.0}];
// [vignetteFilter setValue:monochromeFilter.outputImage forKey:@"inputImage"];
NSNumber* numRad = [NSNumber numberWithFloat:radius];
CIFilter* gaussianFilter = [CIFilter filterWithName:@"CIGaussianBlur" withInputParameters:@{@"inputRadius":numRad}];
[gaussianFilter setValue:inputImage forKey:@"inputImage"];
// 3、得到一个滤镜处理后的图片,并转换至 UIImage
// 创建一个 CIContext
CIContext* ciContext = [CIContext contextWithOptions:nil];
// 将 CIImage 过渡到 CGImageRef 类型
CGImageRef cgImage = [ciContext createCGImage:gaussianFilter.outputImage fromRect:inputImage.extent];
// 最后转换为 UIImage 类型
UIImage* uiImage = [UIImage imageWithCGImage:cgImage];
// 将得到的图片转化成图片数据,通过SendMessage传送到Unity端
NSData *imgData = UIImagePNGRepresentation(uiImage);
NSString *_encodeImageStr = [imgData base64EncodedStringWithOptions:NSDataBase64DecodingIgnoreUnknownCharacters];
if (_encodeImageStr == nil){
UnitySendMessage( "GJCNativeShare", "ToBlurImageFailed", [GJC_DataConvertor NSStringToChar:@"iamge change error! the image format is not support!"]);
}else{
UnitySendMessage( "GJCNativeShare", "ToBlurImageSuccess", _encodeImageStr.UTF8String);
}
}else{
UnitySendMessage( "GJCNativeShare", "ToBlurImageFailed", [GJC_DataConvertor NSStringToChar:@"iamge data is null!"]);
}
}
extern "C" {
void _GJC_ToBlurImage(char* encodedMedia, float radius){
NSString *media = [GJC_DataConvertor charToNSString:encodedMedia];
[[GJCSocialShare sharedInstance] imageToBlurImage:media radius:radius];
}
}
然后Unity这边:
[DllImport ("__Internal")]
private static extern bool _GJC_ToBlurImage(string encodedMedia, float radius);
/// <summary>
/// 调用原生的高斯模糊处理,传递一张图片过去,得到处理之后的图片
/// </summary>
/// <param name="texture">分享的图片</param>
public void TextureToBlur(Texture2D texture, float radius) {
Debug.Log("TextureToBlur");
#if UNITY_IPHONE && !UNITY_EDITOR
if(texture != null) {
Debug.Log("TextureToBlur: Texture");
string bytesString = System.Convert.ToBase64String (texture.EncodeToPNG());
// string bytesString = System.Convert.ToBase64String (texture.GetRawTextureData());
_GJC_ToBlurImage(bytesString, radius);
}else{
ToBlurImageFailed("texture is null!");
}
#else
// string bytesString = System.Convert.ToBase64String (texture.EncodeToEXR());
// Texture2D newTexture = new Texture2D(1,1);
// newTexture.LoadRawTextureData(texture.GetRawTextureData());
// string bytesString = System.Convert.ToBase64String (texture.EncodeToPNG());
ToBlurImageFailed("this platform is not support!");
#endif
}
从原生的回调:
/// <summary>
/// 图片转换成Blur效果之后,回调的结果
/// </summary>
/// <param name="base64">Base64.</param>
private void ToBlurImageSuccess(string base64)
{
Debug.Log ("Native To ToBlurImageSuccess");
if(onToBlurImage != null)
{
onToBlurImage("Success", base64);
}
}
private void ToBlurImageFailed(string error){
Debug.Log ("Native To ToBlurImageFailed: " + error);
if(onToBlurImage != null)
{
onToBlurImage("Failed", error);
}
}
将iOS传递过来的数据,转换成图片
/// <summary>
/// 将ios传过的string转成u3d中的texture
/// </summary>
/// <param name="base64"></param>
/// <returns></returns>
public static Texture2D Base64StringToTexture2D(string base64)
{
Debug.Log ("Run Base64StringToTexture2d");
Texture2D tex = new Texture2D(1,1);
try
{
byte[] bytes = System.Convert.FromBase64String(base64);
tex.LoadImage(bytes);
tex.hideFlags = HideFlags.DontSave;
tex.filterMode = FilterMode.Point;
tex.wrapMode = TextureWrapMode.Clamp;
}
catch(System.Exception ex)
{
Debug.Log ("Create Texture2D Failed!!");
Debug.LogError(ex.Message);
}
return tex;
}
自己使用了之后,速度还是蛮快的,目前这个用在一些固定大背景模糊的位置,实时的话,还是想想如何优化Shader去做吧。