vault backup: 2024-11-26 18:16:19
This commit is contained in:
264
02-Note/ASoul/渲染方案/PVW相关.md
Normal file
264
02-Note/ASoul/渲染方案/PVW相关.md
Normal file
@@ -0,0 +1,264 @@
|
||||
# TsScreenPlayerTextureRenderer
|
||||
- MultiViewActor: UE.MultiViewActor;// 用于渲染pvw/pgm画面
|
||||
|
||||
- ReceiveBeginPlay() =>
|
||||
- this.RegisterLocalEventListener(); =>
|
||||
- this.ChangeCameraTask(TaskData);
|
||||
## RegisterLocalEventListener
|
||||
```ts
|
||||
private RegisterLocalEventListener(): void {
|
||||
this.PVWCameraChangeFunc = (TaskData: UE.CamTaskDataRPC) => {
|
||||
if (this.CurTag == DirectorMode.PVWCameraRenderer) {
|
||||
this.ChangeCameraTask(TaskData);
|
||||
}
|
||||
}
|
||||
this.PGMCameraChangeFunc = (TaskData: UE.CamTaskDataRPC) => {
|
||||
if (this.CurTag == DirectorMode.PGMCameraRenderer) {
|
||||
this.ChangeCameraTask(TaskData);
|
||||
}
|
||||
}
|
||||
this.SwitchDirectorNetTagFunc = (oldTag: UE.GameplayTag, newTag: UE.GameplayTag) => {
|
||||
this.SwitchDirectorNetTagCallback(oldTag, newTag);
|
||||
}
|
||||
|
||||
DirectorEventSystem.RegisterEventListener(this, DirectorEvent.OnPVWTaskRequested, this.PVWCameraChangeFunc);
|
||||
DirectorEventSystem.RegisterEventListener(this, DirectorEvent.OnPGMTaskRequested, this.PGMCameraChangeFunc);
|
||||
DirectorEventSystem.RegisterEventListener(this, DirectorEvent.SwitchDirectorMode, this.SwitchDirectorNetTagFunc)
|
||||
}
|
||||
```
|
||||
## ChangeCameraTask
|
||||
```ts
|
||||
ChangeCameraTask(TaskData: UE.CamTaskDataRPC) {
|
||||
if(!this.bStarted){
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.DirectorCamManagerActor == null){
|
||||
this.DirectorCamManagerActor = this.GetCameraManagerActor();
|
||||
}
|
||||
// double check
|
||||
if(this.DirectorCamManagerActor == null){
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.Task) {
|
||||
this.Task.Stop();
|
||||
}
|
||||
this.Task = DirectorCamUtil.CreateCamTask(this, TaskData, CamTaskType.FullStream, this.DirectorCamManagerActor.droneCamera, null, this.DirectorCamManagerActor.handHeldCamera)
|
||||
if (this.Task) {
|
||||
this.Task.Start()
|
||||
this.BindCamera(this.Task.TryGetBindedMainCamera());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# DirectorCamGroup.cpp
|
||||
```c++
|
||||
UDirectorSequencePlayer* UDirectorCamGroup::GetDirectorSequencePlayerFromPool(int CamIndex, bool IsPreview)
|
||||
{
|
||||
TargetPlayer = NewObject<UDirectorSequencePlayer>(this);
|
||||
TargetPlayer->SetCamSequence(CamIndex, SequenceActor);
|
||||
if(IsPreview)
|
||||
{
|
||||
CachedPreviewingPlayer.AddUnique(TargetPlayer);
|
||||
}
|
||||
else
|
||||
{
|
||||
CachedStreamingPlayer.AddUnique(TargetPlayer);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# PVW & PGM红框效果代码 TsDirectorCamManagerActor.ts
|
||||
```
|
||||
//客户机加入流程:
|
||||
//连接Server->同步当前场景->场景加载完成后收到本地事<E59CB0>?->初始化workShop
|
||||
//->确认机器身份,执行本机任务(异步任务处理流程)
|
||||
|
||||
//异步处理流程:根据机器的性能,加入时间不同,状态差异自适应处理任务逻辑
|
||||
// 服务端收到任务请<E58AA1>?->确保服务端的workShop初始化完<E58C96>?->处理数据及同<E58F8A>??
|
||||
// ->客户机收到同步数据后->等待自己的workshop初始化完<E58C96>?->处理自己的逻辑
|
||||
// 同一种任务只处理最近一<E8BF91>?
|
||||
```
|
||||
|
||||
## HandlePreStreamTaskByNetTag()
|
||||
相关切区域与切镜代码会调用RequestPVWTaskServer()
|
||||
RequestPVWTaskServer() =>
|
||||
RequestPVWTask() => HandlePreStreamTaskDataMulticast() => HandlePreStreamTaskByNetTag()
|
||||
```ts
|
||||
HandlePreStreamTaskByNetTag(): void {
|
||||
if (this.prestreamTaskData) {
|
||||
switch (Utils.GetDirectorMode(this).TagName) {
|
||||
case DirectorMode.PVWAndPGM:
|
||||
if(!DirectorCamUtil.SubmitNewCommandIfDataNotChanged(this.preStreamTask, this.prestreamTaskData)){
|
||||
if (this.preStreamTask) {
|
||||
this.preStreamTask.Stop()
|
||||
}
|
||||
this.preStreamTask = DirectorCamUtil.CreateCamTask(this, this.prestreamTaskData, CamTaskType.FullStream, this.droneCamera,
|
||||
this.PVWWindow, this.handHeldCamera)
|
||||
if (this.preStreamTask) {
|
||||
this.preStreamTask.Start()
|
||||
if (this.PVWWindow) {
|
||||
this.PVWWindow.SetViewBorderColor(0, new UE.LinearColor(0, 1, 0, 1))
|
||||
}
|
||||
console.log('PVW Task:' + this.preStreamTask.workShop.BindPlacement.Title + " " + this.preStreamTask.groupName + " " +
|
||||
this.preStreamTask.camName)
|
||||
}
|
||||
}
|
||||
break
|
||||
case DirectorMode.Preview:
|
||||
this.RefreshWindowViewBorderColor()
|
||||
break
|
||||
case DirectorMode.PVW:
|
||||
this.HandlePVWTask()
|
||||
break;
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# 130mm Bug日志
|
||||
```c++
|
||||
[2024.08.06-05.08.09:625][373]Puerts: (0x00000703D1DF42D0) request PVW: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:9223AA8A478BA88F1217CD86911EDAE1, Index=0, StartFrame:0
|
||||
[2024.08.06-05.08.09:626][373]LogLevelSequence: Starting new camera cut: 'Cam_TalkShowZuo_ZhuJiWei24mm_1'
|
||||
[2024.08.06-05.08.09:626][373]Puerts: (0x00000703D1DF42D0) 设置相机目标:
|
||||
[2024.08.06-05.08.09:626][373]Puerts: (0x00000703D1DF42D0) PVW Task: 线下 站\n4 ZhuJiWei24mm
|
||||
[2024.08.06-05.08.11:550][487]Puerts: Warning: (0x00000703D1DF42D0) PauseOrResumeAllFxProp ,true
|
||||
[2024.08.06-05.08.11:551][487]Puerts: Warning: (0x00000703D1DF42D0) PauseOrResumeAllFxProp ,false
|
||||
[2024.08.06-05.08.11:551][487]LogChaosBone: Display: ResetDynamics: 1, ChaosBoneAssets Name: CBA_SK_JiaRan_Costume_BHair
|
||||
[2024.08.06-05.08.11:551][487]LogChaosBone: Display: ResetDynamics: 1, ChaosBoneAssets Name: CBA_SK_JiaRan_Costume_dress
|
||||
[2024.08.06-05.08.11:602][490]Puerts: Warning: (0x00000703D1DF42D0) BP_JiaRan_Costume_C_0 set visible false
|
||||
[2024.08.06-05.08.11:602][490]Puerts: Warning: (0x00000703D1DF42D0) teleport to livearea 031D1C1742D7EB4C76F6B397FF404FD8
|
||||
[2024.08.06-05.08.11:602][490]Puerts: Warning: (0x00000703D1DF42D0) PauseOrResumeAllFxProp ,true
|
||||
[2024.08.06-05.08.11:602][490]Puerts: (0x00000703D1DF42D0) X=0.000 Y=0.000 Z=0.000
|
||||
[2024.08.06-05.08.11:602][490]Puerts: Warning: (0x00000703D1DF42D0) PauseOrResumeAllFxProp ,false
|
||||
[2024.08.06-05.08.11:602][490]Puerts: (0x00000703D1DF42D0) BP_JiaRan_Costume_C_0,attach prop ,玩具水枪A
|
||||
[2024.08.06-05.08.11:603][490]Puerts: Warning: (0x00000703D1DF42D0) get socket of JiaRan: RightHandSocket
|
||||
[2024.08.06-05.08.11:604][490]Puerts: (0x00000703D1DF42D0) Attach prop 玩具水枪A
|
||||
[2024.08.06-05.08.11:604][490]Puerts: (0x00000703D1DF42D0) Idol.JiaRan successfully switch to 031D1C1742D7EB4C76F6B397FF404FD8
|
||||
[2024.08.06-05.08.12:085][519]Puerts: Error: (0x00000703D1DF42D0) OnFinishDisappearFx(), but the idol visibility is true!!BP_JiaRan_Costume_C_0
|
||||
[2024.08.06-05.08.12:107][520]Puerts: Warning: (0x00000703D1DF42D0) BP_JiaRan_Costume_C_0 set visible true
|
||||
[2024.08.06-05.08.12:108][520]LogBlueprintUserMessages: [BP_JiaRan_Costume_C_0] Apply Material. Oringinal Material: false
|
||||
[2024.08.06-05.08.12:108][520]Puerts: (0x00000703D1DF42D0) RefreshSceneCaptureShowList
|
||||
[2024.08.06-05.08.12:109][520]Puerts: (0x00000703D1DF42D0) CheckItemFxPool, size 0
|
||||
[2024.08.06-05.08.12:109][520]Puerts: (0x00000703D1DF42D0) TriggerHandPose
|
||||
[2024.08.06-05.08.12:109][520]Puerts: (0x00000703D1DF42D0) TriggerHandPose
|
||||
[2024.08.06-05.08.12:109][520]Puerts: Warning: (0x00000703D1DF42D0) Disable instrument pose
|
||||
[2024.08.06-05.08.12:109][520]Puerts: (0x00000703D1DF42D0) Detect hand pose ToyGun
|
||||
[2024.08.06-05.08.12:109][520]Puerts: (0x00000703D1DF42D0) TriggerHandPose ToyGun
|
||||
[2024.08.06-05.08.12:455][541]Puerts: (0x00000703D1DF42D0) request PGM: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:9223AA8A478BA88F1217CD86911EDAE1, Index=0, StartFrame:0 , PushMethod =0
|
||||
[2024.08.06-05.08.12:805][562]Puerts: (0x00000703D1DF42D0) request PGM: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:9223AA8A478BA88F1217CD86911EDAE1, Index=0, StartFrame:0 , PushMethod =0
|
||||
[2024.08.06-05.08.14:606][670]LogBlueprintUserMessages: [BP_JiaRan_Costume_C_0] Apply Material. Oringinal Material: true
|
||||
[2024.08.06-05.08.15:822][743]Puerts: (0x00000703D1DF42D0) request PVW: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:DDB1F27A44E7E5B312830A828EB55464, Index=0, StartFrame:0
|
||||
[2024.08.06-05.08.15:823][743]LogLevelSequence: Starting new camera cut: 'Cine_Camera_Actor_1'
|
||||
[2024.08.06-05.08.15:823][743]Puerts: (0x00000703D1DF42D0) 设置相机目标:
|
||||
[2024.08.06-05.08.15:824][743]Puerts: (0x00000703D1DF42D0) PVW Task: 线下 贝拉2024生日 lengthtest
|
||||
[2024.08.06-05.08.15:824][743]LogBlueprintUserMessages: [BP_Cine_Cam_FOV_1] 35.0
|
||||
[2024.08.06-05.08.16:256][769]LogBlueprintUserMessages: [BP_Cine_Cam_FOV_1] 35.002922
|
||||
```
|
||||
|
||||
相关Log顺序:
|
||||
- request PVW: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:DDB1F27A44E7E5B312830A828EB55464, Index=0, StartFrame:0
|
||||
- LogLevelSequence: Starting new camera cut: 'Cine_Camera_Actor_1'
|
||||
- Puerts: 设置相机目标:
|
||||
- Puerts: PVW Task: 线下 贝拉2024生日 lengthtest
|
||||
- PrintString BP_Cine_Cam_FOV_1 35.0
|
||||
|
||||
***HandlePVWTask中的prestreamTaskData 不对***
|
||||
|
||||
## 日志
|
||||
```
|
||||
Puerts: (0x000009E309FB5E30) request PVW: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:B3441B7649E66555CCB558B2C0FD2872, Index=0, StartFrame:0
|
||||
LogLevelSequence: Starting new camera cut: 'ZhuJiwei_Zheng16-24mm_5'
|
||||
Puerts: (0x000009E309FB5E30) 130mm bug用log:,其他相机1 bindingCam逻辑,ZhuJiwei_Zheng16-24mm_5
|
||||
Puerts: (0x000009E309FB5E30) 130mm bug用log:,其他相机2 bindingCam逻辑,ZhuJiwei_Zheng16-24mm_5
|
||||
Puerts: (0x000009E309FB5E30) 130mm bug用log:,ChangeSequenceCamTarget FullStream Other
|
||||
Puerts: (0x000009E309FB5E30) 设置相机目标: Idol.BeiLa 0
|
||||
Puerts: (0x000009E309FB5E30) PVW Task: 线下 单唱站\nFastRhythm ZhuJiwei_Zheng16-24mm
|
||||
Puerts: (0x000009E309FB5E30) request PVW: WorkShop:3F855CF84C91BBD9207C0FAF5273586C, CamGroup:DDB1F27A44E7E5B312830A828EB55464, Index=0, StartFrame:0
|
||||
Puerts: (0x000009E309FB5E30) Nice Playing Sequence:LevelSequenceActor_2:BP_lengthtest_1
|
||||
Puerts: (0x000009E309FB5E30) RebindTarget: BP_BeiLa_Costume_C_0
|
||||
PIE: Warning: Sequence did not contain any bindings with the tag 'Beila' LevelSequenceActor_2
|
||||
LogLevelSequence: Starting new camera cut: 'CineCameraActor_Focus130MMTest_1'
|
||||
Puerts: (0x000009E309FB5E30) 130mm bug用log:,其他相机1 bindingCam逻辑,CineCameraActor_Focus130MMTest_1
|
||||
Puerts: (0x000009E309FB5E30) 130mm bug用log:,其他相机2 bindingCam逻辑,CineCameraActor_Focus130MMTest_1
|
||||
Puerts: (0x000009E309FB5E30) 130mm bug用log:,ChangeSequenceCamTarget FullStream Other
|
||||
Puerts: (0x000009E309FB5E30) 设置相机目标: Idol.BeiLa 0
|
||||
Puerts: (0x000009E309FB5E30) PVW Task: 线下 贝拉2024生日 BP_lengthtest_1
|
||||
LogBlueprintUserMessages: [BP_Cine_Cam_FOV_1] 35.0
|
||||
```
|
||||
|
||||
|
||||
## 可能的相关代码
|
||||
```c
|
||||
// 播放指定相机到PVW.
|
||||
@ufunction.ufunction(ufunction.ServerAPI, ufunction.Reliable)
|
||||
PlayCamSequenceOnPVWServer(camGroupId:UE.Guid, camIndex:number):void{
|
||||
let shotExists = this.directorCamSubSystem.ShotExistInGroup(this.prestreamTaskData.WorkShopId, camGroupId, camIndex)
|
||||
if (shotExists || camIndex == DirectorCamUtil.DRONE_CAM_INDEX || camIndex == DirectorCamUtil.HANDHELD_CAM_INDEX) {
|
||||
let newPVWTaskData = DirectorCamUtil.CopyTaskData(this.prestreamTaskData)
|
||||
newPVWTaskData.CamGroupId = camGroupId
|
||||
newPVWTaskData.CamIndex = camIndex
|
||||
newPVWTaskData.StartFrame = 0
|
||||
newPVWTaskData.bPreviewOneFrame = false
|
||||
this.RequestPVWTaskServer(newPVWTaskData)
|
||||
}
|
||||
else {
|
||||
console.warn('当前镜头不存<E4B88D>?,切换无效!index=' + camIndex)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class TsDirectorCamSequencePlayBridge extends UE.Actor {
|
||||
PlayCamSequence(camGroupId:UE.Guid, camIndex:number): void {
|
||||
let camManager = TsDirectorCamManagerActor.Get(this);
|
||||
if (camManager) {
|
||||
camManager.PlayCamSequenceOnPVWServer(camGroupId, camIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
```c++
|
||||
// 切换到当前直播区域中的多个workShop
|
||||
SwitchWorkShopInAreaServer(index: number): void {
|
||||
// [Server]监听到场景模块切换了直播区域后,自动切换<E58887>?0个workshop,当前切换事件用来切换当前直播区域中的多个workshop
|
||||
let levelControl = this.GetLevelAreaManager()
|
||||
let liveArea = levelControl.GetCurrentLiveArea()
|
||||
if (!liveArea) {
|
||||
console.error('DirectorCamManager@ cannot find LiveAreaBy id')
|
||||
return
|
||||
}
|
||||
let placement = DirectorCamUtil.GetPlacementInCurLiveArea(index, liveArea)
|
||||
if (!placement) {
|
||||
console.error('DirectorCamManager@SwitchWorkShopEvent:GetPlacementInCurLiveArea failed')
|
||||
return
|
||||
}
|
||||
|
||||
let GroupData = DirectorCamUtil.GetDefaultGroupData(this, placement.UUID)
|
||||
if (GroupData) {
|
||||
// 预览:切换workShop后播放第一个分<E4B8AA>?
|
||||
let newPreviewTaskData = new UE.CamTaskDataRPC()
|
||||
newPreviewTaskData.WorkShopId = DirectorCamUtil.CopyGuid(placement.UUID)
|
||||
newPreviewTaskData.CamGroupId = DirectorCamUtil.CopyGuid(GroupData.UUID)
|
||||
newPreviewTaskData.CamIndex = 0
|
||||
newPreviewTaskData.OperationId = this.previewTaskData.OperationId + 1
|
||||
newPreviewTaskData.StartFrame = 0
|
||||
newPreviewTaskData.bPreviewOneFrame = false
|
||||
this.HandlePreviewTaskDataMulticast(newPreviewTaskData);
|
||||
|
||||
// 预推流:切换workShop后,播放第一个分组的第一个镜头
|
||||
let newPVWTaskData = new UE.CamTaskDataRPC()
|
||||
newPVWTaskData.WorkShopId = DirectorCamUtil.CopyGuid(placement.UUID)
|
||||
newPVWTaskData.CamGroupId = DirectorCamUtil.CopyGuid(GroupData.UUID)
|
||||
newPVWTaskData.CamIndex = 0
|
||||
newPVWTaskData.StartFrame = 0
|
||||
newPVWTaskData.bPreviewOneFrame = false
|
||||
this.RequestPVWTaskServer(newPVWTaskData);
|
||||
}
|
||||
}
|
||||
```
|
737
02-Note/ASoul/渲染方案/Shader部分.md
Normal file
737
02-Note/ASoul/渲染方案/Shader部分.md
Normal file
@@ -0,0 +1,737 @@
|
||||
# Common
|
||||
## Common.ush
|
||||
添加结构体,主要用在材质的CustomNode里。
|
||||
```c++
|
||||
// Used by toon shading.
|
||||
// Define a global custom data structure which can be filled by Custom node in material BP.
|
||||
struct FToonShadingPerMaterialCustomData
|
||||
{
|
||||
// Toon specular
|
||||
float3 ToonSpecularColor;
|
||||
float ToonSpecularLocation;
|
||||
float ToonSpecularSmoothness;
|
||||
// Toon shadow
|
||||
float3 ToonShadowColor;
|
||||
float ToonShadowLocation;
|
||||
float ToonShadowSmoothness;
|
||||
float ToonForceShadow;
|
||||
// Toon secondary shadow
|
||||
float3 ToonSecondaryShadowColor;
|
||||
float ToonSecondaryShadowLocation;
|
||||
float ToonSecondaryShadowSmoothness;
|
||||
// custom data, usually not used
|
||||
float4 CustomData0;
|
||||
float4 CustomData1;
|
||||
float4 CustomData2;
|
||||
float4 CustomData3;
|
||||
};
|
||||
|
||||
static FToonShadingPerMaterialCustomData ToonShadingPerMaterialCustomData;
|
||||
```
|
||||
|
||||
|
||||
## DeferredShadingCommon.ush
|
||||
1. 实现[[#Encode/Decode函数]]
|
||||
2. HasCustomGBufferData()函数添加对应的ToonShadingModel宏判断
|
||||
3. [[#FGBufferData新增变量]]
|
||||
4. [[#Encode/Decode GBufferData新增逻辑]]
|
||||
1. Metallic/Specualr/Roughness => ToonShadowLocation/ToonForceShadow/ToonShadowSmoothness
|
||||
2. AO => ToonSecondaryShadowLocation
|
||||
3. CustomData => ToonShadowColor/ToonSecondaryShadowSmoothness
|
||||
4. PrecomputedShadowFactors => ToonSecondaryShadowColor
|
||||
5. `#define GBUFFER_REFACTOR 0` 以此关闭自动生成Encode/Decode GBufferData代码,并使用硬编码调用Encode/Decode GBufferData。
|
||||
6. `#if WRITES_VELOCITY_TO_GBUFFER` => `#if GBUFFER_HAS_VELOCITY`,以此**关闭写入VELOCITY到GBuffer中**。
|
||||
|
||||
### Encode/Decode函数
|
||||
RGB655 to 8-bit RGB。
|
||||
将R 256 => 64 ,GB 256 => 32。之后使用2个8bit浮点来存储:通道1存储R与G的头两位;通道2存储G的后3位与B。
|
||||
```c++
|
||||
float2 EncodeColorToRGB655(float3 Color)
|
||||
{
|
||||
const uint ChannelR = (1 << 6) - 1;
|
||||
const uint ChannelG = (1 << 5) - 1;
|
||||
const uint ChannelB = (1 << 5) - 1;
|
||||
|
||||
uint3 RoundedColor = uint3(float3(
|
||||
round(Color.r * ChannelR),
|
||||
round(Color.g * ChannelG),
|
||||
round(Color.b * ChannelB)
|
||||
));
|
||||
return float2(
|
||||
(RoundedColor.r << 2 | RoundedColor.g >> 3) / 255.0,
|
||||
(RoundedColor.g << 5 | RoundedColor.b ) / 255.0
|
||||
);
|
||||
}
|
||||
|
||||
float3 DecodeRGB655ToColor(float2 RGB655)
|
||||
{
|
||||
const uint ChannelR = (1 << 6) - 1;
|
||||
const uint ChannelG = (1 << 5) - 1;
|
||||
const uint ChannelB = (1 << 5) - 1;
|
||||
|
||||
uint2 Inputs = uint2(round(RGB655 * 255.0));
|
||||
uint BitBuffer = (Inputs.x << 8) | Inputs.y;
|
||||
uint R = (BitBuffer & 0xFC00) >> 10;
|
||||
uint G = (BitBuffer & 0x03E0) >> 5;
|
||||
uint B = (BitBuffer & 0x001F);
|
||||
|
||||
return float3(R, G, B) * float3(1.0 / ChannelR, 1.0 / ChannelG, 1.0 / ChannelB);
|
||||
}
|
||||
```
|
||||
|
||||
### FGBufferData新增变量
|
||||
```c++
|
||||
struct FGBufferData
|
||||
{
|
||||
...
|
||||
// Toon specular
|
||||
// 0..1, specular color
|
||||
half3 ToonSpecularColor;
|
||||
// 0..1, specular edge position
|
||||
half ToonSpecularLocation;
|
||||
// 0..1, specular edge smoothness
|
||||
half ToonSpecularSmoothness;
|
||||
|
||||
// Toon shadow
|
||||
// 0..1, shadow color
|
||||
half3 ToonShadowColor;
|
||||
// 0..1, shadow egde location
|
||||
half ToonShadowLocation;
|
||||
// 0..1, shadow edge smoothness
|
||||
half ToonShadowSmoothness;
|
||||
// 0..1, force shadow
|
||||
half ToonForceShadow;
|
||||
|
||||
// Toon secondary shadow
|
||||
// 0..1, secondary shadow color
|
||||
float3 ToonSecondaryShadowColor;
|
||||
// 0..1, secondary shadow edge location
|
||||
float ToonSecondaryShadowLocation;
|
||||
// 0..1, secondary shadow edge smoothness
|
||||
float ToonSecondaryShadowSmoothness;
|
||||
|
||||
// Toon render
|
||||
half3 ToonCalcShadowColor;
|
||||
};
|
||||
```
|
||||
|
||||
### Encode/Decode GBufferData新增逻辑
|
||||
```c++
|
||||
|
||||
void EncodeGBuffer(
|
||||
FGBufferData GBuffer,
|
||||
out float4 OutGBufferA,
|
||||
out float4 OutGBufferB,
|
||||
out float4 OutGBufferC,
|
||||
out float4 OutGBufferD,
|
||||
out float4 OutGBufferE,
|
||||
out float4 OutGBufferVelocity,
|
||||
float QuantizationBias = 0 // -0.5 to 0.5 random float. Used to bias quantization.
|
||||
)
|
||||
{
|
||||
...
|
||||
switch(GBuffer.ShadingModelID)
|
||||
{
|
||||
case SHADINGMODELID_TOON_BASE:
|
||||
OutGBufferB.r = ToonShadingPerMaterialCustomData.ToonShadowLocation;
|
||||
OutGBufferB.g = ToonShadingPerMaterialCustomData.ToonForceShadow;
|
||||
OutGBufferB.b = ToonShadingPerMaterialCustomData.ToonShadowSmoothness;
|
||||
OutGBufferC.a = ToonShadingPerMaterialCustomData.ToonSecondaryShadowLocation;
|
||||
OutGBufferD.a = ToonShadingPerMaterialCustomData.ToonSecondaryShadowSmoothness;
|
||||
OutGBufferD.rgb = ToonShadingPerMaterialCustomData.ToonShadowColor.rgb;
|
||||
OutGBufferE.gba = ToonShadingPerMaterialCustomData.ToonSecondaryShadowColor.rgb;
|
||||
break;
|
||||
case SHADINGMODELID_TOON_PBR:
|
||||
OutGBufferB.g = ToonShadingPerMaterialCustomData.ToonShadowLocation;
|
||||
OutGBufferD.a = ToonShadingPerMaterialCustomData.ToonShadowSmoothness;
|
||||
OutGBufferD.rgb = ToonShadingPerMaterialCustomData.ToonShadowColor.rgb;
|
||||
OutGBufferE.gba = ToonShadingPerMaterialCustomData.ToonSpecularColor.rgb;
|
||||
break;
|
||||
case SHADINGMODELID_TOON_SKIN:
|
||||
OutGBufferB.r = ToonShadingPerMaterialCustomData.ToonShadowLocation;
|
||||
OutGBufferD.a = ToonShadingPerMaterialCustomData.ToonShadowSmoothness;
|
||||
OutGBufferD.rgb = ToonShadingPerMaterialCustomData.ToonShadowColor.rgb;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
FGBufferData DecodeGBufferData(
|
||||
float4 InGBufferA,
|
||||
float4 InGBufferB,
|
||||
float4 InGBufferC,
|
||||
float4 InGBufferD,
|
||||
float4 InGBufferE,
|
||||
float4 InGBufferF,
|
||||
float4 InGBufferVelocity,
|
||||
float CustomNativeDepth,
|
||||
uint CustomStencil,
|
||||
float SceneDepth,
|
||||
bool bGetNormalizedNormal,
|
||||
bool bChecker)
|
||||
{
|
||||
FGBufferData GBuffer = (FGBufferData)0;
|
||||
...
|
||||
switch(GBuffer.ShadingModelID)
|
||||
{
|
||||
case SHADINGMODELID_TOON_BASE:
|
||||
GBuffer.ToonShadowColor = InGBufferD.rgb;
|
||||
GBuffer.ToonShadowLocation = InGBufferB.r;
|
||||
GBuffer.ToonShadowSmoothness = InGBufferB.b;
|
||||
GBuffer.ToonForceShadow = InGBufferB.g;
|
||||
GBuffer.ToonSecondaryShadowColor = InGBufferE.gba;
|
||||
GBuffer.ToonSecondaryShadowLocation = InGBufferC.a;
|
||||
GBuffer.ToonSecondaryShadowSmoothness = InGBufferD.a;
|
||||
GBuffer.Metallic = 0.0;
|
||||
GBuffer.Specular = 1.0;
|
||||
GBuffer.Roughness = 1.0;
|
||||
GBuffer.GBufferAO = 0.0;
|
||||
GBuffer.IndirectIrradiance = 1.0;
|
||||
GBuffer.PrecomputedShadowFactors = !(GBuffer.SelectiveOutputMask & SKIP_PRECSHADOW_MASK) ? float4(InGBufferE.r, 1.0, 1.0, 1.0) : ((GBuffer.SelectiveOutputMask & ZERO_PRECSHADOW_MASK) ? 0 : 1);
|
||||
GBuffer.StoredMetallic = 0.0;
|
||||
GBuffer.StoredSpecular = 1.0;
|
||||
break;
|
||||
case SHADINGMODELID_TOON_PBR:
|
||||
GBuffer.ToonSpecularColor = InGBufferE.gba;
|
||||
GBuffer.ToonShadowColor = InGBufferD.rgb;
|
||||
GBuffer.ToonShadowLocation = InGBufferB.g;
|
||||
GBuffer.ToonShadowSmoothness = InGBufferD.a;
|
||||
GBuffer.ToonSecondaryShadowColor = GBuffer.ToonShadowColor;
|
||||
GBuffer.ToonForceShadow = 1.0;
|
||||
GBuffer.ToonSpecularLocation = 1.0;
|
||||
GBuffer.Specular = 1.0;
|
||||
GBuffer.PrecomputedShadowFactors = !(GBuffer.SelectiveOutputMask & SKIP_PRECSHADOW_MASK) ? float4(InGBufferE.r, 1.0, 1.0, 1.0) : ((GBuffer.SelectiveOutputMask & ZERO_PRECSHADOW_MASK) ? 0 : 1);
|
||||
break;
|
||||
case SHADINGMODELID_TOON_SKIN:
|
||||
GBuffer.ToonShadowColor = InGBufferD.rgb;
|
||||
GBuffer.ToonShadowLocation = InGBufferB.r;
|
||||
GBuffer.ToonShadowSmoothness = InGBufferD.a;
|
||||
GBuffer.ToonSecondaryShadowColor = GBuffer.ToonShadowColor;
|
||||
GBuffer.ToonForceShadow = 1.0;
|
||||
GBuffer.Metallic = 0.0;
|
||||
GBuffer.StoredMetallic = 0.0;
|
||||
GBuffer.PrecomputedShadowFactors = !(GBuffer.SelectiveOutputMask & SKIP_PRECSHADOW_MASK) ? float4(InGBufferE.r, 1.0, 1.0, 1.0) : ((GBuffer.SelectiveOutputMask & ZERO_PRECSHADOW_MASK) ? 0 : 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
...
|
||||
};
|
||||
```
|
||||
# BasePass
|
||||
BasePassPixelShader.usf
|
||||
1. `#if 1` => `#if GBUFFER_REFACTOR && 0`,以此关闭自动生成Encode/Decode GBufferData代码,并使用硬编码调用Encode/Decode GBufferData。
|
||||
2. 在FPixelShaderInOut_MainPS()中添加写入FGBufferData逻辑。代码如下:
|
||||
|
||||
```c++
|
||||
...
|
||||
switch(GBuffer.ShadingModelID)
|
||||
{
|
||||
case SHADINGMODELID_TOON_BASE:
|
||||
GBuffer.ToonShadowColor = ToonShadingPerMaterialCustomData.ToonShadowColor.rgb;
|
||||
GBuffer.ToonShadowLocation = ToonShadingPerMaterialCustomData.ToonShadowLocation;
|
||||
GBuffer.ToonShadowSmoothness = ToonShadingPerMaterialCustomData.ToonShadowSmoothness;
|
||||
GBuffer.ToonForceShadow = ToonShadingPerMaterialCustomData.ToonForceShadow;
|
||||
GBuffer.ToonSecondaryShadowColor = ToonShadingPerMaterialCustomData.ToonSecondaryShadowColor.rgb;
|
||||
GBuffer.ToonSecondaryShadowLocation = ToonShadingPerMaterialCustomData.ToonSecondaryShadowLocation;
|
||||
GBuffer.ToonSecondaryShadowSmoothness = ToonShadingPerMaterialCustomData.ToonSecondaryShadowSmoothness;
|
||||
GBuffer.Specular = 1.0;
|
||||
GBuffer.GBufferAO = 0.0;
|
||||
GBuffer.PrecomputedShadowFactors.gba = 1;
|
||||
break;
|
||||
case SHADINGMODELID_TOON_PBR:
|
||||
GBuffer.ToonSpecularColor = ToonShadingPerMaterialCustomData.ToonSpecularColor.rgb;
|
||||
GBuffer.ToonShadowColor = ToonShadingPerMaterialCustomData.ToonShadowColor.rgb;
|
||||
GBuffer.ToonShadowLocation = ToonShadingPerMaterialCustomData.ToonShadowLocation;
|
||||
GBuffer.ToonShadowSmoothness = ToonShadingPerMaterialCustomData.ToonShadowSmoothness;
|
||||
GBuffer.ToonSecondaryShadowColor = ToonShadingPerMaterialCustomData.ToonShadowColor.rgb;
|
||||
GBuffer.ToonForceShadow = 1.0;
|
||||
GBuffer.Specular = 1.0;
|
||||
GBuffer.PrecomputedShadowFactors.gba = 1;
|
||||
break;
|
||||
case SHADINGMODELID_TOON_SKIN:
|
||||
GBuffer.ToonShadowColor = ToonShadingPerMaterialCustomData.ToonShadowColor.rgb;
|
||||
GBuffer.ToonShadowLocation = ToonShadingPerMaterialCustomData.ToonShadowLocation;
|
||||
GBuffer.ToonShadowSmoothness = ToonShadingPerMaterialCustomData.ToonShadowSmoothness;
|
||||
GBuffer.ToonSecondaryShadowColor = ToonShadingPerMaterialCustomData.ToonShadowColor.rgb;
|
||||
GBuffer.ToonForceShadow = 1.0;
|
||||
GBuffer.PrecomputedShadowFactors.g = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
# Lighting
|
||||
|
||||
## ShadingModels
|
||||
### ShadingCommon.ush
|
||||
**添加ShadingModelID宏**:
|
||||
- SHADINGMODELID_TOON_BASE 13
|
||||
- SHADINGMODELID_TOON_PBR 14
|
||||
- SHADINGMODELID_TOON_SKIN 15
|
||||
- SHADINGMODELID_NUM 16
|
||||
|
||||
判断是否是IsToonShadingModel:
|
||||
```c++
|
||||
bool IsToonShadingModel(uint ShadingModel)
|
||||
{
|
||||
uint4 ToonShadingModels = uint4(SHADINGMODELID_TOON_BASE, SHADINGMODELID_TOON_PBR, SHADINGMODELID_TOON_SKIN, 0xFF);
|
||||
return any(ShadingModel.xxxx == ToonShadingModels);
|
||||
}
|
||||
```
|
||||
## DeferredLightingCommon.ush
|
||||
修改了AccumulateDynamicLighting()的逻辑。
|
||||
```c++
|
||||
FLightAccumulator AccumulateDynamicLighting(
|
||||
float3 TranslatedWorldPosition, half3 CameraVector, FGBufferData GBuffer, half AmbientOcclusion, uint ShadingModelID,
|
||||
FDeferredLightData LightData, half4 LightAttenuation, float Dither, uint2 SVPos,
|
||||
inout float SurfaceShadow)
|
||||
{
|
||||
FLightAccumulator LightAccumulator = (FLightAccumulator)0;
|
||||
|
||||
half3 V = -CameraVector;
|
||||
half3 N = GBuffer.WorldNormal;
|
||||
BRANCH if( GBuffer.ShadingModelID == SHADINGMODELID_CLEAR_COAT && CLEAR_COAT_BOTTOM_NORMAL)
|
||||
{
|
||||
const float2 oct1 = ((float2(GBuffer.CustomData.a, GBuffer.CustomData.z) * 4) - (512.0/255.0)) + UnitVectorToOctahedron(GBuffer.WorldNormal);
|
||||
N = OctahedronToUnitVector(oct1);
|
||||
}
|
||||
|
||||
float3 L = LightData.Direction; // Already normalized
|
||||
float3 ToLight = L;
|
||||
float3 MaskedLightColor = LightData.Color;
|
||||
float LightMask = 1;
|
||||
if (LightData.bRadialLight)
|
||||
{
|
||||
LightMask = GetLocalLightAttenuation( TranslatedWorldPosition, LightData, ToLight, L );
|
||||
MaskedLightColor *= LightMask;
|
||||
}
|
||||
|
||||
LightAccumulator.EstimatedCost += 0.3f; // running the PixelShader at all has a cost
|
||||
|
||||
BRANCH
|
||||
if( LightMask > 0 )
|
||||
{
|
||||
FShadowTerms Shadow;
|
||||
Shadow.SurfaceShadow = AmbientOcclusion;
|
||||
Shadow.TransmissionShadow = 1;
|
||||
Shadow.TransmissionThickness = 1;
|
||||
Shadow.HairTransmittance.OpaqueVisibility = 1;
|
||||
const float ContactShadowOpacity = GBuffer.CustomData.a;
|
||||
GetShadowTerms(GBuffer.Depth, GBuffer.PrecomputedShadowFactors, GBuffer.ShadingModelID, ContactShadowOpacity,
|
||||
LightData, TranslatedWorldPosition, L, LightAttenuation, Dither, Shadow);
|
||||
SurfaceShadow = Shadow.SurfaceShadow;
|
||||
|
||||
LightAccumulator.EstimatedCost += 0.3f; // add the cost of getting the shadow terms
|
||||
|
||||
#if SHADING_PATH_MOBILE
|
||||
const bool bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(GBuffer.ShadingModelID);
|
||||
|
||||
FDirectLighting Lighting = (FDirectLighting)0;
|
||||
|
||||
half NoL = max(0, dot(GBuffer.WorldNormal, L));
|
||||
#if TRANSLUCENCY_NON_DIRECTIONAL
|
||||
NoL = 1.0f;
|
||||
#endif
|
||||
Lighting = EvaluateBxDF(GBuffer, N, V, L, NoL, Shadow);
|
||||
|
||||
Lighting.Specular *= LightData.SpecularScale;
|
||||
|
||||
LightAccumulator_AddSplit( LightAccumulator, Lighting.Diffuse, Lighting.Specular, Lighting.Diffuse, MaskedLightColor * Shadow.SurfaceShadow, bNeedsSeparateSubsurfaceLightAccumulation );
|
||||
LightAccumulator_AddSplit( LightAccumulator, Lighting.Transmission, 0.0f, Lighting.Transmission, MaskedLightColor * Shadow.TransmissionShadow, bNeedsSeparateSubsurfaceLightAccumulation );
|
||||
#else // SHADING_PATH_MOBILE
|
||||
//修改了这里
|
||||
bool UseToonShadow = IsToonShadingModel(GBuffer.ShadingModelID);
|
||||
BRANCH
|
||||
if( Shadow.SurfaceShadow + Shadow.TransmissionShadow > 0 || UseToonShadow)//修改结束
|
||||
{
|
||||
const bool bNeedsSeparateSubsurfaceLightAccumulation = UseSubsurfaceProfile(GBuffer.ShadingModelID);
|
||||
//修改了这里
|
||||
BRANCH
|
||||
if(UseToonShadow)
|
||||
{
|
||||
float NoL = dot(N, L);
|
||||
float ToonNoL = min(NoL, GBuffer.ToonForceShadow);
|
||||
//合并SurfaceShadow以及Transmision Shadow
|
||||
Shadow.SurfaceShadow = min(Shadow.SurfaceShadow, Shadow.TransmissionShadow);
|
||||
|
||||
//根据ToonShadowSmoothness、ToonShadowLocation、NoL计算阴影亮度,最后计算主阴影颜色。
|
||||
float RangeHalf = GBuffer.ToonShadowSmoothness * 0.5;
|
||||
float RangeMin = max(0.0, GBuffer.ToonShadowLocation - RangeHalf);
|
||||
float RangeMax = min(1.0, GBuffer.ToonShadowLocation + RangeHalf);
|
||||
float ShadowIntensity = Shadow.SurfaceShadow * smoothstep(RangeMin, RangeMax, ToonNoL);
|
||||
GBuffer.ToonCalcShadowColor = lerp(GBuffer.ToonShadowColor * LightData.SpecularScale, (1.0).xxx, ShadowIntensity);
|
||||
|
||||
//计算次级阴影颜色,并最终合成。
|
||||
RangeHalf = GBuffer.ToonSecondaryShadowSmoothness * 0.5;
|
||||
RangeMin = max(0.0, GBuffer.ToonSecondaryShadowLocation - RangeHalf);
|
||||
RangeMax = min(1.0, GBuffer.ToonSecondaryShadowLocation + RangeHalf);
|
||||
ShadowIntensity = Shadow.SurfaceShadow * smoothstep(RangeMin, RangeMax, ToonNoL);
|
||||
GBuffer.ToonCalcShadowColor = lerp(GBuffer.ToonSecondaryShadowColor * LightData.SpecularScale, GBuffer.ToonCalcShadowColor, ShadowIntensity);
|
||||
}
|
||||
//修改结束
|
||||
|
||||
#if NON_DIRECTIONAL_DIRECT_LIGHTING
|
||||
float Lighting;
|
||||
|
||||
if( LightData.bRectLight )
|
||||
{
|
||||
FRect Rect = GetRect( ToLight, LightData );
|
||||
|
||||
Lighting = IntegrateLight( Rect );
|
||||
}
|
||||
else
|
||||
{
|
||||
FCapsuleLight Capsule = GetCapsule( ToLight, LightData );
|
||||
|
||||
Lighting = IntegrateLight( Capsule, LightData.bInverseSquared );
|
||||
}
|
||||
|
||||
float3 LightingDiffuse = Diffuse_Lambert( GBuffer.DiffuseColor ) * Lighting;
|
||||
LightAccumulator_AddSplit(LightAccumulator, LightingDiffuse, 0.0f, 0, MaskedLightColor * Shadow.SurfaceShadow, bNeedsSeparateSubsurfaceLightAccumulation);
|
||||
#else
|
||||
FDirectLighting Lighting;
|
||||
|
||||
if (LightData.bRectLight)
|
||||
{
|
||||
FRect Rect = GetRect( ToLight, LightData );
|
||||
const FRectTexture SourceTexture = ConvertToRectTexture(LightData);
|
||||
|
||||
#if REFERENCE_QUALITY
|
||||
Lighting = IntegrateBxDF( GBuffer, N, V, Rect, Shadow, SourceTexture, SVPos );
|
||||
#else
|
||||
Lighting = IntegrateBxDF( GBuffer, N, V, Rect, Shadow, SourceTexture);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
FCapsuleLight Capsule = GetCapsule( ToLight, LightData );
|
||||
|
||||
#if REFERENCE_QUALITY
|
||||
Lighting = IntegrateBxDF( GBuffer, N, V, Capsule, Shadow, SVPos );
|
||||
#else
|
||||
Lighting = IntegrateBxDF( GBuffer, N, V, Capsule, Shadow, LightData.bInverseSquared );
|
||||
#endif
|
||||
}
|
||||
//修改了这里
|
||||
float SurfaceShadow = UseToonShadow ? 1.0 : Shadow.SurfaceShadow;
|
||||
float TransmissionShadow = UseToonShadow ? 1.0 : Shadow.TransmissionShadow;
|
||||
Lighting.Specular *= UseToonShadow ? GBuffer.ToonSpecularColor : LightData.SpecularScale;
|
||||
|
||||
LightAccumulator_AddSplit( LightAccumulator, Lighting.Diffuse, Lighting.Specular, Lighting.Diffuse, MaskedLightColor * SurfaceShadow, bNeedsSeparateSubsurfaceLightAccumulation );
|
||||
LightAccumulator_AddSplit( LightAccumulator, Lighting.Transmission, 0.0f, Lighting.Transmission, MaskedLightColor * TransmissionShadow, bNeedsSeparateSubsurfaceLightAccumulation );
|
||||
//修改结束
|
||||
LightAccumulator.EstimatedCost += 0.4f; // add the cost of the lighting computations (should sum up to 1 form one light)
|
||||
#endif
|
||||
}
|
||||
#endif // SHADING_PATH_MOBILE
|
||||
}
|
||||
return LightAccumulator;
|
||||
}
|
||||
```
|
||||
|
||||
## ShadingModels.ush
|
||||
```c++
|
||||
float3 ToonSpecular(float ToonSpecularLocation, float ToonSpecularSmoothness, float3 ToonSpecularColor, float NoL)
|
||||
{
|
||||
float ToonSpecularRangeHalf = ToonSpecularSmoothness * 0.5;
|
||||
float ToonSpecularRangeMin = ToonSpecularLocation - ToonSpecularRangeHalf;
|
||||
float ToonSpecularRangeMax = ToonSpecularLocation + ToonSpecularRangeHalf;
|
||||
return smoothstep(ToonSpecularRangeMin, ToonSpecularRangeMax, NoL) * ToonSpecularColor;
|
||||
}
|
||||
```
|
||||
|
||||
创建了ToonCustomBxDF(**SHADINGMODELID_TOON_BASE**)与ToonLitBxDF(**SHADINGMODELID_TOON_PBR**、**SHADINGMODELID_TOON_SKIN**)2个ShadingModel函数。
|
||||
|
||||
### ToonCustomBxDF的修改
|
||||
Diffuse里面乘以之前在DeferredShadingCommon.ush中计算好的ShadowColor(已经计算了NoL)
|
||||
`Lighting.Diffuse *= AreaLight.FalloffColor * (Falloff * NoL);`
|
||||
=>
|
||||
`Lighting.Diffuse *= AreaLight.FalloffColor * Falloff * GBuffer.ToonCalcShadowColor;`
|
||||
|
||||
Speuclar直接归零,具体是在BasePass阶段进行计算了。
|
||||
`Lighting.Specular = 0;`
|
||||
### ToonLitBxDF的修改
|
||||
Diffuse里面乘以之前在DeferredShadingCommon.ush中计算好的ShadowColor(已经计算了NoL)
|
||||
`Lighting.Diffuse *= AreaLight.FalloffColor * (Falloff * NoL);`
|
||||
=>
|
||||
`Lighting.Diffuse *= AreaLight.FalloffColor * Falloff * GBuffer.ToonCalcShadowColor;`
|
||||
|
||||
Speuclar最后乘以了**Shadow.SurfaceShadow**
|
||||
`Lighting.Specular *= Shadow.SurfaceShadow;`
|
||||
|
||||
|
||||
|
||||
```c++
|
||||
|
||||
FDirectLighting ToonLitBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, half NoL, FAreaLight AreaLight, FShadowTerms Shadow )
|
||||
{
|
||||
BxDFContext Context;
|
||||
FDirectLighting Lighting;
|
||||
|
||||
#if SUPPORTS_ANISOTROPIC_MATERIALS
|
||||
bool bHasAnisotropy = HasAnisotropy(GBuffer.SelectiveOutputMask);
|
||||
#else
|
||||
bool bHasAnisotropy = false;
|
||||
#endif
|
||||
|
||||
float NoV, VoH, NoH;
|
||||
BRANCH
|
||||
if (bHasAnisotropy)
|
||||
{
|
||||
half3 X = GBuffer.WorldTangent;
|
||||
half3 Y = normalize(cross(N, X));
|
||||
Init(Context, N, X, Y, V, L);
|
||||
|
||||
NoV = Context.NoV;
|
||||
VoH = Context.VoH;
|
||||
NoH = Context.NoH;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if SHADING_PATH_MOBILE
|
||||
InitMobile(Context, N, V, L, NoL);
|
||||
#else
|
||||
Init(Context, N, V, L);
|
||||
#endif
|
||||
|
||||
NoV = Context.NoV;
|
||||
VoH = Context.VoH;
|
||||
NoH = Context.NoH;
|
||||
|
||||
SphereMaxNoH(Context, AreaLight.SphereSinAlpha, true);
|
||||
}
|
||||
|
||||
Context.NoV = saturate(abs( Context.NoV ) + 1e-5);
|
||||
|
||||
#if MATERIAL_ROUGHDIFFUSE
|
||||
// Chan diffuse model with roughness == specular roughness. This is not necessarily a good modelisation of reality because when the mean free path is super small, the diffuse can in fact looks rougher. But this is a start.
|
||||
// Also we cannot use the morphed context maximising NoH as this is causing visual artefact when interpolating rough/smooth diffuse response.
|
||||
Lighting.Diffuse = Diffuse_Chan(GBuffer.DiffuseColor, Pow4(GBuffer.Roughness), NoV, NoL, VoH, NoH, GetAreaLightDiffuseMicroReflWeight(AreaLight));
|
||||
#else
|
||||
Lighting.Diffuse = Diffuse_Lambert(GBuffer.DiffuseColor);
|
||||
#endif
|
||||
// Toon Diffuse
|
||||
Lighting.Diffuse *= AreaLight.FalloffColor * Falloff * GBuffer.ToonCalcShadowColor;
|
||||
|
||||
BRANCH
|
||||
if (bHasAnisotropy)
|
||||
{
|
||||
//Lighting.Specular = GBuffer.WorldTangent * .5f + .5f;
|
||||
Lighting.Specular = AreaLight.FalloffColor * (Falloff * NoL) * SpecularGGX(GBuffer.Roughness, GBuffer.Anisotropy, GBuffer.SpecularColor, Context, NoL, AreaLight);
|
||||
}
|
||||
else
|
||||
{
|
||||
if( IsRectLight(AreaLight) )
|
||||
{
|
||||
Lighting.Specular = RectGGXApproxLTC(GBuffer.Roughness, GBuffer.SpecularColor, N, V, AreaLight.Rect, AreaLight.Texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Toon specular
|
||||
Lighting.Specular = AreaLight.FalloffColor * (Falloff * NoL) * SpecularGGX(GBuffer.Roughness, GBuffer.SpecularColor, Context, NoL, AreaLight);
|
||||
}
|
||||
}
|
||||
Lighting.Specular *= Shadow.SurfaceShadow;
|
||||
|
||||
FBxDFEnergyTerms EnergyTerms = ComputeGGXSpecEnergyTerms(GBuffer.Roughness, Context.NoV, GBuffer.SpecularColor);
|
||||
|
||||
// Add energy presevation (i.e. attenuation of the specular layer onto the diffuse component
|
||||
Lighting.Diffuse *= ComputeEnergyPreservation(EnergyTerms);
|
||||
|
||||
// Add specular microfacet multiple scattering term (energy-conservation)
|
||||
Lighting.Specular *= ComputeEnergyConservation(EnergyTerms);
|
||||
|
||||
Lighting.Transmission = 0;
|
||||
return Lighting;
|
||||
}
|
||||
|
||||
FDirectLighting ToonCustomBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, half NoL, FAreaLight AreaLight, FShadowTerms Shadow )
|
||||
{
|
||||
BxDFContext Context;
|
||||
FDirectLighting Lighting;
|
||||
|
||||
float NoV, VoH, NoH;
|
||||
#if SHADING_PATH_MOBILE
|
||||
InitMobile(Context, N, V, L, NoL);
|
||||
#else
|
||||
Init(Context, N, V, L);
|
||||
#endif
|
||||
NoV = Context.NoV;
|
||||
VoH = Context.VoH;
|
||||
NoH = Context.NoH;
|
||||
|
||||
SphereMaxNoH(Context, AreaLight.SphereSinAlpha, true);
|
||||
|
||||
Context.NoV = saturate(abs( Context.NoV ) + 1e-5);
|
||||
|
||||
#if MATERIAL_ROUGHDIFFUSE
|
||||
// Chan diffuse model with roughness == specular roughness. This is not necessarily a good modelisation of reality because when the mean free path is super small, the diffuse can in fact looks rougher. But this is a start.
|
||||
// Also we cannot use the morphed context maximising NoH as this is causing visual artefact when interpolating rough/smooth diffuse response.
|
||||
Lighting.Diffuse = Diffuse_Chan(GBuffer.DiffuseColor, Pow4(GBuffer.Roughness), NoV, NoL, VoH, NoH, GetAreaLightDiffuseMicroReflWeight(AreaLight));
|
||||
#else
|
||||
Lighting.Diffuse = Diffuse_Lambert(GBuffer.DiffuseColor);
|
||||
#endif
|
||||
// Toon Diffuse
|
||||
Lighting.Diffuse *= AreaLight.FalloffColor * Falloff * GBuffer.ToonCalcShadowColor;
|
||||
|
||||
// Toon specular
|
||||
// Lighting.Specular = AreaLight.FalloffColor * (Falloff * NoL) * ToonSpecular(GBuffer.ToonSpecularLocation, GBuffer.ToonSpecularSmoothness, GBuffer.ToonSpecularColor, NoL);
|
||||
// Lighting.Specular *= Shadow.SurfaceShadow;
|
||||
|
||||
// FBxDFEnergyTerms EnergyTerms = ComputeGGXSpecEnergyTerms(GBuffer.Roughness, Context.NoV, GBuffer.SpecularColor);
|
||||
|
||||
// Add energy presevation (i.e. attenuation of the specular layer onto the diffuse component
|
||||
// Lighting.Diffuse *= ComputeEnergyPreservation(EnergyTerms);
|
||||
|
||||
Lighting.Specular = 0;
|
||||
Lighting.Transmission = 0;
|
||||
return Lighting;
|
||||
}
|
||||
|
||||
FDirectLighting IntegrateBxDF( FGBufferData GBuffer, half3 N, half3 V, half3 L, float Falloff, half NoL, FAreaLight AreaLight, FShadowTerms Shadow )
|
||||
{
|
||||
switch( GBuffer.ShadingModelID )
|
||||
{
|
||||
case SHADINGMODELID_DEFAULT_LIT:
|
||||
case SHADINGMODELID_SINGLELAYERWATER:
|
||||
case SHADINGMODELID_THIN_TRANSLUCENT:
|
||||
return DefaultLitBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
case SHADINGMODELID_SUBSURFACE:
|
||||
return SubsurfaceBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
case SHADINGMODELID_PREINTEGRATED_SKIN:
|
||||
return PreintegratedSkinBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
case SHADINGMODELID_CLEAR_COAT:
|
||||
return ClearCoatBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
case SHADINGMODELID_SUBSURFACE_PROFILE:
|
||||
return SubsurfaceProfileBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
case SHADINGMODELID_TWOSIDED_FOLIAGE:
|
||||
return TwoSidedBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
case SHADINGMODELID_HAIR:
|
||||
return HairBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
case SHADINGMODELID_CLOTH:
|
||||
return ClothBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
case SHADINGMODELID_EYE:
|
||||
return EyeBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
case SHADINGMODELID_TOON_BASE:
|
||||
return ToonCustomBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
case SHADINGMODELID_TOON_PBR:
|
||||
case SHADINGMODELID_TOON_SKIN:
|
||||
return ToonLitBxDF( GBuffer, N, V, L, Falloff, NoL, AreaLight, Shadow );
|
||||
default:
|
||||
return (FDirectLighting)0;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## DeferredLightPixelShaders.usf
|
||||
在DeferredLightPixelMain()中添加逻辑:
|
||||
1. 非卡通材质正常渲染。
|
||||
2. 材质材质只有在LightingChannel = 2时才会计算卡通光影效果。
|
||||
```c++
|
||||
bool UseToonShadow = IsToonShadingModel(ScreenSpaceData.GBuffer.ShadingModelID);
|
||||
// LightingChannel Toon Shading only calculate light of LightingChannel = 2
|
||||
BRANCH if (!UseToonShadow || (UseToonShadow && DeferredLightUniforms.LightingChannelMask & 0x4))
|
||||
{
|
||||
const float SceneDepth = CalcSceneDepth(InputParams.ScreenUV);
|
||||
const FDerivedParams DerivedParams = GetDerivedParams(InputParams, SceneDepth);
|
||||
|
||||
FDeferredLightData LightData = InitDeferredLightFromUniforms(CURRENT_LIGHT_TYPE);
|
||||
UpdateLightDataColor(LightData, InputParams, DerivedParams);
|
||||
|
||||
#if USE_HAIR_COMPLEX_TRANSMITTANCE
|
||||
if (ScreenSpaceData.GBuffer.ShadingModelID == SHADINGMODELID_HAIR && ShouldUseHairComplexTransmittance(ScreenSpaceData.GBuffer))
|
||||
{
|
||||
LightData.HairTransmittance = EvaluateDualScattering(ScreenSpaceData.GBuffer, DerivedParams.CameraVector, -DeferredLightUniforms.Direction);
|
||||
}
|
||||
#endif
|
||||
|
||||
float Dither = InterleavedGradientNoise(InputParams.PixelPos, View.StateFrameIndexMod8);
|
||||
|
||||
float SurfaceShadow = 1.0f;
|
||||
|
||||
float4 LightAttenuation = GetLightAttenuationFromShadow(InputParams, SceneDepth);
|
||||
float4 Radiance = GetDynamicLighting(DerivedParams.TranslatedWorldPosition, DerivedParams.CameraVector, ScreenSpaceData.GBuffer, ScreenSpaceData.AmbientOcclusion, ScreenSpaceData.GBuffer.ShadingModelID, LightData, LightAttenuation, Dither, uint2(InputParams.PixelPos), SurfaceShadow);
|
||||
|
||||
OutColor += Radiance;
|
||||
}
|
||||
```
|
||||
|
||||
# PostProcess
|
||||
## ToneMapping
|
||||
c++部分主要修改了:
|
||||
1. PostProcessing.cpp
|
||||
2. PostProcessTonemap.cpp
|
||||
3. PostProcessTonemap.h
|
||||
|
||||
***实现向ToneMaper Shader传递 `TRDGUniformBufferRef<FSceneTextureUniformParameters>`的功能***
|
||||
|
||||
之后再PostProcessTonemap.usf中,对**CustomStencil**进行判断,如果为true,则直接返回之前渲染结果。实际上BufferVisualization里根本看不出来。
|
||||
```c++
|
||||
#include "DeferredShadingCommon.ush"
|
||||
|
||||
// pixel shader entry point
|
||||
void MainPS(
|
||||
in noperspective float2 UV : TEXCOORD0,
|
||||
in noperspective float2 InVignette : TEXCOORD1,
|
||||
in noperspective float4 GrainUV : TEXCOORD2,
|
||||
in noperspective float2 ScreenPos : TEXCOORD3,
|
||||
in noperspective float2 FullViewUV : TEXCOORD4,
|
||||
float4 SvPosition : SV_POSITION, // after all interpolators
|
||||
out float4 OutColor : SV_Target0
|
||||
#if OUTPUT_LUMINANCE
|
||||
, out float OutLuminance: SV_Target1
|
||||
#endif
|
||||
)
|
||||
{
|
||||
float Luminance;
|
||||
FGBufferData SamplerBuffer = GetGBufferData(UV * View.ResolutionFractionAndInv.x, false);
|
||||
if (SamplerBuffer.CustomStencil > 1.0f && abs(SamplerBuffer.CustomDepth - SamplerBuffer.Depth) < 1)
|
||||
{
|
||||
OutColor = SampleSceneColor(UV);
|
||||
}
|
||||
else
|
||||
{
|
||||
OutColor = TonemapCommonPS(UV, InVignette, GrainUV, ScreenPos, FullViewUV, SvPosition, Luminance);
|
||||
}
|
||||
#if OUTPUT_LUMINANCE
|
||||
OutLuminance = Luminance;
|
||||
#endif
|
||||
}
|
||||
```
|
||||
|
||||
## PostProcessCombineLUT.usf
|
||||
主要移植了UE4版本的LUT,以此保证效果统一。
|
||||
|
||||
# 其他
|
||||
## GpuSkinCacheComputeShader.usf
|
||||
注释2行代码,用处不明。
|
||||
```c++
|
||||
#if GPUSKIN_MORPH_BLEND
|
||||
{
|
||||
Intermediates.UnpackedPosition += Unpacked.DeltaPosition;
|
||||
// calc new normal by offseting it with the delta
|
||||
LocalTangentZ = normalize( LocalTangentZ + Unpacked.DeltaTangentZ);
|
||||
// derive the new tangent by orthonormalizing the new normal against
|
||||
// the base tangent vector (assuming these are normalized)
|
||||
LocalTangentX = normalize( LocalTangentX - (dot(LocalTangentX, LocalTangentZ) * LocalTangentZ) );
|
||||
}#else
|
||||
#if GPUSKIN_APEX_CLOTH
|
||||
```
|
||||
=>
|
||||
```c++
|
||||
#if GPUSKIN_MORPH_BLEND
|
||||
{
|
||||
Intermediates.UnpackedPosition += Unpacked.DeltaPosition;
|
||||
// calc new normal by offseting it with the delta
|
||||
//LocalTangentZ = normalize( LocalTangentZ + Unpacked.DeltaTangentZ);
|
||||
// derive the new tangent by orthonormalizing the new normal against
|
||||
// the base tangent vector (assuming these are normalized)
|
||||
//LocalTangentX = normalize( LocalTangentX - (dot(LocalTangentX, LocalTangentZ) * LocalTangentZ) );
|
||||
}#else
|
||||
#if GPUSKIN_APEX_CLOTH
|
||||
```
|
314
02-Note/ASoul/渲染方案/材质部分.md
Normal file
314
02-Note/ASoul/渲染方案/材质部分.md
Normal file
@@ -0,0 +1,314 @@
|
||||
# 相关资产路径
|
||||
Content/ResArt/CommandMaterial
|
||||
- [x] [[#Functions]]
|
||||
- [x] [[#MatCap]]
|
||||
- [x] [[#Materials]]
|
||||
- [ ] [[#MaterialInstance]]
|
||||
- [x] [[#Outline]]
|
||||
- [x] [[#Textures]]
|
||||
|
||||
# Functions
|
||||
- [x] [[#ShadingModels]]
|
||||
- MF_ToonPBRShadingModel
|
||||
- MF_ToonBaseShadingModel
|
||||
- MF_ToonSkinShadingModel
|
||||
- MF_ToonHairShadingModel
|
||||
- [x] [[#Effects]]
|
||||
- MF_Dissolve
|
||||
- MF_EdgeLight
|
||||
- MF_Fur
|
||||
- [x] Tools
|
||||
- MF_DecodeArrayIDAndAlpha:分离输入浮点数的整数与小数部分。整数部分作为TextureArrayID,小数部分作为Alpha参数。
|
||||
- 主要用于MF_FaceOverlay的**Face Overlay Color**效果与M_Penetrate的**Eye Overlay Color**效果。
|
||||
- MF_Hash11
|
||||
- MF_Hash12
|
||||
- MF_Hash13
|
||||
- MF_Hash22
|
||||
- MF_Hash23
|
||||
- [x] ***CameraLightCollection***:各个角色的主光照颜色、边缘光颜色与主光亮度以及LightDir。
|
||||
- MF_CharacterMainLightIntensity:使用CustomNode编写的函数,通过RoleID进行Switch Case计算对应角色的MainLightColor * MainLightIntensity,这些一般在Sequence中进行修改。
|
||||
- MF_ApplyToonHairSpecular:头发高光计算,被M_ToonBase_V02调用。
|
||||
- ***MF_CharacterEffects***:基本所有角色相关材质都有使用。主要调用了MF_EdgeLight、MF_Dissolves实现了**边缘光与溶解效果。
|
||||
- MF_CharacterRimLightIntensity:使用CustomNode编写的函数,通过RoleID进行Switch Case计算对应角色的RimLightColor * RimLightIntensity,这些一般在Sequence中进行修改。
|
||||
- MF_FaceHighlightAndShadow:使用Shadow贴图渲染脸上的阴影效果(通过Dot(LightVector,FaceRight)判断左右)以及边缘高光(通过Dot(LightVector,FaceFront)作为Mask),被M_ToonFace调用,但没有使用脸部阴影效果只使用了高光(实际看不出来)。
|
||||
- 其中的FaceRight、FaceFront、FaceLightDir**使用了CustomPrimitiveData**。
|
||||
- MF_FaceOverlay:脸部材质额外的BaseColorTexture叠加效果,猜测是用来制作一些特殊表情的腮红效果,被M_ToonFace调用。
|
||||
- MF_Inputs:镭射材质效果,只被M_ToonLaserPBR、MI_Leishezhi调用。
|
||||
- MF_Matcap:Matcap效果,输出2种贴图Multip 与 Add效果,被MF_ToonPBRInput调用。
|
||||
- **MF_Matcap_Add**:MF_Matcap的升级版。
|
||||
- OutputAdd = LightMap * LightMatcap
|
||||
- OutputEmissive = Matcap Texture 01 + Matcap Texture 02 + Matcap Texture 03 + Emissive Matcap * Emissive Texture
|
||||
- OutputNeckShadow = lerp( lerp(1.0, Matcap Color 04, Matcap Texture 04), 1, NeckShadow)
|
||||
- OutputInnerline = Innerline Matcap
|
||||
- MF_NormalMapIntensity:Normal强度调整,被大量材质引用。
|
||||
- ***MF_SceneEffects***:调用了MF_Dissolve实现了溶解效果。但备用他的材质并不多。
|
||||
- MF_ShiftTangent:Kajiya-Kay中的ShiftTangent,被M_ToonHair_V01调用。
|
||||
- MF_StrandSpec:Kajiya-Kay中的高光计算逻辑,被M_ToonHair_V01调用。
|
||||
- MF_Surface:Surface材质相关属性逻辑,被MF_ToonPBRInput、MF_ToonBaseInput调用。
|
||||
- **MF_Surface_V02**:Surface材质相关属性逻辑,被MF_ToonBaseInput_V02调用。与MF_Surface相比少了Specular输出。
|
||||
- MF_TextureBooming:材质没有上线。
|
||||
- **MF_ToonBaseInput**:通用ToonBase材质逻辑函数。集合了MF_CharacterMainLightIntensity、MF_Matcap_Add、MF_Surface、MF_ToonBaseShadingModel材质函数以及一些变量材质设置。被**M_ToonBase_V02_Penetrate**、**M_ToonBase_V02_Test**调用。
|
||||
- ***MF_ToonBaseInput_V02***:通用ToonBase材质逻辑函数V02。集合了MF_CharacterMainLightIntensity、MF_Matcap_Add、**MF_Surface_V02**、MF_ToonBaseShadingModel材质函数以及一些变量材质设置。被**M_ToonBase_V02**、**M_NaiLin_AnotherWorld02**、**M_EggGym_Flower**调用。
|
||||
- **MF_ToonHairSpecularMaskUV**:计算Hair高光贴图UV,被MF_ApplyToonHairSpecular(**M_ToonBase_V02**)调用。
|
||||
- 使用dot( float3(0,0,1.0f), CaemraVector)的数值来对**HairMask的采样UV(V轴)** 进行偏移,以此实现高光偏移效果。
|
||||
- **MF_ToonPBRInput**:通用ToonPBR材质逻辑函数。集合了MF_CharacterMainLightIntensity、MF_Matcap、MF_Surface、**MF_ToonPBRInput**l材质函数以及一些变量材质设置。被**M_Penetrate**、**M_ToonBase_V01**、**M_ToonFace**、**M_ToonHair_V01**、**M_ToonSkin**、**M_BeiLa_Skin_AnotherWorld**、**M_Wave**。
|
||||
- ***MF_TranslucentDOF***:Translucent材质的景深效果,***没有看懂***。被MF_Input、**MF_Surface**、**MF_Surface_V02**、M_ToonFacee_old、M_ToonLaserPBR调用。
|
||||
- MF_VectorRotateAboutAxis:向量旋转函数。被MF_WorldSpaceStarring调用。
|
||||
- MF_WorldSpaceStarring:被M_NaiLin_AnotherWorld02调用。
|
||||
- SceneEffectsCollection:场景效果材质参数集,**可能已经废弃,因为UE5大世界不支持关卡流**。会被MF_SceneEffects、BP_EmptyToStageA以及其他材质调用。
|
||||
## ShadingModels
|
||||
采用CustomNode构造FMaterialAttributesde的之后传递到MaterialAttribute模式的材质中,其他骚操作还有:
|
||||
1. 使用宏开启MRT5:`#define PIXELSHADEROUTPUT_MRT5 1`
|
||||
2. 设置ShadingModelID:`Result.ShadingModel = 14;`
|
||||
3. 使用FToonShadingPerMaterialCustomData ToonShadingPerMaterialCustomData(位于Common.ush)来传递卡通渲染用数据,之后在BasePassPixelShader.ush中将数据塞入GBuffer中。
|
||||
### MF_ToonPBRShadingModel
|
||||
```c++
|
||||
FMaterialAttributes Result;
|
||||
Result.BaseColor = float3(1.0, 1.0, 1.0);
|
||||
Result.Metallic = 0.0;
|
||||
Result.Specular = 0.0;
|
||||
Result.Roughness = 0.0;
|
||||
Result.Anisotropy = 0.0;
|
||||
Result.EmissiveColor = float3(0.0, 0.0, 0.0);
|
||||
Result.Opacity = 1.0;
|
||||
Result.OpacityMask = 1.0;
|
||||
Result.Normal = float3(0.0, 0.0, 1.0);
|
||||
Result.Tangent = float3(1.0, 0.0, 0.0);
|
||||
Result.WorldPositionOffset = float3(0.0, 0.0, 0.0);
|
||||
Result.SubsurfaceColor = float3(1.0, 1.0, 1.0);
|
||||
Result.ClearCoat = 1.0;
|
||||
Result.ClearCoatRoughness = 0.1;
|
||||
Result.AmbientOcclusion = 1.0;
|
||||
Result.Refraction = float3(0.0, 0.0, 0.0);
|
||||
Result.PixelDepthOffset = 0.0;
|
||||
Result.ShadingModel = 1;
|
||||
Result.CustomizedUV0 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV1 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV2 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV3 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV4 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV5 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV6 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV7 = float2(0.0, 0.0);
|
||||
Result.BentNormal = float3(0.0, 0.0, 1.0);
|
||||
Result.ClearCoatBottomNormal = float3(0.0, 0.0, 1.0);
|
||||
Result.CustomEyeTangent = float3(0.0, 0.0, 0.0);
|
||||
|
||||
#define PIXELSHADEROUTPUT_MRT5 1
|
||||
|
||||
Result.ShadingModel = 14;
|
||||
ToonShadingPerMaterialCustomData.ToonSpecularColor = saturate(SpecularColor.rgb);
|
||||
ToonShadingPerMaterialCustomData.ToonShadowColor = saturate(ShadowColor.rgb);
|
||||
ToonShadingPerMaterialCustomData.ToonShadowLocation = saturate(CutPosition);
|
||||
ToonShadingPerMaterialCustomData.ToonShadowSmoothness = saturate(CutSmoothness);
|
||||
|
||||
return Result;
|
||||
```
|
||||
|
||||
### MF_ToonBaseShadingModel
|
||||
```c++
|
||||
FMaterialAttributes Result;
|
||||
Result.BaseColor = float3(1.0, 1.0, 1.0);
|
||||
Result.Metallic = 0.0;
|
||||
Result.Specular = 0.0;
|
||||
Result.Roughness = 0.0;
|
||||
Result.Anisotropy = 0.0;
|
||||
Result.EmissiveColor = float3(0.0, 0.0, 0.0);
|
||||
Result.Opacity = 1.0;
|
||||
Result.OpacityMask = 1.0;
|
||||
Result.Normal = float3(0.0, 0.0, 1.0);
|
||||
Result.Tangent = float3(1.0, 0.0, 0.0);
|
||||
Result.WorldPositionOffset = float3(0.0, 0.0, 0.0);
|
||||
Result.SubsurfaceColor = float3(1.0, 1.0, 1.0);
|
||||
Result.ClearCoat = 1.0;
|
||||
Result.ClearCoatRoughness = 0.1;
|
||||
Result.AmbientOcclusion = 1.0;
|
||||
Result.Refraction = float3(0.0, 0.0, 0.0);
|
||||
Result.PixelDepthOffset = 0.0;
|
||||
Result.ShadingModel = 1;
|
||||
Result.CustomizedUV0 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV1 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV2 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV3 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV4 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV5 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV6 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV7 = float2(0.0, 0.0);
|
||||
Result.BentNormal = float3(0.0, 0.0, 1.0);
|
||||
Result.ClearCoatBottomNormal = float3(0.0, 0.0, 1.0);
|
||||
Result.CustomEyeTangent = float3(0.0, 0.0, 0.0);
|
||||
|
||||
#define PIXELSHADEROUTPUT_MRT5 1
|
||||
|
||||
Result.ShadingModel = 13;
|
||||
ToonShadingPerMaterialCustomData.ToonShadowColor = saturate(ShadowColor.rgb);
|
||||
ToonShadingPerMaterialCustomData.ToonShadowLocation = clamp(ShadowLocation, 0, SpecularLocation);
|
||||
ToonShadingPerMaterialCustomData.ToonShadowSmoothness = saturate(ShadowSmoothness);
|
||||
ToonShadingPerMaterialCustomData.ToonForceShadow = saturate(ForceShadow);
|
||||
ToonShadingPerMaterialCustomData.ToonSecondaryShadowColor = saturate(SecondaryShadowColor.rgb);
|
||||
ToonShadingPerMaterialCustomData.ToonSecondaryShadowLocation = clamp(SecondaryShadowLocation, 0, SpecularLocation);
|
||||
ToonShadingPerMaterialCustomData.ToonSecondaryShadowSmoothness = saturate(SecondaryShadowSmoothness);
|
||||
|
||||
return Result;
|
||||
```
|
||||
|
||||
### MF_ToonSkinShadingModel
|
||||
```c++
|
||||
FMaterialAttributes Result;
|
||||
Result.BaseColor = float3(1.0, 1.0, 1.0);
|
||||
Result.Metallic = 0.0;
|
||||
Result.Specular = 0.0;
|
||||
Result.Roughness = 0.0;
|
||||
Result.Anisotropy = 0.0;
|
||||
Result.EmissiveColor = float3(0.0, 0.0, 0.0);
|
||||
Result.Opacity = 1.0;
|
||||
Result.OpacityMask = 1.0;
|
||||
Result.Normal = float3(0.0, 0.0, 1.0);
|
||||
Result.Tangent = float3(1.0, 0.0, 0.0);
|
||||
Result.WorldPositionOffset = float3(0.0, 0.0, 0.0);
|
||||
Result.SubsurfaceColor = float3(1.0, 1.0, 1.0);
|
||||
Result.ClearCoat = 1.0;
|
||||
Result.ClearCoatRoughness = 0.1;
|
||||
Result.AmbientOcclusion = 1.0;
|
||||
Result.Refraction = float3(0.0, 0.0, 0.0);
|
||||
Result.PixelDepthOffset = 0.0;
|
||||
Result.ShadingModel = 1;
|
||||
Result.CustomizedUV0 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV1 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV2 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV3 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV4 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV5 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV6 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV7 = float2(0.0, 0.0);
|
||||
Result.BentNormal = float3(0.0, 0.0, 1.0);
|
||||
Result.ClearCoatBottomNormal = float3(0.0, 0.0, 1.0);
|
||||
Result.CustomEyeTangent = float3(0.0, 0.0, 0.0);
|
||||
|
||||
#define PIXELSHADEROUTPUT_MRT5 1
|
||||
|
||||
Result.ShadingModel = 15;
|
||||
ToonShadingPerMaterialCustomData.ToonShadowColor = saturate(ShadowColor.rgb);
|
||||
ToonShadingPerMaterialCustomData.ToonShadowLocation = saturate(CutPosition);
|
||||
ToonShadingPerMaterialCustomData.ToonShadowSmoothness = saturate(CutSmoothness);
|
||||
|
||||
return Result;
|
||||
```
|
||||
|
||||
### MF_ToonHairShadingModel
|
||||
```c++
|
||||
FMaterialAttributes Result;
|
||||
Result.BaseColor = float3(1.0, 1.0, 1.0);
|
||||
Result.Metallic = 0.0;
|
||||
Result.Specular = 0.0;
|
||||
Result.Roughness = 0.0;
|
||||
Result.Anisotropy = 0.0;
|
||||
Result.EmissiveColor = float3(0.0, 0.0, 0.0);
|
||||
Result.Opacity = 1.0;
|
||||
Result.OpacityMask = 1.0;
|
||||
Result.Normal = float3(0.0, 0.0, 1.0);
|
||||
Result.Tangent = float3(1.0, 0.0, 0.0);
|
||||
Result.WorldPositionOffset = float3(0.0, 0.0, 0.0);
|
||||
Result.SubsurfaceColor = float3(1.0, 1.0, 1.0);
|
||||
Result.ClearCoat = 1.0;
|
||||
Result.ClearCoatRoughness = 0.1;
|
||||
Result.AmbientOcclusion = 1.0;
|
||||
Result.Refraction = float3(0.0, 0.0, 0.0);
|
||||
Result.PixelDepthOffset = 0.0;
|
||||
Result.ShadingModel = 1;
|
||||
Result.CustomizedUV0 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV1 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV2 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV3 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV4 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV5 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV6 = float2(0.0, 0.0);
|
||||
Result.CustomizedUV7 = float2(0.0, 0.0);
|
||||
Result.BentNormal = float3(0.0, 0.0, 1.0);
|
||||
Result.ClearCoatBottomNormal = float3(0.0, 0.0, 1.0);
|
||||
Result.CustomEyeTangent = float3(0.0, 0.0, 0.0);
|
||||
|
||||
Result.ShadingModel = 14;
|
||||
Result.Anisotropy = 1.0;
|
||||
ToonShadingPerMaterialCustomData.CustomData0 = saturate(float4(ShadowColor.rgb, ShadowSmoothness));
|
||||
ToonShadingPerMaterialCustomData.CustomData1 = saturate(float4(SpecularAbsorbance, SpecularRangeParam.xyz));
|
||||
|
||||
return Result;
|
||||
```
|
||||
|
||||
## Effects
|
||||
- **MF_EdgeLight**:边缘光效果,通过UE菲尼尔函数以及一些贴图、变量实现效果。主要被***MF_CharacterEffects***引用。
|
||||
- **MF_Dissolve**:溶解过度效果。主要被***MF_CharacterEffects***、***MF_SceneEffects***引用。
|
||||
- MF_Fur:用于制作Fur效果的材质函数,被**ToonShading_Standard_nooffset_fur**引用。主要还是靠***GFur插件***,没有参考意义,升级难度+1。
|
||||
|
||||
# Matcap
|
||||
存放大量Matcap用的**球形环境贴图**。除此之外`/ResArt/CommonMaterial/Materials/V02/MatCap/`也存储了Matcap贴图。
|
||||
|
||||
## 球形全景图制作方法
|
||||
【如何将无人机拍摄的球形全景图还原成球形视图】 https://www.bilibili.com/video/BV1yz411q7Eg/?share_source=copy_web&vd_source=fe8142e8e12816535feaeabd6f6cdc8e
|
||||
|
||||
# Materials
|
||||
>所有角色与新服装都迁移到V02版本,V01已废弃。
|
||||
|
||||
- Special
|
||||
- M_BeiLa_Skin_AnotherWorld:特别定制的材质。
|
||||
- [ ] V02
|
||||
- Special
|
||||
- M_NaiLin_AnotherWorld02:特别定制的材质。
|
||||
- ***[[#M_ToonBase_V02]]***:**默认的ShadingModel为13**,也就是SHADINGMODELID_TOON_BASE。
|
||||
- ~~M_ToonBase_V02_Test~~:测试用,主要的差别是使用的是MF_ToonBaseInput(里面用的是旧版的MF_Surface)
|
||||
- MI_ToonBase_V02:
|
||||
- MI_ToonSkin_V02:
|
||||
- MI_ToonFace_V02
|
||||
- MI_ToonHair_V02
|
||||
- MI_Brow_V02:
|
||||
- MI_Eye_V02:
|
||||
- MI_EyeGlass_V02:
|
||||
- MI_EyeHighlight_V02:
|
||||
- MI_EyeShadow_V02:
|
||||
- MI_MakeUp_V02:
|
||||
- MI_TeethTongue_V02:
|
||||
- [x] **M_Eye_Highlight**:
|
||||
- M_Hide:隐藏模型用材质。
|
||||
- [x] M_Penetrate:
|
||||
- [x] **M_ToonBase_V01**:主要的逻辑是MF_ToonPBRInput => MF_CharacterEffects。**默认的ShadingModel为14**,也就是**SHADINGMODELID_TOON_PBR**。
|
||||
- [x] M_ToonBase_V02_Penetrate:带有Penetrate功能的M_ToonBase_V01。
|
||||
- [x] **M_ToonFace**:
|
||||
- [x] M_ToonFace_old:
|
||||
- [x] **M_ToonHair_V01**:
|
||||
- [x] **M_ToonSkin**:
|
||||
|
||||
## M_ToonBase_V02
|
||||
与M_ToonBase_V01相比。最主要的逻辑区别在于:
|
||||
1. MF_ToonPBRInput => MF_ToonBaseInput_V02
|
||||
1. MF_Matcap_Add => MF_Matcap。不输出Specular,转而将高光结果输出在BaseColor与Emissive中。
|
||||
2. MF_ToonPBRShadingModel => MF_ToonBaseShadingModel。
|
||||
1. 移除Specular
|
||||
2. 增加ToonShadowSmoothness
|
||||
3. 增加ToonSecondaryShadow
|
||||
4. ShadingModel为13,也就是**SHADINGMODELID_TOON_BASE**。14 => 13。
|
||||
2. 增加MF_ApplyToonHairSpecular()计算头发高光并且将结果叠加到Emissive上。
|
||||
3. 增加Penetrate逻辑,结果加上WPO上。
|
||||
4. 增加Refraction逻辑,通过Normal以及菲尼尔节点插值,以此设置Refraction。
|
||||
|
||||
# MaterialInstance
|
||||
|
||||
# Outline
|
||||
主要存储了Outline主材质以及所有角色所用到的Outline材质,统一放到对应角色文件夹中。描边材质使用***M_Outline_V03***或***MI_Outline_V03***即可。
|
||||
|
||||
1. 材质ShadingModel为Unlit、BlendMode为Maskd。
|
||||
2. 所有描边材质都有**MF_CharacterEffects**、MF_CharacterMainLightIntensity。所以都支持溶解效果,以及调整每个角色的描边光照效果(连接的是材质Emissive引脚)。
|
||||
|
||||
- M_Outline_V01 & M_Outline_V02:
|
||||
- **WPO**引脚逻辑:**描边粗细控制部分逻辑**和V01基本相同,除了V01有Minimum Line Thickness这个粗细最小值。剩下的其他逻辑一模一样。
|
||||
- ***M_Outline_V03***:
|
||||
- **OpacityMask**引脚逻辑:与V01、V02略有不同。会将BaseTexture贴图的a通道乘以HideMask,然而并没有材质使用。
|
||||
- **WPO**引脚逻辑:V03版本的**描边粗细控制部分逻辑**做了更加合理的改动。VertexColor的RGB通道代替Backface外扩时的VertexNormalWS,这样不会影响光照效果。
|
||||
- MaterialInstance
|
||||
- MI_Outline_V03
|
||||
- MI_Outline_Face_V03
|
||||
- MI_Outline_Hair_V03
|
||||
- MI_Outline_Skin_V03
|
||||
- Dissolve:继承自MaterialInstance文件夹中的对应材质实例,**勾选了EnableDissolve**。
|
||||
# Textures
|
||||
存储一些默认贴图与一些测试用(无用)贴图。
|
Reference in New Issue
Block a user