2018-10-12 01:02:00 u012614151 阅读数 7
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2396 人正在学习 去看看 杨石兴

@author:白袍小道

浏览分享随缘,评论不喷亦可。

   

扯淡部分

在temp中,乱七八糟的说了下大致的UE过程。下面我们还是稍微别那么任性,一步步来吧。

   

UE渲染模块牵扯到场景遍历、查询、渲染的具体执行,而UE有是多平台,还在牵扯到上层View,ViewPort,Client等,其中肯定又牵扯到其他系统。(这里就值得我们学习和分析的,如何去管理如此多的模块,如何去平衡,内联下,还能保证有可扩展。此处就不具体扯淡了,后面会具体把相关图和说明在其他二级目录给到)

   

提前说包含的:

1、ModuleManager, World,

2、ViewClient, ViewFamily, SceneRender, viewInfo,

3、GlobalShader

4、Material

5、ShaderCore, Shader,ShaderParameters

6、RHI(DX,OPGL)

   

下面开始就直接跳到渲染执行部分了。

   

正文部分

注:以下基本是在源码,RenderDoc, 调试堆栈下、其他作者分析,结合而来(怕看错)。

表格走走

Pass

内容

备注

源码及其位置

PrePass

利用DepthDrawingPolicy绘制Depth的深度缓存

减少后续中像素填充

  

BasePass_A

绘制Opa和mask属性的集合体,将其Material属性填入G-Buffer

计算了光照填图和天光的贡献量(这个词来源于其他,挺好)给到SceneColorBuffer

  

  

BasePass_B: Compute Light Grid

灯光【点光源,聚光灯,反射截取按照屏幕空间划分空间格子(Gird),

  

  

Occlusion

Queries/Test

遮挡查询和测试(这是物体级别),为NextFrame做好数据)

在根据深度计算query之后数据会传回cpu,就可以计算每个物体有多少像素可见。这样我们就能知道物体最终是否会被渲染。

在不透明物体的query pass之后。Unreal 还有一些其他的query pass,例如灯光(点光源)会有一个ShadowFrustumQUeries(一般是画一个球体)反射则有 PlanarReflection queries(一般是画一个 Cube)/

  

利用集合体的包围盒走z-depth测试(可以看龙书,游戏引擎架构对这部分理论说明)

  

Hierarchical Z

(这个那啥也不好扯,分层Zbuffer,大体是对Zbuffer做连续downSample.后续细说)

https://www.nickdarnell.com/hierarchical-z-buffer-occlusion-culling/

  

  

ShaderMap

   

   

  

实时阴影的计算:按照灯光类型(静固动)做不同处理,

固:StaticMesh Bake到 Static ShadowMap,

动:所有物体投射Shadow

静:非实时

(注意: 对于移动的点光源,用了CubeMap ShadowMap,在CubeShadow

Map的第一个Pass,直接Copy了静态物体的ShadowMap缓存,GeoShader来选择画)

  

  

  

G-prepass

  

  

  

Velocity rendering

  

  

  

Pre-Lighting

AO走起

  

  

Lighting

光照计算:预处理组合型光照(这个也有书嘿嘿),延时贴花,SSAO,RenderLights

  

  

ImageBased lighting

一些光照效果,SSR,ReflectionProbe等

  

  

Draw atmosphere

  

deferred shading 中需要的G-buffers:

  

  

Draw Fog

非透明表面逐像素的算

  

  

Draw Tanslucency

透明(注意下切了底层DX 状态[DX的状态这里不扯],RHICmdList)

  

  

Post

后期

  

  

   

   

细细来说:

(。。。。。待续)

2018-10-27 21:46:00 u012614151 阅读数 39
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2396 人正在学习 去看看 杨石兴

@author: 黑袍小道

随缘查看

   

说明

由于搬山的渲染这部分担心自己理解错误,故而搬移官方下,后面整个完成再反过来更新

(这当且仅当做Unreal的帮助文档)

   

图形编程

模块

渲染器代码存在于其自身的模块中。此模块将编译为非单块版本的一个 dll 文件。这可以使迭代更快,因为在渲染代码变更时无需重新链接整个应用程序。渲染器模块取决于引擎,因为其拥有许多向引擎的回调。然而当引擎需要调用渲染器中的某些代码时,这会通过某个接口来完成,通常为 IRendererModule FSceneInterface

场景代表

UE4 中,渲染器所见的场景由基本组件和 FScene 中存储的多种其他结构的列表定义。将维护一个基元的八叉树,用于加速空间查询。

主要场景类

UE4 中拥有和游戏线程并行运行的渲染线程。

主要的类为:

描述

UWorld

包含多个可交互的 Actor 和组件的世界场景。关卡可以流送进入和退出世界场景,且程序中可以同时有多个世界场景处于激活状态。

ULevel

一同加载/卸载并保存在同一地图文件中的 Actor 和组件合集。

USceneComponent

需要添加到 FScene 中的任意对象的基础类,如光照、网格体、雾等。

UPrimitiveComponent

可渲染或进行物理交互的任意资源的基础类。也可以作为可视性剔除的粒度和渲染属性规范(投射阴影等)。与所有 UObjects 一样,游戏线程拥有所有变量和状态,渲染线程不应直接对其进行访问。

ULightComponent

代表光源。渲染器负责计算和添加其对场景的贡献。

FScene

UWorld 的渲染器版本。对象仅在其被添加到 FScene(注册组件时调用)后才会存在于渲染器中。渲染线程拥有 FScene 中的所有状态,游戏线程无法直接对其进行修改。

FPrimitiveSceneProxy

UPrimitiveComponent 的渲染器版本,为渲染线程映射 UPrimitiveComponent 状态。存在于引擎模块中,用于划分为子类以支持不同类型的基元(骨架、刚体、BSP 等)。实现某些非常重要的函数,如 GetViewRelevanceDrawDynamicElements 等。

FPrimitiveSceneInfo

内部渲染器状态(FRendererModule 实现专有),对应于 UPrimitiveComponent FPrimitiveSceneProxy。存在于渲染器模块中,因此引擎看不到它。

FSceneView

单个视图到一个 FScene 的引擎代表。视图可以通过对 FSceneRenderer::Render 的不同调用的不同视图来渲染(多编辑器视口)或通过对 FSceneRenderer::Render 的同一调用中的多个视图来渲染(分屏游戏)。为每个帧构建新视图。

