unreal 如何导出高度图_unreal4导出资源 - CSDN
  • ue4 导出渲染全景视频序列帧

    万次阅读 2017-08-02 16:29:58
    因为又需要在ue4里面导出全景图片 所以在这里记录下快速导出图片的方式 顺便说一下这个用ue自带的插件导出是立体全景图片,所以会输出左右眼 这里使用的版本是ue 4.16.3 另外导出速度很慢,会一度以为是卡死了,...

    因为又需要在ue4里面导出全景图片

    所以在这里记录下快速导出图片的方式

    顺便说一下这个用ue自带的插件导出是立体全景图片,所以会输出左右眼

    这里使用的版本是ue 4.16.3

    另外导出速度很慢,会一度以为是卡死了,其实并没有卡死,可以看输出目录


    先在项目里勾选插件,切换项目的时候勾上



    上图防止性能造成的掉帧



    这个防止贴图模糊,其他一些防止贴图和渲染异常问题可以看下面的

    http://blog.csdn.net/shenmifangke/article/details/52072969




    然后上面两个

    当然不想输入的可以打开level blueprint  把下面的复制到蓝图里去

    Begin Object Class=K2Node_CallFunction Name="K2Node_CallFunction_22"
       FunctionReference=(MemberParent=Class'/Script/Engine.KismetSystemLibrary',MemberName="ExecuteConsoleCommand")
       NodePosX=224
       NodePosY=-16
       NodeGuid=11178A754D409AB621A487A830D334FA
       CustomProperties Pin (PinId=30971BE3417E9BED6A6ED59AD40C7566,PinName="execute",PinToolTip="\nExec",PinType.PinCategory="exec",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,LinkedTo=(K2Node_Event_0 4DEBACD54F6CDBA70521C5A3703A5E9A,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
       CustomProperties Pin (PinId=8B4F50EB42EBE0647DAE1C8E4F5727FE,PinName="then",PinToolTip="\nExec",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,LinkedTo=(K2Node_CallFunction_23 01A6FD42488A91CBE56099BA826CEB3C,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
       CustomProperties Pin (PinId=31721CDF4824F2E7CB4D089286DA2A3F,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target"),PinToolTip="Target\nKismet System Library Reference",PinType.PinCategory="object",PinType.PinSubCategoryObject=Class'/Script/Engine.KismetSystemLibrary',PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,DefaultObject="/Script/Engine.Default__KismetSystemLibrary",PersistentGuid=00000000000000000000000000000000,bHidden=True,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
       CustomProperties Pin (PinId=AEA672F945920785F2E509A08AF22748,PinName="WorldContextObject",PinToolTip="World Context Object\nObject Reference",PinType.PinCategory="object",PinType.PinSubCategoryObject=Class'/Script/CoreUObject.Object',PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PersistentGuid=00000000000000000000000000000000,bHidden=True,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
       CustomProperties Pin (PinId=61ABAE364F5F1F8AD9B59C8E31882A0C,PinName="Command",PinToolTip="Command\nString\n\nCommand to send to the console",PinType.PinCategory="string",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,DefaultValue="SP.OutputDir E:/ccccc",PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
       CustomProperties Pin (PinId=F19B5D494174445B1306F38A20A1CB03,PinName="SpecificPlayer",PinToolTip="Specific Player\nPlayer Controller Reference\n\nIf specified, the console command will be routed through the specified player",PinType.PinCategory="object",PinType.PinSubCategoryObject=Class'/Script/Engine.PlayerController',PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
    End Object
    Begin Object Class=K2Node_CallFunction Name="K2Node_CallFunction_23"
       FunctionReference=(MemberParent=Class'/Script/Engine.KismetSystemLibrary',MemberName="ExecuteConsoleCommand")
       NodePosX=480
       NodePosY=16
       NodeGuid=61E787F04964F936FB0342AC79CE318A
       CustomProperties Pin (PinId=01A6FD42488A91CBE56099BA826CEB3C,PinName="execute",PinToolTip="\nExec",PinType.PinCategory="exec",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,LinkedTo=(K2Node_CallFunction_22 8B4F50EB42EBE0647DAE1C8E4F5727FE,),PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
       CustomProperties Pin (PinId=2BA80EAA42CBC1A4AF89F296A0226E01,PinName="then",PinToolTip="\nExec",Direction="EGPD_Output",PinType.PinCategory="exec",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
       CustomProperties Pin (PinId=3BF47BE34AF53040ADEF028D2D749950,PinName="self",PinFriendlyName=NSLOCTEXT("K2Node", "Target", "Target"),PinToolTip="Target\nKismet System Library Reference",PinType.PinCategory="object",PinType.PinSubCategoryObject=Class'/Script/Engine.KismetSystemLibrary',PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,DefaultObject="/Script/Engine.Default__KismetSystemLibrary",PersistentGuid=00000000000000000000000000000000,bHidden=True,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
       CustomProperties Pin (PinId=6FC7C43347758A7D138E92951588D28F,PinName="WorldContextObject",PinToolTip="World Context Object\nObject Reference",PinType.PinCategory="object",PinType.PinSubCategoryObject=Class'/Script/CoreUObject.Object',PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PersistentGuid=00000000000000000000000000000000,bHidden=True,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
       CustomProperties Pin (PinId=AD9934904A296DC7B4341C94499E5AC5,PinName="Command",PinToolTip="Command\nString\n\nCommand to send to the console",PinType.PinCategory="string",PinType.PinSubCategoryObject=None,PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,DefaultValue="SP.PanoramicMovie 0 60",PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
       CustomProperties Pin (PinId=6A188951457AFD3F80FA5786D9B01A62,PinName="SpecificPlayer",PinToolTip="Specific Player\nPlayer Controller Reference\n\nIf specified, the console command will be routed through the specified player",PinType.PinCategory="object",PinType.PinSubCategoryObject=Class'/Script/Engine.PlayerController',PinType.PinSubCategoryMemberReference=(),PinType.bIsArray=False,PinType.bIsReference=False,PinType.bIsConst=False,PinType.bIsWeakPointer=False,PersistentGuid=00000000000000000000000000000000,bHidden=False,bNotConnectable=False,bDefaultValueIsReadOnly=False,bDefaultValueIsIgnored=False,bAdvancedView=False,)
    End Object
    
    记得左上角的compile 应该没有问题,比如上面是60帧

    一般只要弄上面的两个就行了,当然测试的时候为了速度可以减小下尺寸

    控制输出图片大小可以再连一个 设置宽度,高度自动是宽度的一半


    记得要把SP.StepCaptureWidth 1024放在前面,这个表示导出的图都是1024×512默认是4096×2048的

    然后就能运行开始录制了,会录制到SP.PanoramicMovie设置的300帧结束



    为了保证恒定帧率 还要以固定帧率打开编辑器

    -usefixedtimestep -fps=60 -notexturestreaming

    上面这句可以加载编辑器的快捷方式里


    一般编辑器位置在

    E:\Program Files\Epic Games\4.13\Engine\Binaries\Win64

    E:\Program Files\Epic Games\UE_4.16\Engine\Binaries\Win64

    这种位置



    中文参考

    https://docs.unrealengine.com/latest/CHN/Platforms/VR/StereoPanoramicCapture/QuickStart/index.html

    其他设置可以参考

    https://docs.unrealengine.com/latest/INT/Platforms/VR/StereoPanoramicCapture/TipsAndTricks/index.html


    各个参数含义可以看这里

    https://docs.unrealengine.com/latest/INT/Platforms/VR/StereoPanoramicCapture/Reference/index.html

    还有一个完整的官方教程

    https://www.unrealengine.com/zh-CN/blog/capturing-stereoscopic-360-screenshots-videos-movies-unreal-engine-4

    展开全文
  • UE4导入高度图

    2020-07-15 08:51:48
    UE4导入高度图查找高度图使用ps编辑图片打开虚幻引擎的地形编辑器 查找高度图 可以从百度直接搜索 使用ps编辑图片 下载下来之后图片是jpg格式的,虚幻引擎不能直接用 需要使用ps编辑一下 选择图像->勾选灰度和...

    查找高度图

    可以从百度直接搜索
    在这里插入图片描述

    使用ps编辑图片

    下载下来之后图片是jpg格式的,虚幻引擎不能直接用
    需要使用ps编辑一下
    在这里插入图片描述
    选择图像->勾选灰度和16位通道,注意:如果不勾选灰度,图片有颜色的话,ue生成地形可能出现问题;还有ue只支持16位通道,不要选择其他通道
    在这里插入图片描述
    点击文件和储存为,之后出现一个弹窗,填写自己图片的名字,注意图片的格式只能是png和raw,其他格式ue不支持

    打开虚幻引擎的地形编辑器

    1.ue4.25的地形在模式下面,勾选地形之后左边才会出现新建地形的选项列表,我们选择从文件导入,选择刚才生成的图片。
    在这里插入图片描述
    2.这个缩放的Z值可以更改地形山峰的锐利度和高度,一半20-40都没问题
    在这里插入图片描述
    点击导入之后就是这样
    在这里插入图片描述
    如果你不改Z值,或者Z值太高,就可能是这样
    在这里插入图片描述

    觉得有用的点个赞呗!!

    展开全文
  • 本节书摘来异步社区《精通Unreal游戏引擎》一书中的第4步,作者: 【英】Ryan ...精通Unreal游戏引擎首先,前往Modes(模式)窗口(通常在项目主窗口的左上角),如19所示。 注意:该工具栏会根据您屏幕的分辨率...

    本节书摘来异步社区《精通Unreal游戏引擎》一书中的第4步,作者: 【英】Ryan Shah(沙哈)译者: 王晓慧 责编: 陈冀康,更多章节内容可以访问云栖社区“异步社区”公众号查看。

    第4步 使用BSP创建地图

    精通Unreal游戏引擎
    首先,前往Modes(模式)窗口(通常在项目主窗口的左上角),如图19所示。


    19

    注意:
    该工具栏会根据您屏幕的分辨率隐藏一些选项。拖拉工具栏的底部和侧面边框扩展它,就可以看到所有选项!

    下面使用BSP刷子创建一些几何体。在此之前,让我来解释一下什么是BSP,使用BSP的好处和注意事项。

    BSP是可编辑的几何体,可以用来充实项目的场景。想一下,您在使用可定制的乐高玩具创建关卡时,可以很快得到雏形,但是乐高玩具并不适用于制作最终产品。为什么呢?因为BSP非常占用资源。BSP的主要功能是帮助您勾勒出一个关卡的轮廓,和正常的静态网格相比,它们在渲染的时候会消耗更多的内存和资源。

    读到这里,您肯定要问“为什么一开始还要使用BSP呢?”因为BSP可以在Unreal Engine 4中快速简单地创建一个游戏关卡。在30秒之内,您就能创建一个可以自由行动的房间。

    此外,您可以将任意的BSP(或者一些BSP的集合)转换为一个静态网格,然后将这个静态网格导出到您喜欢的3D建模程序中,进而以它们为基础创建最终的游戏关卡。一旦创建完毕,还能将该网格导回Engine来代替BSP,给您节省了大量的时间和不必要的努力。

    关于BSP的更多信息,推荐您到Unreal Engine网站上或者在Unreal Engine 4的窗口中单击F1查看相关文档。

    现在我们在场景中创建两面墙,把大块空间分割成几个小块,让我们的地图显得更有深度,也更有趣。

    前往Mode(模式)工具箱(记得调整窗口大小以看到所有选项),选择类别BSP,如图20所示,单击Box(盒子)并拖拽它到项目场景视图中。


    20

    现在场景中在您放置BSP的地方已经有了一个大小合适的盒子。需要注意的是,如果您的盒子有一半陷在了地板里,或者有一半嵌入了墙中,可以使用Transform(平移)工具(由3个箭头组成,分别是蓝色、红色和绿色)移动盒子让它刚好坐落在地面上。如果您没有看到平移工具,在场景中直接单击盒子即可,如图21所示。


    21

    注意:
    为了让您看清图像中的盒子,这里对地面添加了材质。如果书中图像的分辨率不高,可以从http://content.kitatusstudios.co.uk网站上下载本书中所有图像的高清版本。

    这个盒子看起来不错,但是我们需要的是在当前场景中建一面墙。类似前面的操作,可以很容易地把盒子变成一面墙(记住:直接单击盒子,平移工具就出现了),先把盒子移动到地图中间,如图22所示。


    22

    注意:
    当移动盒子的时候,您可能不经意地把它放在了场景中某个物体的上面,这个物体看起来像一个操控杆或者一面旗,且会从中出来一个蓝色的箭头。其中,这个操控杆是玩家的初始位置, 箭头是玩家面朝的方向。如果操纵杆在盒子内部,情况会很糟糕,因为玩家将出现在盒子内部,所以在移动盒子的时候请注意这一点。

    您可以单击它,使用平移工具将操纵杆移出去,或者在Scene Outliner(场景大纲视图,通常在工作区的右上方)中找到Player Start,单击Player Start并用平移工具将其移出去。

    现在,盒子已经在地图中间了,但是它看起来并不像一面墙。再次前往Modes(模式)工具箱(我们创建盒子的地方),您会发现Modes(模式)窗口的上方有5个按钮,如图23所示。


    23

    图 #1 Place (放置)—图标是一个立方体,前面放着一个灯泡。该工具可以实现把光照、BSP、触发器等对象放置到场景中。
    图 #2 Paint (描画)—图标是一个画刷。该工具可以实现在静态网格上绘制顶点信息,例如在岩石上添加苔藓(您需要有带有苔藓的岩石材质,这是后续的内容,这里不再赘述)。
    图 #3 Landscape (地貌)—图标是被雪覆盖的群山。该工具可以生成地貌(类似Far Cry编辑器)或者通过heightmaps(高度图工具)将事先创建好的地貌导入进来。
    图 #4 Foliage (植被)—图标是几片忧郁的叶子。该工具可以实现同时放置许多网格,如草和树木。
    图 #5 Geometry Edit (几何体编辑)—图标是被削去了四分之一的盒子。该工具可以实现编辑BSP对象的顶点。例如,您可以让盒子的一面变大或者变小;让盒子的两个顶角汇合等。
    我们要把立方体变成一面墙,所以使用第五个工具—Geometry Edit(几何体编辑)。直接单击该工具按钮,Modes(模式)工具箱内的选项会发生变化。该工具会自动加载默认设置—Edit(编辑)模式,如图24所示。在这5个按钮下方有一些单选框,直接单击来实现模式的切换。

    这里我们需要Edit(编辑)模式,所以不改变任何设置,但是有必要了解这些模式选项,方便以后使用。


    24

    小提示:
    直接单击Geometry Edit(几何体编辑)按钮来激活该工具。Unreal Engine 4的大部分工具,会有一个明显的激活提示,通常工具按钮会变成橘黄色。Modes(模式)工具栏有一点不同,这里为什么要介绍这个呢?因为很多时候,当您想把一个BSP从位置A移动到位置B时,有可能不经意的选中了盒子的一面然后把盒子变大了。如何阻止这种情况发生呢?很简单!时不时地查看Modes(模式)窗口,以确定当前选中的是Place(放置)工具,而不是其他工具。

    现在已经选中了Geometry Edit(几何体编辑)工具,下面单击选中场景视图中待编辑的BSP。因为我们想编辑之前创建的盒子,所以单击盒子。这时盒子的边缘被黄色和蓝色高亮显示(盒子的顶角上出现蓝色方块),如图25所示,表示盒子已经被选中,就可以进行编辑了。


    25

    注意:
    单击盒子,Gizmo(小工具,选中对象中央的红绿蓝箭头组合)变成了椭圆形状?还是箭头变成了立方体?一旦出现了这两种情况,表示当前处于错误的Gizmo mode(编辑模式)。我们可以在Gizmo Selector(编辑模式选择器)中选择正确的编辑模式。Gizmo Selector(编辑模式选择器)在主场景视图中,位于屏幕的中间或者是右上方(这取决于您屏幕的大小),如图26所示。


    26

    黄色底的选项表示当前选中的编辑模式。一共有3个选项:左边的表示Transform(平移),可以在XYZ平面上移动对象;中间的表示Rotator(旋转),可以沿着XYZ坐标旋转对象;右边的表示Scale(缩放),可以使对象变大或者变小。

    为了借助Geometry Edit(几何体编辑)工具将盒子变成一面墙的形状,我们使用最左边的Transform(平移)模式。如果该模式当前没有被选中,直接单击Gizmo Selector(编辑模式选择器)左边的按钮将编辑模式切换为Transform(平移)。

    现在我们可以编辑盒子的大小了,但是如何精确地控制呢?一旦盒子被选中,可以选择盒子的一个面来编辑。所以首先要确定盒子处于选中状态,然后单击任意一面。正处于编辑状态的面会被黄色高亮显示,您可以准确定位它,如图27所示。


    27

    对于这个面,我们需要把墙变得窄一点。虽然厚墙也可以,但是窄墙看起来更加美观!在Transform(平移)编辑模式下,单击绿箭头,按住鼠标左键拖拽箭头直到盒子的厚度是原来的一半,如图28所示。


    28

    下面就使用上述方法创建一面墙。选中您刚刚编辑的那个面左边的面,拖拽其直至与外墙(首次创建项目时自动生成的)重合,如图29所示。


    29

    墙的一侧已经编辑完毕,单击这面墙的另一侧,拖拽其直至与另一面外墙重合,这时游戏场地被分割成了两部分,如图30所示。

    30

    如何让墙变得高一点?选中最上面的面,拖拽其与外墙的高度一致即可,如图31所示。


    31

    我们已经有了一面墙,把场景分割成了两部分。但是在完成之前,还有一些操作。退出Geometry Edit(几何体编辑)工具,前往Modes(模式)窗口,单击Place(放置)按钮(Modes窗口的最上面,其图标是一个立方体,前面放着一个灯泡),如图32所示。


    32

    然后单击选中刚刚创建好的墙,如图33所示。


    34

    同时按Ctrl+C组合键复制这面墙,然后同时按Ctrl+V组合键粘贴得到墙的一个副本。也可以右键单击这面墙(Mac上是Ctrl键+鼠标左键),在下拉菜单中选择Edit(编辑),在弹出的二级菜单中选择Duplicate(复制)。

    此时您可能看不到复制得到的墙。到场景视图的中间或者中间偏右的位置找到Gizmo Selector(编辑模式选择器),选择中间的Rotator(旋转)模式。将这面墙向左或向右(使用出现的标示符中的蓝色区域)旋转90°,这时在地图中间出现了一个大大的X或+号,如图34所示。


    33

    如何使得新建的墙与外墙恰好吻合呢?使用之前学过的方法调整墙的长度,即使用Geometry Edit(几何体编辑)工具进行缩放得到合适的尺寸。


    35

    现在场景中已经有4个完美分割好的房间让我们来创建一个很酷的项目。但是您有没有注意到哪里有些不对劲,好像忽略了很重要的东西?

    由于这两面墙的缘故,这些房间之间不能穿梭。如何解决这一问题呢?下面我们将学习Subtraction Volume(减法体)。

    展开全文
  • 【转】从Unity过渡到Unreal

    千次阅读 2017-09-14 14:25:51
    Unreal Engine 4.9 开始 虚幻 4 之旅 本页面的内容: 编辑器 快速词汇查找表 项目文件和文件 从 GameObjects 到 Actors 如何在虚幻 4 中编写代码 在虚幻 4 中编写游戏逻辑代码 常见问题 然后呢? 本指南...
    Unreal Engine 4.9
    
    

    image_0.png

    本指南从一个 Unity 的用户视角来整体看待虚幻 4,并帮助将 Unity 的开发经验应用到虚幻 4 的世界中。

    编辑器

    下面是 Unity 编辑器和虚幻编辑器的图片,用颜色标识了同类的区块。每个区块也添加了标签,对应于虚幻术语表。虚幻编辑器完全可以通过对各个区块的拖拽做到窗口布局的自定义。

    image_1.png

    编辑资源素材

    在 Unity 中,Inspector 分页时用来编辑当前项目中选中的素材。在虚幻 4 中,细节 面板则用来展示并修改当前选中物体的属性,然后大量的编辑修改则需要专用的窗口或分页。编辑每种类型的资源时都会打开分页窗口,类似于网页浏览器。当然这些分页窗口也可以任意拖拽,并悬浮在其他窗口之上作为独立窗口显示。

    image_2.png

    快速词汇查找表

    下表左侧包含了常见的 Unity 术语,右侧是对应的(或差不多的)虚幻 4 术语。虚幻 4 的关键词直接链接到更进一步的虚幻在线文档中。

    分类 Unity 虚幻 4
    游戏内容类型 Component 组件
      GameObject Actor,Pawn
      Prefab 蓝图类
    编辑器界面 Hierarchy Panel 世界大纲
      Inspector 细节面板
      Project Browser 内容浏览器
      Scene View 视口
    网格物体 Mesh 静态网格物体
      Skinned Mesh 骨骼网格物体
    材质 Shader 材质,材质编辑器
      Material 材质实例
    特效 Particle Effect 特效,粒子,级联
      Shuriken 级联
    游戏界面 UI UMG (虚幻示意图行 Unreal Motion Graphics)
    动画 Animation 骨骼动画系统
      Mecanim Persona ,动画蓝图
    2D Sprite Editor Paper2D
    编程 C# C++
      Script 蓝图
    物理 Raycast Line Trace, Shape Trace
      Rigid Body 碰撞,物理
    运行平台 iOS Player, Web Player 支持的平台

    项目文件和文件

    那么目录和文件时怎么回事

    和 Unity 的项目一样,虚幻的项目也存在于自有的目录,并有自己的项目文件。可以通过 双击 一个 .uproject 文件打开虚幻编辑器并加载该项目,或者右键 来查看更多选项。项目目录中包含不同的子目录,保存了游戏的资源内容和源代码,以及各种配置文件和二进制文件。最重要的就是Content 子目录和 Source 子目录。

    我的资源素材应该放在哪里?

    在虚幻 4 中,每个项目都有一个 Content 文件夹。类似于 Unity 项目的 Asset 目录,这里就是游戏资源素材保存的地方。要向游戏中导入素材的话,只需要将素材文件拷贝到 Content 目录,它们便会自动导入并出现在内容浏览器 中。当使用外部程序修改这些资源时,编辑器中的资源也会自动的被更新。

    image alt text

    支持哪些通用资源文件格式?

    Unity 支持很多文件格式。虚幻 4 也支持最通用的文件格式,如下表:

    资源类型 支持的格式
    3D .fbx, .obj
    贴图 .png, .jpeg, .bmp ,.tga, .dds, .exr, .psd, .hdr
    声音 .wav
    字体 .ttf, .otf
    视频 .mov, .mp4, .wmv

    场景是如何保存的?

    在 Unity 中,GameObjects 被放置在场景中,并保存为一个场景资源文件。虚幻有一个地图文件,对应于 Unity 场景。地图文件保存了 关卡 的数据以及其中的物件,以及光照数据和某些关卡特定的设置。

    如果修改项目的设置?

    所有的项目设置都可以在主菜单的 Edit / Project Settings 中找到。类似于 Unity 的设置,能够对项目设定所需要的信息(比如项目的名称和图标),配置游戏输入的绑定,并定义运行项目时引擎的行为。可以在这里 了解更多单独项目的设置。Unity 还有被称为 “玩家设置” 的部分,在虚幻中,我们叫 “平台设置”,并且可以在项目设置的 “平台” 分类里找到。

    源文件在哪里?

    在 Unity 中,人们习惯于将 C# 的源文件放在资源目录中。

    虚幻 4 工作机制有点不同。对那些拥有 C++ 代码的项目,可以在项目目录中找到一个 Source 的子目录包含多种文件,包括 C++ 源文件(.cpp)和头文件(.h),以及编译链接的脚本(.Build.cs,.Target.cs)。然后,只有蓝图的项目则不会有 Source 目录。

    在虚幻 4 中开始使用 C++ 最方便的做法是用编辑器的菜单项来 Add Code To Project(在主菜单的文件菜单中),或应用某个模板来新建一个 C++ 的项目。可以直接在内容浏览器 中直接看到 C++ 类,并通过双击它们便能直接在 Visual Studio 或 Xcode 中打开该文件。

    从 GameObjects 到 Actors

    GameObject 去哪里了?

    在 Unity 中,一个 GameObject 是可以被放置在世界中的一个 “东西”。在虚幻 4 中对应的是一个 Actor。在虚幻编辑器中,可以从物体面板中直接拖一个空的 Actor 放置到场景中:

    Youtube 视频

    虽然可以通过搭建并扩展空的 Actor 来制作游戏,但虚幻 4 提供了各种特殊类型的 Actor 并预制了它们的特性,比如 Pawn(用于作为玩家或者 AI 的角色),或者 Character(用于会做动作的生物)。和空的 Actor 一样,可以直接将它们拖拽至场景中,并给它们添加组件,或自定义属性。之后可以学习到更多相关内容,这里只需要了解虚幻 4 有个 (Gameplay 框架)[(Gameplay/Framework)] 来协同各种特殊的 Actor 一起工作。

    虚幻 4 中的 Actor 还是和 Unity 中的 GameObjects 有不同之处。在 Unity 中,GameObject 是 C# 的类并且无法直接扩展。在虚幻 4 中,Actor 是 C++ 类,可以很容易的被继承或扩展来自定义。我们之后将会谈论更多!

    组件在哪里?

    在 Unity 中,可以通过为一个 GameObject 添加组件来达到给予一定的功能。

    在虚幻 4 中,也可以为 Actor 添加组件。在向关卡中放置了一个空的 Actor 后,点击添加组件按钮(在 细节 面板中),并选择一个组件来添加。这里我们通过放置一个空的 Actor 来创建一个火炬,并为它添加一个网格物体组件作为基座,以及一个光源和粒子系统作为它的火焰。

    Youtube 视频

    在 Unity 中,一个 GameObject 保存了组件的简单列表,但在虚幻 4 中,一个 Actor 保存了属于它的组件以及它们的继承结构关系。可以在上面的例子中看到,光源和粒子是连接到网格模型的。之后在复合 Actor 和 复合 GameObject 中会有重要的描述讨论。

    从 Unity 的 prefabs 到虚幻 4 的蓝图类

    Unity 的工作流程是基于 prefabs 的。在 Unity 中,创建一系列 GameObjects 以及它们的组件,并为它们创建 prefab。然后便可以在世界中放置 prefab 的实例,或者在运行时创建它们。

    虚幻 4 则是基于蓝图类来协同工作。在虚幻 4 中,创建一个 Actor 以及它的组件,选择它并点击 蓝图 / 添加脚本 按钮(在细节 面板中)。然后选择保存蓝图类的地方,并点击创建蓝图 来保存新建的蓝图!

    Youtube 视频

    新建的蓝图类可以在 内容浏览器 中找到。可以直接 双击 打开编辑它们,也可以将它们拖拽到任意场景关卡中。

    脚本组件和 MonoBehaviour 在哪里?

    在 Unity 中,GameObject 有脚本组件,并可以添加 C# 脚本。可以创建 MonoBehavior 子类并定义那个组件做什么。

    虚幻 4 也有类似的内容。可以自由创建全新的组件类并将它应用于任意 Actor。组件类可以使用蓝图脚本创建,也可以用 C++ 创建。

    那么在虚幻 4 中如何创建自己的组件类呢?在 细节 面板中,添加组件(Add Component)的下拉框中,可以看到创建新组件,或者选择已经存在的组件:

    image alt text

    在 Unity 中,当创建新的 MonoBahaviour 时,将会有一个框架类文件,并有 Start() 函数和 Update() 函数。

    在虚幻 4 中,也会有一个框架类,有一个 InitializeComponent() 函数和一个 TickComponent() 函数,它们和 Start、Update 具有类似的行为。

    如果创建一个蓝图脚本组件,则会有可视化节点来表示类似的函数:

    image alt text

    可编辑脚本 Actor 蓝图类

    这是个很酷的虚幻 4 功能:新建的 Actor 蓝图类可以拥有自己的可视化蓝图脚本编辑!这样能够为整个物体添加逻辑,而不仅仅是每个组件。结合继承结构关系(稍后下文解释),这将会提供游戏制作很多灵活性。

    In addition to Blueprint Classes supporting visual scripting, UE4 also supports C++ Classes implemented with code. Here are both, side-by-side. 除了蓝图支持可视化脚本编辑,虚幻 4 还支持通过代码 C++ 类来实现。这里是双方的一个对照:

    Unity C# 虚幻 4 C++
    using UnityEngine;
    using System.Collections;
    
    public class MyComponent : MonoBehaviour
    {
        int Count;
    
        // Use this for initialization.
        void Start ()
        {
            Count = 0;
        }
    
        // Update is called once per frame.
        void Update () 
        {
    
            Count = Count + 1;
            Debug.Log(Count);
        }
    }
    #pragma once
    #include "GameFramework/Actor.h"
    #include "MyActor.generated.h"
    
    UCLASS()
    class AMyActor : public AActor
    {
        GENERATED_BODY()
        int Count;
    
        // Sets default values for this actor's properties.
        AMyActor() 
        {
            // Allows Tick() to be called
            PrimaryActorTick.bCanEverTick = true;  
        }
    
        // Called when the game starts or when spawned.
        void BeginPlay()
        {
            Super::BeginPlay();
            Count = 0;
        }
    
        // Called every frame.
        void Tick(float DeltaSeconds)
        {
            Super::Tick(DeltaSeconds);
            Count = Count + 1;
            GLog->Log(FString::FromInt(Count));
        }
    };
    虚幻 4 蓝图
    image_28.png

    虚幻 4 蓝图类的扩展性

    Unity 的 prefabs 和虚幻 4 的蓝图类在游戏中类似的实例化。然后 Unity 在 prefabs 之间的关系上有并发的问题,这限制了创作的扩展性。

    在虚幻 4 中,可以通过扩展已有的蓝图类来创建新的蓝图类,并定义新的属性,组件功能及可视化脚本功能。

    比如,在虚幻 4 中,可以创建一个蓝图类叫做 Monster,实现基本的怪物功能,比如追击人类。然后可以创建一个叫做 Dragon 的蓝图类来扩展它(某种特定的怪物,添加了火焰吐息的功能),再有一个 Grue(一种当它变黑是就有可能吃人的怪物),以及其他 8 种类型。这样一些 Monster 的子类都继承了基础的 Monster 类的功能,并在此基础上添加新的能力。

    在 Unity 中,则需要创建很多不同的 GameObject 的 prefabs:为 Dragon 创建一个,为 Grue 创建一个,等等。假设这时希望为所有的怪物添加某个功能,比如使用一个 Speak 组件来说话,在 Unity 中则需要更新所有的 10 个 prefabs,拷贝粘贴到每个中。

    在虚幻 4 中,只需简单的修改 Monster 的蓝图类,并为它添加新的 Speak 的能力,便做完了!Dragon,Grue 以及其他 8 种 Monster 的子类都会自动的继承这个说话的新功能,并不需要去修改这些子类。

    但还有更多!我们关于蓝图类所说的一切,都同样适用于 C++ 的类,也同样对 Actors 和 组件 适用。我们的体系设计时考虑支持各种不同程度的开发形式,具有功能上的可扩展性,可以为 10 个开发人员的项目服务,也可以为 100 个人的项目人员服务。

    那么应该用蓝图脚本还是 C++ 代码呢?或者同时使用?

    可视化蓝图脚本是对游戏实时逻辑和序列型的事件的理想制作手段。这个系统对策划、美术以及面向可视化编程的程序员是非常好用的,它能够可视化的管理游戏内的物体,并且容易访问。完全可以通过蓝图就完成一个游戏的制作。请参考 Tappy Chicken 示例,它是一个完整的范例。

    C++ 编程可以为更大体量的任务工作,比如构建一个游戏体系,制作复杂的 AI 行为,或者新增引擎功能。对于已有 C++ 技能的开发人员而言,可以翻阅一下 在虚幻 4 中的 C++ 编程简述 页面。

    大部分的项目都将是混合使用蓝图和 C++。很多开发者使用蓝图来创作游戏原型,因为这个过程容易且有趣,但会在之后的性能调整和更严格的引擎使用时将部分蓝图或全部蓝图脚本转移至 C++。

    蓝图类也能扩展 C++ 类

    虚幻 4 的游戏开发中很多令人着迷的过程来存在于程序员用 C++ 实现新的功能,而策划和美术在蓝图中使用这些功能,并提出更多要求!下图是针对一个虚幻 4 的射击游戏项目中实现拾取物品过程时,团队的一种形式,混合了 C++ 类的编程实现,以及蓝图类用于处理行为和表现。

    image alt text

    转换组件

    在 Unity 中,每个 GameObject 都有一个转换组件(Transform Component),赋予该 GameObject 在世界中的位置、角度以及缩放比例。

    在 虚幻 4 中类似,Actor 有一个 Root Component,能够作为场景组件的任意子类,场景组件 赋予 Actor 在世界中的位置、角度及缩放比例,这些参数会费赋予该 Actor 的组件关系结构中在它之下的所有组件。很多有用的组件都是场景组件的子类,因此让它们具有位置信息是非常有用的!

    即便只放置一个空的 Actor,虚幻 4 也会为它创建一个“默认场景 Root 组件”,这是一个最简单的场景组件。当放置一个新的场景组件时,默认场景 Root 则会被替换掉。

    复合物体

    在 Unity 中,可以构建 GameObject 之间的关系并将他们的转换组件绑定,来创建复合物体。

    image alt text

    在虚幻 4 中,通过整洁的组件继承便能创建复合游戏物体。

    image alt text

    从上图可以看到,一个整洁的继承关系可以通过将场景组件互相附加来得到,由于他们有转换功能,类似于 Unity 中的转换的绑定。Actor 的各个组件(所有组件的基类)只能直接依附到 Actor 自己身上。

    我是否应该用组件来创造其他一切?

    其实这完全取决于你自己,大部分情况下应该结合 Actor 的类和自定义组件。我们先前已经提到过,虚幻 4 中已经提供了一些特殊类型的 Actor 用于某种能力并总是附带某些组件。比如一个Character 总是会包含一个Character Movement 组件

    有一些在引擎中常见的 Actor 类型,并且大部分种类的游戏都会用到它们。这里是我们已经制作的最常见类型 Actor 的列表:

    • Pawn - Actor 的一种类型,用于表现一个可供控制的游戏物体,比如是玩家的角色。Pawn 通常都是被玩家或者 AI 通过 Controller 控制并移动。

    • Character - 一种特殊类型的 Pawn,用于双足类型的角色,并具备一些复杂的功能。

    • Controller - 依附并控制一个 Pawn。通过将 Pawn 和 Controller 的分离,我们可以编写 AI Controller,用于控制 Pawn,并且和玩家控制 Pawn 采用相同的接口。

    • Player Controller - 一个更为特殊的 Controller,用于从玩家的手柄中获得输入信息,或者鼠标键盘中获得殊瑞星纳西,并将这些信息驱动它所控制的 Pawn 或者 Character 的行为。

    那么所有的东西都是 Actor 咯?

    并不是所有的。Actor 是虚幻 4 中最常见的用于游戏的类,并是唯一能够在 世界 中被创建生成 Spawn 的类。因此任何被放置在关卡中的东西都将是一个 Actor。

    另外一个需要知道的重要类型是 Object。Object 实际上是所有虚幻引擎的类的基类,包括 Actor 以及一些其他的类。这是一个比 Actor 更加底层的类,具备一些作为虚幻引擎类的可预料的功能,比如反射序列化。Object 是一个非常基础的类,当我们需要定义一个新的类但又并非 Actor 的时候会使用它。比如 Actor Component 是所有组件的基类,而它则是继承 Object 而非 Actor。

    在虚幻 4 中 Gameplay 框架是什么东西?

    好吧,这里开始事情变得一点点疯狂(酷炫的方向)。Unity 提供了一个干净的石板用于设计游戏,虚幻也做了同样的事情。在 Unity 中可以基于 GameObjects 和组件来创建所有的东西,而在虚幻中则是基于 Actor 和组件来创建。

    然后,虚幻在顶层提供了叫做 Gameplay 框架 的部分,而 Unity 中并没有这块内容。虽然做一款游戏并不是一定要用到它,但如果用的话会非常酷!基本上来说,它提供了一些基础功能,如果遵循它的逻辑,您将能够很容易的获得一些很赞的功能,否则可能花费很多时间,并且实现也很困难,或者很难改造。(比如完整的多人游戏支持!)

    已有大量的酷炫游戏基于虚幻的 Gameplay 框架之上制作,花点时间来了解该框架的机制是很值得的。没错,最终您将具有您自己的框架形式,如果想要这么做当然完全没问题!但虚幻 4 当前已有数以百计的炫酷开发者在使用它,因此我们花点时间来了解一下。

    要使用 Gameplay 框架,只需要了解一些预制的 Actor 类,比如 PawnCharacter,和Player Controller,并逐步了解虚幻的网络复制和网络其他功能。现在我们先回到最基本的部分。

    如何在虚幻 4 中编写代码

    我曾习惯于在 MonoDevelop 中写代码

    对于蓝图脚本,只需要虚幻编辑器——所有的东西都已经包括了!要编写 C++ 代码,在 Windows 平台下载 Visual Studio 的免费版本,如果是 Mac 的话则需要安装 Xcode。当第一次创建一个新项目(或者为已有项目添加代码)时,虚幻 4 将会自动的创建 Visual Studio 的项目文件。您只需要在内容浏览器 中双击一个 C++ 的类便能在 Visual Studio 中打开它,或者在主菜单的文件菜单中点击Open Visual Studio

    image alt text

    在虚幻 4 中有个重要的不同:有时必须要手动的更新 Visual Studio 的项目文件(比如,下载了 UE4 的新版本,或者对源代码文件的磁盘存放位置做了人为改变)。可以通过在主菜单中点击Refresh Visual Studio Project 或者在项目目录中右键点击 .uproject 文件 并选择Generate Visual Studio project files 便可。

    image alt text

    编写事件函数(Start,Update 等)

    如果您曾用 MonoBehaviors 工作,那一定熟悉诸如 Start,Update 和 OnDestroy 等方法。以下是对 Unity 的行为和对应的虚幻 4 的 Actor 和组件的比较。

    在 Unity 中,我们可能有一个简单的组件,类似下面的代码:

    public class MyComponent : MonoBehaviour
    {
        void Start() {}
        void OnDestroy() {}
        void Update() {}
    }

    请记住,在虚幻 4 中,您可以直接为 Actor 写代码而无需创建新的组件来添加代码。这其实是很常见并有意义的。

    类似于 Unity 的 Start,OnDestroy 和 Update 函数,虚幻 4 在 Actor 中有类似的方法:

    C++

    UCLASS()
    class AMyActor : public AActor
    {
        GENERATED_BODY()
    
        // Called at start of game.
        void BeginPlay();
    
        // Called when destroyed.
        void EndPlay(const EEndPlayReason::Type EndPlayReason);
    
        // Called every frame to update this actor.
        void Tick(float DeltaSeconds);
    };

    蓝图

    image_29.png

    在虚幻 4 中,组件具有不同的函数。以下是示例:

    C++

    UCLASS()
    class UMyComponent : public UActorComponent
    {
        GENERATED_BODY()
    
        // Called after the owning Actor was created
        void InitializeComponent();
    
        // Called when the component or the owning Actor is being destroyed
        void UninitializeComponent();
    
        // Component version of Tick
        void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction);
    };

    蓝图

    image_30.png

    请记住,在虚幻 4 中调用基类的方法很重要。

    比如,在 Unity C# 中可能是调用 base.Update(),但在虚幻 4 的 C++ 中我们使用 Super::TickComponent():

    void UMyComponent::TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
    {
        // Custom tick stuff here
        Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
    }

    You may have noticed some things begin with "A" and others with "U" in C++. The prefix "A" indicates an Actor sub-class. Where as the prefix "U" indicates anObject sub-class. There are some other prefixes too, for example "F" is used for most plain data structures or non-UObject classes. 您也许已经注意到 C++ 中有些以 “A” 开头,而其他一些以 “U” 开头。前缀 “A” 代表它是一个 Actor 的子类,而前缀 “U” 代表它是一个 Object 的子类。还有其他一些前缀,比如 “F” 用于代表一个平铺的数据结构体,或者其他非 Uboject 的类。

    在虚幻 4 中编写游戏逻辑代码

    好了,现在开始稍微深入一些。我们将谈论一下创建游戏所需要的编程话题。因为您了解 Unity,我们来面向 C# 的用户解释 C++ 的功能,当然您也可以使用蓝图来完成几乎所有的事情!我们尽可能的为范例提供 C++ 的同时也提供蓝图。

    先说一下一些通用的游戏逻辑编程模式,以及如何在虚幻中实现。许多在 Unity 中的函数在虚幻中都有类似的函数。我们先从最常见的开始。

    Instantiating GameObject / Spawning Actor

    在 Unity 中,我们使用 Instantiate 函数来新建物体的实例。

    该函数使用任意的 UnityEngine.Object 类型(GameObject,MonoBehaviour 等),并创建它的拷贝。

    public GameObject EnemyPrefab;
    public Vector3 SpawnPosition;
    public Quaternion SpawnRotation;
    
    void Start()
    {
        GameObject NewGO = (GameObject)Instantiate(EnemyPrefab, SpawnPosition, SpawnRotation);
        NewGO.name = "MyNewGameObject";
    }

    在虚幻 4 中,根据不同的需要,有一些不同的函数用于创建物体。NewObject 用于创建新的 UObject 类型实例,而 SpawnActor 用于创建新的 AActor 类型实例。

    首先我们总体说一下 UObject 和 NewObject。在虚幻中 UObject 的子类很像 Unity 中 ScriptableObject 的子类。对于游戏过程中,它们是那些不需要在游戏世界中创建并看见的存在。

    在 Unity 中,如果要创建自己的 ScriptableObject 子类,可能会像下面这样的初始化:

    MyScriptableObject NewSO = ScriptableObject.CreateInstance<MyScriptableObject>();

    在虚幻中,如果要创建 UObject 的继承类,是像下面这样的初始化:

    UMyObject* NewObj = NewObject<UMyObject>();

    那么 Actor 呢?Actor 的在世界(C++ 中的 UWorld)中生成是通过 SpawnActor 方法。如何获取 World 对象?有些 UObject 会提供一个 GetWorld 的方法,所有的 Actor 则都具有这个方法。

    您可能已经注意到,并没有传递一个 Actor,我们传递了一个 Actor 的 “class” 来作为生成 Actor 的参数。在我们的范例中,是一个 AMyEnemy 类的任意子类。

    但如果想要创建某个东西的“拷贝”,就像 Unity 的 Instantiate 函数那样,该怎么做呢?

    NewObject 和 SpawnActor 函数也能通过给一个 “模板” 对象来工作。虚幻引擎会创建该一个对象的拷贝,而不是从零创建一个新的对象。这将会拷贝该对象的所有属性(UPROPERTY)和组件。

    AMyActor* CreateCloneOfMyActor(AMyActor* ExistingActor, FVector SpawnLocation, FRotator SpawnRotation)
    {
        UWorld* World = ExistingActor->GetWorld();
        FActorSpawnParameters SpawnParams;
        SpawnParams.Template = ExistingActor;
        World->SpawnActor<AMyActor>(ExistingActor->GetClass(), SpawnLocation, SpawnRotation, SpawnParams);
    }

    您也许想知道“从零开始创建”在这里具体是什么意思。每个对象类在创建时都有一个默认模板,包含了它的默认属性和组件。在创建时如果您并不像修改这些默认属性,并没有提供你自己的模板,虚幻将使用这些默认值来创建该对象。为了更好的说明这个,我们先来看一下 MonoBehaviour 的例子:

    public class MyComponent : MonoBehaviour
    {
        public int MyIntProp = 42;
        public SphereCollider MyCollisionComp = null;
    
        void Start()
        {
            // Create the collision component if we don't already have one
            if (MyCollisionComp == null)
            {
                MyCollisionComp = gameObject.AddComponent<SphereCollider>();
                MyCollisionComp.center = Vector3.zero;
                MyCollisionComp.radius = 20.0f;
            }
        }
    }

    在上面这个例子中,有一个 int 属性,默认是 42,并有一个 SphereCollider 组件默认半径是 20。

    在虚幻 4 中,利用对象的构造函数也能达到同样的效果。

    UCLASS()
    class AMyActor : public AActor
    {
        GENERATED_BODY()
    
        UPROPERTY()
        int32 MyIntProp;
    
        UPROPERTY()
        USphereComponent* MyCollisionComp;
    
        AMyActor()
        {
            MyIntProp = 42;
    
            MyCollisionComp = CreateDefaultSubobject<USphereComponent>(FName(TEXT("CollisionComponent"));
            MyCollisionComp->RelativeLocation = FVector::ZeroVector;
            MyCollisionComp->SphereRadius = 20.0f;
        }
    };

    在 AMyActor 的构造函数中,我们为这个类设置了属性的默认值。请注意 CreateDefaultSubobject 函数。我们可以用它来创建组件并赋予组件默认值。所有子对象都将使用这个函数作为默认模板来创建,也可以在子类或者蓝图中对它进行修改。

    类型转换

    在这个例子中,获取了一个已知的组件,并将它转换为一个特定类型并有条件的做一些事情。

    Unity C#:

    Collider collider = gameObject.GetComponent<Collider>;
    SphereCollider sphereCollider = collider as SphereCollider;
    if (sphereCollider != null)
    {
            // ...
    }

    虚幻 4 C++:

    UPrimitiveComponent* Primitive = MyActor->GetComponentByClass(UPrimitiveComponent::StaticClass());
    USphereComponent* SphereCollider = Cast<USphereComponent>(Primitive);
    if (SphereCollider != nullptr)
    {
            // ...
    }

    销毁 GameObject / Actor

    Unity C++ 蓝图
    Destroy(MyGameObject);
    MyActor->Destroy();

    image_23.png

    销毁 GameObject / Actor (1 秒延迟)

    Unity C++ 蓝图
    Destroy(MyGameObject, 1);
    MyActor->SetLifeSpan(1);

    点击查看大图。

    禁用 GameObjects / Actors

    Unity C++ Blueprint
    MyGameObject.SetActive(false);
    // Hides visible components
    MyActor->SetActorHiddenInGame(true);
    
    // Disables collision components
    MyActor->SetActorEnableCollision(false);
    
    // Stops the Actor from ticking
    MyActor->SetActorTickEnabled(false);

    点击查看大图。

    通过组件访问 GameObject / Actor

    Unity C++ 蓝图
    GameObject ParentGO = 
    MyComponent.gameObject; 
     AActor* ParentActor = 
     MyComponent->GetOwner();

    点击查看大图。

    通过 GameObject / Actor 访问组件

    Unity

    MyComponent MyComp = gameObject.GetComponent<MyComponent>();

    C++

    UMyComponent* MyComp = MyActor->FindComponentByClass<UMyComponent>();

    蓝图

    image_33.png

    查找 GameObjects / Actors

    // Find GameObject by name
    GameObject MyGO = GameObject.Find("MyNamedGameObject");
    
    // Find Objects by type
    MyComponent[] Components = Object.FindObjectsOfType(typeof(MyComponent)) as MyComponent[];
    foreach (MyComponent Component in Components)
    {
            // ...
    }
    
    // Find GameObjects by tag
    GameObject[] GameObjects = GameObject.FindGameObjectsWithTag("MyTag");
    foreach (GameObject GO in GameObjects)
    {
            // ...
    }
    
    // Find Actor by name (also works on UObjects)
    AActor* MyActor = FindObject<AActor>(nullptr, TEXT("MyNamedActor"));
    
    // Find Actors by type (needs a UWorld object)
    for (TActorIterator<AMyActor> It(GetWorld()); It; ++It)
    {
            AMyActor* MyActor = *It;
            // ...
    }

    image alt text

    // Find UObjects by type
    for (TObjectIterator<UMyObject> It; It; ++it)
    {
        UMyObject* MyObject = *It;
        // ...
    }
    
    // Find Actors by tag (also works on ActorComponents, use TObjectIterator instead)
    for (TActorIterator<AActor> It(GetWorld()); It; ++It)
    {
        AActor* Actor = *It;
        if (Actor->ActorHasTag(FName(TEXT("Mytag"))))
        {
            // ...
        }
    }

    image alt text

    为 GameObjects / Actors 添加标签

    MyGameObject.tag = "MyTag";
    
    // Actors can have multiple tags
    MyActor.Tags.AddUnique(TEXT("MyTag"));

    image alt text

    为 MonoBehaviours / ActorComponents 添加标签

    // This changes the tag on the GameObject it is attached to
    MyComponent.tag = "MyTag";
    
    // Components have their own array of tags
    MyComponent.ComponentTags.AddUnique(TEXT("MyTag"));

    比较 GameObjects / Actors 和 MonoBehaviours / ActorComponents 的标签

    if (MyGameObject.CompareTag("MyTag"))
    {
        // ...
    }
    
    // Checks the tag on the GameObject it is attached to
    if (MyComponent.CompareTag("MyTag"))
    {
        // ...
    }
    
    // Checks if an Actor has this tag
    if (MyActor->ActorHasTag(FName(TEXT("MyTag"))))
    {
        // ...
    }

    image alt text

    // Checks if an ActorComponent has this tag
    if (MyComponent->ComponentHasTag(FName(TEXT("MyTag"))))
    {
        // ...
    }

    image alt text

    物理:刚体 vs. 元组件

    在 Unity 中药给一个 GameObject 物理特性,需要给它一个刚体组件。在虚幻中,任何元组件(C++ 中为 UPrimitiveComponent)都可以是物理对象。一些通用的元组件,比如 ShapeComponent(胶囊形,球形,盒形),StaticMeshComponent,以及 SkeletalMeshComponent。

    和 Unity 不同,Unity 将碰撞体和可视物体分列到不同的组件中。而虚幻则将潜在的物理碰撞和潜在的可视效果组合到了 PrimitiveComponent 中。任何在世界中具有形状的物体,要么就是能够被渲染显示,要么就是能作物理交互,它们都继承于 PrimitiveComponent。

    层 vs 通道

    在 Unity 中,它们被称为“层(Layer)”。虚幻使用碰撞通道(Collision Channel)来描述,这是类似的概念。可以在 此处 读到更多。

    RayCast vs RayTrace

    Unity C#:

    GameObject FindGOCameraIsLookingAt()
    {
        Vector3 Start = Camera.main.transform.position;
        Vector3 Direction = Camera.main.transform.forward;
        float Distance = 100.0f;
        int LayerBitMask = 1 << LayerMask.NameToLayer("Pawn");
    
        RaycastHit Hit;
        bool bHit = Physics.Raycast(Start, Direction, out Hit, Distance, LayerBitMask);
    
        if (bHit)
        {
            return Hit.collider.gameObject;
        }
    
        return null;
    }

    虚幻 4 C++:

    APawn* AMyPlayerController::FindPawnCameraIsLookingAt()
    {
        // You can use this to customize various properties about the trace
        FCollisionQueryParams Params;
        // Ignore the player's pawn
        Params.AddIgnoredActor(GetPawn());
    
        // The hit result gets populated by the line trace
        FHitResult Hit;
    
        // Raycast out from the camera, only collide with pawns (they are on the ECC_Pawn collision channel)
        FVector Start = PlayerCameraManager->GetCameraLocation();
        FVector End = Start + (PlayerCameraManager->GetCameraRotation().Vector() * 1000.0f);
        bool bHit = GetWorld()->LineTraceSingle(Hit, Start, End, ECC_Pawn, Params);
    
        if (bHit)
        {
            // Hit.Actor contains a weak pointer to the Actor that the trace hit
            return Cast<APawn>(Hit.Actor.Get());
        }
    
        return nullptr;
    }

    虚幻 4 蓝图:

    点击查看大图。

    触发器

    Unity C#:

    public class MyComponent : MonoBehaviour
    {
        void Start()
        {
            collider.isTrigger = true;
        }
        void OnTriggerEnter(Collider Other)
        {
            // ...
        }
        void OnTriggerExit(Collider Other)
        {
            // ...
        }
    }

    虚幻 4 C++:

    UCLASS()
    class AMyActor : public AActor
    {
        GENERATED_BODY()
    
        // My trigger component
        UPROPERTY()
        UPrimitiveComponent* Trigger;
    
        AMyActor()
        {
            Trigger = CreateDefaultSubobject<USphereComponent>(TEXT("TriggerCollider"));
    
            // Both colliders need to have this set to true for events to fire
            Trigger.bGenerateOverlapEvents = true;
    
            // Set the collision mode for the collider
            // This mode will only enable the collider for raycasts, sweeps, and overlaps
            Trigger.SetCollisionEnabled(ECollisionEnabled::QueryOnly);
        }
    
        void BeginPlay()
        {
            // Register to find out when an overlap occurs
            OnActorBeginOverlap.AddDynamic(this, &AMyActor::OnTriggerEnter);
            OnActorEndOverlap.AddDynamic(this, &AMyActor::OnTriggerExit);
    
            Super::BeginPlay();
        }
    
        void EndPlay(const EEndPlayReason::Type EndPlayReason)
        {
            OnActorBeginOverlap.RemoveDynamic(this, &AMyActor::OnTriggerEnter);
            OnActorEndOverlap.RemoveDynamic(this, &AMyActor::OnTriggerExit);
    
            Super:EndPlay(EndPlayReason);
        }
    
        UFUNCTION()
        void OnTriggerEnter(AActor* Other);
    
        UFUNCTION()
        void OnTriggerExit(AActor* Other);
    };

    虚幻 4 蓝图:

    image alt text

    还可以在 这里 读到更多关于设置碰撞的响应。

    刚体运动

    Unity C#:

    public class MyComponent : MonoBehaviour
    {
        void Start()
        {
            rigidbody.isKinimatic = true;
            rigidbody.velocity = transform.forward * 10.0f;
        }
    }

    在虚幻 4 中,碰撞组件和刚体组件是同一个组件,它的基类是 UPrimitiveComponent,它也有不同的子类(USphereComponent,UCapsuleComponent 等)来配合不同的需求。

    虚幻 4 C++:

    UCLASS()
    class AMyActor : public AActor
    {
        GENERATED_BODY()
    
        UPROPERTY()
        UPrimitiveComponent* PhysicalComp;
    
        AMyActor()
        {
            PhysicalComp = CreateDefaultSubobject<USphereComponent>(TEXT("CollisionAndPhysics"));
            PhysicalComp->SetSimulatePhysics(false);
            PhysicalComp->SetPhysicsLinearVelocity(GetActorRotation().Vector() * 100.0f);
        }
    };

    输入事件

    Unity C#:

    public class MyPlayerController : MonoBehaviour
    {
        void Update()
        {
            if (Input.GetButtonDown("Fire"))
            {
                // ...
            }
            float Horiz = Input.GetAxis("Horizontal");
            float Vert = Input.GetAxis("Vertical");
            // ...
        }
    }

    虚幻 4 C++:

    UCLASS()
    class AMyPlayerController : public APlayerController
    {
        GENERATED_BODY()
    
        void SetupInputComponent()
        {
            Super::SetupInputComponent();
    
            InputComponent->BindAction("Fire", IE_Pressed, this, &AMyPlayerController::HandleFireInputEvent);
            InputComponent->BindAxis("Horizontal", this, &AMyPlayerController::HandleHorizontalAxisInputEvent);
            InputComponent->BindAxis("Vertical", this, &AMyPlayerController::HandleVerticalAxisInputEvent);
        }
    
        void HandleFireInputEvent();
        void HandleHorizontalAxisInputEvent(float Value);
        void HandleVerticalAxisInputEvent(float Value);
    };

    虚幻 4 蓝图:

    image alt text

    这里是在项目设置中输入属性的设置界面:

    image alt text

    关于如何设置输入可以从在 这里 阅读。

    常见问题

    如何自动加载最后一个项目?

    如果您习惯于 Unity 会自动加载上次工作的最后一个项目,在虚幻 4 中也一样可以做到。要开启这个功能的话,当打开项目时勾选“启动时总是加载最后一个项目”的选项。可以在任意时刻通过编辑器的主菜单的 编辑/编辑器首选项/加载和保存/启动 的部分来修改。

    哪里可以设置游戏的输入绑定?

    在 Unity 中,如果您习惯于为项目用 Input Manager 来设置默认的输入的话,虚幻 4 也一样。您可以打开项目设置,并选择 Input 的分类。然后就可以添加不同的案件(Action)或者摇杆控制(Axe)。给每一种控制一个名称和默认绑定。然后,在游戏中的 Pawn 中当该输入事件发生时就能获取回调函数。查看输入文档页面 来了解详情。

    如何修改项目的初始场景?

    可以在项目设置的分页中为项目设定初始场景。从主菜单中选择 编辑/项目设置->地图和模式 便能进行修改。

    如何运行游戏?

    运行游戏最简单的方式是点击编辑器的主工具栏上的“运行”按钮,这将会直接在编辑器窗口中运行游戏。如果想要作为单独的程序运行,点击“运行”按钮边上的下拉箭头,并选择“Standalone Game”。如果想要在移动设备或者网页浏览器中运行游戏,那需要使用工具栏中的“启动”按钮(相应的平台需要预先安装所需软件)。

    单位是什么?

    在 Unity 中,主要的测量单位是米,在虚幻 4 中,主要的测量单位是厘米。

    因此在 Unity 中移动一个单位(一米)相当于在虚幻 4 中移动 100 个单位(厘米)。

    如果想要在 Unity 中移动 2 英尺,那么相当于 0.61 个单位,而在虚幻 4 中则是 61 个单位。

    坐标系是怎么回事?那个方向朝上?

    Unity 和虚幻 4 都使用左手坐标系,但坐标轴则需要轮换一下。在虚幻 4 中,X 的正方向是“前”,Y 的正方向是“右”,Z 的正方向是“上”。

    如何查看游戏的输出日志?

    在虚幻 4 编辑器中,可以从“窗口->开发人员工具”的菜单中打开“输出日志”。也可以在运行游戏时增加 “-log” 命令行参数,在游戏窗口以外启动一个专用的日志窗口,这非常有用!

    说道日志输出,Debug.log 在哪里?

    在虚幻 4 中做日志高度的可定制化。阅读 这里 了解如何记录信息。

    如何抛出异常?

    在 Unity 中,您可能习惯于当发生问题是抛出异常。虚幻 4 则并不处理异常。取而代之的做法是,使用 “check()” 函数来触发严重的错误。可以传入一个错误信息提示。如果只是想报告一个错误,但并不希望打断整个程序,可以使用 “ensure()”。这将会记录一个完整堆栈的日志信息,但程序会继续执行。如果当前附加了调试器,那么这两个函数都会暂定并进入调试器。

    .NET Framework 去哪里了?

    和 Unity 不同,虚幻 4 并不使用 .NET Framework。虚幻 4 自有一套容器类和库。常见的容器来对照:

    .Net Framework 虚幻 4
    String FString,FText
    List TArray
    Dictionary TMap
    HashSet TSet

    这里 可以阅读到更多虚幻 4 的容器。

    代码改变时虚幻会自动重新加载吗?

    是的!您可以在编写代码是保持编辑器开启的状态。要在编写完成后直接从 Visual Studio 中编译代码,编辑器则会“热加载”您刚刚做的改动。也可以点击编辑器主工具栏上的编译 按钮。当您在 Visual Studio 调试器连接的状态下这也很有用。

    然后呢?

    感谢阅读本篇指引!这篇文章的创建时为了帮助各地的虚幻社区和虚幻开发者,我们很希望能收到您的反馈意见或者纠错意见。在我们不断了解如何能帮助大家过渡到虚幻 4 的过程中,我们将会保持改进这篇文档。

    我们还有很多虚幻 4 的学习资料!

    展开全文
  • Unreal引擎术语表

    千次阅读 2015-11-21 08:39:08
    Unreal引擎术语表 转载自UDN: ‍Actor - 一个可以放置在世界中或者在世界中产生的对象。这包括类似于Players(玩家)、Weapons(武器)、 Trash.StaticMeshes(静态网格物体)、Emitters(编辑器)、 Infos以及 ...
  • Unreal术语表

    2019-10-14 17:03:22
    Unreal引擎术语表 转载自UDN: ‍Actor - 一个可以放置在世界中或者在世界中产生的对象。这包括类似于Players(玩家)、Weapons(武器)、 Trash.StaticMeshes(静态网格物体)、Emitters(编辑器)、 Infos以及 Sounds(声效...
  • BlackBody(黑体) BumpOffset(凹凸贴图偏移) ConstantBiasScale(常量偏差比例) DDX DDY DepthFade(深度消退) DepthOfFieldFunction(视野深度函数) ...FeatureLevelSwitch(功能级别开关)
  • 这篇博客来自于Fabrice Piquet,翻译工作已获得作者授权,原文传送门。 我决定分享一下我在当前项目中处理真实第一人称相机的方法。针对真实第一人称视角,目前没有太多相关的文档。因此研究一段时间过后,尤其是...
  • 为什么Unreal 4引擎能轻易实时渲染出vray要花半天才能渲染出的场景? 这不是真的!This is Unreal! 看了这个文章,大为感慨。如果有人以unreal 4为基础开发渲染软件,和rhino、su、revit等常用建筑软件对接,...
  • 首先点云数据我们是可以到https://opentopography.org/进行获取的,也可以去任何你知道的点云数据库下载,并需要将得到的文件转化为.las格式。 Houdini中我们使用Lidar Import节点来导入点云数据,File设置为.las...
  • UNREAL ENGINE 4.13 正式发布!

    千次阅读 2016-09-09 19:56:42
    这次的版本带来了数百个虚幻引擎 4 的更新,包括来自 GitHub 的社区成员们提交的 145 个改进!感谢所有为虚幻引擎 4 添砖加瓦贡献的人们: alk3ovation, Allegorithmic (Allegorithmic), Alwin Tom (alwintom), ...
  • 自由骑士笃志原创- -欢迎转载,呃 BigWorld:澳大利亚 优点: 1:动态负载均衡,服务器承受能力好。  2:服务器有较高的容错性,对服务器状况有专业的记录和管理报表分析。  3:功能全面,使用非常方便,开发速度...
  • 几款引擎比较 BigWorld Unreal CryEngine等
  • UnrealScript语言参考

    千次阅读 2011-01-23 01:15:00
    最初作者是Tim Sweeney (EpicGames)  内容UnrealScript语言参考介绍快速链接本文档的目的UnrealScript的设计目标虚幻引擎3中UnrealScript的新功能代码结构示例Unreal虚拟机对象层次类变量变量类型内置类型集合...
  • 1:AtmosphericFogColor:大气雾颜色,input: world pos 2.Desaturation(去饱和度):根据特定百分比将其输入的颜色转换为灰色阴影,输入亮度系数Luminance Factors和百分比(饱和度系数)Fraction ...
  • 虚幻引擎3(Unreal Engine 3)概要

    千次阅读 2009-03-11 18:51:00
    虚幻引擎3(Unreal Engine 3)概要虚幻引擎3概要 虚幻引擎3是一个面向下一代游戏机和DirectX 9个人电脑的完整的游戏开发平台,提供了游戏开发者需要的大量的核心技术、数据生成工具和基础支持。 虚幻引擎3的设计...
  • ue4 Worldmachine 结合使用

    千次阅读 2019-02-21 11:35:42
    最近项目需求制作一个场景的远景部分。...所以我们决定使用 WorldMachine 作为地形的生成工具,将地形的高度图导入 Editor,再在 Editor 中对细节进行修改。WorldMachine 生成的高度图相对人工算...
1 2 3 4 5 ... 20
收藏数 448
精华内容 179
关键字:

unreal 如何导出高度图