AndroidStudioC#NDK开发Unity

UnityNDK开发之通过ndk加载ExternalTexture

Spread the love

在游戏中有一些需求,例如相册,或者是聊天的自定义表情,这些时候我们通常需要直接从文件而不是从AssetBundle中读取图片,这个时候Unity提供了一个比较方便的方法:LoadImage

但是这个方法有意者巨大的缺陷,需要传入Texture大小相同的bytes,导致我们每加载一张图片就需要申请相对应的bytes数组,导致大量的GC出现。这个时候,我们想到上一篇文章中我们通过指针的方式来读取数组……Unity是否提供了这样的方法呢,答案是肯定的:

还有另外一种方案,就是直接把图片的指针(id)传给Unity:

这一次我使用的是第二种方案:
实际上也有人这么干过:
https://github.com/hecomi/UnityNativeTextureLoader
很可惜他使用了WWW去加载bytes导致GC出现,我们会在他的基础上写的更好,实际上在最后的工程中我也实现了iOS版本的加载。
那么这个时候NDK大现身手的时候又到了。
在这之前,我们其实知道,Android使用的图形API是OpenGLES,我们可以调用Android的图形API来创建图片。
实际上Java也可以直接调用OpenGLES的API,但是这个地方有个坑,Android在多线程渲染的时候Java层是无法直接拿到OpenGL的上下文的,导致在开启多线程渲染的时候无法正常渲染图片。(然而iOS和PC都不存在这个问题)

https://stackoverflow.com/questions/33324753/how-to-use-unity-createexternaltexture-on-android

所以我们选择了UnityNativePlugin配合NDK的方式来编写我们需要的代码。
在此之前,我们需要知道如何加载图片,这个时候我用到了一个比较知名的第三方库:libpng。

https://github.com/glennrp/libpng

可以直接通过autoconf或者cmake进行编译,对编译不熟悉的同学可以直接使用另外一个已经写好了给安卓的libpng的工程:

https://github.com/julienr/libpng-android

然后我们进行jni的编写:
工程目录如下:

 

这里我们使用的是静态库,随后跟着ndk一起打入我们的.so文件。
首先看看我们的CMake文件:

在普通的ndk开发之外我们需要引入GLES的库,所以我们就加入了GLESv1以及v2,详细库我们可以看官方文档。

Gradle中我们使用的c++14的库并且libpng需要链接libz所以加上了-lz的参数。(虽然这个写在cmake里面也行

我们编写了一个PngLoader进行图片的加载:

下面是实现

 

在pngloader中我们已经可以把图片创建出来了。
然后我们需要提供NativePlugin相应的事件方法:

这个方法会帮我们把渲染Texture的代码插入到渲染管线之中以保障我们的Texture能够正常加载出来,其中的callback是我们提供的C++的函数指针,在c++中的代码如下:

 

我们可以看到方法GetPngRenderEventFunc返回了一个函数指针,当我们加载一个贴图的时候我们会将其加入到队列之中,当我们调用了OnRenderEvent的时候,队列里的所有贴图都会进行更新。

然后我们就可以将这些方法进行导出:(我们可以先忽略iOS的代码)

然后我们可以对这些方法进行封装了,并且保证在卸载的时候能够及时释放图片的内存:(同样地先忽略iOS的代码)

我们使用了IDisposable的方式去写这个Loader,以保证我们的图片能够及时释放,需要注意的是Disposable的写法要标准,GC.SuppressFinalize保证了我们在手动Dispose之后GC的时候不会再次调用Dispose,否则指针释放两次可能会造成致命错误。(详细可以看Effective C#中对IDisposable的描述)

注意我们需要在帧的末尾对我们的回调进行调用,这样才能够帮助我们及时更新图片。
最后是Demo代码的呈现:

 

Debug.Log(“Load ” + imgpath);
if (!File.Exists(imgpath))
{
Debug.LogError(imgpath + ” not exist!!!”);
}
currentRawTexture = new NativeTexture(imgpath);
img.texture = currentRawTexture.Tex;

 

工程地址:
https://github.com/vgvgvvv/ResetCore/tree/master/Unity/NativeReadBytes

发表评论

电子邮件地址不会被公开。 必填项已用*标注