FViewInfo

视图的内部渲染器代表,存在于渲染器模块中。

FSceneViewState

ViewState 存储有关在多个帧中需要的某个视图的私有渲染器信息。在游戏中,每个 ULocalPlayer 只有一个视图状态。

FSceneRenderer

为每个帧创建的类,用于封装跨帧的临时对象。

下面按其所在的模块列出了各种主类。

引擎模块

渲染器模块

UWorld

FScene

UPrimitiveComponent / FPrimitiveSceneProxy

FPrimitiveSceneInfo

FSceneView

FViewInfo

ULocalPlayer

FSceneViewState

ULightComponent / FLightSceneProxy

FLightSceneInfo

以及相同类(按哪个线程对其状态拥有所有权进行排列)。

游戏线程

渲染线程

UWorld

FScene

UPrimitiveComponent

FPrimitiveSceneProxy / FPrimitiveSceneInfo

  

FSceneView / FViewInfo

ULocalPlayer

FSceneViewState

ULightComponent

FLightSceneProxy / FLightSceneInfo

   

材质类

描述

FMaterial

连接用于渲染的材质的接口。可用于访问材质属性(如混合模式)。包含被渲染器用于检索个体着色器的着色器地图。

FMaterialResource

UMaterial FMaterial 接口实现。

FMaterialRenderProxy

材质在渲染线程上的代表。可用于访问 FMaterial 接口和各个标量、向量和纹理参数。

UMaterialInterface

[abstract] 用于材质功能的游戏线程接口。用于检索用于渲染的 FMaterialRenderProxy 和用作来源的 UMaterial

UMaterial

材质资源。授权为节点图形。计算用于着色、设置混合模式等的材质属性。

UMaterialInstance

[abstract] UMaterial 的实例。使用 UMaterial 中的节点图形,但提供不同参数(标量、向量、纹理、静态切换)。每个实例都有一个父项 UMaterialInterface。因此,材质实例的父项可能是 UMaterial 或另一个 UMaterialInstance。这会形成一个链,最终通往 UMaterial

UMaterialInstanceConstant

只能在编辑器中修改的 UMaterialInstance。可以提供标量、向量、纹理和静态开关参数。

UMaterialInstanceDynamic

可以在运行时修改的 UMaterialInstance。可提供标量、向量和纹理参数。无法提供静态开关参数,且无法成为另一 UMaterialInstance 的父项。

   

基元组件和代理

基元(就是Prim)组件是可视性和相关性确定的基本单位。例如,遮蔽和视锥剔除都是按基元进行的。因此在设计系统时,考虑组件的大小十分重要。每个组件都有一个边界,用于多种操作,如剔除、阴影投射和光照影响确定。

组件只有在注册之后才会对场景(以及渲染器)可见。

更改组件属性的游戏线程代码必须调用组件上的 MarkRenderStateDirty(),将更改传播到渲染线程。

FPrimitiveSceneProxy FPrimitiveSceneInfo

FPrimitiveSceneProxy UPrimitiveComponent 的渲染线程版本,用于根据组件类型划分子类。

它存在于引擎模块中,并在渲染通道中调用函数。

FPrimitiveSceneInfo 是基元组件状态,为渲染器模块私有。

重要的 FPrimitiveSceneProxy 方法

函数

描述

GetViewRelevance

在帧的开始从 InitViews 调用,并返回填充的 FPrimitiveViewRelevance

DrawDynamicElements

调用,以便在某代理相关的任何通道中绘制该代理。仅在代理表示自己拥有动态相关性时调用。

DrawStaticElements

调用以在基元与游戏线程相连时提交代理的 StaticMesh 元素。仅在代理表示自己拥有静态相关性时调用。

   

场景渲染顺序

渲染器按照其希望将数据整合给渲染目标的顺序处理场景。例如,仅 Depth 的通道会比 Base 通道先渲染,先填充 Heirarchical Z (HiZ),从而降低基础通道中的着色消耗。此顺序是按通道函数在 C++ 中调用的顺序静态决定的。

相关性

FPrimitiveViewRelevance 是说明通道与基元相关的信息。基元可能有存在不同相关性的多个元素,因此 FPrimitiveViewRelevance 相当于一个所有元素的相关性的逻辑 OR。这表示基元可以同时存在不透明和透明相关性,或动态和静态相关性;它们并非相互排斥。

FPrimitiveViewRelevance 还会显示基元是否需要使用动态 (bDynamicRelevance) /或静态 (bStaticRelevance) 渲染路径。

绘制规则

绘制规则包括通过通道特定的着色器渲染网格体的逻辑。它们使用 FVertexFactory 接口来抽取网格体类型,并使用 FMaterial 接口来抽取材质详情。在最底层,一条绘制规则会负责一组网格体材质着色器以及一个顶点工厂,将顶点工厂的缓冲区与渲染硬件接口 (RHI) 绑定,将网格体材质着色器与 RHI 绑定,设置适当的着色器参数,然后执行 RHI 绘制调用。

绘制规则方法

函数

描述

Constructor

从给定的顶点工厂和材质着色器地图,并存储这些引用。

CreateBoundShaderState

为绘制规则创建 RHI 边界着色器状态。

Matches/Compare

提供排列绘制规则与静态绘制列表中的其他项目的方法。Matches 必须比较 DrawShared 依赖的所有因素。

DrawShared

设置在从 Matches 返回 True 的绘制规则之间一致的 RHI 状态。例如,大多数绘制规则会为材质和顶点工厂排序,因此着色器参数只依赖可以设置的材质,并且可以绑定特定于该顶点工厂的顶点缓冲区。应尽可能在此处设置状态,而非在 SetMeshRenderState 设置,因为 DrawShared 在静态渲染路径中调用较少。

SetMeshRenderState

设置特定于此网格体的 RHI 状态,或 DrawShared 中未设置的任何项目。这比 DrawShared 调用的次数多得多,因此此处性能非常重要。

DrawMesh

实际发出 RHI 绘制调用。

   

渲染路径

UE4 拥有动态路径(能够提供更多的控制,但转换较慢)和静态渲染路径(缓存尽可能靠近 RHI 级别的场景转换)。差异基本上是整体上的,因为它们都在最底层使用绘制规则。应确保各个渲染通道(绘制规则)在需要时能够同时处理两个渲染路径。

