Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >PhysX 和 NavMesh 在服务器的应用

PhysX 和 NavMesh 在服务器的应用

原创
作者头像
王亚昌
修改于 2020-06-03 07:07:54
修改于 2020-06-03 07:07:54
11.2K0
举报
文章被收录于专栏:王亚昌的专栏王亚昌的专栏

一、 引言

本文源于一个简单的想法 “在LINUX服务器进程中,加载Unity搭建的场景,并驱动AI在客户端的行为”,这个想法引发了一系列的思考:

  • 物理引擎的选择
  • 如何从Unity导出场景
  • 如何用PhysX加载场景,并验证其正确性
  • 如何驱动AI寻路
  • 等等

带着上面的问题,作者花了大概两周的时间完成了组件选型、搭建、测试验证的工作,也整理完了这篇文章,分享给有相同疑问的同事。 因此,本文主要侧重于工作流的介绍和工具的使用,原理的介绍只会在必须的情况下提及,更多的原理需要大家去自行查阅,比如PhysXAPI的使用、CharacterController的应用、Detour库的使用等,可以详读最后一节的参考文献。

下面开始,会逐步解决上面的问题,另外,列举一下文中用到的组件列表,方便大家提前查阅。

  • PhysX
  • PhysX Visual Debugger(PVD)
  • UnityPhysXExport
  • RecastNavigation
  • Microsoft Visual Studio
  • Premake5

首先是物理引擎的选择,这里选择了PhysX,主要有两个原因:

  • 开源,支持Unity\UE3\UE4
  • 有很多成功的游戏,已经成为腾讯内部的主流技术选型

下一节开始,会开始介绍Linux环境下PhysX环境的搭建。

二、 Linux环境PhysX搭建

1. 下载

下载PhysX,首先需要申请加入NVIDIAGameWorks,进入NVIDIA官网,找到PhysX下载页,然后按步骤操作就好,系统会自动审核,大概10分钟就可以搞定了。

得到授权后,可以进入github主页下载版本,地址如下:https://github.com/NVIDIAGameWorks/PhysX-3.4

2. 编译

PhysX的编译十分简单,github上写的也很清楚,开发机是linux64环境,所以直接进入PhysX-3.4-master/PhysX_3.4/Source/compiler/linux64文件夹,输入make执行即可,编译成功会生成一系列的静态和动态库。

