unity3d 水的物理模拟

2014-04-11 17:30:16 kuloveyouwei 阅读数 28735
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

Unity内置了NVIDIA的Physx物理引擎,Physx是目前使用最为广泛的物理引擎,被很多游戏大作所采用,开发者可以通过物理引擎高效、逼真地模拟刚体碰撞、车辆驾驶、布料、重力等物理效果,使游戏画面更加真实而生动。

Rigidbody(刚体)组件可使游戏对象在物理系统的控制下来运动,刚体可接受外力与扭矩力用来保证游戏对象像在真实世界中那样进行运动。任何游戏对象只有添加了刚体组件才能受到重力的影响,通过脚本为游戏对象添加的作用力以及通过NVIDIA物理引擎与其他的游戏对象发生互动的运算都需要游戏对象添加了刚体组件。

依次打开GameObject->Create Empty,创建一个空游戏对象,然后选择该对象,打开菜单栏中的Component->Physics->Rigidbody,如下图:


Rigidbody组件的属性面板,如下图:


Mass:质量,该项用于设置游戏对象的质量

Drag:阻力,当对象受力运动时受到的空气阻力,0表示没有空气阻力,阻力极大时游戏对象会立即停止运动

Angular Drag:当对象受扭矩力旋转时受到的空气阻力,0表示没有空气阻力,阻力极大时游戏对象会立即停止运动

Use Gravity:使用重力,若开启此项,游戏对象会受到重力的影响

Is Kinematic:是否开启动力学,若开启此项,游戏对象将不再受物理引擎的影响从而只能通过Transform属性来对其操作

Interpolate:插值,该项用于控制运动的抖动情况,有3项可以选择,None:没有插值;Interpolate:内插值,基于前一帧的Transform来平滑此次的Transform;Extrapolate:外插值,基于下一帧的Transform来平滑此次的Transform

Collision Detection:碰撞检测,该属性用于控制避免高速运动的游戏对象穿过其他的对象而未发生碰撞,有3项可以选择,Discrete:离散碰撞检测,该模式与场景中其他的所有碰撞体进行碰撞检测;Continuous:连续碰撞检测;Continuous Dynamic:连续动态碰撞检测模式

Constraints:约束,该项用于控制对于刚体运动的约束

Collides碰撞体,碰撞体是物理组件的一类,它要与刚体一起添加到游戏对象上才能触发碰撞。如果两个刚体相互撞在一起,除非两个对象有碰撞体时物理引擎才会计算碰撞,在物理模拟中,没有碰撞体的刚体会彼此相互穿过

选中游戏对象,打开菜单栏中的Component->Physics->。。。,如下图:


Box Collider:盒碰撞体,盒碰撞体是一个立方体外形的基本碰撞体,该碰撞体可以调整为不同大小的长方体,可用作门、墙、以及平台等,也可以用于布娃娃的角色躯干或者汽车等交通工具的外壳,当然最适合用在盒子或是箱子上,属性如下图:


Is Trigger:触发器,勾选该项,则该碰撞体可用于触发事件,并将被物理引擎所忽略

Material:材质

Center:中心,碰撞体在对象局部坐标中的位置

Size:大小,碰撞体再X、Y、Z方向上的大小

Sphere Collider:球形碰撞体,球形碰撞体是一个基于球体的基本碰撞体,球体碰撞体的三维大小可以均匀等地调节,但不能单独调节某个坐标轴方向的大小,该碰撞体适用于落石、乒乓球等游戏对象


Radius:半径,球形碰撞体的大小

Capsule Collider:胶囊碰撞体,胶囊碰撞体由一个圆柱体和与其相连的两个半球体组成,是一个胶囊形状的基本碰撞体,胶囊碰撞体的半径和高度都可以单独调节,可用在角色控制器或与其他不规则形状的碰撞结合来使用


Height:高度,该项用于控制碰撞体中圆柱的高度

Direction:方向,在对象的局部坐标中胶囊的纵向方向所对应的坐标轴,默认是Y轴

Mesh Collider:网格碰撞体,网格碰撞体通过获取网格对象并在其基础上构建碰撞,在与复杂网格模型上使用基本碰撞相比,网格碰撞体要更加精细,但会占用更多地系统资源


