You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将iOS端的id<MTLTexture>发送至Unity并实现接收?

解决iOS端传递MTLTexture到Unity的问题

Hey,我来帮你搞定这个跨端纹理传递的问题——你现在直接把id<MTLTexture>对象传给UnitySendMessage肯定不行,因为它只接受C风格的char*参数。核心思路是把Metal纹理的内存地址转换成字符串传递,再在Unity端解析回指针,具体步骤如下:

一、iOS端代码修改

在OC中,我们可以通过__bridge把Objective-C对象转为void*,再把指针地址格式化为十六进制字符串,最后转成char*传给Unity:

// iOS side
id<MTLTexture> _texture = CVMetalTextureGetTexture(texture);
// 将MTLTexture的内存地址格式化为十六进制字符串
NSString *textureAddrStr = [NSString stringWithFormat:@"%p", _texture];
// 转成C风格字符串传给UnitySendMessage
UnitySendMessage(CALLBACK_OBJECT, CALLBACK_TEXTURE_READY, [textureAddrStr UTF8String]);

这里%p是OC中格式化指针地址的标准方式,UTF8String方法刚好能把NSString转换成UnitySendMessage需要的char*类型。

二、Unity端接收逻辑调整

你之前用Int32.Parse会有大问题——iOS设备都是64位系统,指针长度是8字节,用32位解析会直接截断地址导致崩溃。正确的做法是把十六进制字符串解析成long类型再转IntPtr:

// Unity side
private void OnTextureReady(string texture_str)
{
    // 把十六进制字符串解析为64位整数,再转成IntPtr
    IntPtr texturePtr = new IntPtr(long.Parse(texture_str, System.Globalization.NumberStyles.HexNumber));
    
    // 建议不要硬编码宽高,最好从iOS端同步获取(下面会说怎么实现)
    int width = (int)GetMetalTextureWidth(texturePtr);
    int height = (int)GetMetalTextureHeight(texturePtr);
    
    // 创建外部纹理,注意格式要和Metal纹理匹配!
    rawImage.texture = Texture2D.CreateExternalTexture(width, height, TextureFormat.ARGB32, false, false, texturePtr);
}

// 通过C#调用iOS原生方法获取纹理宽高
[DllImport("__Internal")]
private static extern uint GetMetalTextureWidth(IntPtr texturePtr);

[DllImport("__Internal")]
private static extern uint GetMetalTextureHeight(IntPtr texturePtr);

对应的,iOS端需要新增两个C风格的导出方法,供Unity调用:

// iOS side 新增方法
extern "C" uint GetMetalTextureWidth(void* texturePtr) {
    // 把void*转回到MTLTexture对象
    id<MTLTexture> texture = (__bridge id<MTLTexture>)texturePtr;
    return texture.width;
}

extern "C" uint GetMetalTextureHeight(void* texturePtr) {
    id<MTLTexture> texture = (__bridge id<MTLTexture>)texturePtr;
    return texture.height;
}

三、必须注意的几个关键点

  • 生命周期管理:Unity创建的外部纹理依赖iOS端的MTLTexture,所以一定要确保在Unity用完这个纹理之前,iOS端不要释放它。可以在Unity端不再使用时,调用iOS的方法手动释放纹理,或者用OC的引用计数来管理。
  • 纹理格式匹配:Unity的TextureFormat必须和Metal纹理的像素格式对应,比如Metal的MTLPixelFormatBGRA8Unorm对应Unity的TextureFormat.BGRA32,格式不匹配会出现花屏或者黑屏。
  • 64位兼容性:一定要用long.Parse而不是Int32.Parse,这是很多人踩坑的点,64位系统下指针是8字节,32位解析会直接导致地址无效崩溃。

这样就能完美实现iOS端把MTLTexture传递到Unity并显示的需求了。

内容的提问来源于stack exchange,提问作者uchar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:09:52