Unity中如何加入液体物理效果

发表于2018-04-16
评论0 1.39w浏览
在这个教程中我会展示如何扩展你自己的水粒子(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/

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引