2019-05-10 21:25:45 qq_33465047 阅读数 158
  • 从这里开始虚幻4-第2辑-蓝图 v4.18

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

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

首先,找一个文件夹,然后右击,会弹出下面所示的,点击Material建立一个材质,然后给命名,

在这儿将新建材质,命名为Wall,然后双击,进入材质编辑器。如下图:

材质编辑器,主要由5部分组成,1

1 :菜单栏+工具栏,2视口面板:预览材质实时的效果,3细节面板-----列出材质,所选材质的表现, 4 :代码编辑区:显示创建材质的指令 5:控制面板:列出所有材质着色器指令的材质表现和函数。

下面介绍一下材质中特别重要的基础部分:如左图所示。

其中常用的是:

 

 基础颜色,金属,高光,粗糙度,自发光颜色,法线.

基础颜色(Base Color):材质的基本颜色

金属(Metallic):定义材质有金属特性,设置范围在0-1之间。

高光(Specullar):调整的是非金属材质的高光反射程度。默认是0.5

粗糙度(Roughness):数值低的材质镜面反射的程度就越高,也就是越光滑。

自反光颜色(Emissive):定义材质自主发出光线的参数

法线(Normal):用于连接贴图,

了解这些就可以做出很多材质了,

 

 

 

在材质编辑器一些常见的快捷键(注意,按键的同时,左击鼠标,才会有反映)

键盘撒上的数字1,2,3,:是用来创建常量和向量的节点,

U:贴图坐标

T:贴图取样器

M和D:创建加法、乘法和除法的节点。

删除节点:就是delete

 

然后实际操作一下:

首先,按下键盘的数字3同时单机左键,会出现一个向量,用来设置基础颜色,双击这个向量,选择一个颜色。然后再按下数字1的同时单机左键,会出现一个标量,将它与金属属性相连,然后单机编辑器的左上方,Apply按钮,会出现一下效果。

 

2020-02-07 10:16:19 qq_23030843 阅读数 14
  • 从这里开始虚幻4-第2辑-蓝图 v4.18

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

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

Unreal 材质系统

材质(Material) 是可以应用到网格物体(Mesh)上的资源,用它可控制场景的可视外观。从较高的层面上来说,可能最简单的方法就是把材质视为应用到一个物体的"描画"。但这种说法也会产生一点点误导,因为材质实际上定义了组成该物体所用的表面类型(质感)。您可以定义它的颜色、它的光泽度及您是否能看穿该物体(半透明)等等。

在这里是默认大家对使用材质系统拥有基本的基本操作经验,所以本文并不会对一般的简单操作做任何的解释和说明,如果大家想对Unreal材质系统的基本操作感兴趣的话,参考官方文档:

https://docs.unrealengine.com/zh-CN/Engine/Rendering/Materials/index.html

对与某些高端的材质TA向的技巧和经验总结以后会在之后的文档中进行总结和归纳。

因此,本文的重点主要是来分析材质系统的运行逻辑和手段,从自动的代码生成到生成变体的过程,最终到如何和几何信息绑定提交渲染的一整套的流程。

一.简介

由于后文即将阐述的编译功能或者变体功能更加的抽象和难以理解,所以我们需要一个比较直观的切入来审视Unreal的整个材质系统。

我希望呈现一种较为直接的介绍模式,这一切就在我们打开一个Materal.asset开始。其对应于代码中的UMaterial

1.1 PBR和它的输出

当我们打开材质编辑器,最开始我们能最直接看见的就是我们的材质的输出。如下图的左

 

右图是迪斯尼的PBR参考,这是unreal 的PBR材质节点。

对应代码中,是对应的各种FXXXMaterialInput。材质输出属性在UE4中的基类叫FMaterialInput,它有一些子类用于表达具体的输出属性的具体数据类型,如FColorMaterialInput,FScalarMaterialInput,FVectorMaterialInput等。

UMaterial中对应的材质输出属性和材质编辑器上的输出节点属性几乎是一一对应的(注,显示出来的名字可能会和变量量不同,因为名字因材质类型,光照模型而显示不同的名字),完整定义如下:

  1. FColorMaterialInput BaseColor;
  2. FScalarMaterialInput Metallic;
  3. FScalarMaterialInput Specular;
  4. FScalarMaterialInput Roughness;
  5. FVectorMaterialInput Normal;
  6. FColorMaterialInput EmissiveColor;
  7. FScalarMaterialInput Opacity;
  8. FScalarMaterialInput OpacityMask;
  9. FVectorMaterialInput WorldPositionOffset;
  10. FVectorMaterialInput WorldDisplacement;
  11. FScalarMaterialInput TessellationMultiplier;
  12. FColorMaterialInput SubsurfaceColor;
  13. FScalarMaterialInput ClearCoat;
  14. FScalarMaterialInput ClearCoatRoughness;
  15. FScalarMaterialInput AmbientOcclusion;
  16. FScalarMaterialInput Refraction;
  17. FVector2MaterialInput CustomizedUVs[8];
  18. FMaterialAttributesInput MaterialAttributes;
  19. FScalarMaterialInput PixelDepthOffset;
  20. FShadingModelMaterialInput ShadingModelFromMaterialExpression;
     

 

这里比较重要的是有一个WITH_EDITORONLY_DATA的宏,其关闭和IOS竟然相关!那按道理来说如果平台不同的话确实在最后呈现上会有明显的不同。

 

1.2顶层设计

至此我们先来高屋建瓴的看一下与Material相关的类,来更加清楚地了解其顶层设计。

 

描述

FMaterial

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

FMaterialResource

FMaterialResource是FMaterail的子类。连接用于渲染的材质的接口。可用于访问材质属性(如混合模式)。包含被渲染器用于检索个体着色器的着色器地图。 FMaterialResource负责为各个渲染API和材质所支持的各种质量等级生成对应的Shader组合。所以,每个UMaterial都会包含多个FMaterialResource。