Smooth Sphere Collisions:平滑碰撞,在勾选该项后碰撞会变得平滑

Mesh:网格,获取游戏对象的网格并将其作为碰撞体

Convex:凸起,勾选该项,则网格碰撞体将会与其他的网格碰撞体发生碰撞

Wheel Collider:车轮碰撞体,车轮碰撞体是一种针对地面车辆的特殊碰撞体,它有内置的碰撞检测、车轮物理系统以及滑胎摩擦的参考体


Suspension Distance:悬挂距离,该项用于设置车轮碰撞体悬挂的最大伸长距离,按照局部坐标来计算,悬挂总是通过其局部坐标的Y轴延伸向下

Center:中心,该项用于设置车轮碰撞体在对象局部坐标的中心

Suspension Spring:悬挂弹簧,该项用于设置车轮碰撞体通过添加弹簧和阻尼外力使得悬挂达到目标位置

Forward Friction:向前摩擦力,当轮胎向前滚动时的摩擦力属性

Sideways Friction:侧向摩擦力,当轮胎侧向滚动时的摩擦力属性

Character Controller,角色控制器,角色控制器主要用于对第三人称或第一人称游戏主角的控制,并不使用刚体物理效果

character controller组件属性如下图:


Slope Limit:坡度限制,该项用于设置所控制的角色对象只能爬上小于或等于该参数值的斜坡

Step Offset:台阶高度,该项用于设置所控制的角色对象可以迈上的最高台阶的高度

Skin Width:皮肤厚度,该参数决定了两个碰撞体可以相互渗入的深度,较大的参数值会产生抖动的现象,较少的参数值会导致所控制的游戏对象被卡住,较为合理地设定上是:该参数值为Radius值的10%

Min Move Distance:最小移动距离,如果所控制的角色对象的移动距离小于该值,则游戏对象将不会移动

Center:中心,该参数决定了胶囊碰撞体再世界坐标中得位置,

Radius:半径,胶囊碰撞体的长度半径,

Height:高度,该项用于设置所控制的角色对象的胶囊碰撞体的高度

Interactive Cloth:交互布料,交互布料组件可在一个网格上模拟类似布料的行为状态

Skinned Cloth:蒙皮布料,蒙皮布料组件与蒙皮网格渲染器一起用来模拟角色身上的衣服,如果角色动画使用了蒙皮网格渲染器,那么可以为其添加一个蒙皮布料,使其看起来更加真实、生动

Cloth Renderer:布料渲染器


Hinge Joint:铰链关节,铰链关节由两个刚体组成,该关节会对刚体进行约束,使得它们就好像被连接再一个铰链上那样运动,它非常适用于对门的模拟,也适用于对模型及钟摆等物体的模拟

Fixed Joint:固定关节,固定关节组件用于约束一个游戏对象对另一个游戏对象的运动

Spring Jonit:弹簧关节,弹簧关节组件可将两个刚体连接在一起,使其像连接着弹簧那样运动

Character Joint:角色关节主要用于表现布娃娃效果,它使扩展的球关节,可用于限制每一个轴向上的关节

Configurable Joint:可配置关节,可配置关节组件支持用户自定义关节,它开放了physx引擎中所有与关节相关的属性,因此可像其他类型的关节那样来创造各种行为


力场是一种为刚体快速添加恒定作用力的方法,适用于类似火箭等发射出来的对象,这些对象在起初并没有很大的速度但却是再不断加速的



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



2016-04-26 15:23:16 a2587539515 阅读数 2706
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