代码语言:txt
AI代码解释
复制
[root@SH-todo-1412181717 /data/physx/PhysX-3.4-master/PhysX_3.4]# find -name "*.a"
./Lib/linux64/libLowLevelCHECKED.a
./Lib/linux64/libLowLevelAABBCHECKED.a
./Lib/linux64/libLowLevelDynamicsCHECKED.a
./Lib/linux64/libLowLevelClothCHECKED.a
./Lib/linux64/libLowLevelParticlesCHECKED.a
./Lib/linux64/libPhysX3VehicleCHECKED.a
./Lib/linux64/libPhysX3ExtensionsCHECKED.a
./Lib/linux64/libSceneQueryCHECKED.a
./Lib/linux64/libSimulationControllerCHECKED.a
./Lib/linux64/libLowLevelDEBUG.a
./Lib/linux64/libLowLevelAABBDEBUG.a
./Lib/linux64/libLowLevelDynamicsDEBUG.a
./Lib/linux64/libLowLevelClothDEBUG.a
./Lib/linux64/libLowLevelParticlesDEBUG.a
./Lib/linux64/libPhysX3VehicleDEBUG.a
./Lib/linux64/libPhysX3ExtensionsDEBUG.a
./Lib/linux64/libSceneQueryDEBUG.a
./Lib/linux64/libSimulationControllerDEBUG.a
./Lib/linux64/libLowLevelPROFILE.a
./Lib/linux64/libLowLevelAABBPROFILE.a
./Lib/linux64/libLowLevelDynamicsPROFILE.a
./Lib/linux64/libLowLevelClothPROFILE.a
./Lib/linux64/libLowLevelParticlesPROFILE.a
./Lib/linux64/libPhysX3VehiclePROFILE.a
./Lib/linux64/libPhysX3ExtensionsPROFILE.a
./Lib/linux64/libSceneQueryPROFILE.a
./Lib/linux64/libSimulationControllerPROFILE.a
./Lib/linux64/libLowLevel.a
./Lib/linux64/libLowLevelAABB.a
./Lib/linux64/libLowLevelDynamics.a
./Lib/linux64/libLowLevelCloth.a
./Lib/linux64/libLowLevelParticles.a
./Lib/linux64/libPhysX3Vehicle.a
./Lib/linux64/libPhysX3Extensions.a
./Lib/linux64/libSceneQuery.a
./Lib/linux64/libSimulationController.a
./Snippets/lib/linux64/libSnippetUtilsCHECKED.a
[root@SH-todo-1412181717 /data/physx/PhysX-3.4-master/PhysX_3.4]# find -name "*.so"
./Bin/linux64/libPhysX3GpuCHECKED_x64.so
./Bin/linux64/libPhysX3GpuDEBUG_x64.so
./Bin/linux64/libPhysX3GpuPROFILE_x64.so
./Bin/linux64/libPhysX3Gpu_x64.so
./Bin/linux64/libPhysX3CommonCHECKED_x64.so
./Bin/linux64/libPhysX3CHECKED_x64.so
./Bin/linux64/libPhysX3CharacterKinematicCHECKED_x64.so
./Bin/linux64/libPhysX3CookingCHECKED_x64.so
./Bin/linux64/libPhysX3CommonDEBUG_x64.so
./Bin/linux64/libPhysX3DEBUG_x64.so
./Bin/linux64/libPhysX3CharacterKinematicDEBUG_x64.so
./Bin/linux64/libPhysX3CookingDEBUG_x64.so
./Bin/linux64/libPhysX3CommonPROFILE_x64.so
./Bin/linux64/libPhysX3PROFILE_x64.so
./Bin/linux64/libPhysX3CharacterKinematicPROFILE_x64.so
./Bin/linux64/libPhysX3CookingPROFILE_x64.so
./Bin/linux64/libPhysX3Common_x64.so
./Bin/linux64/libPhysX3_x64.so
./Bin/linux64/libPhysX3CharacterKinematic_x64.so
./Bin/linux64/libPhysX3Cooking_x64.so

PhysX提供DEBUG和RELEASE库,使用DEBUG库编译可以连接PVD进行调试,另外,因为执行时需要动态链接,所以也需要把动态库的路径添加到ld.so.conf配置中,完成配置后执行ldconfig刷新,同时也可以执行ldconfig -p进行检查是否添加成功。