FMaterialRenderProxy

FMaterialRenderProxy是FMaterial用于渲染线程的代理,它可以透过FMaterail和UMaterialInterface访问到Shader、渲染状态,光照模型等所有用户设置好的材质参数。

UMaterialInterface

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

UMaterial

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

UMaterialInstance

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

UMaterialInstanceConstant

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

UMaterialInstanceDynamic

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

1.2.1UMaterialInstance和UMaterialInstanceDynamic

材质实例,是我们在编辑器中经常使用的一种资源,通过将通用的材质统合起来,有效的减少材质的数量。使用上,如果材质之间就只有贴图或者参数不同的话,就可以构建一个基础的材质,然后将需要变化的材质进行参数化。并创建材质实例以应对不同的情况。

只有UMaterial材质模板带有可编辑的节点图并可拒此生成对应的Shader组合,而UMaterialInstance材质实例则只需要引用UMaterial对应的Shader.UMaterialInstance只能修改材质模板暴露出来的材质参数。

有几点是非常需要注意,其一是UMaterialInstance的继承关系,UMaterialInstance并不是继承自UMaterial而是和UMaterial一样继承自UMaterialInterface。这和我们在使用时的感觉是不太一样的,因为我们在使用时一般都是使用UMaterial来生成UMaterialInstance。

这种设计模式的目的应该是非常的清楚,因为UMaterialInstance是可以用另一个UMaterialInstance来进行创建的。具体的实现细节就需要深入到代码中来细细品来。

 

UMaterialInstanceDynamic实际继承的是UMaterialInstance,这是我们在程序运行时经常使用的一种。

1.2.1FMaterial

这是没有GC的UMaterial的剥离产物。

1.2.2FMaterialResource

抛开PhysicalMaterial(UMaterial中包含的成员变量),UE4中的UMaterial包含在不同的硬件条件(FeatureLevel)和不同的材质质量(MateialQualityLevel)设定下的不同材质表现,同时它可能它在引擎的其它子系统下也可能有自己的特殊表现。如LightMass下就和实时渲染的材质参数不同。

这些表现方式被封装为FMaterialResource类,FMaterialResource是UMaterial为指定FeatureLevel和MateialQualityLevel后的具体表现形式。

 

FMaterialResource包含用于渲染的Shaders、Shaders参数、RenderStates、LightingMode等数据。因LightingMode在UE4中不可定制只可选择内蕴的几种固定模型,故其可看作一种特殊的RenderState,在此前提下FMaterailResource简化为ShaderMap + Shaders参数 + RenderStates。其中Shader参数和RenderStates来源于对材质本身的引用数据,ShaderMap则来源于编译材质节点图所生成的Shader变种。

 

1.2.3FMaterialRenderProxy

FMaterialRenderProxyFMaterial用于渲染线程的代理,它可以透过FMaterail和UMaterialInterface访问到Shader、渲染状态,光照模型等所有用户设置好的材质参数。

1.3材质节点

当我们了解了顶层的设计框架,我们接下来将深入到另一个代码生成的领域当中,来探究材质编辑器的连连看是如何工作的。

在所有的材质表达式中,我们会将所有的表达式存入Expressions。

 

类似于蓝图,材质编辑器中典型的节点包含节点本身,节点的输入,节点的输出三个部分。特殊情况下,一些节点没有输入,如const数据,各类parameters,内置的inputs节点等等。

UMaterialExpression是材质节点的基类,UMaterialExpression继承自UObject。其定义了通用的材质节点的属性和方法。

UMaterialExpression的主要属性

//在材质编辑器中代理节点 ,

UEdGraphNode*        GraphNode;

//隶属于哪个母材质或函数函数

class UMaterial* Material;

class UMaterialFunction* Function;

//是否是参数节点

uint32 bIsParameterExpression:1;

//是否是Shader输入数据

uint32 bShaderInputData:1;

//节点的输出数据

TArray<FExpressionOutput> Outputs;

 

UMaterialExpression的主要方法

//编译该节点,生成节点树的shader代码 ,每个Expression子类具体实现它,目前的实现是生成HLSL源码

virtual int32 Compile(class FMaterialCompiler* Compiler, int32 OutputIndex) { return INDEX_NONE; }

//获取节点的输入和输出

virtual TArray<FExpressionOutput>& GetOutputs();

virtual const TArray<FExpressionInput*> GetInputs();

virtual FExpressionInput* GetInput(int32 InputIndex);virtual FName GetInputName(int32 InputIndex) const;

FExpressionInput是材质节点的输入,它是个结构体,持有一个UMaterialExpression指针,并指定它自己取的是该Expression的哪个输出。它基本上就是对UMaterialExpression的一个简单的封装。

FExpressionOutput是材质节点的输出,同样是个结构体,它比Input简单,结构体里只有名字和Mask。Mask用于Mask输出的结果,可能同一个结果会显示为多个输出,如TextureSampler2D有RGB,R,G,B,A四个输出,它们都是对TextureSample出来的RGBA进行不同分量Mask的结果。

 1.3.1材质节点的种类

内置输入节点 ,显示为红色Tile的节点,输入类节点本身没有输出接口,这些节点可能来源于前一Shader阶段的输出数据(如TexCoord[0]),也可能来源于引擎内置的UniformParameter(如Time节点)。

内置函数和运算符节点,显示为暗绿色的节点,内置的函数节点可能来源于HLSL语言层面的原生函数(如sin,cos),也可能来源于引擎自己在usf中定义的标准函数库(如sinFast,cosFast)等。

常数节点,这类节点同样显示为亮绿色。如Constant、Const2Vector,Const3Vector,StaticBool等节点

