NPR相关记录
1. 对阴影的控制
卡通渲染的漫反射一般是梯度的,有明显的明暗线。在这个基础之上出现了很多中对暗面和明暗分界线控制的方法。
1.1 明暗交界线的处理
1.1.1 比如用SmoothStep使明暗过度变得平滑
https://zhuanlan.zhihu.com/p/86726394
下面的图来自于链接
half NdotL = dot(N, L) * 0.5 + 0.5;
half diffuseMin = saturate(_DiffuseCutLocation - _DiffuseCutSmoothness);
half diffuseMax = saturate(_DiffuseCutLocation + _DiffuseCutSmoothness);
half diffuseColor = smoothstep(diffuseMin, diffuseMax, NdotL) * col;
但是因为法线变化不均匀,不一定能找到合适的Smoothness值。
1.1.2 根据NdotL采样RampMap
可以平滑过度明暗面还可以控制过度的颜色。
1.1.3 明暗过度的Ramp图
类似上面的方法,下图只作用于明暗交接处。而且更加细致,可以画多条,分别作用于不同的Section,比如装备,皮肤,头发的区分,还可以在不同时间段应用不同的过度颜色。
1.2 对阴影的控制
1.2.1 阴影的范围
https://www.cnblogs.com/TracePlus/p/4205798.html
https://gameinstitute.qq.com/community/detail/110916
https://gameinstitute.qq.com/community/detail/110879
https://www.onlinegamer.jp/news/202009040001/
使用顶点色或者贴图来控制阴影出现的权重
先把颜色Remap到[-1.0, 1.0],然后叠加到NdotL上,再进行二值化。
除了权重之外,对法线也进行了调整
对于面部手动调整法线、或者用建模映射。对于衣服而言,可以平滑法线。
平滑法线的具体方法可以参考UE的Recomputetangets那两个CS。基本上是第一个Pass算三角形法线,第二个Pass给顶点取占有面法线的均值。
除此之外,还有对光照分布图采样与N‘dotL做阈值的方法。
关于SDF生成可查
https://blog.csdn.net/Brick_Moving/article/details/119298804?spm=1001.2014.3001.5501
除了这些之外,还有对光源方向的控制:如果光源再头顶,会很难搞
背光时增加亮面范围:
背光时根据权重压暗阴影:
1.2.2 阴影的颜色
可用贴图,或者Uniform Vector。不再赘述
2. 描边
2.1 屏幕空间卷积描边
蓝色协议里有一些特别的处理
根据深度区分出了角色轮廓,和内部。这样可以控制不同粗细
内描边有单独的Buffer来补充差异辅助边缘检测
2.2 额外绘制Cull Front的模型
在屏幕上显示固定宽度的描边,那么顶点向外延伸的距离就应该是NDC空间下的固定距离,而不是投影空间下的固定距离。于是,在投影空间下计算向外延伸的距离的时候,乘上w的值,这样,在之后的齐次除法中会将坐标值除以w,得到的就是不会随距离相机远近不同的描边宽度了。
output.vertex = TransformObjectToHClip(input.positionOS.xyz);
float3 normal = TransformObjectToWorldNormal(input.normalOS);
float2 offset = normalize(TransformWorldToHClipDir(normal).xy);
//将近裁剪面右上角位置的顶点变换到观察空间
float4 nearUpperRight = mul(unity_CameraInvProjection, float4(1, 1, UNITY_NEAR_CLIP_VALUE, _ProjectionParams.y));
//求得屏幕宽高比
float aspect = abs(nearUpperRight.x / nearUpperRight.y);
offset.y *= aspect;
output.vertex.xy += offset * output.vertex.w * _Outline;
绘制的粗细、颜色可以通过顶点色控制;颜色也可以是Uniform Vector * Base Color之类的。
为了使这种描边在硬拐角不断开,一般会存一份平滑过的法线。
3. 轮廓光
3.1 step(a, 1 - NdotV)
描边的范围有时候会因为法线变化程度不同导致粗细不一。
可以通过Mask遮挡大面积平面的区域,只留下边缘部分;还可以通过光源方向或者将法线转化到屏幕空间来控制边缘光的位置:
3.2 通过深度进行边缘检测
需要在角色正式渲染之前额外渲染一次深度
在渲染的时候,沿着法线方向外扩一段距离,然后采样深度做比较,如果当前像素深度和偏移之后采样的深度差距很小,就无。
这种方法出的边缘光不会有太大的宽度差异。
4. 高光
4.1 二值化的高光
身体和头发的高光一般是直接画好Mask:
用两个通道分别控制强度和阈值之类的
4.2 写实的高光
比如:Phong + Matcap
或者装备直接整PBR:
未完待续