动态渲染路径

动态渲染路径使用 TDynamicPrimitiveDrawer 并对每个要渲染的基元场景代理调用 DrawDynamicElements。需要使用动态路径来渲染的一组基元通过 FViewInfo::VisibleDynamicPrimitives 来跟踪。每个渲染通道都需要在此阵列上迭代,并调用各个基元上的 DrawDynamicElements。随后,代理的 DrawDynamicElements 需按需要组合出多个 FMeshElements,并将其随 DrawRichMesh TDynamicPrimitiveDrawer::DrawMesh 提交。这样最终会创建一个新的临时绘制规则,调用 CreateBoundShaderStateDrawSharedSetMeshRenderState 以及 DrawMesh

静态渲染路径

静态渲染路径通过静态绘制列表实现。网格体在连接到场景时会插入到绘制列表中。在插入过程中,将调用代理上的 DrawStaticElements,以收取 FStaticMeshElements。随后将随 CreateBoundShaderState 的结果创建并存储一个绘制规则实例。新的绘制示例将根据其 Compare Matches 函数排序,并插入到绘制列表中的适当位置(参见 TStaticMeshDrawList::AddMesh)。在 InitViews 中,包含静态绘制列表中的可见性数据的 bitarray 会初始化并传递到 TStaticMeshDrawList::DrawVisible(实际绘制绘制列表的地方)。DrawShared 只会对所有相互匹配的绘制规则调用一次,而 SetMeshRenderState DrawMesh 会对每个 FStaticMeshElement(参见 TStaticMeshDrawList::DrawElement)调用。

静态渲染路径会将许多工作移动连接时间,这会大大加快渲染时的场景转换。在渲染线程上针对静态网格体时,静态绘制列表的渲染会快 3 倍,从而允许场景中出现多得多的静态网格体。由于静态绘制列表会在连接时间缓存数据,因此它们仅能缓存与视图无关的状态。很少重新连接但经常需要渲染的基元非常适合静态绘制列表。

静态渲染路径可能会暴露出 bug,因为它每个状态桶只调用 DrawShared 一次。这些 bug 可能会很难发现,因为它们取决于场景中网格体的渲染顺序和连接顺序。特别的视图模式(如仅光照、无光照等)会强制所有基元使用动态路径,因此如果在强制动态渲染路径时 bug 消失,则其很可能是由于某绘制规则的 DrawShared / Matches 函数的错误实现而出现的。

总体渲染顺序

下面将说明从 FDeferredShadingSceneRenderer::Render 开始渲染一个帧时的控制流程:

操作

描述

GSceneRenderTargets.Allocate

按需要重新分配全局场景渲染目标,使其对当前视图足够大。

InitViews

通过多种剔除方法为视图初始化基元可见性,设立此帧可见的动态阴影、按需要交叉阴影视锥与世界场景(对整个场景的阴影或预阴影)。

PrePass / Depth only pass

RenderPrePass / FDepthDrawingPolicy。渲染遮挡物,对景深缓冲区仅输出景深。该通道可以在多种模式下工作:禁用、仅遮蔽,或完全景深,具体取决于活动状态的功能的需要。该通道通常的用途是初始化 Hierarchical Z 以降低 Base 通道的着色消耗(Base 通道的像素着色器消耗非常大)。

Base pass

RenderBasePass / TBasePassDrawingPolicy。渲染不透明和遮盖的材质,向 GBuffer 输出材质属性。光照图贡献和天空光照也会在此计算并加入场景颜色。

Issue Occlusion Queries / BeginOcclusionTests

提出将用于下一帧的 InitViews 的延迟遮蔽查询。这会通过渲染所查询物体周围的相邻的框、有时还会将相邻的框组合在一起以减少绘制调用来完成。

Lighting

阴影图将对各个光照渲染,光照贡献会累加到场景颜色,并使用标准延迟和平铺延迟着色。光照也会在透明光照体积中累加。

Fog

雾和大气在延迟通道中对不透明表面进行逐个像素计算。

Translucency

透明度累加到屏外渲染目标,在其中它应用了逐个顶点的雾化,因而可以整合到场景中。光照透明度在一个通道中计算最终光照以正确融合。

Post Processing

多种后期处理效果均通过 GBuffers 应用。透明度将合成到场景中。

以上是相当简单概略的介绍。如需了解详情,请通读相关代码或输出的"profilegpu"日志。

渲染硬件接口 (RHI)

RHI 是平台特定的图形 API 之上的一个薄层。UE4 中的 RHI 抽象层尽可能低,这样大多数功能都能以与平台无关的代码写成,从而能够在支持所需功能层级的任何平台上运行。

功能集将量化到 ERHIFeatureLevel 中,降低复杂程度。如果平台无法支持某个功能层级所需的全部功能,则其必须降低层级,直至能够全部支持。

功能层级

描述

SM5

通常对应于 D3D11 Shader Model 5,但由于 OpenGL 4.3 限制,仅有 16 种纹理可以使用。支持曲面细分、计算着色器和立方体贴图阵列。支持延迟着色路径。

SM4

对应 D3D11 Shader Model 4,这与 SM5 基本相同,但没有曲面细分、计算着色器和立方体贴图阵列。支持延迟着色路径。不支持眼适应,因为其使用计算着色器。

ES2

对应大多数 OpenGL ES2 移动设备支持的功能。使用削减向前着色路径。

渲染状态分组

渲染状态根据其影响的流程部分而分组。例如,RHISetDepthState 可设置所有与景深缓冲相关的状态。

渲染状态默认值