可变参数节点(UniformParameter) ,这类节点显示为亮绿色,其来源于用户在运行时可修改的Shader参数。如ScalarParameter,TextureSampleParameter2D等。TextureSample节点虽然在编辑器语义下是常数类节点,但实际上它在编译为Shader参数时同样为UniformParameter,实际上所有Texture相关的节点在编译后都表示为UniformParameter。

Static节点族:StaticBool为常数节点,StaticBoolParameter是允许材质instance修改的常数节点(因为修改节点后会导致shader重编),StaticSwitch类似于在usf中进行宏定义,其结果是只编译通过StaticSwitch测试的那个分支的代码,另一个分支会被直接丢弃。StaticSwitchParamter是在instance中可以修改可通过分支的StaticSwitch,同样它的修改会导致shader重编。

FeatureLevelSwitch和QualitySwitch节点 : 这两个节点直接对应UMaterial中的材质切换条件:根据硬件条件和质量等级切换不同品质和实现的材质。
 

关于if节点

UE4中不存在流程跳转节点,有同学可能会注意到,材质编辑器中存在if节点。

实际上材质编辑器上的If节点不会被编译成if指令,它会被编译成一个或两个三元运算符:

A > B ? C : D 或 A==B? C : (A>B ? D : E)

既然不存在流程跳转节点,所以循环节点也就无从谈起了——在材质编辑器中找不到for和while节点的原因也在于此。

在没有动态分支if且staticswitch需要instance使用过才会展开对应分支的前提下,要实现诸如四季切换或昼夜切换的时候,对整个美术生产流程就不太友好了。

二.材质的编译

本节将要讨论UE4从材质蓝图生成原始的HLSL代码的基本流程,这儿的材质特指的Surface Domain类材质,其对应的Shader种类为MeshShader,只因这一类材质应用最为广泛,可用于描述任何3D Primitive表面属性,一个游戏中可见的90%以上材质都属此类。
 

2.1材质编译的入口和时机

对于UMaterial,其生成Shader的入口函数有二,

  1. 一个用于资源Cooking,名为CacheResourceShadersForCooking。
  1. 一个用于材质编辑和引擎运行时渲染,名为CacheResourceShadersForRendering,

在不同的阶段,如果我们寻找一个shadermap在内存或者DDC中没有找到,那么就会调用这两个函数。

 

我们仅针对一下CacheResourceShadersForRendering来做一下比较深入的探讨。首先的问题就是其调用时机是什么。

  1. 在反序列化时会进行调用。
  1. 当我们打开材质编辑器中的实时预览按键时其会在每一次的改动后进行调用。其始于 UMaterial::PostEditChangeProperty。
  1. 当我们没有勾选实时预览时,我们点击apply按键才会进行UMaterial::PostEditChangeProperty的调用。

因此,我们将调用接口和时机讨论完后,我们将进行更加细节的探讨,讨论这个函数到底干了一些什么我们关心的事情。

2.2材质编译做了什么

当我们发生了材质的更改,接下来会发生如下事件

  1. FlushRenderingCommands(),会被直接调用,强制之前的命令缓冲渲染完毕,这里确保线程安全。之后调用
  1. CancelOutstandingCompilation(),强制所有的目前的编译工作取消,这也是很自然的意见事情。
  1. 之后我们调用CacheResourceShadersForRendering(bRegenerateId);

我们正式进入到CacheResourceShadersForRendering里面

2.2.1RebuildShadingModelField

这里顾名思义是用来重新编译我们的ShadingMode,这里需要注意的是,处理我们默认的shading model外,还有一个MSM_FromMaterialExpression,这个是需要特殊处理的。

 

目前这个阶段仅仅是识别,并没有任何其他的处理。

2.2.2FlushResourceShaderMaps

在这里我们需要更加深入的讲解一下我们的FMaterialResource。

FMaterialResourceFMaterail的子类,用于UMaterial的渲染,FMaterialResource代表的是从一个截面(在某个Render API FeatureLevel、指定的平台下、指定材质品质预设下)时它对应的UMaterial的具体呈现。

 

虽然来说我们这里的FMaterialResource并不是函数名称关于ShaderMaps代表之以,不过我们并不打算在这里进行对变体这一特性的深入探讨,我们将在下一节,进行更加细致和缜密的探究。

回归正题,我们FlushResourceShaderMaps调用的FMaterial::ReleaseShaderMap()函数,实际是对于我上图中我们对不同的质量不同的RHIFeaturelevel的二维数组中的每个FMaterialResource的调用。

  1. ENQUEUE_RENDER_COMMAND(ReleaseShaderMap)(
                    [Material](FRHICommandList& RHICmdList)
                    {
                            Material->RenderingThreadShaderMap = nullptr;
                    });

     

2.2.3UpdateResourceAllocations

从这里我们很明显的看到,关于对MaterialResources的空间分配和设置更新

 

2.2.4CacheShadersForResources

在这里,我们会所有的单个FMaterial执行Shader生成的函数为CacheShadersForResources,CacheShadersForResources先会重建材质函数依赖信息、材质收集器依赖信息,并把此材质(或材质函数)所依赖的输出和输入纹理填充到依赖列表里。

2.2.4.1搜集阶段

  1. RebuildMaterialFunctionInfo:这里会将所有的材质表达式,进行筛选
  2. RebuildMaterialParameterCollectionInfo
  3. AppendReferencedTextures这里会将材质中所有引用的贴图进行收集

不管如何,这个阶段也仅仅只是搜集填充MaterialFunctionInfos,MaterialParameterCollectionInfos,InOutTextures,CurrentFunction

2.2.4.2CacheShaders(ShaderPlatform, TargetPlatform);

