与传统的一般电子游戏相比,区块链游戏有着以下特点:
1)去中心化,区块链游戏的所有执行代码和游戏数据都存储在区块链上,由于区块链分布式账本的特性,这意味着游戏运行方式是完全开放透明的.
2)资产所有权,玩家对游戏内资产的所有权层级在游戏之上,也就是说,即便游戏不再更新、运营,甚至不再有玩家参与游戏,但是玩家在游戏中获得的虚拟资产仍然永久存在于游戏所依托的区块链中,只要资产存在市场,就可以出售其获取代币。
3)游戏性不同,从游戏的角度看,区块链游戏的优势是其建立在区块链上所获得的天然经济体系,潜在的盈利能力使得老玩家具有粘性,也能吸引新玩家的加入。另一方面,由于区块链的分布式账本在处理数据时,必须经过验证、记账、存储、维护和传输等一系列操作,且是在去中心化的网络上完成,导致处理所需要的时间较之中心化网络更长,去中心化属性与高性能、低延迟难以兼得,意味着区块链游戏在即时响应的性能上较弱。
静态物体的核心类是UStaticMesh,它有两个成员变量分别是FStaticMeshSourceModel以及FStaticMeshRenderData。FStaticMeshSourceModel包含了FMeshDescription数据,而FMeshDescription数据则是由FBX文件解析得来的。换句话说FStaticMeshSourceModel是对FBX原始数据的一份拷贝,并对其进行了整理。
FStaticMeshRenderData是供UE4引擎渲染的数据,它由两个重要的部分组成,分别是FStaticMeshLODResourcesArray和FStaticMeshVertexFactoriesArray。
StaticMesh的每一层LOD都要生成对应的渲染资源,FStaticMeshLODResourcesArray数组包含了所有LOD层的FStaticMeshLODResources。FStaticMeshLODResources中包含了FStaticMeshVertexBuffers及各种Index Buffer。FStaticMeshVertexBuffers中包含了FPositionVertexBuffer,FPositionVertexBuffer是由FVertexBuffer继承而来的,而FVertexBuffer中包含了图形API的渲染数据FRHIVertexBuffer,因为我调试使用的是DX12,所以对应的实际资源是FD3D12VertexBuffer。FPositionVertexBuffer中存储了cpu端的数据,FD3D12VertexBuffer中存储了GPU端使用的ID3D12Resource资源。
由流程图中可以看到FPositionVertexBuffer数据是由FMeshDescription转换而来的,这个过程是在逻辑线程中完成的,而创建ID3D12Resource资源则是在渲染线程中执行,因为逻辑线程中保证了提交指令的顺序,所以渲染线程会先创建资源,然后才会使用资源。
FStaticMeshVertexFactoriesArray中包含了每一个LOD层的VertexFactory,VertexFactory中包含了多个FVertexStream,每一个FVertexStream对应了一个FVertexBuffer,这个FVertexBuffer就是上面创建的ID3D12Resource资源。另外每一个FVertexStream还对应了一个FVertexElement,VertexFactory会根据FVertexElement创建顶点描述资源,也就是DX12的D3D12_INPUT_ELEMENT_DESC,具体流程可以参考上面的流程图。
资源准备完毕后,我们看看这些资源是如何被渲染的。对于静态物体,在创建Actor的时候渲染指令就会生成。创建Actor的时候会创建UPrimitiveComponent组件,这个组件代表actor会在场景中渲染。UPrimitiveComponent组件中包含了UStaticMesh。UPrimitiveComponent是逻辑线程使用的组件,FPrimitiveSceneInfo是渲染线程使用的组件,因此中间加了一个FPrimitiveSceneProxy来做数据的传递。逻辑线程会将新创建的FPrimitiveSceneInfo加入到FScene中。
逻辑线程Tick的时候会调用ENQUEUE_RENDER_COMMAND(UpdateScenePrimitives)命令调用渲染线程处理场景中增加,更新或删除的FPrimitiveSceneInfo。根据FPrimitiveSceneInfo中的数据进行Batch合并,将场景中的物体组织成FStaticMeshBatch,而FStaticMeshBatch则会转变成FMeshDrawCommand供底层渲染。对于静态物体来说FScene会将FMeshDrawCommand缓存起来。
不同的Pass及不同的变体会生成不同的FMeshDrawCommand。UE4中的Pass是写死的,因此想要扩展UE4中的Pass必须要改UE4源码。
动态物体每一次tick的时候都会进行Batch的合并以及生成对应的FMeshDrawCommand,当然这些动态物体必须是通过可见性剔除留下的物体。
最后每一个FMeshDrawCommand会调用SubmitDraw()将渲染指令加入到RHICmdList中,RHI线程会读取RHICmdList指令将其转换成对应图形API的操作。