光照模型
光照模型记录一下学习过的光照模型的公式,顺便记录记录相关代码,预防哪天需要找轮子的时候还要在线搜索。 兰伯特光照模型$ Diffuse_{漫反射颜色} = Color_{直射光颜色} * Color_{材质颜色}* max(0,\theta _{光和法线})$ 左边是兰伯特,右边是 Unity built in Standard,并且左边只有 albedo,右边还有 normal、MetalMask AO。 1234567fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;fixed3 worldNormal = normalize(i.worldNormal);fixed3 worldLightDir = normalize(_WorldSpaceLightPos0.xyz);fixed4 texColor = tex2D(_MainTex, i.uv);fixed3 diffuse = _LightColor0.rgb * _Diffuse.rgb * saturate(dot(worldNormal, worldLightD...
纸张折叠
Page Fold纸张折叠效果也是很常见了,做系统的应该大概率都会遇到,简单的从思路和原理记录一下。 思路 肯定是两个 Pass,设置一个角度的参数,然后一个 Pass 渲染正面,一个 Pass 渲染背面。然后在 Pass 里面根据角度决定渲染顶点的位置和是否被显示。 根据上面的效果图,先求第一个 Pass 里面的横纵坐标 12x = r * cos(angle);y = r * sin(angle); 此时这个横纵坐标要先赋给拿到的模型坐标,然后再转为世界坐标。 第二个 Pass 肯定要渲染背面了,所以要 1Cull Front 代码逻辑还是一样的,不过用背面的图片。 边界限定在我一开始没考虑角度边界的时候得到了这样的效果:其实这是个很傻缺的问题,不要把折叠的角度设置为0,设置 Range 范围为 (1,180) 就好了,这样第二个 Pass 就会显示在上面。 翻页的长度仔细看的话会发现如果不给半径增加一个可调节值,他默认是在模型的中心点翻页的,所以增加一个可调节值,就可以实现整张纸的翻页了。
渲染状态
渲染状态CGPROGRAM 前面可以放许多关键字,还没系统总结下,顺便写写笔记。 面剔除 shaderLab语句 说明 Cull Off 不剔除 Cull Back(默认) 剔除背面(内表面),即背对着摄像机的图元不会被渲染 Cull Front 剔除正面(外表面),即朝向摄像机的渲染图元不会被渲染 当一个mesh组件的信息被传递后,我们可以通过代码决定哪些部分渲染(render)出来,而哪些部分不要,这个过程就像把那些不要的部分剔除了,我们看不到他,虽然他的mesh信息还在,但是我们的GPU不会去处理它,肯定比剔除前GPU的性能消耗要低。这个过程就好比我们的mesh组件是一个透明的膜,我们假设这个胶纸我们根本看不到,而片段着色器在着色的时候像毛笔选择性地上色,最后的效果是我们可能看到膜的一部分是可见的,但是不见的地方,膜还是存在的,只是我们没有给他上色,我们既看不看他们,也不需要再他们上面画宝贵的墨水(GPU并行处理能力) 举个例子,入门精要的 8_7_1 里面场景: 1Cull Off 1Cull Back //(默认就是这个,相当于把上面的 Cull...
边缘光
边缘光本来打算把边缘光和透视效果一起折腾的,忽然发现边缘光可以写的东西也不少,单独开个坑吧,凑凑字数。 菲涅尔效果图最常见的边缘光实现方式之一,通过获取法线和视线的点乘的结果来判断,越靠近模型的边缘,那么法线和视线的夹角就会越接近90度。核心代码如下: 12345678910111213141516171819202122232425v2f vert (appdata_base v){ ... //求法线坐标 o.worldNormal = mul(v.normal,(float3x3)unity_WorldToObject); //获得世界坐标系下顶点坐标 float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz; //获得世界坐标系下视线向量 o.worldViewDir = _WorldSpaceCameraPos.xyz - worldPos; ...}fixed4 frag (v2f i) : SV_Target{ ... /...
透视效果
透视效果是我们经常会遇到的,比如我心中最好的线性游戏 “Dishonored2”。 今天的目标就是实现这个最终效果。理一下思路,因为是隔墙,所以肯定是两个 Pass 来实现了,毕竟要考虑到一半一半的情况。第一个 Pass 用来显示边缘形成的模型,第二个 Pass 用来画剩下没有被遮挡的模型,也就是正常的 Pass 就不说了。 第一个 Pass: 要显示墙后面的物体,那么自己本身肯定是不透明的,渲染队列先设置为 Geometry,既然是不透明的,那么深度信息也不能写入。考虑到该 Pass 渲染完后,挡在他前面的物体还是要显示的,所以如下: 123"Queue" = "Geometry"ZWrite OffZTest Greater 第一个 Pass 渲染状态设置完,就直接考虑画模型边缘就行了,可以用最简单的 N dot V 来实现看一下效果。 感觉视线部分和后面的模型重叠了,那么最终应该给个颜色强度值改下。暂时先这样,美化工作和其他的效果有时间再整整看。 参考链接 https://www.cnblogs.com/Colored-Mr/p...
靠近消失Shader
靠近就消失或者出现的功能看了林新发大佬的功能,觉得很不错,大佬是用 Shader Graph实现的,我在 Builtin 里面用手写熟练一下。 实现思路大佬讲的挺明白的,这个功能也比较简单,主要就是传入坐标,判断距离,用一种方式消失,增加边缘颜色。先上效果图。 具体步骤如下: 获取世界坐标 判断是否处于阈值范围,然后 Clip。 增加噪声溶解效果 增加溶解边缘颜色 部分源码12345678910111213141516171819202122232425262728293031323334353637383940414243fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); // apply fog UNITY_APPLY_FOG(i.fogCoord, col); ...
描边
描边记录一下基础的一些 Shader, 分别写一下 2D 和 3D 的外描边 3D 外描边3D外描边一般来说都是用 Cull Front 来做,效果也还行,放一个简单的伪代码。 1234567891011121314151617Pass{ Cull Front v2f vert (appdata v) { v2f o; v.vertex.xy += normalize(v.normal) * _OutlineWidth; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; } fixed4 frag (v2f i) : SV_Target { return _OutlineColor; }...
类行为树的循环判断框架
行为树 用了很久的行为树了,用来做过 AI、新手引导,感觉说一些使用细节属实是没啥必要,说一个我自己遇到的问题把,有的时候就想代码做一些判断重复的事情,这个时候用行为树就很傻了,如果节点只有 20 个以下我还能接受。 但是如果是策划配表没有什么上限的东西呢,总不能一个个拖动吧,所以我用行为树的这种逻辑写了一个代码版本的行为树。 实现思路 想一下行为树的逻辑,从头到尾依次判断,然后一直到某个节点成功,如果所有的节点都失败了,就结束当前树,算是一次行为完成。 如果你勾选了外部的完成后重新开始,那么就变成了一个不断循环的逻辑。 分析完毕,开始构思代码逻辑。 首先需要一个类来表示整个树,假设我们叫它 LoopTaskTree。 然后 Tree 里面需要放置各种各样的节点,BaseLoopTask,分析一下发现代码上暂时不用考虑 or 这个状态,目前我们需要的是重复判断某个事情,也就是说 Task 的状态有 Success、Failure、Running 三种。 接着就是让这个树循环判断起来。 用 Update() 就可以完成这件事,然后写一个 Manager 来管理,里面执行三个重要逻...
关于噪声和溶解效果
溶解效果 溶解效果是最常见的效果之一,实现原理也很简单,通过 Clip() 函数剪裁掉不想要的区域。 1clip(currentColor.r - _TargetDissolveThreshold); 不过一般都不会专门为了这两句话写一个单独的 Shader,毕竟多加一个材质就多一份消耗,所以都是在需要用到的地方加一个开关和阈值,然后用 step() 方法直接将结果加入总的结果中。 自定义 Standard Shader 这里就有一个题外话,如果用了 Unity 默认的 Standard Shader 或者类似的默认 Shader,需要在效果结束的时候添加一些东西怎么办,这就需要一个套娃操作。 先去 Unity 的官方 Github 上面下载默认的 Shader,然后复制一份改个名字变成自己的放入到工程里。 然后把 StandardShader 引用的 Shader (除了粒子系统相关的)都复制一份到工程里,然后修改刚才操作的所有 Shader 的引用。这里放一个参考链接 https://blog.csdn.net/SnoopyNa2Co3/article/details...
动画水
实现场景大纲一个经典的简单的带坡度的小池塘,池塘岸边带有泡沫,池塘表面有起伏动画,池塘表面透明可以看到池塘中的物体。 实现思路 根据深度设定不同坡度下水的颜色 通过噪声和深度值获得池塘岸边表面的白色浪花 通过 UV 动画获得波浪起飞 使用法线缓冲区来区分平缓的表面和垂直的表面,然后在垂直的表面出增加泡沫。 通过调整混合设置获得不透明效果 简单代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081struct appdata{ float4 vertex : POSITION; float4 uv : TEXCOORD0; float3 normal : NORMAL;};struct v2f{ float4 vertex : SV_POSITION; float2 n...