之前做过一版涟漪,参考的是:
https://seblagarde.wordpress.com/2013/01/03/water-drop-2b-dynamic-rain-and-its-effects/seblagarde.wordpress.com理论就是这张图:
做完了然后效果其实还行,但是盯着只要看两个周期,就会发现涟漪的位置太规律了,虽然是模拟,就算不能真正做到雨滴落地位置和涟漪生成位置产生关联,那起码也要看不出规律。可能这就是强迫症吧。
大佬之前给我发过一篇闪耀暖暖技术分享:
《闪耀暖暖》如何实现顶级美术表现?先看看叠纸怎么做3D建模吧mp.weixin.qq.com这不就是晶格么,噪声生成啊,好像的确可以这样做随机。
理一下思路,现在是需要一个位置随机,闪烁随机的点。那不就是相当于一个float3(x,_Time,y)为变量的3DWorley么,先在SD里拖出来验证一下:
毛的问题,好像可以搞!
下面new shader开始搞,voronoiNoise我就不多说了,但是在抄下面代码之前建议去看一下噪声生成原理,不然下下步看不懂。
float voronoi(float3 value)
{
float3 baseCell = floor(value);
//first pass to find the closest cell
float minDistToCell = 10;
float3 toClosestCell;
float3 closestCell;
[unroll]
for (int x1 = -1; x1 <= 1; x1 ++)
{
[unroll]
for (int y1 = -1; y1 <= 1; y1 ++)
{
[unroll]
for (int z1 = -1; z1 <= 1; z1 ++)
{
float3 cell = baseCell + float3(x1, y1, z1);
float3 cellPosition = cell + rand3dTo3d(cell);
float3 toCell = cellPosition - value;
float distToCell = length(toCell);
if (distToCell < minDistToCell)
{
minDistToCell = distToCell;
closestCell = cell;
toClosestCell = toCell;
}
}
}
}
return minDistToCell;
}
//frag
float3 value = float3(i.uv.x / _CellSize, _Time.x * _TimeScale, i.uv.y / _CellSize);
world = voronoi(value);
return world;
好,voronoi出来了,但是仔细思考了一下,涟漪到最大范围的时候应该直接消失啊,可是这个Distance是一个-1到1的过程。
求点Distance的时候:
float3 toCell = cellPosition - value;
float distToCell = length(toCell);
这个distToCell是现在点到目标点的向量,直接把这个向量在Y负半轴的Discard掉应该可行,改一下:
float3 cellPosition = cell + rand3dTo3d(cell);
float3 toCell = cellPosition - value;
float distToCell = 10;
if (toCell.y > 0)
{
distToCell = length(toCell);
}
/*if (distToCell < minDistToCell)
{
minDistToCell = distToCell;
closestCell = cell;
toClosestCell = toCell;
}*/
minDistToCell = min(distToCell, minDistToCell);
好,完美!剩下就是拟合一下,把这个图拟合得像涟漪一点:
float world = voronoiNoise(value);
float Color = 0;
Color = 1 - world;
// Color += 1.0 - step(0.02, world);
Color = saturate((Color - 0.5) * 2);
Color = sin(clamp(Color * 9.0, 0.0, 4.0) * 3.141592);
不要问我怎么拟的,问就是魔术!
然后求曲率转法线!ddx、ddy操作一下:
float3 heightToNormal(float height, float intensity)
{
float dU = ddx(height);
float dV = ddy(height);
float3 n = normalize(float3(0, 0, 1) + float3(dU, dV, 0) * intensity);
n = n * 0.5 + 0.5;
return n;
}
伽马矫正一下:
float3 n = pow(heightToNormal(Color, _Intensity), 2.2);
矫正完颜色就对了。
贴上去,完事!
当然,这部分计算最好是要拿去ComputeShader里算。
最后我贴一下大佬的Git,上面的代码有用到大佬的Random.cginc:
ronja-tutorials/ShaderTutorialsgithub.com