【问题标题】:Convert uintptr_t to id<MTLTexture>将 uintptr_t 转换为 id<MTLTexture>
【发布时间】:2016-01-18 12:30:30
【问题描述】:

我想创建一个简单的 iOS 插件,它可以将纹理绘制到统一的 Texture2D。我已经通过 CreateExternalTexture() 和 UpdateExternalTexture() 完成了它,它工作正常,但我很好奇我是否可以直接从 iOS 端填充 Unity 纹理。这是我的 iOS 插件代码:

//
//  testTexturePlugin.m
//  Unity-iPhone
//
//  Created by user on 18/01/16.
//
//

#import <OpenGLES/ES2/gl.h>
#import <OpenGLES/ES2/glext.h>
#import <UIKit/UIKit.h>

#include "UnityMetalSupport.h"

#include <stdlib.h>
#include <stdint.h>

static UIImage* LoadImage()
{
    NSString* imageName = @"logo"; //[NSString stringWithUTF8String: filename];
    NSString* imagePath = [[NSBundle mainBundle] pathForResource: imageName ofType: @"png"];

    return [UIImage imageWithContentsOfFile: imagePath];
}

// you need to free this pointer
static void* LoadDataFromImage(UIImage* image)
{
    CGImageRef imageData    = image.CGImage;
    unsigned   imageW       = CGImageGetWidth(imageData);
    unsigned   imageH       = CGImageGetHeight(imageData);

    // for the sake of the sample we enforce 128x128 textures
    //assert(imageW == 128 && imageH == 128);

    void* textureData = ::malloc(imageW * imageH * 4);
    ::memset(textureData, 0x00, imageW * imageH * 4);

    CGContextRef textureContext = CGBitmapContextCreate(textureData, imageW, imageH, 8, imageW * 4, CGImageGetColorSpace(imageData), kCGImageAlphaPremultipliedLast);
    CGContextSetBlendMode(textureContext, kCGBlendModeCopy);
    CGContextDrawImage(textureContext, CGRectMake(0, 0, imageW, imageH), imageData);
    CGContextRelease(textureContext);

    return textureData;
}

static void CreateMetalTexture(uintptr_t texRef, void* data, unsigned w, unsigned h)
{
#if defined(__IPHONE_8_0) && !TARGET_IPHONE_SIMULATOR

    NSLog(@"texRef iOS = %lu", texRef);

    id<MTLTexture> tex = (id<MTLTexture>)(size_t)texRef;

    MTLRegion r = MTLRegionMake3D(0, 0, 0, w, h, 1);
    [tex replaceRegion: r mipmapLevel: 0 withBytes: data bytesPerRow: w * 4];

#else

#endif
}

extern "C" void FillUnityTexture(uintptr_t texRef)
{
    UIImage*    image       = LoadImage();
    void*       textureData = LoadDataFromImage(image);

    if (UnitySelectedRenderingAPI() == apiMetal)
        CreateMetalTexture(texRef, textureData, image.size.width, image.size.height);

    ::free(textureData);
}

这是 Unity 代码:

using UnityEngine;
using System;
using System.Collections;
using System.Runtime.InteropServices;

public class TextureHandler : MonoBehaviour {

    [SerializeField]
    private Renderer _mesh;

    private Texture2D _meshTexture;

    [DllImport("__Internal")]
    private static extern void FillUnityTexture(IntPtr texRef);

    void Start () {

        _meshTexture = new Texture2D(200, 200, TextureFormat.ARGB32, false);
        _mesh.material.SetTextureScale ("_MainTex", new Vector2 (-1, -1));
        _mesh.material.mainTexture = _meshTexture;

        IntPtr texPtr = _meshTexture.GetNativeTexturePtr();
        Debug.Log("texPtr Unity = " + texPtr);

        FillUnityTexture(texPtr);
    }
}

Unity 纹理上的指针正确地传递给 iOS 插件,我检查了。但是我在 iOS 插件的这一行中遇到了崩溃:

[tex replaceRegion: r mipmapLevel: 0 withBytes: data bytesPerRow: w * 4];

我很确定我遇到了这个问题,因为将 Unity 纹理 (uintptr_t) 上的指针错误地转换为金属纹理 (id)。

所以我的问题是 - 如何正确地将指向纹理的指针转换为 MTLTexture?

【问题讨论】:

  • 虽然不是很漂亮,但该演员应该可以工作,因为GetNativeTexturePtr 返回一个id&lt;MTLTexture&gt;。如果您加载的图像的尺寸超过纹理的尺寸(200x200),您的代码似乎可以写在纹理的边界之外。您是否确认不是这种情况?
  • 你的猜测是正确的 :) 但是仍然没有任何关于统一纹理的图片,只有紫色。可能是因为我正在尝试上传分辨率比 200x200 大得多的图像吗?

标签: c# ios unity3d metal


【解决方案1】:

我想您应该阅读有关 ARC 的信息。

您可以使用__bridge_retained 将新创建的id&lt;MTLTexture&gt; 对象的所有权转移给uintptr_t 代码。当您想将uintptr_t 转换回id&lt;MTLTexture&gt; 时,如果您不想转让所有权,请使用__bridge,或者在您这样做时使用__bridge_transfer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-09
    • 1970-01-01
    • 2017-12-04
    • 1970-01-01
    • 2016-03-21
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多