官方的demo(http://unity3d.com/cn/showcase/live-demos#shadows)中的Room of Shadows,一开始抱着学习室内灯光效果的想法去看的,后来发现这个demo中有一个拖拽物体的脚本,正好最近玩了好多游戏都是这样的,好奇心来了,学习下原理,看了之后发现原理蛮简单的,单纯使用SpringJoint即可实现,这里把脚本的代码沾上了来,做个记录。(这个脚本中不止是拖拽,还有高光,基于重绘Mesh的,一并记了)

DragRigdbodyShadow.js

var spring = 50.0;
var damper = 5.0;
var drag = 10.0;
var angularDrag = 5.0;
var distance = 0.2;
var pushForce = 0.2;
var attachToCenterOfMass = false;

var highlightMaterial : Material;
private var highlightObject : GameObject;

private var springJoint : SpringJoint;

function Update()
{
	var mainCamera = FindCamera();
	
	highlightObject = null;
	if( springJoint != null && springJoint.connectedBody != null )
	{
		highlightObject = springJoint.connectedBody.gameObject;
	}
	else
	{
		// We need to actually hit an object
		var hitt : RaycastHit;
		if( Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition),  hitt, 100 ) ) {
			if( hitt.rigidbody && !hitt.rigidbody.isKinematic ) {
			    highlightObject = hitt.rigidbody.gameObject;
			    //这里通过射线判断选中物体,加入highlightObject中,之后通过OnPostRender函数重绘
			}
		}
	}
	
		
	// Make sure the user pressed the mouse down
	if (!Input.GetMouseButtonDown (0))
		return;

		
	// We need to actually hit an object
	var hit : RaycastHit;
	if (!Physics.Raycast(mainCamera.ScreenPointToRay(Input.mousePosition),  hit, 100)) {
		return;
	}
	// We need to hit a rigidbody that is not kinematic
	if (!hit.rigidbody || hit.rigidbody.isKinematic) {
		return;
	}
	
	if (!springJoint)
	{
		var go = new GameObject("Rigidbody dragger");
		body = go.AddComponent.<Rigidbody>();
		springJoint = go.AddComponent.<SpringJoint>();
		body.isKinematic = true;
	    //建立一个SpringJoint(反弹关节),弹簧,来模拟力
	}
	
	springJoint.transform.position = hit.point;
	if (attachToCenterOfMass)
	{
		var anchor = transform.TransformDirection(hit.rigidbody.centerOfMass) + hit.rigidbody.transform.position;
		anchor = springJoint.transform.InverseTransformPoint(anchor);
		springJoint.anchor = anchor;
	}
	else
	{
	    springJoint.anchor = Vector3.zero;
	}
	//这里判断是否强制连接物体重心,是的话将锚点置为重心
	springJoint.spring = spring;
	springJoint.damper = damper;
	springJoint.maxDistance = distance;
	springJoint.connectedBody = hit.rigidbody;
	
	
	DragObject(hit.distance, hit.point, mainCamera.ScreenPointToRay(Input.mousePosition).direction);
    
}

function DragObject (distance : float, hitpoint : Vector3, dir : Vector3)
{
	var startTime = Time.time;
	var mousePos = Input.mousePosition;
	
	
	var oldDrag = springJoint.connectedBody.drag;
	var oldAngularDrag = springJoint.connectedBody.angularDrag;
	springJoint.connectedBody.drag = drag;
	springJoint.connectedBody.angularDrag = angularDrag;
	var mainCamera = FindCamera();
	while (Input.GetMouseButton (0))
	{
		var ray = mainCamera.ScreenPointToRay (Input.mousePosition);
		springJoint.transform.position = ray.GetPoint(distance);
		yield;
	}
    //这个地方就是拖动弹簧,拉动物体,这个拉动很有意思,这里用的是distance,这样的话拉动的范围是以摄像机为圆心,以点击时记录下来的distance为半径的球,效果还不错,有立体拉动的感觉
	if (Mathf.Abs(mousePos.x - Input.mousePosition.x) <= 2 && Mathf.Abs(mousePos.y - Input.mousePosition.y) <= 2 && Time.time - startTime < .2 && springJoint.connectedBody)
	{
		dir.y = 0;
		dir.Normalize();
		springJoint.connectedBody.AddForceAtPosition(dir * pushForce, hitpoint, ForceMode.VelocityChange);
		ToggleLight( springJoint.connectedBody.gameObject );
	}	
	//这个的作用是点击的时候,做出一个拍打物体的感觉
	
	if (springJoint.connectedBody)
	{
		springJoint.connectedBody.drag = oldDrag;
		springJoint.connectedBody.angularDrag = oldAngularDrag;
		springJoint.connectedBody = null;
	}
}

