c# – 从C本机插件更新float数组

在尝试将数组从C传递到C#时,我看到了一个非常奇怪的问题.我正在使用Marshal.Copy(具体来说:https://msdn.microsoft.com/en-us/library/a53bd6cz(v=vs.110).aspx).

问题:从C到C#的浮点数组在结果数组中产生一些NaN.
(注意:我在Unity游戏引擎的上下文中工作)

示例C代码:

extern "C" bool UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API getSomeFloats(float** points, int* count) {
        std::vector<float> results;
        std::vector<SOME_TYPE> key_points = <SOME_POINTS>

        for (auto iter = key_points.begin(); iter < key_points.end(); iter++) {
            results.push_back(static_cast<float>(iter->pt.x));
            results.push_back(static_cast<float>(iter->pt.y));
        }

        *points = results.data();
        *count = results.size();

        //<Print results to csv here>

        return true;
}

示例C#代码:

[DllImport("NativePlugin")]
private static extern bool getSomeFloats (ref IntPtr ptrResultItems, ref int resultItemsLength);

private static float[] getFloatArrayFromNative() {
        IntPtr ptrResultItems = IntPtr.Zero;
        int resultItemsLength = 0;
        bool success = getSomeFloats (ref ptrResultItems, ref resultItemsLength);
        float[] resultItems = null;
        if (success) {
            // Load the results into a managed array.
            resultItems = new float[resultItemsLength];
            Marshal.Copy (ptrResultItems
                , resultItems
                , 0
                , resultItemsLength);

            // <PRINT out resultItems to csv here>

            return resultItems;
        } else {
            Debug.Log ("Something went wrong getting some floats");
            return new float[] { -1, -2 };
        }
    }

示例输出:
请看以下示例:
C输出(print_out.csv):

123, 456, 789

C#输出(print_out_cs.csv):

123, NaN, 789

我完全被这个困扰了.我只是不明白为什么只有一些(大约7/100)花车返回NaN.有没有人有任何可能有帮助的建议/见解?

谢谢!

解决方法:

在您的代码中发现几个问题:

1. std :: vector< float>结果;在堆栈上声明.它会在函数返回时消失.将其声明为指针

std::vector<float> *results = new std::vector<float>(10);

但请务必声明一个将在C端释放它的函数.

2.功能参数不匹配.

你的C:

getSomeFloats(float** points, int* count, CameraPose* pose)

你的C#:

getSomeFloats (ref IntPtr ptrResultItems, ref int resultItemsLength);

您必须从C侧删除CameraPose * pose或将IntPtr姿势添加到C#侧.

3.使用UNITY_INTERFACE_EXPORT UNITY_INTERFACE_API.

你不需要那个.当您想使用Unity的内置函数(如GL.IssuePluginEvent)时使用此选项.在这种情况下,您不使用它.

这应该这样做:

#define DLLExport __declspec(dllexport)

extern "C"
{
    DLLExport void fillArrayNative(float* data, int count, int* outValue) 
    {
    }
}

4.C#有一个垃圾收集器,可以在内存中移动变量.如果要从C端修改C#数组,则必须将其固定.你只需要固定C#数组.另一种选择是在C端分配数组,将其返回C#将其复制到C#端的临时变量,然后在C端删除它.

5.将结果复制回数组而不是分配它.

推荐方法:

有很多方法可以做到这一点,其中一些非常慢.如果你想使用Marshal.Copy,你必须在C端分配数组,否则你将遇到一些未定义的行为.

最快和最有效的方法是将C#端的数组分配为全局变量.将数组及其长度传递给本机端.还传递第三个参数,C可用于告诉C#已更新或写入的索引量.

这比创建新数组要好得多,将其复制到C#变量,然后在每次调用函数时将其销毁.

这是你应该使用的:

C :

#define DLLExport __declspec(dllexport)

extern "C"
{
    DLLExport void fillArrayNative(float* data, int count, int* outValue) 
    {
        std::vector<float> results;
        for (int i = 0; i < count; i++)
        {
            //Fill the array
            data[i] = results[i];
        }
        *outValue = results.size();
    }
}

