次表面散射材质_虚幻4移动管线角色渲染(一)次表面散射

本文探讨了在虚幻4移动管线中实现次表面散射材质的技术,包括散射项的计算、阴影处的SSS效果处理、动态光源支持以及球谐预计分散射的应用。通过 lut 和拟合曲线优化了移动端性能,同时指出了在室内场景中sss效果的挑战。
摘要由CSDN通过智能技术生成

73c3c994d0b84fa59704ef31a48e48ee.png

散射项:

散射项使用的是预计分的方法,在材质编辑器中去计算散射,代替管线中的NdotL

dc3d1b09ab20e716cf060ba8cf337266.png

散射结果:

78905f784e026470afeb0d79dfeb0ec5.png

整体的散射ok,但是在detial normal上散射缺乏质感

a4c421cd952af9306e0597b3b1e4fbc4.png

siggraph2011 的论文中有提到,对于有次表面散射的物体,其R通道散射的结果要想对于G通道和B通道而言要更加低频。G通道的散射要略低于B通道。这个结果和散射的高斯分布很像

d3d1e28e90da1a7b54bcd841f0851b8d.png

实现方法:

96896214dd2c5fa328f5c5b99e37e606.png

结果对比

64e807ce522912503762cb2dd40a834e.png

细节上的对比:

c4e05626633ded869879b80c08754ae7.png

SSS in Shadow:

直接光部分有SSS效果,但是阴影的交界处没有,就感觉很怪。所以果断安排上。预计分的SSS shadow也是使用一张lut去做。

7bdad1c3a21a7647f3cf4d5bc146618d.png

由于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);
					
					
				}
				
			}  
               

效果对比:

b52dd498c0584e3ab6fb17a2f356e12b.png

对移动管线动态光源的支持:

点光源我就不想用lut了、在移动端多次纹理采样还是很费的。因此使用拟合曲线去代替:

8da1f1c8828c26daabd60c3298e8a379.png

在basspass的点光源部分去加个宏,替换成我们的方法:

65abdbd30e97b13ee47bd4c4d9eb3538.png

结果:

d020c713410c3716de259cf78243608b.png

基于球谐的预计分散射:

目前我们把虚幻4移动管线的所有灯光支持都补全了,但当角色进入到室内场景时,sss效果就会消失。我们还没考虑到球谐对sss的支持。

基于球谐的预计分散射在教团1886中有实现,有兴趣的小伙伴可以用自己实现一下。

7b6018b854f77d61b314988f50452809.png

这里提供一个拟合曲线的方法给大家:

7836bf50b052464ab704554271ec6e79.png

在basspass中去替换:

c1d6ee5f2f32efdc2e13e044079e0533.png

最终结果:

dc4c511032c205e8959cd39e48cf6ea7.png

1a5dd04ace7a3539f4b3568a77a31256.png

引用:

http://simonstechblog.blogspot.com/2015/02/pre-integrated-skin-shading.html​simonstechblog.blogspot.com http://advances.realtimerendering.com/s2011/Penner%20-%20Pre-Integrated%20Skin%20Rendering%20(Siggraph%202011%20Advances%20in%20Real-Time%20Rendering%20Course).pptx​advances.realtimerendering.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值