散射项:
散射项使用的是预计分的方法,在材质编辑器中去计算散射,代替管线中的NdotL
散射结果:
整体的散射ok,但是在detial normal上散射缺乏质感
siggraph2011 的论文中有提到,对于有次表面散射的物体,其R通道散射的结果要想对于G通道和B通道而言要更加低频。G通道的散射要略低于B通道。这个结果和散射的高斯分布很像
实现方法:
结果对比
细节上的对比:
SSS in Shadow:
直接光部分有SSS效果,但是阴影的交界处没有,就感觉很怪。所以果断安排上。预计分的SSS shadow也是使用一张lut去做。
由于shadow map啥的数据都在basspass里头,材质编辑器不好拿。我们只好把这张lut塞到basspass里头了。传到basspass里头的方法可以参考一下的文章:
Shadowell:虚幻4向MobilebassPass传入Lut的两种方法zhuanlan.zhihu.com我使用的是上文中的方法2去传lut。lut的生成代码:
if (InFeatureLevel>=ERHIFeatureLevel::ES2)
{
{
FPooledRenderTargetDesc Desc(FPooledRenderTargetDesc::Create2DDesc(FIntPoint(32, 32), PF_R16G16B16A16_UNORM, FClearValueBinding::None, 0, TexCreate_None| TexCreate_NoFastClear, false));
Desc.AutoWritable = false;
GRenderTargetPool.FindFreeElement(RHICmdList, Desc, PreIntegratedShadowLut, TEXT("PreIntegratedShadowLut"), true, ERenderTargetTransience::NonTransient);
// Write the contents of the texture.float Roughness = (float)(y + 0.5f) / Desc.Extent.Y;
uint32 DestStride;
uint8* DestBuffer = (uint8*)RHICmdList.LockTexture2D((FTexture2DRHIRef&)PreIntegratedShadowLut->GetRenderTargetItem().ShaderResourceTexture, 0, RLM_WriteOnly, DestStride, false);
Desc.Extent.X = 32;
Desc.Extent.Y = 32;
float v = 0.0064f;
float v1 = 0.0484f;
float v2 = 0.187f;
float v3 = 0.567f;
float v4 = 1.99f;
float v5 = 7.41f;
FLinearColor C0 = { 0.233f, 0.455f, 0.649f ,0.0f};
FLinearColor C1 = { 0.1f, 0.366f, 0.344f,0.0f };
FLinearColor C2 = { 0.118f, 0.198f, 0.0f,0.0f };
FLinearColor C3 = { 0.113f, 0.007f, 0.007f,0.0f };
FLinearColor C4 = { 0.358f, 0.004f, 0.0f ,0.0f };
FLinearColor C5 = { 0.078f, 0.0f, 0.0f,0.0f };
//float pi = 3.14159265359;
for (int32 x=0; x < Desc.Extent.X; x++)
{
//float step = 0.001f;
for (int32 z=0;z< Desc.Extent.Y;z++)
{
float offset = (float)(x) / Desc.Extent.X;
float Theta = (1.148431f - offset)*PI;
float y = (float)(z) / Desc.Extent.Y;
float xp = -PI;
FLinearColor DisM = { 0.0f,0.0f,0.0f,0.0f };
FLinearColor DisD = { 0.0f,0.0f,0.0f ,0.0f };
for (int32 i=0;i<2048;i++)
{
float dis = FMath::Abs(2.0f * (2.330973f + y * 4.0f)*FMath::Sin(xp*0.5f));
//float dis =(xp*z/128*5);
FLinearColor Gus0 = FMath::Exp(-dis * dis / (2.0f * v))*C0;
FLinearColor Gus1 = FMath::Exp(-dis * dis / (2.0f * v1))*C1;
FLinearColor Gus2 = FMath::Exp(-dis * dis / (2.0f * v2))*C2;
FLinearColor Gus3 = FMath::Exp(-dis * dis / (2.0f * v3))*C3;
FLinearColor Gus4 = FMath::Exp(-dis * dis / (2.0f * v4))*C4;
FLinearColor Gus5 = FMath::Exp(-dis * dis / (2.0f * v5))*C5;
FLinearColor D = Gus0 + Gus1 + Gus2 + Gus3 + Gus4 + Gus5;
DisM += FMath::Clamp(FMath::Cos(xp + Theta), 0.0f, 1.0f)*D;
//DisM += (xp + x/128)*D;
DisD += D;
xp += 0.1f;
if (xp == (PI ))
{
break;
}
}
FLinearColor result = DisM / DisD;
float a = 2.51f;
float b = 0.03f;
float c = 2.43f;
float d = 0.59f;
float e = 0.14f;
/*result.R = ((result.R*(a*result.R + b)) / (result.R*(c*result.R + d) + e));
result.G = ((result.G*(a*result.G + b)) / (result.G*(c*result.G + d) + e));
result.B = ((result.B*(a*result.B + b)) / (result.B*(c*result.B + d) + e));
result.R = FMath::Pow(result.R, 1 / 2.2);
result.G = FMath::Pow(result.G, 1 / 2.2);
result.B = FMath::Pow(result.B, 1 / 2.2);*/
uint16* Dest = (uint16*)(DestBuffer + x * 8 + z * DestStride);
Dest[0] = (int32)(FMath::Clamp(result.R, 0.0f, 1.0f)* 65535.0f + 0.5f);
Dest[1] = (int32)(FMath::Clamp(result.G, 0.0f, 1.0f)* 65535.0f + 0.5f);
Dest[2] = (int32)(FMath::Clamp(result.B, 0.0f, 1.0f) * 65535.0f + 0.5f);
// Dest[3] = (int32)(FMath::Clamp(1.0f, 0.0f, 1.0f) * 255.9999f);
}
}
效果对比:
对移动管线动态光源的支持:
点光源我就不想用lut了、在移动端多次纹理采样还是很费的。因此使用拟合曲线去代替:
在basspass的点光源部分去加个宏,替换成我们的方法:
结果:
基于球谐的预计分散射:
目前我们把虚幻4移动管线的所有灯光支持都补全了,但当角色进入到室内场景时,sss效果就会消失。我们还没考虑到球谐对sss的支持。
基于球谐的预计分散射在教团1886中有实现,有兴趣的小伙伴可以用自己实现一下。
这里提供一个拟合曲线的方法给大家:
在basspass中去替换:
最终结果:
引用:
http://simonstechblog.blogspot.com/2015/02/pre-integrated-skin-shading.htmlsimonstechblog.blogspot.com http://advances.realtimerendering.com/s2011/Penner%20-%20Pre-Integrated%20Skin%20Rendering%20(Siggraph%202011%20Advances%20in%20Real-Time%20Rendering%20Course).pptxadvances.realtimerendering.com