static function ToggleLight( go : GameObject )
    {	
	var theLight : Light = go.GetComponentInChildren(Light);
	if( !theLight )
		return;
		
	theLight.enabled = !theLight.enabled;
	var illumOn = theLight.enabled;
	var renderers = go.GetComponentsInChildren(MeshRenderer);
	for( var r : MeshRenderer in renderers )
	{
		if( r.gameObject.layer == 1 )
		{
			r.material.shader = Shader.Find(illumOn ? "Self-Illumin/Diffuse" : "Diffuse");
		}
}
//开关灯,场景互动
}

function FindCamera ()
{
	if (GetComponent.<Camera>())
		return GetComponent.<Camera>();
	else
		return Camera.main;
}

function OnPostRender()
{
	if( highlightObject == null )
		return;
		
	var go = highlightObject;
	highlightMaterial.SetPass( 0 );
	var meshes = go.GetComponentsInChildren(MeshFilter);
	for( var m : MeshFilter in meshes )
	{
		Graphics.DrawMeshNow( m.sharedMesh, m.transform.position, m.transform.rotation );
	}
///setPass就是设置通道,走的是Shader中的第一个通道,下面的将网格重新绘制一次,做到高光效果,从实现上看,绘制的时候实用的就是上面的高光贴图
}


Highlight.shader
Shader "Shadows/Drag Highlight" {
Properties {
	_Color ("Main Color", Color) = (1,1,1,1)
}
SubShader {
	Pass {
		ZWrite Off
		Offset -1, -1
		Blend SrcAlpha OneMinusSrcAlpha
		Color [_Color]
	}
} 
}

这里的Blend是一个自身颜色和其他颜色的混合,在设置透明度时候用,这里使用它来设置重绘网格的透明度,表现为高光强度

具体见http://blog.sina.com.cn/s/blog_471132920101d8z5.html

2015-09-17 10:41:12 pizi0475 阅读数 9191
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

first,I wish you a happy new year, and study in spring festival’s eve means you are hardworking,haha. I write in two languages. One passage write in Chineseone passage translate into English. My English is poor., If I write some thing wrong, welcome to correct my article.
首先祝各位看官新春快乐,能在大年三十看博文学习的都是勤奋的人。
我用了两种语言,一段英文一段中文。我英语不太好,如果有英语语法错误,或者写的不对的各位可以告诉我及时改正
I study some about water lately. Looks like this in the gif; It looks not bad, but it is incomplete and regret.This shader is surface shader, used the tessellation technology by DX11.Because of used the  tessellation ,this shader’s vertex function can’t pass parameter like position and normal, then, caused the water’s reflect light inaccuracy、can’t specular other things ,etc. The reason that can’t specular other things is can’t analysis reflection map. But just now I try to write a fragment shader that can use the tessellation, and succeed, then the shader can pass parameter. I will write it in the second blog article, this blog article just talk about water waves.
最近研究了一下水体,效果如下图gif所示,乍看感觉还可以,但是有很多残念,这个例子是用surface shader写的,运用了曲面细分等技术。由于用了曲面细分,所以surface shader的vert不能传出值,所以不能传出顶点坐标和normal值,造成了反光不准确,而且不能反射(大残念,水体不能反射= =),不能反射的原因是不能解析脚本传入的反射贴图reflection map。 但是写本文的同时突然试了一下 fragment shader,居然好用,这样也能传出值了,就在本文的(二)中研究,今天的(一)只研究水体的波动。

Most of maves are caused by the action of wind, it’s better to use circular waves in the pond scence.we just talk about the directional waves.
大多数的波动是由于风吹动引起的,对于池塘中的水用圆形波更好一点,我们只讨论方向波

Mentioned waves, we all think of sin、cos ,etc. This shader also used them.
if we just use sin , that effects looks awful.
说起波动,大家想到的肯定是sin,cos,等函数,我们的水体也是用它做一些变换。
如果单单是sin 未免有些单调,看起来也不真实。

