password
type
status
date
slug
summary
tags
category
icon
作品概述(省流):
学习风格化渲染和MME知识,并在URP管线下自写Shader并渲染出的MMD!
【【碧蓝航线MMD】極楽浄土(by HMS Sirus)】 https://www.bilibili.com/video/BV1SC4y1u7Qi/?share_source=copy_web&vd_source=cda669443fe5fb241b9390b1393c5680
—————————————————————————————————————————————
何妨吟啸且徐行:
- 基础光照与多光源关系:
一开始使用了Step二阶化光影+Shadowsmooth进行小平滑,后来在舍友的帮助下将step替换为了更加美观的Rampmap.
同时使用了shadowmap对物体阴影进行了采样,根据距离和强度,在多个光源中找到最大光源,根据最大光源进行上色。
- 后处理景深:
使用深度纹理进行了景深效果的制作。
- 其他RenderFeature(辉光):
根据光照方向,对模型的背部渲染边缘光效果。
下面是一些创作中的小日志,如果有兴趣可以随便看看~
创作记录:
10.19
理解了MMD的toon贴图的使用方法,拿来上高光和阴影。
正片叠底结果 = (正叠结果AB-A)*系数+A
风格色、基础色、高光。
首先我需要把风格色添加在基础色上,同时需要能控制保持极出色的程度。那么我们这样,先用lerp差一个基础色和风格色的比例。然后再正片叠底风格色和插值后的基础色。
10.19
光的问题大概解决了,但是现在问题是模型不可以分开了,因此需要用Unlit多pass来做描边和边缘光。
10.20
描边问题感觉可以尝试使用几何着色器对边缘处顶点进行一个平滑反向缩放?
不过目前还是能复刻MMD就复刻MMD吧,不想太复杂。
没想到逻辑最复杂的就是面部法线控制。