由于渲染状态数量众多,要在每次绘制之前对它们全部设置一遍是不现实的。为此,UE4 具有隐性设置的一组状态,它们被认为是设置为了默认值(因此在变更后必须恢复为默认值),另外还有一组少得多的状态需要显性设置。没有隐性默认值的状态有:

  • RHISetRenderTargets
  • RHISetBoundShaderState
  • RHISetDepthState
  • RHISetBlendState
  • RHISetRasterizerState
  • RHISetBoundShaderState 设置的着色器的任何依赖性

    其他所有状态均视为已设置为其默认值(即相关 TStaticState 的定义,如默认的蜡纸模板状态由 RHISetStencilState(TStaticStencilState<>::GetRHI()) 设置。

2018-10-24 21:48:00 u012614151 阅读数 6
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2396 人正在学习 去看看 杨石兴

@author: 白袍小道

转载悄悄说明下

随缘查看,施主开心就好

   

说明:

本篇继续Unreal搬山部分的渲染模块的Shader部分,

主要牵扯模块RenderCore, ShaderCore, RHI, Materia.

可能分成N篇。

(这里放入的UE的模块框)

(下一篇主要是UE灯光和着色简要[ush以及对应结构,和UE代码和DX部分],然后是巴拉巴拉)

   

前言:

部分算法和流程的实现原理,和细节(往往这部分会成为优化的处理口)。

梳理UEShader的结构,底层的接入,分层。

UE着色使用和细节部分。

对比反观差距和原因

   

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第一部分、渲染管线和着色

Shading Models

描述物体的颜色如何根据表面等因素而变化 (例如方向,视图方向,和照明)

1、通常具有控制外观变化的属性。

2、控制这些变化的属性而决定了变化。

   

评估

设计着色实现时,需要根据计算结果进行划分他们的评估频率。

首先,确定一个给定的结果在整个绘制调用中,计算总是不变的。在这种情况下,计算应用程序可以通过GPU计算(通常在CPU上)执行吗。着色器可以用于特别昂贵的计算。结果被传递给图形API通过统一着色器输入。

   

说明

1、虚拟机

a\ 目前的着色语言都是 C-likelike 的着色语言,比如 HLSL,CG 和 GLSL GLSL,其被编译成独立于机器的汇语言 语言,也称为中间( IL )。

这些汇编语言在单独的阶段,通常是驱动中被转化成实际机器 )。

这些汇编语言在单独的阶段,通常是驱动中被转化成实际机器 语言。这样的安排可以兼容不同硬件实现些汇编被看做是定义一个作为着色译器.

b\ 着色语言虚拟机可以理解为一个处多种类型寄存器 和数据源、预编了一系列指令的处理器。

2、单指令多数据( SIMD), 寄存器.

a\ 一次DrawCall会通过API做一次(一系列)的图元绘制,从而驱使图形管线运行。[如Draw,DrawInstance, …..]

b\ 输入,输出和交接。

c\ Shader的语句、加载和编译。

DX10 虚拟机

  

   

语法树

划分

1、顶点着色

发生在图元装配后

顶点着色器(VS)阶段处理来自输入汇编器的顶点,执行每个顶点的操作,如转换、蒙皮、变形和每个顶点的光照,并编制到输出结构交付给下一个管道。

(顶点着色器总是操作单个输入顶点并产生单个输出顶点。顶点着色器阶段必须始终处于活动状态,以便管道执行。

如果不需要顶点修改或转换,则必须创建一个直通顶点着色器并将其设置为管道。)

   

a\ 输入和输出:

每个顶点着色器输入顶点可以由16个32位向量组成(每个顶点最多4个分量),每个输出顶点可以由16个32位4分量向量组成。

所有顶点着色器都必须至少有一个输入和一个输出,可以是一个标量值。

 

b\ vertexshader阶段可以使用输入汇编程序生成的两个系统值:VertexID和InstanceID(参见系统值和语义)。

由于VertexID和InstanceID在顶点级别都是有意义的,并且硬件生成的ID只能被输入到理解它们的第一阶段,因此这些ID值只能被输入到vertexshader阶段。

 

c\ 顶点着色器总是在所有顶点上运行,包括带有邻接的输入基元拓扑中的相邻顶点。

顶点着色器执行的次数可以使用VSInvocations管道统计从CPU查询。

   

   

2、可选镶嵌

描述:

Direct3D 11运行时支持三个实现镶嵌的新阶段,它将低细节细分曲面转换为GPU上的高细节原语。

镶嵌瓷砖(或分解)高阶表面成适合渲染的结构。

通过在硬件中实现镶嵌,图形管道可以评估较低的细节(较低的多边形计数)模型和渲染较高的细节。

虽然可以进行软件镶嵌,但是由硬件实现的镶嵌可以生成大量的视觉细节(包括对位移映射的支持),而不需要向模型大小添加视觉细节和刷新率。

   

概括:镶嵌使用GPU计算更详细的表面从一个由四边形斑块,三角形斑块或等值线构成的表面。

   

HullShader:

一个可编程的着色器阶段,它产生一个几何贴片(和贴片常量),对应于每个输入贴片(四边形、三角形或直线).

外壳着色器(每个补加点调用一次)将定义低阶表面的输入控制点转换为构成补加的控制点。

ID3D11Device::

CreateHullShader

   

ID3D11DeviceContext::HSSetShader

  

  

Tessellator

一个固定的函数管道阶段,它创建表示几何patch的域的抽样模式,并生成一组较小的对象(三角形、点或线)来连接这些样本

将一个域(四边形、三边形或直线)细分为许多较小的对象(三角形、点或直线)。将uv(和可选的w)坐标和表面拓扑(归一化的坐标域)输出到域着色器阶段。

域着色器在每个tessellator阶段点调用一次,并计算表面位置。

  

Domain

一个可编程着色器阶段,计算对应于每个域样本的顶点位置

域着色器计算输出补丁中细分点的顶点位置,其中每个tesselator阶段输出点运行一次,并且对tesselators阶段输出UV坐标、船体着色器输出补丁和船体着色器输出补删常量具有只读访问权限。

ID3D11Device::

CreateDomainShader

  

  

 

   

   

3Geometry Shader

几何着色器(GS)阶段运行应用程序指定的着色器代码,将顶点作为输入,并能够在输出上生成顶点。

(不像顶点着色器操作单个顶点,几何着色器的输入是一个完整语义的顶点(两个顶点表示线,三个顶点表示三角形,或者单个顶点表示点)。

几何体着色器还可以将边缘相邻基元的顶点数据作为输入(对于一条直线,额外的两个顶点,对于三角形,额外的三个顶点)。

下图显示了一个三角形和一条有相邻顶点的直线。)

   

a\ 可以使用由IA自动生成的SV_PrimitiveID系统生成的值。

b\ 能够输出多个顶点,形成单个选定的拓扑(可用的GS阶段输出拓扑有:tristrip、linestrip和pointlist)。

