5.2 KiB
title, date, excerpt, tags, rating
title | date | excerpt | tags | rating |
---|---|---|---|---|
Untitled | 2024-12-08 12:18:54 | ⭐ |
前言
阴影渲染笔记:Shadow
实现功能:
- 控制深度偏移
- CustomDepth制作头发阴影偏移效果哦 https://zhuanlan.zhihu.com/p/689578355
- ContactShadow接触阴影实现衣服细节的DetailShadow
- 半程阴影
半程阴影
由晨风&Neverwind提出:
- 【[UFSH2024]用虚幻引擎5为《幻塔》定制高品质动画流程风格化渲染管线 | 晨风 Neverwind 完美世界游戏】 【精准空降到 07:27】 https://www.bilibili.com/video/BV1rW2LYvEox/?share_source=copy_web&vd_source=fe8142e8e12816535feaeabd6f6cdc8e&t=447
阴影Setup阶段:
if 启用半程阴影:
{
额外进行一次CreatePerObjectProjectedShadow()
{
处理阴影光照Matrix //猜测:
//在ProjectedShadowInfo->SetupPerObjectProjection()中调整,FProjectedShadowInfo.TranslatedWorldToView。
//在LightSceneInfo->Proxy->GetPerObjectProjectedShadowInitializer(Bounds, ShadowInitializer)之后,修改WorldTolight。
向阴影信息写入IsHalfViewShadowFlag//猜测:在FProjectedShadowInfo中添加判断Flag并且写入。
用新的光源方向画Atlas //猜测:给带有对应Flog的DirectionLigh多创建一个对应的Atlas?
}
}
截图代码(半程阴影修改LightDirection逻辑):
if(PrimitiveSceneinfo->Proxy->IsToonDisableSelfShadow())
{
...
for (int32 ViewIndex = 0; ViewIndex < Views.Num(); ViewIndex++)
{
const FViewInfo& View = Views[ViewIndex];
const FMatrix& ViewMatrix = View.ShadowViewMatrices.GetViewMatrix()
FVector LightDirection = Lightsceneinfo->Proxy->GetDirection();
const FVector CameraDirection = ViewMatrix.GetColumn(2).GetSafeNormal()
float LightViewBlendFactor = PrimitiveSceneinfo->Proxy->GetToonHalfVienShadowFactor();
Fvector HalfViewLightDir = (LightDirection + ( 1 - LightViewBlendFactor) + CameraDirection * LightViewBlendFactor).GetSafeNormal();
FMatrix FinalCombineMatrix = FInverseRotationMatrix(HalfViewLightDir.Rotation())
ShadowInitializer.WorldToLight = FinalCombineMatrix;
}
...
}
相关代码位于FDirectionalLightSceneProxy::GetPerObjectProjectedShadowInitializer()
,在在FSceneRenderer::CreatePerObjectProjectedShadow()被调用。
virtual bool GetPerObjectProjectedShadowInitializer(const FBoxSphereBounds& SubjectBounds,FPerObjectProjectedShadowInitializer& OutInitializer) const override
{
OutInitializer.PreShadowTranslation = -SubjectBounds.Origin;
OutInitializer.WorldToLight = FInverseRotationMatrix(FVector(WorldToLight.M[0][0],WorldToLight.M[1][0],WorldToLight.M[2][0]).GetSafeNormal().Rotation());
OutInitializer.Scales = FVector2D(1.0f / SubjectBounds.SphereRadius,1.0f / SubjectBounds.SphereRadius);
OutInitializer.SubjectBounds = FBoxSphereBounds(FVector::ZeroVector,SubjectBounds.BoxExtent,SubjectBounds.SphereRadius);
OutInitializer.WAxis = FVector4(0,0,0,1);
OutInitializer.MinLightW = -UE_OLD_HALF_WORLD_MAX;
// Reduce casting distance on a directional light
// This is necessary to improve floating point precision in several places, especially when deriving frustum verts from InvReceiverMatrix
// This takes the object size into account to ensure that large objects get an extended distance
OutInitializer.MaxDistanceToCastInLightW = FMath::Clamp(SubjectBounds.SphereRadius * CVarPerObjectCastDistanceRadiusScale.GetValueOnRenderThread(), CVarPerObjectCastDistanceMin.GetValueOnRenderThread(), (float)WORLD_MAX);
return true;
}
PS.很有可能需要创建2个Atlas。Atlas的创建位于FSceneRenderer::AllocateCachedShadowDepthTargets()。数据存储在SortedShadowsForShadowDepthPass.ShadowMapAtlases中。大致由FSceneRenderer::FinishInitDynamicShadows()调用。
阴影Projection阶段: //此阶段需要屏蔽角色投射到自己的非半程阴影 //和角色投射到场景中会跟随视角移动的阴影
if(Toon材质,且没有半程阴影Flag的阴影
&&非Toon材质但有半程阴影Flag的阴影)
{
屏蔽此阴影
}
PS.很有可能在FProjectedShadowInfo::RenderProjection()阶段进行判断以此保证合成正确的ScreenShadowMask。
实现方法
const FMaterialRenderProxy* MaterialRenderProxy = MeshBatch.MaterialRenderProxy;
bool bEnableToonMeshDrawOutline = MaterialRenderProxy->GetToonOutlineDataAssetRT()->Settings.bEnableToonMeshDrawOutline;
FProjectedShadowInfo->Scene FPrimitiveSceneProxy
深度偏移
方法一
- FProjectedShadowInfo添加变量。 FSceneRenderer::RenderShadowDepthMaps() => RenderShadowDepthMapAtlases() => ProjectedShadowInfo->RenderDepth()
已放弃,FProjectedShadowInfo无法判断MeshSection。
方法二
在材质中使用ShadowPassSwitch再对ViewSpace的Z轴方向(使用DirectionalLightVector比较可以只对方向光进行偏移)进行WPO偏移实现。
其优点就是可以用贴图来控制偏移过渡。
DirectionOffsetToViewShadow
- 在FProjectedShadowInfo添加变量。 FSceneRenderer::CreateDynamicShadows() => SetupInteractionShadows(),在CreatePerObjectProjectedShadow()添加相关逻辑。
CreatePerObjectProjectedShadow() => ProjectedPreShadowInfo->SetupPerObjectProjection
- GetBestShadowTransform()