鞋子和那个脖饰可能需要一些其他光照模型。
10.21
理解了URP下的多光源。只有聚光和平行才能产生额外阴影。
场景中只能存在一个主光源.
今天需要让天狼星投射并接收阴影!
然后接下来是修改场景内物体,根据角色简化即可.
1.移除风格化. √
2.移除副高光 √
2.移除Toon,添加一个简单的阈值,控制视线模拟阳光阴影. √
10.22
今天证明了角色多光源情况下不能再强套单光源的思路了,需要进行多光源多步迭代.
因此今天需要大改单光源shader,大概就是做一个夜晚版本多光源shader,然后再修改日光,变成单光源阴影多光源光照。
大体思路是这样的:
首先修改基础色:主要有四个变量,环境光色、光源色、toonshader,物体表面色
我们最终需要的是物体最终表面色和最终光强的关系。
那么原理就很简单了:
取样MainTex,获得物体初始表面色。
首先物体表面附着环境光色,即使用Blender中MMDshadeDev风格进行混合,使得表面色混合了全局环境光。
然后最烦的就是toonShader和物体表面色的关系。ToonShader是一个非常不讲理的东西,一个强行用于描述一个“假光源”和“物体表面色”关系的贴图。它可以将假光源的阴影,根据我们的视线和物体表面的角度,赋予物体表面对应的阴影并修改最终颜色(目前还不知道应该如何正确的修改,blender中直接修改了物体的初始表面色,但是我觉得这样恐怕有些唐突,会导致阴影的相乘,让画面变脏.)。没错,一个光源却通过修改物体表面色的形式起作用,这一关系非常的不讲道理.
然而,如果考虑到场景中的真光源,如果让两者简单正片叠底,那么会出现”暗部“ * ”暗部“双重混合变暗,从而破坏二次元光影二分的感觉。因此接下来需要寻找一个合理的办法,来控制真光源和toonTex产生的阴影的混合。
那么首先我们需要理解一下ToonTex的意义,只有理解ToonTex为何而来,才能明白它和真光源的关系应该如何。
Unity的URP管线中,场景中分为主光源和副光源,并且由于性能原因(?),场景中只允许拥有一个主光源。那么,如果Unity中主光源是基于物理计算的主光源的话,那么ToonShader,根据我仅仅写了三天shader的浅薄理解,就是二次元中我们风格化定义的场景主光源,并且这个光源是相对于我们的视角产生的!!!
说实话,咱也拿不出什么证据证明这一论点,毕竟这个玩意只要好看,可以完全不讲道理(二刺螈的事你少管!kora!)。所以我们稍微调转枪口,看看画中是如何体现这个toonTex的。
非常自大的声明一下:我不会美术,不会画画,也不懂光照,只是一个非常废柴的LSP。所以以下都是我在瞎扯,如果有任何不满,那么肯定是你对;倘若如果有任何专业性的建议或指导,我非常愿意倾听。
我们分析一下K大(Kincora)的光照风格,挑选K大最新的一张图,同样也是光影很鲜艳的一张图。
我们根据ToonTex的采样方式进行分析。ToonTex使用相机空间的法线x,y值进行采样。简单来说,就是一个面它面对我们”相对朝向”映射到纹理坐标进行采样。
(以及在这里突然发现描边颜色直接偷过来就好了!)
这张图云仙躺着,我们低头看她,太阳从前上方打过来.所以本质上和两个人站着,阳光从云仙斜正方打过来是等价的.
我们的toonshader根据我们我们的相机,与这一阳光的相对角度,便这样生成了.怎么画我不知道,我也不太清除长什么样.应该是上半部分白色会更多一点,因为是顺光.
各位请跟我一起看。胖次上面的小环环似乎几乎没有透视,因此可以判断基本这里就是视线和法线平行的地方。顺着这里向下转,看到大腿部从向上逐渐过渡到向下,这里出现了非常明显的从亮变暗的转变.
根据上面的介绍,各位大概理解了toonshader的基本原理了,于是我们分组讨论:
1)toon光(以下简称t光)和a光都照亮了片元,那么显然这一个地方是亮的,毋庸置疑.
2)t光没有,a光有.此时便出现了冲突,到底让不让阴影产生.从物理的角度来说,这是一个”或”运算,两个光能量是相加的,因为只要有一个光源能照亮物体,那么物体便应该能够得到对应的能量.并且如果a光在此处强度足够,按理说应该是甚至可以超过(1)中的双亮情况.
此时冲突便产生了,其实即使a光照亮了此处,我们也需要”强调”主光,来体现主光源的存在.或许这就是二刺螈吧,二次元真恐怖捏QWQ.
所以,显然这里得出了第一个结论,t光更”强”,更”优先”.这也就是为什么说T光是主光源的原因了.
3)t光有,a光没有.这里也很抽象,因为t光并不参与真正的光照计算,我们这里讨论参与光照计算的是a光.所以这里a光会产生正常的阴影色效果.那么根据上面说的理论,我们要体现t光的存在,此时理想当然的优先考虑t光光照,你会觉得这里是个亮部.
然而并没有想象中那么简单,如果这样做的话,所有a光的阴影都会被t光覆盖掉,虽然这很二次元,但是就会失去大部分的阴影效果,这也是我们不想看到的.
所以,暂时先将这里赋予正常的a光阴影色.
4)t光没有,a光也没有。这时该片元处应当是最暗的情况。两个都是暗部,那么我们给予a光阴影色和toontexture的阴影的正片叠底。
至此,我们便理解了t光和其他光源的关系。根据这一思想,我们便可以做出比较好的ToonTex和基本光源阴影的融合。(要开放ToonTex强度,用于控制不同部位ToonTex的影响).

仔细观察此处的头发和面部底部,都有对应的ToonTex效果,但是强度不同。

