Unity 3D液体浮力实现

来源:互联网 发布:知党史,学党史,跟党走 编辑:程序博客网 时间:2024/04/27 12:05

前言

本文以unity的StandardAssets中的water资源为基础,实现物体在水中的漂浮效果。

 

 

概述

1.    建立场景并添加水详见https://docs.unity3d.com/Manual/HOWTO-Water.html

2.    给水添加碰撞体组件,编写脚本现实物体出入水的检测。

3.    创建立方体预制体,添加刚体组件,碰撞体组件,编辑脚本处理入水后的浮力计算。

 

实现细节

1.    给水体添加碰撞体

需要注意的是要勾选 Is Trigger ,y方向的范围要控制好,不然可能会出现物体掉到水面一下太多会触发OnTriggerExit() (见脚本部分)。

 

 

2.    创建立方体

我创建了一个长宽高分别为1,质量为0.5的立方体,预期效果是在水中漂浮一半露出水面。之后可以通过脚本改变大小及质量验证效果。

3.    水的脚本

水的脚本主要实现OnTriggerEnter和OnTriggerExit两个方法,当其他碰撞体进入水中,触发OnTriggerEnter,将cube中的isInWater置为ture,OnTriggerExit相反。

4.    立方体脚本

       立方体脚本的核心是calFloatage方法,计算立方体下表面与水面高度差,通过公式计算浮力,并通过Rigidbody.AddForce()方法施加浮力。

       进入水中后将阻力系数调高。

       需要注意的是物体完全进入水中后保持h = 立方体高度

5.    代码

 

using System.Collections;using System.Collections.Generic;using UnityEngine;public class Floatage : MonoBehaviour {// Use this for initializationvoid Start () {}// Update is called once per framevoid Update () {}/// <summary>/// OnTriggerEnter is called when the Collider other enters the trigger./// </summary>/// <param name="other">The other Collider involved in this collision.</param>void OnTriggerEnter(Collider other){if(other.gameObject.GetComponent<Cube>()){other.gameObject.GetComponent<Cube>().setIsInWater(true);}}/// <summary>/// OnTriggerExit is called when the Collider other has stopped touching the trigger./// </summary>/// <param name="other">The other Collider involved in this collision.</param>void OnTriggerExit(Collider other){if(other.gameObject.GetComponent<Cube>()){other.gameObject.GetComponent<Cube>().setIsInWater(false);}}}
using System.Collections;using System.Collections.Generic;using UnityEngine;public class Cube : MonoBehaviour {private bool isInWater;private GameObject water;  private float waterY;private const float floatageForce = 0;private const float density = 1;private const float g = 9.8f;private const float waterDrag = 5;public bool getIsInWater(){return isInWater;}public void setIsInWater(bool isInWater){ this.isInWater = isInWater;}// Use this for initializationvoid Start () {isInWater = false;water = GameObject.FindWithTag("water");}// Update is called once per framevoid Update () {}/// <summary>/// This function is called every fixed framerate frame, if the MonoBehaviour is enabled./// </summary>void FixedUpdate(){if(isInWater){//calculate floatagecalFloatage();//change dargGetComponent<Rigidbody>().drag = waterDrag;}}//calculate and add floatage force to the box.private void calFloatage(){waterY = water.transform.position.y;if(waterY>(transform.position.y-transform.localScale.y)){float h = waterY-(transform.position.y-transform.localScale.y/2)>transform.localScale.y? transform.localScale.y:waterY-(transform.position.y-transform.localScale.y/2);float floatageForce = density * g *transform.localScale.x*transform.localScale.z*h;GetComponent<Rigidbody>().AddForce(0,floatageForce,0);}}}


 

6.    效果

 

 

 

 

 

 

 

 

问题

1.    物体出现旋转的话要很久才能停下来,不知道调整什么阻力可以实现更加逼真的效果,或者手动实现。

      已经解决。进入水中增大angular drag即可。

 

 

 

小弟第一次写博客,才开始学习unity,望大佬们多多指教!


原创粉丝点击