• 【非真实渲染】【卡通渲染技术点介绍】


    阅读指南

    文本介绍卡通渲染的基本技术,实现会放在另外的文档

    关键词

    Cel Shading,ToonShading,色块、色调,各向异性,描边,高光

    特征

    看起来像手绘的图片

    少渐变(指光影的变换),有明显的分界

    颜色少

    色调少

    看起来粗略(凸出主要特征)

    卡通渲染的技术是为了实现这些特征

    光照模型

    卡通渲染光照组成

    一般是 = 环境光 + 漫反射 + 高光,根据需要也可以加入对环境的反射

    特效

    边缘线 + 边缘光

    头发天使环

    头发上的高光反射

    技术点

    色块化

    把渐变分出好几个级别,渐变变成突变,在边界做一点过渡,一般是根据【法线和视线】or 【法线和光线】计算一个值,根据这个值进行分段,某个范围映射到一个固定的值。

    如果要美术定制,可以使用光照查询纹理,是一个分块的颜色纹理,根据光照计算的结果(也就是上面的方法里计算出来的值的相关值),一般是一个[0,1]的值作为uv来查询映射纹理

    称为RampMap

    色调

    使用冷色调,暖色调,根据需要使用的色调配置不同的查询纹理,比如冷白皮肤,热带环境,极地环境

    漫反射

    色块化方式:

    if dot(normalWS, lightDirectionWS) > 0

    明亮

    else

    使用smoothstep做明暗变化的过渡

    float lightIntensity = smoothstep(0, 0.01, NdotL);

    高光

    现实世界效果

    卡通渲染效果

    真实世界光照表现的不同在于,卡通渲染的高光区不会有太多过渡,是大块大块的突变

    float specularIntensity = pow(NdotH * lightIntensity, _Glossiness * _Glossiness);

    float specularIntensitySmooth = smoothstep(0.005, 0.01, specularIntensity);

    外轮廓线

    根据法线和视线的夹角

    dot(normal, viewDirectionWS)越小,夹角越接近90度,说明是模型的边,但是获得的轮廓不均匀

    优化,将法线变换到投影空间要乘以transform的转置逆再乘projection矩阵,这样法线不会受到非等比缩放的影响,即使用NDC空间的距离

    这里面的精髓:多乘了一个w,这样进行透视除法的时候不影响我们设置的数值

    v2f o;

    o.pos = UnityObjectToClipPos(v.vertex);

    float3 norm = mul((float3x3)UNITY_MATRIX_IT_MV, v.normal);

    float2 extendDir = normalize(TransformViewToProjection(norm.xy));

    //o.pos.xy += extendDir * (_OutlineWidth * 0.1);//拉动镜头粗细会变化,下面是优化的

    o.pos.xy += extendDir * (o.pos.w * _OutlineWidth * 0.1);

    参考

    【02】卡通渲染基本光照模型的实现 - 知乎

    2个Pass,根据法线外扩模型,剔除正面

    背面扩张法(Procedural Geometry Silhouetting),缺点是同一个顶点在不同面上有不同法线的地方会有缺口(模型交接的位置出现缺口)

    缺点:背面可能和原来的模型发生深度冲突,导致遮挡模型

    一种解决方法是给backfaces设置Z-offset,使轮廓线埋没到临近的面里。另一种解决方法是修改backfaces扩张的法线,使轮廓线扁平化

    后处理,根据法线和深度变化程度

    一般使用Sobel边缘检测算子

    缺点:

    一些z变化很小的轮廓,比如桌子上的纸张,就无法检测出来

    不能区分Silhouette edge和Crease Edge

    后处理,边缘检测算子进行检测

    内轮廓线

    如果直接在贴图上绘制线条,缩放会模糊

    使用本村线,角色表面描边的方法,并不是外描边,它是将模型的 UV 打直,只绘制于垂直于 U 轴或者 V 轴的直线,避免斜线线条的采样问题

    缺点:

    制作周期会比较长

    解释下UV打直

    把模型上没有整齐排布的uv给排整齐

    不直的UV

    直的UV

    边缘光

    根据相机位置和法线,夹角越接近90度,边缘光越强

    如果用视线方向,如果模型在右侧45度,并且正面朝着相机,边缘光会出问题,所以要用相机位置

    viewDir = normalize(cameraPos - position)

    float4 rimDot = 1 - dot(viewDir, normal);

    使用smoothstep进行过渡

    float rimIntensity = smoothstep(_RimAmount - 0.01, _RimAmount + 0.01, rimDot);

    去掉暗处的边缘光

    float rimIntensity = rimDot * NdotL;

    rimIntensity = smoothstep(_RimAmount - 0.01, _RimAmount + 0.01, rimIntensity);

    根据法线和光源夹角调整边缘光,夹角越大,边缘光越弱

    float rimIntensity = rimDot * pow(NdotL, _RimThreshold);

    rimIntensity = smoothstep(_RimAmount - 0.01, _RimAmount + 0.01, rimIntensity);

    阴影

    卡通渲染的阴影也是一块一块呈现,没有渐变,只在交界处有过渡

    float shadow = SHADOW_ATTENUATION(i);

    float lightIntensity = smoothstep(0, 0.01, NdotL * shadow);

    阴影倾向

    有些地方容易产生阴影,有些地方则很难产生阴影。用一张贴图或者顶点色控制阴影的倾向,对上面的映射函数进行偏移

    PBR

    在PBR光照模型的计算中加入卡通渲染,使用NDotL、NDotV的值进行操作

    头发高光-天使环

    一般的高光都是使用法线方向进行制作的,但是此处使用了副切线(T)。原因是我们模拟的对象(发丝)是一个圆柱形,它的形状导致了它的法线的不唯一性,所以法线不能用来计算我们的高光。法线不确定,导致我们的切线也不确定,但是他们的平面是固定的,所以我们可以使用副切线(同时垂直于由法线与切线的向量)

    算法说明http://web.engr.oregonstate.edu/~mjb/cs519/Projects/Papers/HairRendering.pdf

    经验

    法线

    卡通渲染的模型一般需要人工调整法线

    ilm map

    用于调整阴影和高光区域的形状

    sss map

    用于调整阴影的颜色,暗部颜色 = mainTex * sssMap

    参考资料

    unity官方卡通渲染方案

    Unity Toon Shader (Unity-Chan Toon Shader 3) | Unity Toon Shader | 0.6.1-preview

    基础技术

    Unity Toon Shader Tutorial - Roystan

    outline

    GitHub - IronWarrior/UnityOutlineShader: Source code for Outline Shader tutorial for Unity. Detects edges in a scene using the depth and normals buffers.

    综合

    【02】从零开始的卡通渲染-着色篇1 - 知乎

    天使环

    多了噪声做扰动

    【Cel-Shading】各向异性发丝高光 | Invictus maneo

    头发各向异性渲染写的详细且深入

    图形学基础|各项异性与头发渲染_桑来93的博客-CSDN博客_头发各向异性

    各向异性(Anisotropic)指的是在不同方向上表现出的光照效果会产生差异

  • 相关阅读:
    【Python搜索算法】广度优先搜索(BFS)算法原理详解与应用,示例+代码
    LEETCODE 169 189 121 122 55
    【C++】函数重载
    webpack实战:最新QQ音乐sign参数加密分析
    Hadoop(五)C#操作Hive
    Cookie与Session
    微服务框架 SpringCloud微服务架构 22 DSL 查询语法 22.4 地理查询
    尚硅谷Vue系列教程学习笔记(3)
    pytorch的GPU版本(torch.cuda.is_available()返回False)
    7、NoClassDefFoundError: sun/misc/BASE64Encoder
  • 原文地址:https://blog.csdn.net/ak47007tiger/article/details/126321708