Unity中如何加入液体物理效果
发表于2018-04-16
在这个教程中我会展示如何扩展你自己的水粒子(water particle),以使流体物理能在很多机器上运行(当然也包括手机)。
效果不是很现实,不过我可以保证这很简单而且可能是最省性能的方式。如果你知道如何如何在unity中编码以及使用刚体碰撞,你将用他们做一些疯狂的实验。
我建议你在开始这个教程之前先下载这个example project,尝试在一个新的场景中用相同的assets重新实现这个效果,你会更清晰地了解这是如何运作的。
在开始这个教程之前,希望你具备如下条件:
- Unity中刚体的知识
- 了解并能在Unity中使用shader
- 能使用Render Texture
Metaballs
Ok, 如果你已经做过相关功课,那你应该大致了解metaball是如何运作的,如果还没有的话,那么这里有不错的教程你可以了解一下。
这里稍微讲一下,metabll是3D空间中的等值面。想象空间中有两个电子,会形成一个磁场,类似如下:
图片上的亮度代表了磁场的强度。这种效果类似水滴的融合或者细胞的分裂,所以我们在游戏里可以用meataball来模拟水滴(运用这个技术就可以实现《小鳄鱼爱洗澡》中的流体效果了)。
那么metaball中的shader是怎么起作用的呢,那么请看这段shader代码
#ifdef GL_ES precision mediump float; #endif uniform float time; uniform vec2 mouse; uniform vec2 resolution; float MetaBall(vec2 position){ return 1.0/(pow(position.x,2.0)+pow(position.y,2.0)); } float Blob(vec2 position,vec2 point, float radius){ float temp=pow(position.x-point.x,2.0)+pow(position.y-point.y,2.0); float result=0.0; if( temp<pow(radius,2.0)){ float distance=sqrt(pow(position.x-point.x,2.0)+pow(position.y-point.y,2.0))/radius; result=pow((1.0-pow(distance,2.0)),2.0); } return result; } void main( void ) { float PI=3.141516; vec2 position = gl_FragCoord.xy / resolution.xy ; vec2 pointA= vec2(0.35,0.5),pointB= vec2(0.65,0.5); vec2 mousePosition = ( gl_FragCoord.xy / resolution.xy ) + mouse / 4.0; float radius=0.3; float blobValue=0.0; blobValue+=Blob(position,pointA,radius); blobValue+=Blob(position,pointB,radius); blobValue+=Blob(position,mouse,radius); vec4 color=vec4(0.0,blobValue/2.0,blobValue,1.0); color=floor(color/0.1)*0.5; gl_FragColor = color; }
这段代码中的最后一句是
color=floor(color/0.1)*0.5;
这句是metaball效果的精髓所在。
Metaballs in Unity
现在已经基本了解了什么是metaball,那么下一步,我们要将GLSL转换成Unity中使用的shaderlab,其中最重要的fragment部分如下:
half4 frag (v2f i) : COLOR{ half4 texcol,finalColor; texcol = tex2D (_MainTex, i.uv); finalColor=half4(0.0,texcol.g/2.0,texcol.b,texcol.a); if(finalColor.a>0.2){ finalColor.a=0.5; finalColor.b=floor((finalColor.b/0.1)*0.5); } return finalColor; }
完整的shader代码在project中。
不知道你注意到没有,我使用一张纹理而不是计算每个像素来表示一个水滴,这是空间换时间点方法,直接从图片上读取效率更高(毕竟PS能轻松完成这件事)。那么让我们创建一张类似水滴的图片并将这张纹理应用进去。
接下去用我们刚才的shader创建一个材质
结果看起来应该如下:
为了模拟水滴,我们需要为我们的水滴添加碰撞体,3D中添加sphere collider,这个碰撞体要比图片中的像素轮廓小一点,这样我们就能模拟水滴融合但又不完全重叠的效果了
Render Textures
render texutre 表现得和普通纹理差不多,所以我们可以用shader做用于它。当我们将metaball shader用于这个render texture的时候, 如果摄像机看到的白色的东西,它将会如我们实验中一样merge这些颜色。
为了避免不把和metabll不相关的白色混进去,我们需要两个摄像机,一个只追踪metaball的图像,一个追踪正常的场景:
那么创建一张render texture吧。
复制一个摄像机,将输出定向到创建的render texture(culling mask只设置Liquids):
我们在场景中添加一些水滴, 运行游戏,你将会看到:
从上面的右边部分可以看到,水滴已经有类似磁场线的分割了。那么这个水滴融合效果算是成功了。
原文地址:http://codeartist.mx/tutorials/liquids/