Primitive类型技术指南

创建新类型的渲染Primitive的程序员指南。

Windows
MacOS
Linux

本页面是从虚幻引擎3文档转换的页面,当前正在接受审查。信息可能已过时。

UPrimitiveComponent是可以进行渲染和碰撞的Actor组件。本页面介绍如何创建新的UPrimitiveComponent类型。

渲染

Primitive是可视性的单位。视锥剔除和遮挡剔除是针对Primitive的边界框进行的。必须实现USceneComponent::CalcBounds才能将Primitive的包围体写入Bounds成员。

Primitive作为网格体元素、线、Sprite和点渲染。Primitive向场景管理器列举构成其外观的元素。

创建你自己的PrimitiveComponent派生类时,你也必须实现相应的FPrimitiveSceneProxy。这是Primitive组件的渲染线程副本,应包含渲染该组件所需的所有数据。此代理在附加/分离时添加到渲染线程的场景或从渲染线程的场景中移除。通常在这些时候你还需要初始化代理所需的渲染资源。

Primitive场景代理

对场景有效的渲染线程指定游戏线程后的帧。必须为渲染线程复制游戏线程可能会动态更改的Primitive属性,这可以使游戏线程同时为下一帧更新它们。PrimitiveComponent必须创建镜像动态成员的Primitive场景代理。注册Primitive以为Primitive类型提供创建其场景代理的机会时,场景管理器会调用UPrimitiveComponent::CreateSceneProxy。

当镜像的成员中有一个被更改时,你必须调用MarkRenderStateDirty以创建新的场景代理。在帧结束时场景代理将被重新创建。

绘制元素

场景管理器通过调用FPrimitiveSceneProxy::DrawDynamicElements列举Primitive的元素。Primitive对提供的FPrimitiveDrawInterface调用DrawMesh、DrawLine、DrawPoint或DrawSprite,以为调用方列举其元素。每视图每帧可能多次调用DrawDynamicElements;结果不缓存,可能需要在多个通道中渲染Primitive的元素。DrawDynamicElements在渲染线程中被调用,因此可能被写入游戏线程的PrimitiveComponent的任何成员都必须在FPrimitiveSceneProxy中被镜像且通过重新附加Primitive被更新。

存在针对网格体元素的优化路径,它在Primitive附加到场景之后保持静态。当Primitive被附加时,场景管理器调用FPrimitiveSceneProxy::DrawStaticElements,它使用类似于FPrimitiveDrawInterface的接口列举Primitive的静态网格体元素。静态网格体元素会缓存并且使用优化的渲染路径。与DrawDynamicElements不同,DrawStaticElements在游戏线程中被调用。

渲染视图的帧时,场景渲染代码调用FPrimitiveSceneProxy::GetViewRelevance来确定Primitive与视图的相关性。它返回FPrimitiveViewRelevance结构体,此结构体是描述Primitive与视图的相关性的一系列标记。最重要的标记是bStaticRelevance和bDynamicRelevance;这些标记确定DrawStaticElements或DrawDynamicElements列举的网格体元素是否会被绘制。你应该根据Primitive使用半透明、变形还是场景颜色材质来设置剩余的标记。GetViewRelevance在渲染线程中被调用。

你可以使用命中代理来断开单击检测精度与Primitives的联系。命中代理与每个绘制的元素相关联,以提供有关用户在编辑器中单击了什么的额外信息。默认行为是使用指向Primitive的所有者的HActor。如果希望提供有关Primitive的不同元素的更多信息,必须实现FPrimitiveSceneProxy::CreateHitProxies来分配Primitive使用的命中代理。然后,命中代理会被传递给FPrimitiveDrawInterface::SetHitProxy和FStaticPrimitiveDrawInterface::SetHitProxy。CreateHitProxies在游戏线程中被调用。

从渲染线程访问PrimitiveComponent

PrimitiveComponent使用渲染命令栅栏来确保只要它的一个Primitive场景代理可被分配并在渲染线程中执行代码,它就不会作为垃圾被回收。

如果在游戏进程中PrimitiveComponent的一个成员是静态的,你可以在渲染进程中直接从Primitive场景代理访问该成员。

如果在游戏进程中PrimitiveComponent的一个成员是动态的,你必须在Primitive场景代理中镜像它或序列化对它的访问。你可以使用全局FlushRenderingCommands函数序列化对它的访问。FlushRenderingCommands会等待渲染线程进入闲散状态。然后,你可以写入共享成员(假设该渲染线程不会访问它,直至一个渲染命令加入队列)。

光照

渲染器在延迟着色通道中应用动态光源。

你可以通过实现FLightCacheInterface并在网格体元素的LCI成员中传递实现来为网格体元素提供静态光照。FLightCacheInterface提供可选的光照贴图,并从光源GUID映射到详细的光干扰信息。光干扰信息包含在FLightInteraction中,可能是未缓存的、不相关的、光照贴图的、顶点阴影贴图的或纹理阴影贴图的。

要计算静态光照,必须实现UPrimitiveComponent::GetStaticLightingInfo。静态光照系统在预计算过程中调用它来列举Primitive的网格体和映射。

静态光照网格体是遮挡或反射静态光照的一系列三角形。

静态光照映射是静态光照纹理或顶点缓冲区到静态光照网格体的映射。静态光照系统计算映射的光照贴图和阴影贴图,然后将它们传递给映射的Apply函数的实现。

Tags
Select Skin
Light
Dark

Welcome to the new Unreal Engine 4 Documentation site!

We're working on lots of new features including a feedback system so you can tell us how we are doing. It's not quite ready for use in the wild yet, so head over to the Documentation Feedback forum to tell us about this page or call out any issues you are encountering in the meantime.

We'll be sure to let you know when the new system is up and running.

Post Feedback