三渲二

三渲二

1. 三渲二

通用快捷引导

主页目录
文集目录

代码只能作为入门学习,实际生产中还是要靠 可视化编辑器。因此ShaderForge 、 Shader Graph 成为必备!
卡通渲染(常称为:三渲二,NPR(非真实渲染))主要分为:美式、日式。
主要技术包括:描边。可以通过:G-Buffer (几何缓存)中的深度、法线贴图计算。

  • 术语:NPR(Non-photorealistic rendering)、RBR(Physically Based Rendering)

2. 初级卡通渲染

由于我只有基础的Shader 知识,并没有多的ShaderForge 知识。因此需要一些基础的ShaderForge知识。

2.1. 基本思路

  1. 分出亮面、暗面。(1,0) = 法线 dot 光向。

  2. Step节点 + 阈值 分出亮暗面。—— S值

  3. 亮面:S值=1,乘亮面颜色。 此时暗面Color = 黑(0,0,0)

  4. 暗面:S值=0,Remap 一下。得到暗面 =1.乘 暗面颜色。

  5. 亮暗面颜色相加得到完整值。

最终 颜色 Multiply 光源颜色、纹理颜色 即可。 此时,卡通渲染由于是自定义 光照模型,不会受到 其他模型阴影、光线衰减等影响。因此需要添加 Light Attenuation 节点,和最初的1 步骤结果相乘。

需要注意 受到阴影影响。Light Attenuation 值会在阴影处 =0 .而 Step的阈值 相等 ,算通过,因此阈值不要设置为 临界值:0.

