738 lines
28 KiB
Markdown
738 lines
28 KiB
Markdown
|
# 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
|
|||
|
```
|