c\ 输出可以通过流输出阶段反馈到光栅化阶段和/或内存中的顶点缓冲区。提供给内存的输出被扩展到单独的点/线/三角形列表(它们将被传递给光栅化器)。

   

4Pixel Shader

像素着色器阶段(PS)支持丰富的着色技术,例如逐像素光照和后期处理。

像素着色器是一个程序,它结合了常量变量、纹理数据、每个顶点值的插值和其他数据来产生每个像素的输出

对于一个原语覆盖的每个像素,rasterizer阶段只调用一次像素着色器,但是,可以指定一个空着色器来避免运行一个着色器。

   

a\ 当对纹理进行多采样时,每个覆盖的像素只调用一次像素着色器,同时对每个覆盖的多采样进行深度/模板测试。通过深度/模版测试的样本将使用像素着色器输出颜色进行更新。(所以适当减少)

   

b\ 像素着色器固有函数产生或使用屏幕空间x和y的数量导数,导数最常用的用途是计算纹理采样的详细程度计算,在各向异性滤波的情况下,选择沿各向异性轴的样本。

通常,硬件实现同时在多个像素(例如2x2网格)上运行一个像素着色器,以便在像素着色器中计算的量的导数可以合理地近似为相邻像素中同一执行点上的值的增量。

   

c\ 输入:

输入将被限制(超过会截取)在16(无配置Geo着色)or 32、 32位、4个组件。

关键词:顶点属性,插值,覆盖,抽样,

   

d\ 输出

像素着色器最多可以输出8 32位4分量的颜色,如果像素被丢弃,则不输出颜色。像素着色器输出寄存器组件在使用之前必须声明;每个寄存器都允许有一个不同的输出-写入掩码。

使用depth-write-enable状态(在输出合并阶段)来控制是否将深度数据写入深度缓冲区(或使用丢弃指令丢弃该像素的数据)。

像素着色器还可以输出可选的32位、1个组件、浮点数、深度值来进行深度测试(使用SV_Depth语义)。

深度值在深度寄存器中输出,并替换深度测试的插值深度值(假设启用深度测试)。无法在使用固定函数深度和着色器深度之间动态变化。

像素着色器不能输出模板值。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

第二部分、Unreal 着色器相关

DX

1、编译,读写

D3DCompileFromFile(_In_ LPCWSTR pFileName,

_In_reads_opt_(_Inexpressible_(pDefines->Name != NULL)) CONST D3D_SHADER_MACRO* pDefines,

_In_opt_ ID3DInclude* pInclude,

_In_ LPCSTR pEntrypoint,

_In_ LPCSTR pTarget,

_In_ UINT Flags1,

_In_ UINT Flags2,

_Out_ ID3DBlob** ppCode,

_Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorMsgs);

D3DCompile(_In_reads_bytes_(SrcDataSize) LPCVOID pSrcData,

_In_ SIZE_T SrcDataSize,

_In_opt_ LPCSTR pSourceName,

_In_reads_opt_(_Inexpressible_(pDefines->Name != NULL)) CONST D3D_SHADER_MACRO* pDefines,

_In_opt_ ID3DInclude* pInclude,

_In_opt_ LPCSTR pEntrypoint,

_In_ LPCSTR pTarget,

_In_ UINT Flags1,

_In_ UINT Flags2,

_Out_ ID3DBlob** ppCode,

_Always_(_Outptr_opt_result_maybenull_) ID3DBlob** ppErrorMsgs);

   

D3DCompressShaders(_In_ UINT uNumShaders,

_In_reads_(uNumShaders) D3D_SHADER_DATA* pShaderData,

_In_ UINT uFlags,

_Out_ ID3DBlob** ppCompressedData)

   

D3DReadFileToBlob(_In_ LPCWSTR pFileName,_Out_ ID3DBlob** ppContents)

D3DWriteBlobToFile(_In_ ID3DBlob* pBlob,_In_ LPCWSTR pFileName, _In_ BOOL bOverwrite)

   

2、创建

CreateVertexShader(

_In_reads_(BytecodeLength) const void *pShaderBytecode,

_In_ SIZE_T BytecodeLength,

_In_opt_ ID3D11ClassLinkage *pClassLinkage,

_COM_Outptr_opt_ ID3D11VertexShader **ppVertexShader)

CreateXXXShader类似

   

Unreal

UnrealShader处理包括了:ush的包含,编译得到转储的着色器usf,平台编译器编译,创建和使用(绑定)。

1、Global Shaders

全局shader是用于操作固定几何体(如:full screen quad)的shader,并且它不需要与materials产生交互,例如:阴影过滤、后处理。

这种类型的shader在内存中只有一份实例.

   

2Materia

材质由一些控制材质如何渲染的状态和一些控制材质如何与渲染Pass shader交互的材质输入(material inputs)组成。

   

3、Vertex Factories 和 MeshTypes

Material必须能够赋给各种类型的Mesh Types, 这个是通过和Vertex Factories 配合完成的。 一个FVertexFactoryType表示唯一的Mesh Type。

一个FVertexFactory的实例存有每个几何体的数据,以便支持特定的Mesh Type。

   

引擎内Shader位于:Engine\Shaders\Private(Public)

(详细分析和说明在下一篇)

使用部分

   

   

ShaderCore

FShader、FGlobalShader、

FShaderType, FVertexFactory

FShaderPipeline, FShaderTarget

   

   

   

   

   

材质的编译

   

过程说明:

1、生成材质的Shader代码【只是Shader文件】

2、构建编译环境,且添加相关文件路径

3、编译[可以异步],成功就缓存起来

3.1 创建了一个临时引用计数指针[主要是确保操作一个引用的着色器映射[或查找]将导致这个着色器映射被删除]

3.2 往ShaderMapsBeingCompiled添加[占个位置]

3.3 分配唯一编译ID,配置编译环境

3.4 迭代处理所有顶点工厂的类型,编译这个材质和顶点工厂类型组合的所有网格材质着色器。---------FVertexFactoryType

3.5 迭代处理所有材质Shader的类型 ------FShaderType

3.6 迭代处理所有材质Shader管线的类型 ------FShaderPipelineType

3.7 进入映射编译着色器

   

类关系:

   

   

