魔药液体研究
实现效果——
- 液体(mesh部分填充、高度可调)
- 液体因移动晃动
- 液体浮沫
- 液体中气泡
- 液体粘度
液体
基本思路是:确定一个高度,截掉高度上方的几何体,只保留该高度下方的几何体。使用step
判断填充范围,如果顶点高度在液面高度下,则返回1,否则返回0。
return step(i.fillEdge,0)*col
截面使用Unity内置语义VFACE,声明变量facing
,朝向摄像机正面的返回1,背面返回0——所以记得加上Cull Off
,截面处为背面,统一颜色填充,视觉上像是整个面被封起。
fixed4 frag (v2f i, fixed facing : VFACE) : SV_Target
{
// ...
return step(i.fillEdge, 0) * (facing > 0 ? col : topColor);
}
液体光泽
添加液体光泽rim。
fixed4 frag (v2f i, fixed facing : VFACE) : SV_Target
{
//...
float dotProduct = 1 - pow(dot(i.normal, i.viewDir), _RimPower);
float4 RimResult = smoothstep(0.5, 1.0, dotProduct);
RimResult *= _RimColor;
//...
return step(i.fillEdge, 0) * ((facing > 0 ? col : topColor) + RimResult);
}
液体浮沫 ver.1
参考Minionsart的做法,在液体表面添加一层其他颜色,作为“浮沫”。声明一个浮沫层厚度变量,取高度差区域,填充上色与液体部分同理。
Q:啊这…浮沫的表面怎么填不起来… A:step返回要取一下负…卡半天QAQ
fixed4 frag (v2f i, fixed facing : VFACE) : SV_Target
{
//...
float4 foam = step(i.fillEdge, _Rim) - step(i.fillEdge, 0);
//...
return (facing > 0 ? //facing front or back
(foam * (_FoamColor + RimResult) //foam color
+ (step(i.fillEdge, 0)) * (col + RimResult)) //liquid color
: step(i.fillEdge, _FoamWidth) * _TopColor); //top color
}
液体晃动
晃动液体时,瓶中液体的表面也会跟随晃动。(暂停,Minions的有一点假,只适用于轻度摇动,过大幅度时效果不好。extra用一张noise效果就…啊这…更假了)
以下切换到Gil的思路
用到compute buffer。
- 储存历史顶点位置,并从中获得顶点的local速度
- 液体表面Spring位置(这里的spring指的就是物理上的,F=-kx那个),用spring模拟液体表面波动
找到一篇2D水面的,可以参考
- spring的速度以及向上还是向下
- sine+世界坐标模拟波纹
- 液面折射反光(偏真实的)
以下暂时记录一下compute shader相关内容:
numthreads(X, Y, Z)
X\Y\Z分别是在某一方向上的线程数量,总线程数量则为XYZ。
Q:为什么线程分到二维速度变慢好多…
第一张图,显示了Dispatch(drawcall?)的内容,一个方块代表一个线程组。Dispatch函数将三维(?)线程组传入(?)指定kernel。图中X\Y\Z即三维上线程组数。合计XYZ个线程组。
第二张图,显示了单个线程组内的存储模式,一个方块代表一个线程。
- SV_GroupThreadID:线程ID,就第二张图上根据索引确定
- SV_GroupID:线程组ID,第一张图上索引确定
- numthreads:线程组三围尺寸。
- SV_DispatchThreadID:求上面仨的乘积计算出的索引值。SV_DispatchThreadID = SV_GroupID * numthreads + SV_GroupThreadID,也是个三维数。
这篇文章讲得很详细。
public void Dispatch(int kernelIndex, int threadGroupsX, int threadGroupsY, int threadGroupsZ);
创建新ComputeBuffer
public ComputeBuffer(int count, int stride);
public ComputeBuffer(int count, int stride, ComputeBufferType type);
- count:buffer中元素数量
- stride:单一元素尺寸,需要匹配自定义的buffer类型
- type:buffer类型,默认为ComputeBufferType.Default,这个定义在compute文件中,也就是所谓的CS kernel,这里定义了具体的图形计算规则。
用完记得Release。
液体中气泡
想起之前在推上看到的啤酒瓶效果,现在仿佛似乎大概有了一点思路?作者在80lv写了文,从液体到气泡到液体粘度的思路都有分享。
实现气泡和浮沫,需要追踪液体的活跃度。最简单的方法就是添加一个变量储存模型受到的外力(我觉得速度来算也可以),随后这个外力会逐渐减少平复,营造气泡和浮沫从有到无的效果。→这个和minions的脚本一样,可以直接用。
气泡的渲染时是用3D noise(?3D)实现的,用smoothstep控制泡泡大小。
泡沫也是用贴图制作,通过顶点移位实现。→用Minions的需要改改。