这里我们就进入了FMaterial类中。在这里,我们的不会有static parameters和相应的ShaderPlatform,TargetPlatform宏的开关问题,因为这里都会被指定。

 

FMaterialShaderMapId,是唯一标识FMaterialShaderMap的ID,内置变量很多,列出比较重要的几个

  1. FSHAHash CookedShaderMapIdHash;
  2. FGuid BaseMaterialId;
  3. EMaterialQualityLevel::Type QualityLevel;
  4. ERHIFeatureLevel::Type FeatureLevel;

在这个FMaterialResource中存在两个FMaterialShaderMap指针,这两个指针一个用于游戏线程(GameThreadShaderMap),一个用于渲染线程(RenderingThreadShaderMap),实际上这两个ShaderMap指针指向的是同一个FMaterialShaderMap对象。

 

之后,会把所有的依赖注入给FMaterialShaderMapId,当然数据仅仅是TArray<FGuid>。

随后判断,如果自己本身是MaterialInstance,那么我们将要把配置的StaticParmeterValue进行打开关闭。

得到一个FMaterialShaderMapId后,继续进行调用另一个FMaterial::CacheShaders来进行后续的操作

2.2.4.3CacheShaders(ShaderMapId, Platform, TargetPlatform);

这里会区分是否是第一次还是拥有基本的cache,我们现在仅讨论第一次创建的情况。我们将排除其他非常良好的情况。我们看需要进行编译的地方。BeginCompileShaderMap

 

2.2.4.4BeginCompileShaderMap

真正的编译环节是通过FHLSLMaterialTranslator来完成初始的翻译工作,然后,再进行编译。

 

2.2.4.4.1翻译阶段

直接的调用MaterialTranslator.Translate();

FHLSLMaterialTranslator类是材质由表达式编译(翻译)成HLSL的核心类,实现了几乎所有材质表达式的代码生成功能:几乎每个UMaterialExpression的子类在FHLSLMaterialTranslator类中都有一个唯一的函数与之一一对应。这样在UMaterialExpressionCompile函数被调用时步骤分为三步,先检查表达式的合法性和前置条件,再处理表达式的输入节点,最后把表达式的条件和输入节点一起送入FHLSLMaterialTranslator与之对应的函数中进行HLSL代码生成。

我们将要扩展材质编辑器的节点,就必须要处理翻译这里的流程。

这是一段非常独立且极其庞大的代码段,这里并没有对我们介绍其他部分会有影响,所以我们暂且不谈。

2.2.4.4.1编译阶段

当我们得到翻译结果后,我们将翻译后的字节码存储为FString,然后增加一些path,或者是设置环境和平台的操作后就进行编译。

在编译阶段,我们需要再次更加深刻的去理解几个概念。

2.3 变体的基本概念

2.3.1FVertexFactoryType:

材质必须支持应用于不同的网格类型,而这是通过顶点工厂来实现的。

我们来看一下我们的系统当中到底拥有多少的FVertexFactoryType

  1. FGPUBaseSkinVertexFactory
  2. FGeometryCacheVertexVertexFactory
  3. FLandscapeVertexFactory
  4. FLocalVertexFactory
  5. FNiagaraVertexFactoryBase
  6. FParticleVertexFactoryBase
  7. FPointCloudVertexFactory
  8. FVectorFieldVisualizationVertexFactory

以上只是一级继承关系,还有更多的二级继承的类别。其中的每一个都是作用于不同的地方,但其实我们一般而言会进行使用的是则是FLocalVertexFactory。这是一般的mesh的不同渲染的顶点工厂。

其实我们可以更进一步的来看一下这些顶点工厂的不同,但是我们还是将这种细致的差别比较放在shader篇更加的妙。我们在这里仅仅是想让大家知道我们的material不是仅支持FLocalVertexFactory的,其实它还要支持非常非常多的顶点工厂。

2.3.2FShaderType

shadertype看似比较少,其实不是的。

  1. FGlobalShaderType

  2. FMaterialShaderType

  3. FNiagaraShaderType

  4. FOpenColorIOShaderType

  5. FMeshMaterialShaderType

这些只是内置的shaderType,但是,你只要在程序里继承FShader的shader,都会生成自己的ShaderType。所以,可以预见的是,shaderType的数量是极其巨大的。

这里其实对unreal的shader有一个非常重要的思考,那就是对于我们日常见到的材质,其实都是生成的模板,也就是把连线连接到PBR节点的输出当中,但是具体的如何使用,是通过shader中的代码来使用的。所以如果不加限制,那么变体的数量则会非常急速的增加。

例如,我们自己实现的喷射管线的shader

 

其中的一个函数ShouldCompilePermutation就是判断FShaderType能给哪些生成变体的。

如果我们返回的是true,那它将对所有的场景中所有的material生成对应的变体!

2.3.3FShaderPipelineType

 

  1. 这里蕴含着和Mesh相关Rendering 的个数(如DepthRendering ,ShadowRendering,BasePassRendering)等等,对每一个材质,我们都会生成不同的生成阴影贴图的pipline

具体的pipeline的组合数非常的多,例如

 

2.4 材质的变体

FMaterialResource不是持有一个Shader,而是持有在指定截面下此材质所有的Shader变体(Shader Permutations)。

影响变体多寡主要因素包括我们已经在上述讲完了。

一个材质动辄150+的Shader Permations是很正常的事,所以在UE开发中,ShaderPermation Reduce对包体和运行效率均为不可回避的优化项。

三.材质的管线路径

当我们了解了材质系统的编译时机,存储位置,变体策略,我们将更加细致的来看一下其传入渲染线程的路径和时机。目前暂且不论

 