代码语言:txt
AI代码解释
复制
[root@SH-todo-1412181717 /data/physx/PhysX-3.4-master/PhysX_3.4]# cat /etc/ld.so.conf
include ld.so.conf.d/*.conf
/data/physx/PhysX-3.4-master/PxShared/bin/linux64/
/data/physx/PhysX-3.4-master/PhysX_3.4/Bin/linux64/

3. DEMO测试

这里选择的是PhysX-3.4-master/PhysX_3.4/Snippets/SnippetHelloWorld.cpp进行测试,首先需要修改代码中的snippetMain为main,不然编译时会找不到main函数。同时编写makefile,这里的链接顺序不要错了,makefile内容如下

代码语言:txt
AI代码解释
复制
BINARY = $(patsubst %.cpp,%,$(wildcard *.cpp))

DEBUG_FLAG=-g -Werror -Wall -fPIC -fno-strict-aliasing -I ../../Include/ -I ../../../PxShared/include/ -DNDEBUG  \
        -L ../../Bin/linux64/ \
        -lPxFoundationDEBUG_x64 \
        -lPhysX3CommonDEBUG_x64 \
        -lPhysX3DEBUG_x64 \
        -lPhysX3CookingDEBUG_x64  \
        -lPhysX3PROFILE_x64 \
        -lPhysX3CommonPROFILE_x64 \
        -lPhysX3CharacterKinematicDEBUG_x64 \
        -L ../../Lib/linux64/ \
        -lLowLevel \
        -lPhysX3Extensions \
        -l PhysX3Vehicle \
        -l SceneQuery \
        -l SimulationController \
        -L ../../../PxShared/bin/linux64/ \
        -lPxFoundationDEBUG_x64 \
        -lPxPvdSDKDEBUG_x64 \
        -lPxFoundationPROFILE_x64 \
        -lPxPvdSDKPROFILE_x64 \
        -L ../../../PxShared/lib/linux64/ \
        -lPsFastXmlDEBUG \
        -lPxCudaContextManagerDEBUG \
        -lPxTaskDEBUG \
        -lpthread -ldl -rdynamic

RELEASE_FLAG = -Werror -Wall -fPIC -fno-strict-aliasing -I ../../Include/ -I ../../../PxShared/include/ -DNDEBUG  \
        -L ../../Bin/linux64/ \
        -lPxFoundation_x64 \
        -lPhysX3Common_x64 \
        -lPhysX3_x64 \
        -lPhysX3Cooking_x64  \
        -lPhysX3PROFILE_x64 \
        -lPhysX3CommonPROFILE_x64 \
        -lPhysX3CharacterKinematic_x64 \
        -L ../../Lib/linux64/ \
        -lLowLevel \
        -lPhysX3Extensions \
        -l PhysX3Vehicle \
        -l SceneQuery \
        -l SimulationController \
        -L ../../../PxShared/bin/linux64/ \
        -lPxFoundation_x64 \
        -lPxPvdSDK_x64 \
        -lPxFoundationPROFILE_x64 \
        -lPxPvdSDKPROFILE_x64 \
        -L ../../../PxShared/lib/linux64/ \
        -lPsFastXml \
        -lPxCudaContextManager \
        -lPxTask \
        -lpthread -ldl -rdynamic

#all:$BINARY)

all:SnippetHelloWorld.cpp
        g++ SnippetHelloWorld.cpp $(DEBUG_FLAG)

这里只编译SnippetHelloWorld.cpp测试,执行make all即可,生成a.out,执行a.out测试是否成功。

三、 PVD调试

上一小节,已经完成了PhysX在服务器端的编译,下面我们开始测试PVD和服务器进程的连通调试。

首先介绍一下PVD的工作原理,PVD启动后会监听127.0.0.1:5425端口,服务器上启动的进程,需要连接上PVD进行,连通后PVD界面上会出现服务器创建的场景。

1. PVD安装

PVD安装十分简单,进入NVIDA官方下载页,下载安装即可,启动后可以看到PVD的主界面,同时在当前机器上,telnet 127.0.0.1 5425可以连通,说明PVD正常启动,并监听端口成功。

下面是连接的示例代码:

代码语言:txt
AI代码解释
复制
    gFoundation = PxCreateFoundation(PX_FOUNDATION_VERSION, gAllocator, gErrorCallback);

    gPvd = PxCreatePvd(*gFoundation);
    PxPvdTransport* transport = PxDefaultPvdSocketTransportCreate(PVD_HOST, 5425, 10);
    if ( transport == NULL ) {
        printf("Transport Create failed\n");
    }
    int ret = gPvd->connect(*transport,PxPvdInstrumentationFlag::eALL);
    printf ("connect ret:%d\n", ret);

2. 搭建反向隧道

当前公司的LINUX开发机无法直接连上办公区的开发机,这里需要建立反向隧道。这里的反向隧道是把LINUX开发机上127.0.0.1:5425的请求,转到办公区的开发机上,这里才能实现和PVD的连通。

Mac开发机上建反向隧道比较简单,执行ssh -N -f -R 5425:127.0.0.1:5425 username@10.12.234.153 -p 36000就可以,其中10.12.234.153是开发机。

Windows开发机相对麻烦一些,作者先用的openssh测试,启动后进程没有常驻,最后用putty解决了,putty的配置如下所示:

1.jpg
1.jpg

配置完成后,点击open,登陆完成后,就可以连接上了。

这时可以在Linux开发机上telnet 127.0.0.1 5425端口,如果可以连通,就说明反向隧道已经建立成功。

3. 连通PVD测试

在Linux开发机上执行a.out,可以在PVD上看到服务器进程创建的场景,下图中的测试场景是从一个UNITY测试场景导出的。

2.jpg
2.jpg

下面开始介绍如何从一个UNITY测试场景导出在PhysX中可以加载的场景。

4. 场景导出

下载UnityPhysXExport(Github:github.com/tnqiang/UnitySceneExport2PhysX3

),并按照说明操作,可以导出一份xml文件,需要注意的是,要把场景加到BuildSettings中,导出文件如下所示:

代码语言:txt
AI代码解释
复制
<PhysX30Collection version="3.3.4" >
    <UpVector >0 0 0</UpVector>
    <Scale >
        <Length >0</Length>
        <Mass >0</Mass>
        <Speed >10</Speed>
    </Scale>
    <PxMaterial >
        <Id >2253976624</Id>
        <DynamicFriction >0.6</DynamicFriction>
        <StaticFriction >0.6</StaticFriction>
        <Restitution >0</Restitution>
        <FrictionCombineMode >eAVERAGE</FrictionCombineMode>
        <RestitutionCombineMode >eAVERAGE</RestitutionCombineMode>
    </PxMaterial>

服务器端的加载配置并添加到场景中的代码如下:

代码语言:txt
AI代码解释
复制
    //load config
    PxDefaultFileInputData inputData("./MainScence.xml");
    PxCollection * collection = PxSerialization::createCollectionFromXml(inputData, *cooking, *registry );    
    if (NULL == collection) {
        printf("CreateCollectionFromXml failed\n");
        return;
    }

    //create scene
    PxSceneDesc sceneDesc(gPhysics->getTolerancesScale());
    sceneDesc.gravity = PxVec3(0.0f, -9.81f, 0.0f);
    gDispatcher = PxDefaultCpuDispatcherCreate(2);
    sceneDesc.cpuDispatcher    = gDispatcher;
    sceneDesc.filterShader    = PxDefaultSimulationFilterShader;
    gScene = gPhysics->createScene(sceneDesc);
    gScene->addCollection(*collection);

四、 从Unity场景导出NavMesh

从Unity场景导出NavMesh的方法,查到的资料主要有两种方法,这两种方法都是基于Recastnavigation库。

方法一是使用CritterAI库,安装插件到Unity中,项目地址在https://github.com/kbengine/unity3d_nav_critterai ,项目主页上介绍的方法比较简单,但依赖于地形数据,比较耗性能,网上还有一篇采用query_tag选项导出的方法,尝试多次后没有成功,所以放弃了这一方法。

方法二是直接使用Recastnavigation库,这里主要介绍下这种方法的导出过程。

Recast/Detour在线手册http://masagroup.github.io/recastdetour/index.html ,有兴趣的同学可以研究下。

1. 导出场景描述的OBJ文件

从wiki上的源码,生成两个cs文件ObjExporter.cs和EditorObjExporter.cs

http://wiki.unity3d.com/index.php?title=ObjExporter

把两个文件放到当前项目Assets/Editor文件夹下,然后选择一个网格对象,在 Custom 菜单中根据需要选择导出为 Obj 文件,文件将被保存在项目目录中,扩展名为.obj的文件。

3.png
3.png

2. 安装Recastnavigation库

首先要从github主页下载项目,https://github.com/recastnavigation/recastnavigation

下载完后,根据主页上的说明,下载premake5,放到RecastDemo下,通过cmd命令行,生成vs2010依赖的编译文件,premake5的使用方法这里不再介绍,执行的命令如下:

premake5.exe —os=windows vs2010

然后需要下载SDL2库,进入http://www.libsdl.org/download-2.0.php ,下载SDL2-devel-2.0.5-VC.zip即可,下载完成后放到RecastDemo/Contrib目录下,如下图所示:

4.png
4.png

用vs2015打开项目,执行编译(如果出现了连接错误,可以尝试将项目——项目属性——配置属性——连接器——清单文件——嵌入清单 “是”改为“否”),编译成功后,可以在bin目录下找到RecastDemo.exe文件,双击打开即可。Demo中提供了两个测试场景,在InputMesh中选择其中一个进行加载,关于Recastnavigation的使用,这里不再详述.

5.png
5.png

3. 导入场景文件,导出NavMesh文件

把上面导出的.obj文件放到Bin/Meshes下,然后选择目标obj文件,执行Build,即可完成NavMesh的构建,如下图所示:

6.png
6.png

右侧支持调整参数,调整完成后点击build可以再次生成,确认OK后点击save即可生成服务器可以使用的navmesh.bin文件。

五、 服务器加载NavMesh文件

1. Linux环境,Recastnavigation环境搭建

服务器加载NavMesh文件,需要用到Recastnavigation中的Detour库,所以,首先需要在Linux开发环境,搞完编译问题。

把之前下载的Recastnavigation,在Linux下解压,并在Detour的Source目录下创建makefile,Detour库没有任何外部的依赖,所以编译比较简单,编译生成一个静态库。

代码语言:txt
AI代码解释
复制
OBJS = $(patsubst %.cpp,%.o,$(wildcard *.cpp))
FLAG=-g -Werror -Wall -fPIC -fno-strict-aliasing -I ../Include/ 

TARGET = libdetour.a
all:$(TARGET)

$(TARGET):$(OBJS)
        ar q $@ $(OBJS)

%.o:%.cpp
        g++ -c $< $(FLAG) 

clean:
        rm -rf $(TARGET) $(OBJS)

编译成功后,在之前的demo编译的makefile中,加下对Detour库的链接。

代码语言:txt
AI代码解释
复制
DETOUR = -I /data/physx/recastnavigation-master/Detour/Include/ -L /data/physx/recastnavigation-master/Detour/Source/ -l detour

#all:$BINARY)

all:SnippetHelloWorld.cpp
        g++ SnippetHelloWorld.cpp $(DEBUG_FLAG) $(DETOUR)

2. 加载NavMesh文件

加载NavMesh文件,需要用到Detour中的dtNavMesh类,类提供了Init接口,但是使用RecastDemo导出的bin文件,不能直接用使用Init接口打开,因为这里用到了自定义的头部结构,头部结构定义在Sample_TileMesh.cpp中,如下所示:

代码语言:txt
AI代码解释
复制
struct NavMeshSetHeader
{
    int magic;
    int version;
    int numTiles;
    dtNavMeshParams params;
};

struct NavMeshTileHeader
{
    dtTileRef tileRef;
    int dataSize;
};

RecastDemo生成的文件头部是NavMeshSetHeader结构,而不是MeshHeader,这里官方没有一个很好的说明,详细可以看下面的加载代码:

代码语言:txt
AI代码解释
复制
    FILE* fp = fopen(path, "rb");
    if (!fp) return 0;

    // Read header.
    NavMeshSetHeader header;
    size_t readLen = fread(&header, sizeof(NavMeshSetHeader), 1, fp);
    if (readLen != 1)
    {
        fclose(fp);
        return 0;
    }
    if (header.magic != NAVMESHSET_MAGIC)
    {
        fclose(fp);
        return 0;
    }
    if (header.version != NAVMESHSET_VERSION)
    {
        fclose(fp);
        return 0;
    }

    dtNavMesh* mesh = dtAllocNavMesh();
    if (!mesh)
    {
        fclose(fp);
        return 0;
    }
    dtStatus status = mesh->init(&header.params);
    if (dtStatusFailed(status))
    {
        fclose(fp);
        return 0;
    }

初始化成功后,就可以读取所有的Tiles

代码语言:txt
AI代码解释
复制
    // Read tiles.
    for (int i = 0; i < header.numTiles; ++i)
    {
        NavMeshTileHeader tileHeader;
        readLen = fread(&tileHeader, sizeof(tileHeader), 1, fp);
        if (readLen != 1)
        {
            fclose(fp);
            return 0;
        }

        if (!tileHeader.tileRef || !tileHeader.dataSize)
            break;

        unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
        if (!data) break;
        memset(data, 0, tileHeader.dataSize);
        readLen = fread(data, tileHeader.dataSize, 1, fp);
        if (readLen != 1)
        {
            fclose(fp);
            return 0;
        }

        mesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0);
    }

    gMeshQuery = dtAllocNavMeshQuery();
    if (!gMeshQuery) {
        printf("alloc nav mesh query failed\n");
        return -1;
    }

    static int max_node = 1024;
    status = gMeshQuery->init(mesh, max_node);
    if (dtStatusFailed(status)) {
        printf("nav query  init failed\n");
        return -1;
    }

到此,navmesh结构已经构建完成,MeshQuery对象也完成初始化,下一步可以用MeshQuery对象进行寻路。

3.关于坐标系

在寻路测试中,碰到一个很奇怪的问题,在LINUX寻路控制一个角色移动时,发现角色会穿墙,对比了RacastDemo中的测试路径和PVD中的移动轨迹发现二者是镜像关系,这才发现原来是坐标系的问题。

Unity采用的是左手坐标系,PVD中可选左手\右手,当然这里设置的是左手,而RecastNavigation中采用的是右手坐标系。

7.png
7.png

实测发现,RacastNavigatoin里的坐标点和Unity中的坐标点,只有X坐标是反的。 也就是说Unity中的(20, 1, 30),对应NavMesh中应该是(-20, 1, 30)。 所以这里在调用Detour API的时候,坐标系的X坐标需要乘上-1转换为右手坐标系,得到的路径点座标结果,也需要再乘上-1,还原为左手坐标系。

这里建议大家把坐标转换封装起来,对上层调用的人来说,就不需要关注坐标的问题了。

4. 寻路测试

下面,我们来测试下服务器的寻路,这里的测试方法是,在RecastDemo中选择一个路径,在服务器上输出起始点,在PVD上观察角色移动的路径,是否和RecastDemo中一致。

首先我们在RecastDemo中选择一个测试路径:

8.png
8.png

起点在(24.53, 0, -18.70), 终点在(-24.03, 0, 27.95).

在服务器上输出起始点,因为坐标系的原因,这里的X是取反的,另外,因为Y轴没有变化,所以暂不输出Y坐标。

代码语言:txt
AI代码解释
复制
start:-24.530001 0.000000 -18.700001
end:24.030001 0.000000 27.950001
start_poly:5505024 end_poly:7143425
path_count = 26
straight_path_count:9
24.530001 0.000000 -18.700001
30.800003 0.200000 -15.999999
30.500004 0.200000 -13.899999
14.000003 0.200000 4.700002
-1.899998 0.200000 23.000004
-10.899999 0.200000 29.000004
-13.899999 0.200000 32.900002
-15.999999 0.200000 33.200005
-24.030001 0.000000 27.950001

测试一共经过9个点后,到达目标。

在PVD上,可以看到实际的模拟情况,这里抽取了几个截图。

9.jpg
9.jpg

测试结果显示,服务器的寻路结果和RecastDemo中是一致的。

六、 总结

回头我们最初的问题,如何从“Unity中,导出物理场景给服务器使用,同时借助NavMesh实现在场景中的角色导路”,借助于上面的工具,这个问题已经实现,最后我们再总结下具体的工作流。

工作流启动于Unity中的场景修改后,需要依次执行以下步子骤:

  1. 使用UnityPhysXExport生成PhysX加载的配置,同步到服务器,现在的格式是XML文件。
  2. 导出场景描述文件.obj,采用RacastDemo生成.bin文件,同步到服务器,现在是二进制的bin文件。
  3. 连接PVD,检查步骤1生成的配置是否OK;测试几次寻路点,检查步骤2生成的NavMesh文件是否OK。

最后附上参考资料和API手册。

七、 参考资料

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
一步一步解读神经网络编译器TVM(二)——利用TVM完成C++端的部署
在上一篇文章中<一步一步解读神经网络编译器TVM(一)——一个简单的例子>,我们简单介绍了什么是TVM以及如何利用Relay IR去编译网络权重然后并运行起来。
老潘
2023/10/19
1.3K0
一步一步解读神经网络编译器TVM(二)——利用TVM完成C++端的部署
【Unity3D】自动寻路系统Navigation实现人物上楼梯、走斜坡、攀爬、跳跃
Radius:烘培的半径,也就是物体的烘培的半径。这个值影响物体能通过的路径的大小
恬静的小魔龙
2020/03/11
11.4K1
【Unity3D】自动寻路系统Navigation实现人物上楼梯、走斜坡、攀爬、跳跃
Unity NavMesh & LineRenderer AI寻路及导航路径的绘制
Nav Mesh是Unity中用于寻路行为的AI功能,下面简单介绍Nav Mesh的使用以及如何使用Line Renderer组件将寻路的路径通过如下方式绘制出来:
CoderZ
2022/08/29
2.8K0
Unity NavMesh & LineRenderer AI寻路及导航路径的绘制
人机智能交互技术示例-Leap Motion通过ROS控制机械手Gazebo仿真
http://blog.csdn.net/zhangrelay/article/details/52356417
zhangrelay
2019/01/23
1.4K0
如何入侵linux服务器?这几个命令够用了
写个php一句话后门上去: [jobcruit@wa64-054 rankup_log]$ echo -e "<?php @eval(\$_POST[md5])?>" >rankuplog_time.
马哥linux运维
2019/02/28
3.2K0
如何阅读一个前向推理框架?以NCNN为例。
CNN从15年的ResNet在ImageNet比赛中大放异彩,到今天各种层出不穷的网络结构被提出以解决生活中碰到的各种问题。然而,在CNN长期发展过程中,也伴随着很多的挑战,比如如何调整算法使得在特定场景或者说数据集上取得最好的精度,如何将学术界出色的算法落地到工业界,如何设计出在边缘端或者有限硬件条件下的定制化CNN等。前两天看到腾讯优图的文章:腾讯优图开源这三年 ,里面提到了NCNN背后的故事,十分感动和佩服,然后我也是白嫖了很多NCNN的算法实现以及一些调优技巧。所以为了让很多不太了解NCNN的人能更好的理解腾讯优图这个"从0到1"的深度学习框架,我将结合我自己擅长的东西来介绍我眼中的NCNN它是什么样的?
BBuf
2020/12/23
2K0
​在tinycolinux32上装tinycolinux64 kernel和toolchain
本文关键字:高版本gcc cross compile 交叉编译低版本gcc,boostrap,为tinycolinux低版本linux kernel生成gcc,在32位linux cross build gcc target for linux64 execution,32位64位混合rootfs制作,运行cross build的应用。
minlearn
2020/09/29
8790
Oracle 大数据量导出工具——sqluldr2 的安装与使用
近期在做一些国产数据库的 POC 工作,在数据迁移导出时用到了数据导出工具 sqluldr2,它是一款十分不错的 oracle 数据导出工具,还支持导出时同时生成 sqlldr 的控制文件,它可以将数据以 TXT/CSV 等格式导出,能导出亿级数据为 excel 文件,包含32、64 位程序,不仅在大数据量导出方面速度超快,导入速度也是非常快速。
JiekeXu之路
2023/09/06
3.6K0
Oracle 大数据量导出工具——sqluldr2 的安装与使用
Linux下编译并使用miracl密码库
参考:http://blog.sina.com.cn/s/blog_53fdf1590102y9ox.html
墨文
2020/02/28
2.9K0
Linux下编译并使用miracl密码库
编译FFMpeg n4.2.5、OpenCV-3.4.16、OpenCV-4.5.4
做测试时需要用OpenCV。虽然网络上有大量的关于编译OpenCV的教程,但是还是遇到了问题。因此记录了编译的过程,希望以后能更加顺利。
hankfu
2021/12/10
2.6K0
3D 小姐姐模型是怎么“捏”成的? 初识 Mesh 知识点!
今天菜鸟和大家一起来讨论一下3D入门的基础性知识:「Mesh」它是3D模型能正常展现的重要因素。(文末有奖问卷调查,感谢各位老铁支持!)
张晓衡
2023/02/23
1.2K0
3D 小姐姐模型是怎么“捏”成的? 初识 Mesh 知识点!
rtsp服务器测试的“骚”操作!
大家晚上好,今天在写文章之前,先事先说明一下,以后的文章都会分成专题来进行写,这样方便大家可以查看。
用户6280468
2022/03/21
2.5K0
rtsp服务器测试的“骚”操作!
Nimcrypt2:一款功能强大的PE封装器加载器
Nimcrypt2一款功能强大的PE封装器和加载器,该工具基于Nim开发,除了PE之外,该工具还支持对.NET、和原始Shellcode进行封装和加载。该工具能够通过尝试绕过AV/EDR来检测系统的安全性能。
FB客服
2022/06/08
8470
Linux实现树莓派3B的国密SM9算法交叉编译——(二)miracl库的测试与静态库的生成
Linux实现树莓派3B的国密SM9算法交叉编译——(一)环境部署、简单测试与eclipse工程项目测试
墨文
2020/02/28
1.2K0
Linux实现树莓派3B的国密SM9算法交叉编译——(二)miracl库的测试与静态库的生成
如何使用Ascend的ATB加速库?
Ascend Transformer Boost加速库(下文简称为ATB加速库)是一款高效、可靠的加速库,基于华为Ascend AI处理器,专门为Transformer类模型的训练和推理而设计。具体请阅读:ATB是什么? - 知乎 (zhihu.com)
zjun
2024/12/04
1420
如何使用Ascend的ATB加速库?
Unity链接Photon服务器
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
bering
2019/12/03
2.4K0
Ubuntu22安装N卡驱动以及CUDA
官网网址:https://www.nvidia.com/Download/index.aspx?lang=en-us
Here_SDUT
2024/02/03
3.8K0
Ubuntu22安装N卡驱动以及CUDA
TensorRT + YOLOv5第六版C++部署全解
点击上方↑↑↑“OpenCV学堂”关注我 OpenCV单目相机标定,图像畸变校正 前言 之前对YOLOv5第六版分别在OpenCV DNN、OpenVINO、ONNXRUNTIME 上做了测试,因为版本兼容问题,一直无法在TensorRT上做测试,我当时跑CUDA11.0 + cuDNN8.4.x时候给我报的错误如下: Could not load library cudnn_cnn_infer64_8.dll. Error code 126Please make sure cudnn_cnn_infe
OpenCV学堂
2022/04/08
5.7K2
TensorRT + YOLOv5第六版C++部署全解
使用 SCF 无服务器云函数定时备份数据库
最近有客户询问到使用云函数进行数据库导出备份时的一些问题,在此也进行一下总结,描述如何使用云函数来进行数据库备份。
腾讯云serverless团队
2018/07/10
10.2K0
【老张监控技术】Zabbix监控redis
2013年开始使用Zabbix,2014-2016年负责Zabbix二次开发及架构设计,目前从事PaaS平台及微服务的开发和运维工作,Zabbix实践爱好者,Cactifans作者,golang爱好者
Zabbix
2021/02/03
1.5K0
推荐阅读
相关推荐
一步一步解读神经网络编译器TVM(二)——利用TVM完成C++端的部署
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档