观察ToonShader和原本阴影的交融,只要调整好阴影色的颜色就不会太违和.
1.首先主光源打底(但是所有光源都是按照这一思路来).进行半兰伯特计算,然后使用半兰伯特与阴影和距离权重相乘计算光源到该片元的强度。
2.得到强度后,根据强度进行SmoothStep进行二值化,并且加入shadowsmooth,从而让阴影钝化,也能缓解一些阴影抖动,并根据结果作为shadowStep的值,0为阴影,1为亮部。
3.
10.23
今天通过课堂学习屏幕后处理,进而掌握景深效果的实现。
同时考虑对描边平滑效果进行修改,利用几何着色器的面平均切线来制作平滑法线效果。
- 25
RT只能同时存在一个,用完之后一定要release,不然永远id都是那一个。(后面的RT)
因此中间的RenderTexture就是用普通的RT即可,不需要Handle.
今天攻克后效,争取把DepthOfFieldCtrl做出来,然后上高光!还有基于几何着色器的平滑。
CameraDepthTexture直接在shader中普通定义TEXUTRE(CameraDepthTexture)和SAMPLER(_CameraDepthTexture)即可直接用了.
或者直接引用
然后使用
LinearEyeDepth(采样结果,_ZBufferParams)
转化为线性深度即可。今天发现了惊天秘密!
DepthNormals
这个逆天玩意儿。以后自己写shader如果想要写入URP深度图需要加入这个pass才行。
10.26
今天de了一个light色的bug,之前光照颜色会错误的影响整个场景的颜色,而现在加入shadowstep来钳制后可以只让光照影响照亮部位的颜色。

10.27
再次修复了多光源的叠加问题,现在可以让多光源稍微自然一点的进行融合了。
更多理解了二次元卡渲光源的意义以及“假光源”的存在。
总之,还调整了一下心态,明白了自己存在的意义。我是美术的大副,而不是船长。
10.30
各向异性的宗旨就是“法线不唯一性”。如果仅仅按照表面宏观”假法线”的方式来制作光照模型,那么就是各向同性。而各项异性的效果恰好相反,本来在同一空间角下看应当是有着相同的颜色,然而在各向异性的状态下,就会产生不同的光照颜色。而这就是我们各向异性渲染要达到的效果。
所以,根据这种“法线不唯一性”,我们就要去思考如何实现这种“多法线”的效果.
那么首先最重要的一点就是理解各向异性的法线是如何存在于顶点上的,如果理解不了这一点,就无法掌握各向异性高光的灵魂。
网上虽然有很多文章提到各向异性高光时,都会说到卡基亚模型,然而据我所见,很少有人把卡基亚背后的思路清晰的阐述出来。
我们根据卡基亚(Kajyiya-Kay)模型来对各向异性的顶点法线进行理解。首先,卡基亚模型是用于描述头发的各向异性法线的,因此它将拥有各向异性法线的物体表面抽象为了一个圆柱体。

如图,假设我们现在在观察一根在空间中恒定不变的头发,而这跟头发上有无数逼近于连续分布的顶点。
如果按照正常模型的思路,一个顶点只会保存一个对应的表面法线。而一般对于头发的模型,就是可以理解为每一个顶点所存储的法线都是该顶点在头发模型上的单位梯度。
因此,这个原本的法线一定是死的。
此时,如果把头发”竖直“地摆在我们的面前,我们将视线V垂直于这跟头发的切线T看过去的话,我们的视线V和梯度法线N的点积,是会随着我们逐渐绕着这跟头发360°旋转所改变的。一个[-1,1]的区间内。
而这并不符合我们对于一根头发的基础认知。
真正的头发是一根半径极其小的圆柱体,当我们的V和T垂直时,其表面法线N应当和我们观测一个圆柱体的法线一样,距离我们最近的表面顶点的法线永远是保持与视线V共面的。
至此,我们便清晰彻底的认识了卡基亚模型对于头发法线的概括。
所以,我认为Kajiyaa-Kay Model本质上仍然是Blinn-Phong,只是它用切线T帮我们找到当前视线下的使高光最强的法线N。
至此,关于各向异性法线N的原理已经大白。
接下来是将该法线的计算引入到我们计算光照的考虑当中。
由于我们使用的是拟合法线,因此这个法线对于L和V算出的不同H所产生的“还原度”是不同的。
我们的需要一个量来衡量通过卡基亚模型拟真出来的法线对于我们最终计算光照的贡献是否有意义。
此时我们引入了一个新的量—dirAtten = smoothstep(-1., 0., dotTH);
dotTH用于衡量H对于T的偏移,而H是我们V和L的平均半程向量。
因此,我们不难发现,这一计算量衡量了V和L两者对于切线T的相对偏差的相对差。越接近-1,两者相对于切线T的角度差的差就越大;反之越小。
如果两者相对于切线的角度差的差过大,那么我们不予采用该拟真出来的法线。
于是就有了下面的函数。
- 作者:白萧
- 链接:https://whitesou.work/article/SirusMMD1
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。