2018-06-11 15:38:10 zsyddl2 阅读数 460
  • 从这里开始虚幻4-第2辑-蓝图 v4.18

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

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

   目前未找到直接手动创建完整材质的办法,感觉不太方便。 目前的办法是:在编辑器中创建需要的材质比如 顶点颜色材质、颜色材质、图片材质等。并将输入的数据添加到参数,这样可以在程序运行中修改顶点颜色,材质颜色,或者材质图片。

  顶点颜色材质:

    

   颜色材质创建:

  

 动态修改颜色:

  FString strMaterial = TEXT("/Game/StarterContent/Materials/M_Color.M_Color");

    ((AUeCustomActor*)m_pUeActor)->LoadSpecialMaterial(strMaterial, pColorMaterial, false);

    FLinearColor linearColor(color.m_fR, color.m_fG, color.m_fB, color.m_fA);
    
 
    UMaterialInstanceDynamic* pDynamicMaterial = UMaterialInstanceDynamic::Create(pColorMaterial, nullptr);// new UMaterialInstanceDynamic();
 
    pDynamicMaterial->SetVectorParameterValue(FName("BaseColor"), linearColor);

    pProcMesh->SetMaterial(nSection, pDynamicMaterial);

 图片材质 未测试。这种应该是可以冬天替换,比如用于播放视频。


  补充 LoadSpecialMaterial:

  
void AUeCustomActor::LoadSpecialMaterial(const FString& MaterialName, UMaterial*& Material, bool bCheckUsage)
{
    // only bother with materials that aren't already loaded
    if (Material == NULL)
    {
        // find or load the object
        Material = LoadObject<UMaterial>(NULL, *MaterialName, NULL, LOAD_None, NULL);

        if (!Material)
        {
#if !WITH_EDITORONLY_DATA
            UE_LOG(LogEngine, Log, TEXT("ERROR: Failed to load special material '%s'. This will probably have bad consequences (depending on its use)"), *MaterialName);
#else
            UE_LOG(LogEngine, Fatal, TEXT("Failed to load special material '%s'"), *MaterialName);
#endif
        }
        // if the material wasn't marked as being a special engine material, then not all of the shaders
        // will have been compiled on it by this point, so we need to compile them and alert the use
        // to set the bit
        else if (!Material->bUsedAsSpecialEngineMaterial && bCheckUsage)
        {
#if !WITH_EDITOR
            // consoles must have the flag set properly in the editor
            UE_LOG(LogEngine, Fatal, TEXT("The special material (%s) was not marked with bUsedAsSpecialEngineMaterial. Make sure this flag is set in the editor, save the package, and compile shaders for this platform"), *MaterialName);
#else
            Material->bUsedAsSpecialEngineMaterial = true;
            Material->MarkPackageDirty();

            // make sure all necessary shaders for the default are compiled, now that the flag is set
            Material->PostEditChange();

            FMessageDialog::Open(EAppMsgType::Ok, FText::Format(NSLOCTEXT("Engine", "SpecialMaterialConfiguredIncorrectly", "The special material ({0}) has not been marked with bUsedAsSpecialEngineMaterial.\nThis will prevent shader precompiling properly, so the flag has been set automatically.\nMake sure to save the package and distribute to everyone using this material."), FText::FromString(MaterialName)));
#endif
        }
    }
}

2017-11-17 10:28:48 UWA4D 阅读数 1483
  • 从这里开始虚幻4-第2辑-蓝图 v4.18

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

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

原文链接:https://blog.uwa4d.com/archives/Study_unreal4_Rendering_2.html


上周的Unreal 4引擎文章介绍了渲染模块的光照系统,在本篇文章中,我们继续介绍渲染模块的另一重要部分:材质系统。

在此,特别感谢Unreal中国团队对于本篇文章中Unreal引擎相关内容的审核,并在我们学习其引擎的道路上提供的大力支持。


材质系统

材质描述了场景中物体与光照进行交互的过程,它是决定物体表面外观的最重要部分之一。Unreal 4引擎的材质系统为开发者提供了丰富的功能,使得开发者能够非常便捷地设计出具有真实感的场景和角色。本文将在接下来的内容中对Unreal 4引擎的材质系统功能进行逐一介绍,其中主要分为四个部分:材质编辑、材质模型、材质使用和特殊功能。在介绍前三部分内容时,本文会根据需要与Unity引擎功能的相似性进行比较。

一、材质编辑

在Unreal 4引擎中创建材质可以通过“Content Browser”中的“Add New”按钮或者右键弹出菜单中选择Material创建,如下图所示:

然后,双击“Content Browser”中的材质资源,即可打开材质编辑器。

传统引擎的材质系统对于材质编辑的支持都是需要开发工程师和美术设计师合作完成。通常情况下,技术美术(Technical Artist)或图形程序工程师编写和修改Shader代码,然后美术设计师提供输入纹理以及调试Shader参数。Unreal 4引擎则提供了一套更为方便的编辑方式,使得美术能够几乎不依赖于程序员制作出较为理想的材质资源。这种编辑方式类是一种似于Blueprint的节点图。在编辑材质时,只需要用引擎提供的节点和连线即可制作出逻辑较为复杂的材质效果,如下图所示:

请输入图片描述
上图取自Unreal 4官方网站

其中,上图左边是材质编辑的预览,右边是材质节点图。该节点图中的节点在编辑完成后会被自动替换成HLSL代码段,并生成相应的Shader代码在实时渲染时使用。在调试过程中,编辑完节点图并保存后,即可在场景视图中看到最新的结果。

Unity引擎原生仅支持通过修改Shader代码的方式制作新的材质。但在Unity引擎Asset Store中有第三方插件Shader Forge提供了类似的编辑功能【1】,如下图所示:

请输入图片描述
上图取自Unity Asset Store 【1】

此外,在Unreal 4引擎中的材质编辑界面的“HLSL Code”页面中可以查看由节点图生成的代码,如下图所示:

请输入图片描述

在“Stats”页面中可以看到当前Shader的Instruction和Texture Sampler的数目,如下图所示。这是一个直观简单、但却很实用的功能。Unity引擎暂时还未原生支持该功能,研发团队需要使用第三方工具来自行进行计算。

请输入图片描述

除了使用节点图进行材质编辑,Unreal 4引擎也支持直接采用HLSL代码进行编辑。其详细内容可参考Unreal 4官方网站。

材质编辑Unreal 4 vs Unity小结


  • 相比较而言,Unreal 4引擎原生提供了非常方便的节点图交互方式,Unity引擎通过第三方工具也可以达到类似的效果

二、材质模型

与Unity引擎5.x的Standard Shader类似,Unreal 4引擎的材质系统使用了当前游戏渲染中非常流行基于物理的渲染材质(Physically Based Rendering,以下简称PBR)模型。因此,它们都只需要少量的输入参数,就能表达丰富的材质外观,如下图所示:

请输入图片描述

其中,左图是Unreal 4引擎的材质系统节点图中的基础节点,其白色圆圈表示的引脚表示可设置的输入参数,通过设置不同的输入参数可以达到不同的材质效果。右图是Unity 5.x的Standard Shader材质设置界面。两者大部分参数表示含义是相似的,可通过以下各参数的对应关系来进行理解(Unreal 4 Unity):

  • Base Color Albedo:材质颜色、贴图
  • Metallic Metallic:金属度
  • Roughness Smoothness:粗糙、光滑度
  • Emissive Color Emission:自发光颜色、贴图
  • Normal Normal Map:法线贴图
  • World Position Offset Height Map:高度图
  • Ambient Occlusion Occlusion:AO贴图

上图显示了Unreal 4引擎与Unity引擎中不透明物体渲染的Shader参数设置。对于半透明渲染和Alpha Test渲染Unreal 4引擎和Unity引擎也都支持,并且可以通过修改参数选项进行设置,如下图所示:

请输入图片描述

其中,左图显示了Unreal 4引擎材质编辑器中“Blend Mode”设置选项,右图显示了Unity引擎“Rendering Mode”设置选项。其对应关系为(Unreal 4 Unity):

  • Opaque Opaque:不透明渲染
  • Masked Cutout:Alpha Test
  • Translucent Transparent:半透明渲染

Unity引擎中的Fade模式是用于渲染模型逐渐消失的效果。Unreal 4引擎另外三种“Blend Mode”的含义如下,通过这三种参数开发团队可以达到更为灵活的半透明效果。

  • Additive:将Pixel的结果叠加到背景
  • Modulate:将Pixel的结果乘以背景
  • AlphaComposite:预乘Alpha值Blend

Unreal 4引擎材质编辑器的基础节点中有许多“默认”输入参数,对不同的“Blend Mode”,其可供设置的参数也不相同,如下图所示:

请输入图片描述

其中,从左到右分别是:不透明、半透明以及Alpha Test的材质输入参数。对于无效的输入参数,Unreal 4引擎将其变成灰色,并且无法连接节点图。

Unreal 4引擎除了提供“常规”PBR的材质模型,还提供了一些用于制作特殊效果的材质模型。在我们来看,这些更像是Unreal引擎为开发者制作了一些快捷开发的材质模板。在材质编辑器中可以通过设置“Shading Model”进行选择,如下图所示:

其中,“Default Lit”表示默认的PBR材质模型。对于不同的材质模型,基础节点提供的输入参数也不相同。关于不同材质模型的输入参数和效果,本文不逐一介绍,读者有兴趣可参考Unreal 4官方网站。文本选择了几种我们认为效果特殊的材质模型进行介绍。

- Subsurface、Preintegrated Skin、Subsurface Profile 这三种材质模型的渲染效果比较相似,都属于次表面散射类。与Subsurface有所不同的是,Preintegrated Skin和Subsurface Profile都是专用于模拟人体皮肤渲染效果的模型。但是,Preintegrated Skin使用的方法更加高效并适合于低端设备,而Subsurface Profile的渲染效果更好适合高端设备。其效果如下图所示:

请输入图片描述
Subsurface

请输入图片描述
Preintegrated Skin

请输入图片描述
Subsurface Profile
上图取自Unreal 4官方网站

其中,上图从上到下分别是Subsurface、Preintegrated Skin以及Subsurface Profile的渲染效果。Subsurface效果渲染需要比较高的硬件资源,在Mobile端目前还不支持。

- Clear Coat 这种材质模型用于渲染不透明物体表面覆盖一层半透明的效果,如下图所示:

请输入图片描述
上图取自Unreal 4官方网站

其中,左图是Unreal 4引擎渲染结果,右图是实际拍摄结果。可以看出,该材质的渲染效果相当惊艳!

- Two Sided Foliage 这种材质模型用于渲染树木材质效果,它比Default模型能更好地模拟树叶的透射效果,如下图所示:

请输入图片描述
上图取自Unreal 4官方网站

其中,上图左边是采用Two Sided Foliage模型渲染结果,右图是Default模型渲染结果。

材质模型Unreal 4 vs Unity小结


  • 相比较而言,Unreal 4引擎和Unity引擎都提供了丰富的、通用的基于物理的材质模型。Unreal 4引擎原生对于特殊效果提供了更多的材质模型。Unity引擎则通过Asset Store提供了一些特殊效果材质【2】【3】

三、材质使用