3. B站视频观察总结

  • 卡通渲染分为多种,我追求的的是“次世代卡通渲染”。(实时渲染CG技术
  • 次世代卡通渲染除开:shader部分,最关键的是 各种需求的:(合成)图。把光照信息、落影容易度、AO(Ambient Occlusion环境光遮蔽)、高光通过 RGB通道 存储起来。

3.1. 卡通渲染需要做什么?

虽然不知道到底怎么做,但一定要明白需要做什么,这是 “无中生有”的第一步。

视频一观察

  1. 头发高光
  2. 暗部颜色
  3. 受光颜色
  4. 轮廓光影色
  5. 阴影影色(和暗部颜色有区别吗?)
  6. 软硬边(阴影)过度
  7. 阴影Fade Out(褪去)、Cut Out(裁剪)

米哈游技术文章

此次只针对人物,所以场景就不用分析了。

我们的目标是实现完全动态的光照和阴影,所有材质都对各种光照现象做出正确的反应,包括主光源和区域环境光。这就要求我们不能使用任何在纹理上画死的光照表现。

主要(关键)特性有:
多通道Ramp的材质Shading(遮蔽,绘影)方法
眼睛,头发和其它各向异性材料等特殊材料的处理
PCSS角色软阴影和高品质的勾线。

pcss:一种好看的阴影模式。相关联的有:软阴影。

3.2. 米哈游技术文章分析

分析文章,扩展见识。

3.2.1. 多通道Ramp的Shading方法

我们希望角色的阴影和颜色的变化可以表现出更细腻的插画风格,所以我们使用2D ramp纹理来表示这些细微的变化,其中RGB通道分辨用于描述于不同阴影层的漫射阴影范围。每个层都可以制定不同的颜色,这样就能在明暗变化中做到精细的色彩变化控制。

  • 分析:所以我前面看见的哪些 合成纹理 应该就是—— 2D Ramp 纹理。他们用来表示细微变化(漫射、阴影范围)。

对于卡通风格的画面,如果上色只是纯明暗变化,阴影处就会显得比较脏,缺乏表现力,而如果提升暗处的饱和度和色相变化,整体色彩看起来就会比较鲜活。而且通过调整垂直纹理采样坐标,我们可以实现动态的软硬风格转换。 从另一角度来看这种方法还间接表现了皮肤的次表面散射效果。

  • 分析:卡通风格画面,阴影的变化并非 纯明暗变化,而需要伴随 色相饱和度的变化。 同时通过 纹理坐标采样(垂直,由于纹理)可以实现软硬风格。无意中达到皮肤此表面散射。

高质量的边缘光。
同样是基于菲涅尔方法,我们有参数来控制它,比如:边缘宽度和平滑度;除了这些全局控制参数之外,我们也使用笔刷纹理来增加一些局部变化。我们定义边缘光既可以来自于方向光源也可以来自于环境贴图,使用方向光我们可以按需求定义边缘光,使用环境贴图,我们可以根据环境光照来获得边缘光以显得更真实,二者都比较有用,可以结合使用。
为避免边边缘光出现在不需要的区域,我们使用AO纹理和shadowmap来频闭掉遮挡区域。我们可以看到,对比图中左边带有边缘光的形状显得效果更突出。

  • 分析:卡通风格是需要边缘光。但是边缘光 需要被控制。边缘光使用的是涅斐尔,控制是通过AO 纹理、Shadowmap 精细控制。不过边缘光可以不弄,我没看懂 图中的原理。

卡通风格对于面部一般不会有太多阴影层次的变化,如果我们直接套用之前的ramp方法应用在脸部,效果就会像右侧的图看起来一样不自然,为了改善这种情况我们使用顶点色的一个通道作为mask来控制脸部的上色层的强弱,通过压低漫反射表现来达到想要的卡通效果。

  • 分析:卡通风格面部和身体 略有不同。主要压低脸部的漫反射。同时漫反射导致的阴影为软,投影阴影为硬看起来效果更好。

高质量角色软阴影的实现。
如果我们直接使用Unity内置的CSM阴影,在镜头靠近角色的时候阴影品质并不能满足需求,所以我们就为角色单独渲染了一张shadowmap,以确保恒定的阴影品质。为此我们还实现了基于视锥的shadowmap,根据角色的boundingbox和视锥求交集部分,以此作为渲染区域。就可以最大化阴影贴图的使用率,
此外还使用了Variance shadow map以及PCSS来减少阴影瑕疵以及获得自然的软阴影效果。另外,如果要实现正确的透明材质阴影,还需要额外的通道根据材质的透明度来存储阴影强度。我们可以从实例图片中看到半透明的裙子可以投射出自然的阴影。

  • 分析:高质量角色软阴影就先不管。

3.2.2. 特殊材料处理

眼睛的处理我们使用了基于物理的折射计算。普通卡通模型处理眼部的做法通常是把眼白留空,瞳孔凹陷下去,这样在侧面的时候也不会鼓出来显得比较自然,然而如果要做眼部近距离特写,这种做法看上去就不能令人信服。使用真实折射算法,眼球本身还是按照球面来做,然后根据视线角度算出折射系数去偏移查找贴图对应点 。
下面对比图显示了有无折射的实际效果, 我们可以看到,如果没有折射效果,眼部侧面看上去较为奇怪。

  • 分析:眼睛和头发都属于难点。后面单独分析。眼睛 关键 :焦散计算。 头发关键: 各项异性计算。

头发是卡通渲染角色较为重要且独特的部分。我们想要实现根据光源动态变化的高光和阴影渐变,并且这个实现还应具备直观的所见即所得的色彩调节能力。
和皮肤的材质一样,对于头发的漫反射渲染我们同样使用了Multi-ramp的方法,而镜面反射高光我们则使用了二层高光做叠加,通过组合高低频的高光成分在一起,我们可以得到满意的结果。此外,我们还使用Glossy Map和AO纹理来进一步增强头发的质感。

  • 分析:头发渲染上次的各项异性因该是对的。但是缺少 要给Rampa 图控制高光的位置。外加一个发丝通道。

3.2.3. 高品质勾线

使用backface (背面渲染)方法勾线,缺点是折线硬表面会有问题,可以预处理,将这些部分单独提出来处理。

  • 分析:或使用基于边缘检测的Sober算子后处理。米哈游通过更多的色相、饱和度、深度、法线 综合计算边缘。

3.3. 剩下两个视频分析

主要更加深入了解 不同贴图的使用。为接下来的实践做准备。

3.3.1. 视频一分析

  • 底色贴图

  • SSS(Subsurface Scattering)次表面散射图。专门用来做皮肤 透光效果。—— 色系偏向红紫色。
    还可以用来修饰阴影的颜色。

  • ILM——篇绿、灰系。包含四个通道。
    G通道:一个Shadow map 用来表示落影的容易度。类似于原话术语中的“闭塞”。
    A通道:表示内部需要描线的地方。主体使用BackFace 方式描边。
    R通道:记录Specular(高光)的强度。
    B通道:记录Specular(高光)的区域大小。

卡通渲染要出效果,第一步:落影的计算。正常球体Diffuse 一半黑一半白。

题外:还有一种落影方案。AO贴图。+ 顶点色绘制。

3.3.2. 视频二分析

大佬开场.正常的 卡通渲染有 三张贴图.(底色贴图+光照(光相关)贴图(ILM)+此表面散射贴图(SSS))
着色器没什么,主要是贴图。

案例中只使用了 Base+ILM贴图.

本视频中ILM贴图:

R通道:高光的范围。
G通道:阴影贴图,假的AO贴图。
B通道:高光的强度。

利用不同通道颜色在模型上绘制完后,将贴图导出。
在PS-图像-模式-灰度。转化为灰度贴图。 此时只有一个灰色的通道。
其他两张相同操作。

转化完成后,选择合并通道。将打开的三个窗口中的贴图合并即可。

Shader界面:

主要了解需要哪些参数。

阴影强度、阴影面积受到G通道影响。

参数

4. 开始编写Shader

人物Shader 主要分为:身体、脸部、眼睛、头发。四种Shader。

4.1. 遇到一个大坑—— 阴影(身体)

用来接受阴影 的面片,不论正反面,都会接受到阴影。不会因为你是不渲染而接受不到阴影。

正常情况下,是不会遇到这个问题,因为投影和 漫反射暗面 相互融合。但是,卡通渲染,导致需求漫反射 暗面小。导致 问题出现明显。

—— 基于这个问题,就导致了必须先将阴影融合(不论PBR、NPR)。或者换一种阴影计算方式。

—— 阴影计算,在光源出放置一个摄像机,拍摄ShadowMap。再基于位置是否光照等信息确定是否 采样Shadowmap。 这也就是说:采样过程是封闭的。

—— 这个阴影计算,还是比较复杂的。如果是光追的话,就不会出现这种问题吧。

—— 回过头去看:视频中的“动态投影”并未被实现过,(ShaderGraph)中也一样。

4.1.1. 尝试解决——阴影

  1. 首先明确本次只关注受光(是否接受到投影)区域。
  2. 在 光源方向 假设 Camera,对区域渲染。只需要深度信息。
  3. 目标Shader 中,对深度进行比较。比其小的进行采样…… 这种方式行不通。

4.1.2. 尝试第二种方式。

多次渲染——……也好像不行。 毕竟ShadowMap的机制摆在这里。

先用摄像机渲染

4.1.3. 尝试解决方案三。

结果: 效果还不错。

  1. 可以缩减:漫反射的暗部区域—— Diffuse暗部。
  2. 融合:投影阴影。—— 投影的不完美导致最低可以缩减的 漫反射暗部 被限制了最低。不过调到最低 效果还不错。
  3. 可以融合ILM 图中的G 通道,辅助生成阴影。并通过LN点积值计算是否落影。

注意,阴影采样模块不应褪色。这导致阴影的物体丢失了其“色相”。因该直接链接,不褪色。

4.2. 比较简单—— 高光(身体)

主要考虑三个因素:高光范围、高光位置、高光强度。

  1. 高光位置:比较简单就是 BPhone模型(半角向量和视向量的点积的 高次幂)—— 次方计算的底数。

  2. 高光范围:分两个部分。

  • 漫反射暗部+接受投影 (不包含ILM图中的辅助阴影贴图)
  • ILM贴图的 R 通道遮罩。
  1. 高光强度,需要结合ILM纹理的B通道与一个基础Float值。——次方计算的幂。

结果如下:

4.3. 脸部Shader

之所以不用身体的Shader?

  • 脸部基本没有高光区域。
  • 脸部的受光要多(阴影要少) 才符合卡通渲染。

4.3.1. 一个注意点—— 暗部

为了缩减脸部的阴影。采用Remap 的方式。 但是由于 对Text 采用Uv 采样的方式获取对应的值,所以此时出现一个 临界值问题。 Uv >1、<0 时都会出错,此时注意把 图片格式修改一下。

也可能是因为如上原因,导致我上次错怪了 Dot 的 “Normalize”模式。

还好我有这部分知识,否则郁闷一下午。所以见识很重要。

4.3.2. 最终决定——自定义阴影采样

卡通渲染的脸部重中之重,因此 采用 自己用纹理渲染的方式渲染你。

由于采用自定义阴影采样的方式,可以轻松解决头发投影的问题,因此漫反射暗部就不用那么麻烦了。

4.3.3. 相机Shader替换渲染技术

unity官方手册有介绍。

一个复合Shader 里面有多个 SUbShader(具有特定标签),该SHader 被设置为替换SHader。
当相机 渲染一个物体时。该物体的Shader 的SubShader的 标签的 值 和替换Shader中的标签值 相同,则判断成立,SubShader 会被替换。

4.3.4. 获取深度纹理

仔细一思考,我不能沿用传统的阴影方式。而是基于深度的的阴影。

主要有两种解决思路:

4.3.4.1. 方案一、 通过Shader 内置的获取深度方式,渲染出深度。—— 推荐,方便
  • 通过代码 设置相机为深度相机。
  • 编写输出屏幕深度渲染缓冲信息的Shader。
  • 通过代码:相机后处理方式,直接输出深度SHader的信息。
  • 特别注意摄像机的 边界长度,太长 差距太大,输出一片白色。视野越小越精确。
    深度Shader:

Shader "Unlit/NewUnlitShader01"
{
    
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100
        Pass{

        ZTest Always Cull Off ZWrite Off

        CGPROGRAM

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma glsl
        #pragma fragmentoption ARB_precision_hint_fastest
        #pragma target 3.0
        #pragma vertex vert
        #pragma fragment frag
        #include "unityCG.cginc"
        sampler2D _CameraDepthTexture;

    struct v2f {
        float4 pos : SV_POSITION;
        float4 scrPos:TEXCOORD0;
    };
    //Vertex Shader
    v2f vert(appdata_base v) {
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);
        o.scrPos = ComputeScreenPos(o.pos);
        return o;
    }

    //Fragment Shader
    float4 frag(v2f i) :COLOR{
    float depthValue = 1 - Linear01Depth(tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.scrPos)).r);
    return float4(depthValue, depthValue, depthValue, 1.0f);
    }
        ENDCG
    }
    }
}