您还可以使用:std :: copy(data,data count,results.begin());而不是循环来复制数据.

C#:

[DllImport("NativePlugin", CallingConvention = CallingConvention.Cdecl)]
private static extern void fillArrayNative(IntPtr data, int count, out int outValue);

public unsafe void getFillArrayNative(float[] outArray, int count, out int outValue)
{
    //Pin Memory
    fixed (float* p = outArray)
    {
        fillArrayNative((IntPtr)p, count, out outValue);
    }
}

用法:

const int arraySize = 44500;
float[] arrayToFill = new float[arraySize];

void Start()
{
    int length = arrayToFill.Length;
    int filledAmount = 0;
    getFillArrayNative(arrayToFill, length, out filledAmount);

    //You can then loop through it with with the returned filledAmount
    for (int i = 0; i < filledAmount; i++)
    {
        //Do something with arrayToFill[i]
    }
}

这只是一个例子,它比我之前使用过的所有其他方法都快.避免按照Marshal.Copy目前的方式进行操作.如果您仍然希望按照自己的方式进行操作或使用Marshal.Copy,那么here是执行此操作的合适方法,需要在每次调用中分配,复制数据和取消分配内存.

原文地址:https://codeday.me/bug/20190926/1819714.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章将为大家详细讲解有关Unity3D中如何通过Animator动画状态机获取任意animation clip的准确播放持续时长,小编觉得挺实用的,因此分享给大家做个参考,
这篇文章主要介绍了Unity3D如何播放游戏视频,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解
这篇文章给大家分享的是有关Unity3D各平台路径是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1、Resources路径 Reso...
小编给大家分享一下Unity3D如何实现移动平台上的角色阴影,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!由于目前主流使用Unity3.x在移动平...
如何解析基于Unity3D的平坦四叉树地形与Virtual Texture的分析,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希
这篇文章主要介绍Unity3D如何实现动态分辨率降低渲染开销,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!之前项目降低分辨率我们都普...
这篇文章主要介绍了unity3d中如何使用屏幕空间改善shadowmap漏光,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编...
这篇文章主要介绍unity3d如何实现基于屏幕空间的描边,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!Outline(Based on Image Space)由...
这篇文章给大家分享的是有关unity3d中导入fbx时的Scale是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。在Unity中点击GameOb...
这篇文章主要为大家展示了“unity3d中如何实现ttc转ttf及制作字体”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习
这篇文章主要介绍了unity3d中水彩风渲染有什么用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了...
这篇文章将为大家详细讲解有关unity3d中图像压缩原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1 图像可压缩...
这篇文章给大家分享的是有关unity3d中光照公式有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。漫反射、高光、物理渲染(PBR...
小编给大家分享一下unity3d中光照探针的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我...
这篇文章将为大家详细讲解有关Unity3D中Rendering Paths及LightMode的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有
这篇文章将为大家详细讲解有关unity3d中图形学的光照原理是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。首先,在...
这篇文章给大家分享的是有关unity3d中图片渲染流程是什么的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。相关名词GPU(Graphic Pr...
本篇我们来介绍一下左侧工具栏中基本绘制的应用。 一、墙体绘制直墙 & 矩形墙绘制墙体时,可以看到上方的工具栏中对墙体进行参数的设定。 弧形墙在建筑版的户...
xlua是由腾讯维护的一个开源项目,我们可以在github上下载这个开源项目并查看一些相关文档官网:https://github.com/Tencent/xLua配置文档:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/hotfix.md常见问题解答:https://github.com/Tencent/xLua/blob/master/Assets/
我们都知道,一个三维场景的画面的好坏,百分之四十取决于模型,百分之六十取决于贴图,可见贴图在画面中所占的重要性。在这里我将列举一些贴图,并且初步阐述其概念,理解原理的基础上制作贴图,也就顺手多了。我在这里主要列举几种UNITY3D中常用的贴图,与大家分享,希望对大家有帮助。01 首先