Unreal 4引擎的材质在使用时与Unity引擎有所不同。在Unity引擎中,材质资源一旦被创建,就可以添加到各种渲染组件中进行渲染。同时,我们可以在运行时通过代码修改材质参数。但是,需要注意的是,当Shader中的某些功能没有被用到时,Unity引擎会自动对其进行优化。经过优化过后的Shader则不再包含这部分的功能,即使在运行时重新设置材质参数也不会生效。对于这种情况,在Unity引擎中可以通过Graphics Setting中的Always Included Shaders或在Shader中设置 “multi_compile”来实现,即告诉Unity引擎不要在Shader Stripping时去掉一些后续运行时需要使用的Key words。

在Unreal 4引擎中,修改材质资源的节点图以及参数不会立刻生效,需要点击右上角“Save”或者“Apply”,此时会引起材质重新编译。因此,材质资源中的参数并不支持在编辑器中实时或运行时更改。Unreal 4引擎提供了另一种材质资源Instanced Material。该种资源继承自材质资源,它拥有与其父类材质资源相同的节点图,并且支持在编辑器中实时或运行时修改参数。


  • Instanced Material

该种资源的创建与材质创建类似,在“Content Browser”中即可创建。然后双击资源图标即可打开编辑器。在“Details”页面中可以设置其继承的材质资源。下图显示了Instanced Material资源的设置界面,Parent参数即为其父类材质资源:

请输入图片描述

在使用之前,还需要在父类材质资源中将需要修改的参数用节点图中的“Parameter”类型节点表示,如下图所示:

请输入图片描述

然后,即可在Instanced Material编辑器的“Details”页面中看到,如下图所示:

请输入图片描述

其中,上图“Parameter Groups”中的“Color”和“Roughness”参数即为其父类材质资源中“Parameter”节点表示的参数。

该Instanced Material支持实时在编辑器中修改“Color”和“Roughness”参数,而不需要重新编译材质。但是这种Instanced Material仅支持在编辑其中修改参数,其在Unreal 4引擎中被称为Material Instance Constant

如果需要运行时修改,则需要通过蓝图或者代码动态创建Instanced Material,这种材质在Unreal 4引擎中被称为“Material Instance Dynamic”。如果想在项目运行时,根据一些特殊情况调整材质参数(比如怪物/角色受击后改变颜色、死亡时改变透明度等等),那么就需要通过Material Instance Dynamic来实现这些效果。

材质使用Unreal 4 vs Unity小结


在Unreal 4中,Material主要分为三类:原始Material、Material Instance Constant和Material Instance Dynamic。与Unity中的材质系统比较,有以下三点非常值得注意:


  • Unreal 4中的Material类似于Unity中的Shader,其节点图则可认为是Shader代码的定义;

  • Unreal 4中的Material Instance Constant类似于Unity中Material,它是Shader和输入参数的集合. 只有导出的 Parameters 可以进行修改,但仅限在 Editor 下修改,在运行时是不能动态修改参数的。所以一般场景物件(不用动态改材质)都是使用各种Material Instance Constant来进行渲染;

  • Unreal 4中的Material Instance Dynamic类似于Unity中的Material(Instance)。主要区别是,前者需要在Unreal 4中手动指出,后者是Unity在项目运行时,当修改Material参数时动态生成。

四、特殊功能

Unreal 4引擎不仅提供了通用的材质创建、编辑和使用功能,而且还提供了一些辅助的特殊功能。本文将对其中的三种进行详细介绍。

  • Material Function

Unreal 4引擎的材质编辑器内置了丰富的功能性节点,使得开发者在编辑材质节点图时能够灵活地实现许多功能。但是,当编辑的节点图到达一定复杂程度后,维护起来就变得非常困难。Unreal 4引擎提供了一种类似函数式的用户自定义节点,Material Function。当某些功能在多种材质中共用时,可以采用Material Function将其封装成一个节点进行重复利用,降低了维护难度。

Material Function是Unreal 4引擎材质系统中的一种资源,通过右键菜单进行创建,双击即可打开Material Function的编辑器。Material Function的编辑方式与Material类似,也是采用节点图的方式,如下图所示:

请输入图片描述
上图取自Unreal 4官方网站

当Material Function创建好后,在“Details”设置界面中勾选“Expose to Library”即可在Material的编辑的“Palette”中找到该节点,并可在节点图中使用,如下图所示:

请输入图片描述
请输入图片描述

使用方式与Unreal 4内置的节点相同,如下图所示:

请输入图片描述

  • Layered Materials

在Unreal 4引擎中,Material Function实现了将某种通用功能封装成一个节点重复利用。而利用Material Function的特点以及“Make Material Attributes”节点可以在一个材质资源中,将多种材质进行混合,如下图所示:

请输入图片描述
上图取自Unreal 4官方网站

其中,上图是一个Material Function的节点图,“Make Material Attributes”类似于材质资源中的基础节点,它可以被认为是在Material Function内部完成了一种材质的定义。而在编辑材质资源时,通过将多个预先定义好材质的Material Function进行混合,就可达到Layered Materials混合效果。它可以被用于制作模型表面不同位置用不同材质渲染的情况,如下图所示:

请输入图片描述
请输入图片描述
上图取自Unreal 4官方网站

其中,角色模型用了5种不同的材质进行渲染。这几种材质可以通过Layered Materials方式在一个模型上实现。


  • Material Parameter Collections

在编辑材质资源的过程中,通常会遇到某一个参数在不同的材质资源中使用的情况。此时,可以利用Unreal 4引擎提供的Material Parameter Collections资源进行管理。该种资源可以维护一系列变量和向量的参数值。这些参数可以在不同的材质中进行引用。当需要修改时,只需修改Material Parameter Collections资源中的共用参数值即可。在Unity中也有类似功能,即使用Shader的SetGlobal方法对全局参数进行设置。

请输入图片描述

特殊功能Unreal 4 vs Unity小结


  • 相比较而言,Unreal 4引擎提供了更多、更复杂特殊效果支持,使得美术在制作时能够更灵活、便利地实现复杂的材质。