so, in this shader, I used the Displacement mapping that I write a blog article about it before.
That can add some other waves in water.
所以本例中加入了之前写过曲面细分中的贴图置换(Displacement mapping),对水面加入一些杂波。
But why to use the tessellation?
our water in unity is a model. The plan model’s has little points, may be 100++. Used tessellation can add much more points, make the waves more smooth. The figure below is the waves not used tessellation.Looks like jag.
为什么要加入曲面细分呢?
我们的水面是一个平面,也就是plane,unity中的plane模型顶点数显而易见,看起来貌似100++,加入了曲面细分,顶点数就是原有的数倍,波浪看起来精致圆滑,
下图为未经曲面细分的水面,(= =;这不就是锯齿吗);

If you don’t want the real wave effect, you don’t need tessellation, like unity’s water4, water4 not wave truly, just some effects like normal, reflect ,etc. Brain always be cheated by eyes.

about tessellation you can see this I write before
如果你不想要真实可见的波浪效果,你大可不用曲面细分,如unity自带的那种水体water4,water4等没有真正的波动,只是normal,反光等对你眼睛的一种欺骗。
关于unity曲面细分的详细可见博主之前的这篇文章



Above I talked my shader is use sin, there are also many good waves like this. I refer to the water in 《GPU Gems》 , it used Gerstner Waves, its reality. The real waves have sharper peaks and wider troughs.
刚刚说我的例子用的是sin波,还有很多很好的波形,参考了一下GPU gems中的水体,书上用的是Gerstner波,理由是—真实,真实的浪波比较尖,波谷比较宽

Gerstner’s function is:
Gerstner波的函数是:

then I try this

然后我就试了一下

That’s pretty good, the waves has many transformation, sharper peaks and wider troughs, with some small waves. Cause of used tessellation, the plane’s mesh and vertex is disappeared in unity, may be that is a bug in unity.
效果巨好,变化也多,明显看出浪头很尖,还有很多小浪波,由于是用了曲面细分导致水平面不显示网格顶点,貌似是unity的bug,残念。。
Here are the code, Cause of that can’t pass parameter, the water not have graet highlight, shade inaccurate, looks bad.
给出代码,有兴趣的看官可以研究下Gerstner波。
因为surface shader不能传出normal信息,没有高光,明暗的显示,再好的波也看不出来= =;

 

		float wave(float x, float z, float timer)
		{
			float y = 0;
			float oct = _OCT;
			float fac = _FAC;
			float d = sqrt(x * x + z * z);// length(float2(x, z));
			for (oct; oct>0; oct--)
			{
				y -= fac * cos(timer * _SP + (1 / fac) * x * z * _WS);
				fac /= 2;

			}
			return 2 * _VS * d * y;

		}



 


Then again to talk about sin, although less detail than Gerstner. But I think that’s also great. It’s not troublesome.
再说回sin波,前面的例子是sin波的,没有Gerstner波变化细致,但我也很满足了,本例的实现不需要像Gerstner波一样需要叠加,也没有Gerstner波那么复杂,
首先让我们研究下波:
1.    Wavelength(L): the crest-to-crest distance between waves;
2.    Amplitude(A): the height from the water plane to the wave crest.
3.    Speed(S):the distance the crest moves forward per second.
4.    Direction(D):the horizontal vector perpendicular to the wave front along which the crext travels.
1.    波长(L):波峰到波峰之间的距离。
2.    振幅(A):从水平面到波峰的高度。
3.    速度(S):每秒钟波峰移动的距离。
4.    方向(D):运动方向,垂直于波阵面的水平方向;
We can use this to defined the wave:
 我们就可以通过这些参数定义波了
 
the code:
主要代码如下:

float time = _Time * _Speed/2;
float waveValueA = sin((v.vertex.x + v.vertex.z) * _Frequency + time * _Frequency) * _Amplitude;


That’s very easy, right?
很简单对吧

Simply put how to find the normal ,although can’t pass it,
The normal is given by the cross product of the binormal and tangent,as:
N = B * T;
虽然传不了normal值求normal也没什么意义,简单说下求法,
求出副法线B和切线T向量,分别为x,z方向的偏导数,
向量N = B * T;
然后就ok了。
我们得到了普通的波如下:

Then, we used the Displacement mapping.
We used the texture in unity’s water ----water4 to be our displacement map.
之后就要杂波登场了,贴图置换(Displacement mapping)。
我们用unity自带water4中的贴图作为贴图置换的资源