2019-02-26 00:58:00 u012614151 阅读数 7
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2396 人正在学习 去看看 杨石兴

@authot: 白袍小道

 

  • 转载说明那啥即可。
  • (图片和本文无关,嘿嘿,坑一下)

       

       

  • 以下为Unreal4.18版本中对GPUBuffer部分的分析结果
  • (插入:比之够着,知至目的)

       

  • Memo of GBuffer (UE4.18)

       

    • GBufferA : Normal(rgb), PerObjectGBufferData(a)

         

    • GBufferB : Metallic(r), Specular(g), Roughness(b), ShadingModelID(a&0xF),

         

    • SelectiveOutputMask(a&0xF0)

         

    • GBufferC : BaseColor(rgb), IndirectIrradiance(a)

         

    • GBufferD : CustomData(rgba)

         

    • GBufferE : PrecomputedShadowFactors(rgba)

         

    • SceneDepth

         

    • CustomNativeDepth : depth®

         

    • CustomStencilTexture

         

    • GBufferVelocity : rgba

      补充说明:注意源码中对这一块的对齐处理,线程,访问方式的处理

         

  • Dbuffer

       

    • DBufferA : PreMultColor(rgb), ColorOpacity(a)

         

    • DBufferB : PreMulWorldNormal(rgb), NormalOpacity(a)

         

    • DBufferC : PreMulRoughness(r ), RoughnessOpacity(g)

       

    (一)、DeferredShadingRender中对Buffer的处理

    从调式和RenderDoc可以详细看到过程,这里就不做详细说明

       

    结果:

       

    (二),代码抓取

    结局:

    https://twitter.com/i/status/1096091562642001920

    这里主要用两种方式去获取,一种是通过Fmemory,一种直接用Unreal提供CopyShareMip

    具体如下:

       

    以下为全部代码:

       

    DynamicAccessGBufferRenderTarget.h

    //////////////////这里就没有按照Buff处理做分装了,直接怼的(嘿嘿)

    #pragma once

    #include <memory>

    #include "Engine/Texture2D.h"

    #include "Object.h"

    #include "DynamicAccessGBufferRenderTarget.generated.h"

       

    UENUM(BlueprintType)                //"BlueprintType" is essential to include

    enum class EDZShowGbuffer : uint8

    {

    VE_GDZSHOWBUFFERA         UMETA(DisplayName = "ShowGBuffA"),

    VE_GDZSHOWBUFFERB         UMETA(DisplayName = "ShowGBuffB"),

    VE_GDZSHOWBUFFERC        UMETA(DisplayName = "ShowGBuffC"),

    VE_GDZSHOWBUFFERD        UMETA(DisplayName = "ShowGBuffD"),

    VE_GDZSHOWBUFFERE        UMETA(DisplayName = "ShowGBuffE"),

    };

       

    UENUM(BlueprintType)                //"BlueprintType" is essential to include

    enum class EDZCOPYGbufferType : uint8

    {

    VE_GDZSHOWGBUFFER_COPYMIP         UMETA(DisplayName = "COPY_Mip"),

    VE_GDZSHOWBUFFERR_COPYMEMO         UMETA(DisplayName = "COPY_Memory"),

    VE_GDZSHOWBUFFERC_CPUARRAY        UMETA(DisplayName = "COPY_MemoryForWhile"),

    };

       

    USTRUCT()

    struct FCommitRenderData

    {

    GENERATED_BODY()

    public:

    EDZCOPYGbufferType ECOPYBuffType;

    EDZShowGbuffer EShowBuff;

    UTextureRenderTarget2D* mTextureTarget;

    EPixelFormat format;

    int32 canvasWidth = 512;

    int32 canvasHeight = 512;

    bool isGetGBufferData = false;

    };

       

    UCLASS(Blueprintable, BlueprintType)

    class DZRENDERSTUDIOPLUGIN_API UDynamicAccessGBufferRenderTarget : public UObject

    {

    GENERATED_BODY()

       

    public:

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DynamicAccessGBufferRenderTarget)

    EDZCOPYGbufferType ECOPYBuffType;

       

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DynamicAccessGBufferRenderTarget)

    EDZShowGbuffer EShowBuff;

       

    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = DynamicAccessGBufferRenderTarget)

    UTextureRenderTarget2D* mTextureTarget;

       

    UFUNCTION(BlueprintCallable, Category = DynamicAccessGBufferRenderTarget)

    void InitializeTexture(UTextureRenderTarget2D* pTextureTarget,EDZShowGbuffer pEShowBuff, EDZCOPYGbufferType pECOPYBuffType);

       

    UFUNCTION(BlueprintCallable, Category = DynamicAccessGBufferRenderTarget)

    void CaputerGBuffer();

       

    UFUNCTION(BlueprintCallable, Category = DynamicAccessGBufferRenderTarget)

    void ClearTexture();

       

    UDynamicAccessGBufferRenderTarget();

    ~UDynamicAccessGBufferRenderTarget();

       

    static void CaputerGBufer_Rebuild_RenderThread(FCommitRenderData* pRenderData);

    static void CaputerGBuffer_RenderThread(FCommitRenderData* pRenderData);

       

    static void Copy_TextureRHI(FRHICommandListImmediate& RHICmdList, FRHITexture2D* pDesc, FRHITexture2D* pSrc);

    static void Copy_MemoryRHI(FRHICommandListImmediate& RHICmdList, FRHITexture2D* pDesc, FRHITexture2D* pSrc);

    static void Copy_CPUArrayRHI();

       

    private:

    EPixelFormat format;

    UPROPERTY()

    FCommitRenderData CatchRenderData;

       

    UPROPERTY()

    bool isRebulidRenderTargetSuccess = false;

    };

       

       

       

    DynamicAccessGBufferRenderTarget.cpp

    /**

    * 1、这里步骤基本为先得到当前Buffer的大小,刷新RT目标的数据。并在基础属性变化时* 候再次刷新

    * 2、抓取数据(由于BUFF在Render管线处理时候有获取和释放的处理也是为了能及时释* 放,所以手动加1,

    * 当然成对的写法在DepthRender, Slate等都可以看到,这非常好。

    * 3、CopyShare或者利用FMemory::Memcpy(但拷贝前需要加锁,完成后还需要解锁,所* * 以你懂的

    **/

       

    #include "DynamicAccessGBufferRenderTarget.h"

    #include "private/PostProcess/SceneRenderTargets.h"

    #include "Engine.h"

    #include "RHICommandList.h"

       

       

       

       

    UDynamicAccessGBufferRenderTarget::UDynamicAccessGBufferRenderTarget()

    {

       

    }

       

    UDynamicAccessGBufferRenderTarget::~UDynamicAccessGBufferRenderTarget()

    {

       

    }

       

    void UDynamicAccessGBufferRenderTarget::InitializeTexture(UTextureRenderTarget2D* pTextureTarget

    , EDZShowGbuffer pEShowBuff, EDZCOPYGbufferType pECOPYBuffType)

    {

    if (mTextureTarget != pTextureTarget || EShowBuff != pEShowBuff || ECOPYBuffType != pECOPYBuffType)

    {

    mTextureTarget = pTextureTarget;

    EShowBuff = pEShowBuff;

    ECOPYBuffType = pECOPYBuffType;

    isRebulidRenderTargetSuccess = false;

    }

       

    }

       

    void UDynamicAccessGBufferRenderTarget::ClearTexture()

    {

       

    }

       

       

    void UDynamicAccessGBufferRenderTarget::CaputerGBuffer()

    {

    if (!CatchRenderData.isGetGBufferData)

    {

    isRebulidRenderTargetSuccess = false;

    CatchRenderData.EShowBuff = EShowBuff;

    CatchRenderData.ECOPYBuffType = ECOPYBuffType;

    CatchRenderData.mTextureTarget = mTextureTarget;

    ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(

    DZRenderSutioBP_AccessGBufferRenderTarget_init,

    FCommitRenderData*, RenderData, &CatchRenderData,

    {

    UDynamicAccessGBufferRenderTarget::CaputerGBufer_Rebuild_RenderThread(RenderData);

    }

    );

    }

    else

    {

    if (!isRebulidRenderTargetSuccess)

    {

    if (IsInGameThread())

    {

    mTextureTarget->InitCustomFormat(CatchRenderData.canvasWidth, CatchRenderData.canvasHeight, CatchRenderData.format, false);

    mTextureTarget->ForceRebuildPlatformData();

    }

    isRebulidRenderTargetSuccess = true;

    }

    else

    {

    CatchRenderData.EShowBuff = EShowBuff;

    CatchRenderData.ECOPYBuffType = ECOPYBuffType;

    CatchRenderData.mTextureTarget = mTextureTarget;

    ENQUEUE_UNIQUE_RENDER_COMMAND_ONEPARAMETER(

    DZRenderSutioBP_InterceptSceneGBufferToRenderTarget,

    FCommitRenderData*, RenderData, &CatchRenderData,

    {

    UDynamicAccessGBufferRenderTarget::CaputerGBuffer_RenderThread(RenderData);

    }

    );

    }

    }

       

    }

       

    void UDynamicAccessGBufferRenderTarget::CaputerGBufer_Rebuild_RenderThread(FCommitRenderData* pRenderData)

    {

    FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();

    //计数加一避免Render完成后直接清空了GBuffer,但会慢一帧,你猜

    FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, 1);

    FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);

    if (SceneContext.GBufferA)

    {

    FTexture2DRHIRef vTextTarget;

    switch (pRenderData->EShowBuff)

    {

    case EDZShowGbuffer::VE_GDZSHOWBUFFERA:

    vTextTarget = SceneContext.GetGBufferATexture();

    break;

    case EDZShowGbuffer::VE_GDZSHOWBUFFERB:

    vTextTarget = SceneContext.GetGBufferBTexture();

    break;

    case EDZShowGbuffer::VE_GDZSHOWBUFFERC:

    vTextTarget = SceneContext.GetGBufferCTexture();

    break;

    case EDZShowGbuffer::VE_GDZSHOWBUFFERD:

    vTextTarget = SceneContext.GetGBufferDTexture();

    break;

    case EDZShowGbuffer::VE_GDZSHOWBUFFERE:

    vTextTarget = SceneContext.GetGBufferETexture();

    break;

    default:

    vTextTarget = SceneContext.GetGBufferATexture();

    break;

    }

     

    pRenderData->format = vTextTarget->GetFormat();

    pRenderData->canvasWidth = vTextTarget->GetSizeX();

    pRenderData->canvasHeight = vTextTarget->GetSizeY();

    pRenderData->isGetGBufferData = true;

    }

    FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, -1);

    }

       

    void UDynamicAccessGBufferRenderTarget::CaputerGBuffer_RenderThread(FCommitRenderData* pRenderData)

    {

    FRHICommandListImmediate& RHICmdList = GRHICommandList.GetImmediateCommandList();

    //计数加一避免Render完成后直接清空了GBuffer,但会慢一帧,你猜

    FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, 1);

    FSceneRenderTargets& SceneContext = FSceneRenderTargets::Get(RHICmdList);

    if (SceneContext.GBufferA && pRenderData->mTextureTarget != nullptr)

    {

    FTexture2DRHIRef vTextTarget;

    switch (pRenderData->EShowBuff)

    {

    case EDZShowGbuffer::VE_GDZSHOWBUFFERA:

    vTextTarget = SceneContext.GetGBufferATexture();

    break;

    case EDZShowGbuffer::VE_GDZSHOWBUFFERB:

    vTextTarget = SceneContext.GetGBufferBTexture();

    break;

    case EDZShowGbuffer::VE_GDZSHOWBUFFERC:

    vTextTarget = SceneContext.GetGBufferCTexture();

    break;

    case EDZShowGbuffer::VE_GDZSHOWBUFFERD:

    vTextTarget = SceneContext.GetGBufferDTexture();

    break;

    case EDZShowGbuffer::VE_GDZSHOWBUFFERE:

    vTextTarget = SceneContext.GetGBufferETexture();

    break;

    break;

    default:

    vTextTarget = SceneContext.GetGBufferATexture();

    break;

    }

    pRenderData->format = vTextTarget->GetFormat();

    if (pRenderData->canvasWidth != vTextTarget->GetSizeX())

    {

    pRenderData->isGetGBufferData = false;

    return;

    }

    FTextureReferenceRHIRef vTexRHIRef = pRenderData->mTextureTarget->TextureReference.TextureReferenceRHI;

    FRHITexture* vRTTexture = vTexRHIRef->GetTextureReference()->GetReferencedTexture();

    FRHITexture2D* vtex = (FRHITexture2D*)vRTTexture;

    if (vtex == nullptr)

    {

    return;

    }

    switch (pRenderData->ECOPYBuffType)

    {

    case EDZCOPYGbufferType::VE_GDZSHOWGBUFFER_COPYMIP:

    UDynamicAccessGBufferRenderTarget::Copy_TextureRHI(RHICmdList,vtex, vTextTarget);

    break;

    case EDZCOPYGbufferType::VE_GDZSHOWBUFFERR_COPYMEMO:

    UDynamicAccessGBufferRenderTarget::Copy_MemoryRHI(RHICmdList, vtex, vTextTarget);

    break;

    case EDZCOPYGbufferType::VE_GDZSHOWBUFFERC_CPUARRAY:

    UDynamicAccessGBufferRenderTarget::Copy_CPUArrayRHI();

    break;

    default:

    break;

    }

    RHICmdList.CopySharedMips(vtex, vTextTarget);

    }

    //移除

    FSceneRenderTargets::Get(RHICmdList).AdjustGBufferRefCount(RHICmdList, -1);

    }

       

    //利用SharedMip的共享方式在这里会快一些

    //扩展方式

    void UDynamicAccessGBufferRenderTarget::Copy_TextureRHI(FRHICommandListImmediate& RHICmdList,FRHITexture2D* pDesc,FRHITexture2D* pSrc)

    {

    RHICmdList.CopySharedMips(pDesc, pSrc);

    }

       

    //内存CPY,但需要锁住,这样就会让另外的渲染不能访问,会造成掉帧率。

    void UDynamicAccessGBufferRenderTarget::Copy_MemoryRHI(FRHICommandListImmediate& RHICmdList, FRHITexture2D* pDesc, FRHITexture2D* pSrc)

    {

    uint32 Lolstrid = 0;

    void * UAVRenderTargetData = RHILockTexture2D(pDesc, 0, RLM_WriteOnly, Lolstrid, true);

    void * UAVCSData = RHILockTexture2D(pSrc, 0, RLM_ReadOnly, Lolstrid, true);

    FMemory::Memcpy(UAVRenderTargetData, UAVCSData, GPixelFormats[pSrc->GetFormat()].BlockBytes * pSrc->GetSizeX() * pSrc->GetSizeY());

    RHICmdList.UnlockTexture2D(pDesc, 0, false);

    RHICmdList.UnlockTexture2D(pSrc, 0, false);

    }

       

    void UDynamicAccessGBufferRenderTarget::Copy_CPUArrayRHI()

    {

       

    }

       

    蓝图和资源部分

    1、RT (1个对应一个结果)

    2、一个UI材质(用于做一些额外效果)

    3、一个UI蓝图(就是调用代码和绑定资源,用C++也可以,偷懒下)

    RT赋予

    BP部分

    UI_ShowCapResul_Child

       

    除了一些我们自己做的方式和LitMode中调试方式

       

    还以通过像素检查器进行分析和查看

       

    题外:

    1、Create Custom GBUFFER :http://www.catalinzima.com/xna/tutorials/deferred-rendering-in-xna/creating-the-g-buffer/

       

    2Buffer,RT ,Pipeline

    https://medium.com/@lordned/unreal-engine-4-rendering-part-4-the-deferred-shading-pipeline-389fc0175789

       

    3https://en.wikipedia.org/wiki/Deferred_shading

       

    4、高效的GPU GBUFFER管理:http://www.klayge.org/2015/05/25/%E9%AB%98%E6%95%88gpu-buffer%E7%AE%A1%E7%90%86%E4%B9%8Btransient-buffer/