材质系统小结

与我们熟悉的Unity引擎一样,Unreal 4引擎对当前流行的PBR材质模型同样进行了深度的支持,且在材质编辑方面,Unreal 4原生提供了更为直观方便的节点图交互方式。而在功能和效果上,Unreal 4引擎提供了丰富的模板和Material Function功能,从而让开发团队可以高效地创作出惊艳的渲染效果。希望随着移动硬件设备的逐渐提升,这些惊艳的效果可以在更多的项目中得到体现。


参考文献

【1】 https://www.assetstore.unity3d.com/en/#!/content/14147
【2】 https://www.assetstore.unity3d.com/en/#!/content/100332
【3】 https://www.assetstore.unity3d.com/en/#!/content/3254

以上即为我们对Unreal 4引擎就渲染模块的材质系统的讲解,之后我们会将继续分享渲染模块下的图像后处理等其他学习心得,欢迎大家的关注!我们希望本系列文章能让更多的中国游戏开发者了解和理解Unreal 4引擎的重要功能和所能达到的效果,也让更多的中国游戏开发者对Unreal引擎和Unity引擎融会贯通,提升技术储备。

最后非常感谢您能阅读到这里,希望能对您的项目有所帮助,如对文中的内容有异议或者进一步的补充说明,欢迎在后台给我们留言,谢谢!


2016-06-17 09:50:12 fyyzwsws 阅读数 12400
  • 从这里开始虚幻4-第2辑-蓝图 v4.18

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

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

Unreal Engine4(虚幻4)学习心得-材质

材质

制作材质的过程其实就相当于在写shader,只是UE4制作材质使用的是可视化方式在写shader。下面将介绍一些材质属性:

  • Blend Mode混合模式
    用于决定材质颜色如何和背景颜色混合。
    1. Opaque不透明
    2. Masked蒙版,蒙版材质可以利用蒙版贴图,将一些区域设置为可见或者不可见,比如铁丝网就可以使用蒙版
    3. Translucent半透明,可以以某种形式允许光线透过,比如玻璃
    4. Additive叠加,有透明度,用于增加颜色信息,比如各种粒子效果
    5. Modulate调制,将材质颜色乘以背景颜色,适合做贴花效果
  • Lighting Mode光照模式
    当半透明/透明的时候使用。
    1. Volumetric NonDirectional,是最节省的光照模式,只使用漫反射颜色,不用考虑材质法线。严格的说,只对动态光照的物体有效。
    2. Volumetric Directional,考虑材质法线。
    3. Volumetric PreVertex NonDirectional,同Volumetric NonDirectional,但是光照只在顶点计算,这样会减轻PS的消耗。
    4. Volumetric PreVertex Directional,同Volumetric Directional,但是光照只在顶点计算,这样会减轻PS的消耗。
  • Base Color常规色
    通常会通过PS制作一些贴图,作为基本色。所有的贴图都可以通过UV设置其平铺状态
  • Emissive自发光
    能让材质自己发光,可以用于制作材质外边缘的光晕效果。
  • Specular高光
    用于控制高光的颜色。光源照射到物体然后反射到人的眼睛里时,物体上最亮的那个点就是高光。高光控制着光线的反射,以展现一种光泽的效果。
  • Opacity不透明
    用于控制物体的透明度。
  • OpacityMask不透明蒙版
    用于和混合模式中的Masked蒙版模式组合使用,包含了可见还是不可见信息蒙版贴图就在这里连接。
  • Normal法线
    法线贴图是材质具有凹凸效果的原因。除非制作的是玻璃或者金属球之类的非常光滑的物体,否则一定要用法线。可以再加上一张细节贴图,与法线贴图相加,一起当做法线贴图。但是法线贴图中的凹凸信息其实是存在于RG通道中,B通道好比基准线,也就是被RG弄皱的底平面,因此如果想再加上一张细节贴图的话,蓝色通道千万不能动。法线贴图通过RGB的信息,以像素为单位来指定表面角度。
  • WorldPositionOffset世界位置偏移量
    只有要跟踪某个材质的世界位置,并且要沿某个方向移动它,这个属性才会被用到。

材质的其他属性(UDK)

  • Diffuse漫反射
    提供不透明颜色,好比常规颜色。通常会通过PS制作一些贴图(包含alpha通道,法线贴图),作为漫反射的基本色。
  • DiffusePower漫反射次幂
    描述颜色随光照信息的流失,从饱和向阴暗渐变的速度。
  • SpecularPower高光次幂
    用来模拟光滑度。
  • Distortion扭曲
    它能使一个对象表面的材质发生扭曲。使用方式比如:把混合模式设置为Additive叠加,然后设置无光照,然后把法线贴图连接到扭曲上(扭曲接收的就是法线信息,它要利用RGB通道来决定把像素点移到多远),就能看到热浪的效果,类似折射。
  • TransmissionColor透射色
    设置一个颜色,这样穿过物体表面的光线,好像会穿透物体扩散开来,呈现出次表面散射(3S)的样子(透射蒙版要设置为1才能看到)。比如设计角色的耳朵的时候,将耳朵部分的透射蒙版设置为1,然后将投射色设置为深红,那么当光线射到耳朵背面的时候,耳朵看上去就有次表面散射的效果。(这里只是模拟S3,而非真正的S3,但是很逼真,移动光源就可以看到半透明的效果)
  • TransmissionMask透射蒙版
    0和1组成的蒙版贴图用于决定哪里需要透射。透射色和透射蒙版主要用于蜡和人皮肤之类的地方
  • BumpOffset凹凸偏移
    凹凸偏移需要借用高度贴图。高度贴图可以使用法线贴图的alpha作为其高度值,然后将高度贴图作为基本色和法线的UV即可。
没有更多推荐了,返回首页