You can extract the texture in the water4.
Then is the blog article I write before about tessellation.We define a _Displacement value to control the other waves’s amplitude.
Define a _SpeedStrength value to control the other waves’s speed and direction.
看官们可从water4中自取。
然后就是之前曲面细分的内容了,我们设置随法线偏移度设为外部变量_Displacement来控制杂波的振幅,
又在外部定义了个参数_SpeedStrength来控制杂波移动速度和移动方向,
code:
此处代码如下:

			float d = tex2Dlod(_MainTex, float4(v.texcoord.xy+_SpeedStrength.xy*_Time.x,0,0)).r * _Displacement;			
			v.vertex.xyz += v.normal * d;


here is the effect:
之后就可以看效果了

That is the end effect about waves.
就是本例最终实现的波形。

正题结束。
Cause of the real waves have sharper peaks and wider troughs. I try to change the sin waves.That is 1- abs(sin);  
由于真实的浪波比较尖,波谷比较宽,博主右对sin波进行了小变换。就是1-(sin的绝对值),

Then we have the waves like the figure above, that’s more better than “Just sin”.
得到了这种波形,比普通的sin波好上许多。。。。
I will gonna to try the fragment shader water wish to have a better effect.
博主会继续研究fragment shader争取得到更好的效果,(= =;开学在即,在模电的煎熬中。。。逃太多了)
The waves here is over, the surf function will write in the second blog article, maybe I will write things about the refraction.
In the end, I wish you a happy spring festival, again.
波的研究结束了,具体的着色surf函数会在(二)中详细讨论,有关折射反射等等;
最后祝大家过个愉快的春节;

                                                                       ------------------------------by wolf96 


前篇:unity3d 制造自己的水体water effect(一)

曲面细分:Unity3d 使用DX11的曲面细分

PBR:

讲求基本算法

Unity3d 基于物理渲染Physically-Based Rendering之specular BRDF

plus篇

Unity3d 基于物理渲染Physically-Based Rendering之实现
最终篇
Unity3d 基于物理渲染Physically-Based Rendering之最终篇
 

之前一直在用unity4.6写shader,终于下定决心换unity5,然后发现,unity5的渲染比4强太多,
这次完成之前2月份自制拖着没解决的normal问题,算出normal真的很简单。
本次水体分别使用两种波动算法,一个是ShaderX6 中Szecsi 和 Arman的算法,另一个是Gpu gems1里的Gerstner波算法。然后再用PBR渲染。然后还是曲面细分。
这次的效果:


Szecsi & Arman波动算法

首先来看ShaderX6 中的波动算法:
求波动速度,λ为波长,波长就是波峰到波峰之间的距离,速度v为每秒钟波峰移动的距离。
    
然后是相函数,k为波动方向,运动方向,垂直于波阵面的水平方向,p为position,t为时间(_Time.y)
 
求得一个波的位移S,a为振幅,振幅就是从水平面到波峰的高度。
 

最终我们的水是多个波组合在一起的,所以最终结果为:
    

 

 

博主整共合了4个波

关键代码如下:

                               vv = sqrt(_G * _Lambda / (2 * _PIE));
				psi = 2 * _PIE / _Lambda *(dot(v.vertex.xyz, _K.xyz) + vv*_Time.y);
				s = lerp(-cos(psi), sin(psi), _A)*0.05;
				p.y += s;
				vv = sqrt(_G * _Lambda2 / (2 * _PIE));
				psi = 2 * _PIE / _Lambda2 *(dot(v.vertex.xyz, _K2.xyz) + vv*_Time.y);
				s = lerp(-cos(psi), sin(psi), _A2)*0.05;

				p.y += s;

				vv = sqrt(_G * _Lambda3 / (2 * _PIE));
				psi = 2 * _PIE / _Lambda3 *(dot(v.vertex.xyz, _K3.xyz) + vv*_Time.y);
				s = lerp(-cos(psi), sin(psi), _A3)*0.1;

				p.y += s;

				vv = sqrt(_G * _Lambda4 / (2 * _PIE));
				psi = 2 * _PIE / _Lambda4 *(dot(v.vertex.xyz, _K4.xyz) + vv*_Time.y);
				s = lerp(-cos(psi), sin(psi), _A4)*0.1;

				p.y += s;

				v.vertex.xyz = p.xyz;</span>



 

 

 

 

