738 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
```