camera.depthTextureMode = DepthTextureMode.Depth;


    private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        if (camera != null)
        {
            Graphics.Blit(src, dest, r_material);

        }
    }
4.3.4.2. 方案二、 通过相机渲染替换Shader技术获取—— 为实验,理论可行
  • 用于替换的Shader 需要获取到摄像机的距离(ShaderForge有节点)
  • 获取摄像机的视野范围。用于归一化。
  • 利用相机渲染时,替换Shader的技术,将深度信息输出。

4.3.5. 最终决定

放弃! 渲染出来的质量有点差,效果并不好。而且还非性能,需要多两个摄像机,以及控制摄像机 的移动。

根据观察,大多数unity实时渲染都没有投影。

所以还是直接采用 身体的Shader,稍微调整后还是能够观看的。

4.4. 头发Shader——各项异性

准备采用各向异性达到效果。

4.4.1. 各项异性高光——完美

前提:由于我的模型头发法线反了所以这里给出 球体的图片参考。

  • 主要参数:半角向量(视角、光源)、切线方向、副切线方向(叉积运算)
  • 主要运算:点积、叉积、ACos、Sin、Power、+SmoothStep

途中的其余参数都是调整参数,经过以前的实验:法线副切线、主切线的权重将影响 结果的 横竖方向。

  • 参数参考:K系数:01、P系数:011.

途中球体效果参数:0.28、0、0.65、11.

4.4.2. 完美完成

本次还 法线了 投影和漫反射暗部的最佳融合方式:暗部映射0~1 + Light Atten

4.5. 本次卡通渲染意外

记录一些其他杂七杂八的问题。

4.5.1. 模型导入FBX没有贴图问题

Unity2019.3中,如果默认使用新的Load 方式导入模型。Material 会嵌入到“模型文件之下” ,并不会有 单独的文件夹存放 材质、纹理。甚至会丢失纹理贴图。

此时需要切换为 “Legacy” 的Load 模式。——在模型的Material面板

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值