产生了波动效果:




加上之前的pbr,可以模拟各种液体

牛奶

血,等等



但是由于曲面细分,离近了看水面上还是有小面的细节,这点有待解决。

Gerstner波

然后Gerstner波

 

关键代码如下:

  float wave(float x, float z, float timer)  
    {  
        float y = 0;  
        float oct = _OCT;  
        float fac = _FAC;  
        float d = sqrt(x * x + z * z);// length(float2(x, z));  
        for (oct; oct>0; oct--)  
        {  
            y -= fac * cos(timer * _SP + (1 / fac) * x * z * _WS);  
            fac /= 2;  
      
        }  
        return 2 * _VS * d * y;  
      
    }  </span>

 

 

 

曲面细分带来的小面不是很明显,而且面不用分得很细就能看到平滑的效果

normal的生成

最后我们讲讲normal的生成,
Normal的生成有复杂的和简单的,但本质上都是求偏导。
先看复杂的,来自GPU Gems1的42章
首先求出Jacobian
 




举个例子(直接截图了^ _ ^):
 
 
是不是很麻烦。。

法线本质上的求法就是这样的,但是,我们有函数:ddx,ddy这两个神器
我们只需要求出世界坐标点,worldpos
就可以简单地求出法线:
N = cross(ddx(worldpos),ddy(worldpos))
方法很简单,不过别忘记,本质上还是上面的一大串。。。
切记:ddx,ddy只能在fragment shader中使用。

只有漫反射的水体如下:

 

                            --------   by wolf96 、

 


2017-07-12 22:43:43 Kaitiren 阅读数 18211
  • Unity 值得看的500+ 技术内容列表

    Unity3D是由Unity Technologies开发的一个让玩家轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型互动内容的多平台的综合型游戏开发工具,是一个全面整合的专业游戏引擎。

背景

  在重度手游的研发过程当中,游戏中的车辆模拟,场景互动,特效展示等功能很多时候需要物理引擎的介入,以提供丰富的交互体验。目前3D手游的开发主要工具是使用Unity3D引擎,于是,如何在Unity3D的开发过程中结合入物理功能变一个需要仔细考虑的问题。

  我们考察的2种物理效果实现方案:Unity3D物理引擎和Havok物理引擎。

  Unity3d物理引擎介绍

  Unity3d在内部集成了PhysX物理引擎,为其提供了物理模拟能力。

  Physx是目前使用最为广泛的物理引擎,PhysX目前由Nvidia公司开发并维护,特点是免费且带N卡的GPU物理计算加速功能(1)。

  PhysX被很多游戏大作所采用,使用PhysX制作的游戏:


                                  

4.X版本的Unity3D集成的是2.8.3的PhysX,该版本较为老旧。在Unity5中将集成PhysX3.3,较2.8.3版本在功能和性能上有较大幅的提升,但是目前unity5并不是非常稳定。

  Havok物理引擎介绍

  Havok物理引擎是由Havok公司开发的老牌物理引擎,与PhysX不同,Havok专注于CPU端+多线程模拟方案,并且与PhysX的强大市场推广以及免费策略不同,Havok授权很严格,而且基本不提供试用版本下载(2)。

  使用Havok引擎的游戏大作在数量上与使用PhysX的不相上下,而且很多令人印象深刻:

  Unity3D物理与Havok物理的功能对比

  Unity3D集成的PhysX物理功能:

  Unity3D通过其提供的各种Component访问PhysX的物理功能,打开菜单栏中的Component->Physics便可以看到各种组件:


  其中,

  Rigidbody提供了刚体的访问接口。

  各种XXXCollider提供了3种碰撞包围体方案(Primitive,Mesh,Terrain)。

  WheelCollider组件提供了车轮模拟方案。

  XXXCloth组件提供了布料模拟方案。

  XXXJoint组件提供了关节与连接点模拟方案。

  PhysicsMaterial资源类型提供了表面物理材质描述功能。

  在Unity3D中每一种物理组件都有对应的编辑界面,且即拖即用,非常方便。