2018-10-06 18:13:00 u012614151 阅读数 6
  • 从这里开始虚幻4-Editor介绍 v4.18

    本课程系列取名英译系列,是录制人员参考国外英文原版经典教程,结合中国人的习惯录制而成。希望能够给大家以帮助。从这里开始虚幻4系列教程,是Unreal的官方发布的入门教学,非常经典,是学习Unreal的佳入口。

    2396 人正在学习 去看看 杨石兴

   

   

@author:白袍小道

   

引言

本文只在对Unreal渲染模块做一些详细的理解,务求能分析出个大概。

其中框架的思想和实现的过程,是非常值得学习和推敲一二的。

涉及资源系统,材质系统,场景系统,渲染系统

   

通常渲染模块组成:

  • 场景的描述
    • FScene
    • FPrimitiveSceneProxy
    • FPrimitiveSceneInfo
    • FMaterial
    • FMaterialResoruce
    • FMaterialRenderProxy

       

  • 场景遍历和拣选
    • 分类处理(得到静态列表,动态列表
    • 可见性搞定

   

  • 渲染的执行
    • 一个是源码,一个RenderDOC,配合DX文档梳理
    • 多个Pass阶段

       

    渲染模块层次划分:

  • 核心代码模块 
    • RenderCore
    • Renderer

         

  • RHI 抽象层 
    • RHI(Render Hardware Interface)
    • D3D分层分装

         

  • RHI 实现层,API封装: 
    • EmptyRHI
    • Windows 上 D3D11RHI
    • Metal、VulkanRHI、OpenGLdRV

   

--------------------------------------------------------------------------------------------------------------------------------------------------

乱入说明

--------------------------------------------------------------------------------------------------------------------------------------------------

基本图:包含了引擎到渲染模块涉及到的类,层次。

1、UnrealEngine、UEditorEngine, EngineLoop

2、UGameViewoirtClient为一个入口点,接着进入到RenderModule

3、渲染线程

【可以先查阅Core下的Thread,异步等处理方法和封装,然后再到渲染。基本就记得提交渲染命令,然后巴拉巴拉,然后就到RenderFam,,,,,.这里作为随笔,后面正式的分类,和说明会放在渲染模块中】

   

渲染部分

   

   

   

渲染实例化部分

   

接入到渲染中间操作部分

   

   

   

Unreal接入底层操作部分

Unreal RHI模块,对应平台的渲染模块

DX渲染管线

   

   

   

unreal4 源码引言

阅读数 256

没有更多推荐了,返回首页