有趣交互的场景:
弹性球的实现:
1、该球模型带有 BlendShape:可以进行变形,在手抓取时,根据按压手柄的按钮的程度,控制球的变形。
2、由于该球也是可交互的物体,因此也具有 Interactable 脚本组件
3、该球要能能被手扔出,所以具有 Throwable 脚本组件,Rigidbody 组件,Sphere Collider 组件,在sphere collider 上指定物理材质,带有弹性的材质 : Squishy 物理材质
4、在添加Throwable 脚本组件 时,自动添加VelocityEstimator 脚本组件。
VelocityEstimator 脚本组件: -------根据位置的变化估计物体的速度5、自定义脚本 : SquishyBall :用来控制弹性球的形变,以及显示其交互状态
相关组件:
如图:
- BlendeShape : 用于变形,在制作模型时导出该BlendeShape
- Rigidbody 勾选使用重力 :让其在被手扔出后受重力落地
- Sphere Collider 使用 弹性物理材质:squishy : 让它在碰撞到其他物体进行反弹
- Interactable 脚本组件 :使该物体可以交互,这个物体将获得悬停事件,并可以被附加到手上(之前已经详细介绍)
Throwable 脚本组件 :
- 使物体能被手扔出的组件,同时也是一个基类,可以继承进行扩展与重写
可设置属性:
- Attachment Flags : 该物体所属于的附加类型标志
- Atachment Offset : 作为定位和旋转偏移使用的局部坐标位置点
- Catching Speed Threshold : 该对象必须以多快的速度移动才能在按键一直按下而不是点击时将物体抓取(-1 :表示禁用)
- Release Velocity Style : 释放物体时,力的来源类型(默认:Get From Hand)
- NoChange : 没有改变,直接使用物体的原来的刚体力
- GetFromHand : 来自手的世界空间的力
- ShortEstimation : 短时预估计,根据所受的最后时刻的力来估计
- AdvancedEstimation : 高级预估,根据所受的力的最佳平均值来预测物体的受力
- Release Velocity Time Offset : 当选择力来自手时,获取力的时间偏移量
- Scale Release Velocity : 释放力的大小缩放
- Restore Original Parent : 释放时是否回到原来的父物体下
- Attach Ease In : 附着抓取物体时,是否启用缓动曲线
- Snap Attach Ease In Curve : 预设缓动曲线编辑
- Snap Attach Ease In Time : 缓动曲线持续时间
可设置事件:
- On Pick Up():在抓取上手的事件
- On Detach From Hand():在与手分离时的事件
- Snap Attach Ease In Completed : 是否发送曲线完成事件
可访问方法或属性:
- GetReleaseVelocities(Hand hand, out Vector3 velocity, out Vector3 angularVelocity) : 获取释放的速度力与角力
VelocityEstimator 脚本组件:
根据位置的变化估计物体的速度
可设置属性:
- Velocity Average Frames : 平均每多少帧计算力速度
- Angular Velocity Average Frames : 平均每多少帧计算角速度
- Estimate On Awake : 是否一开始就开始计算力
可访问的方法或属性:
- BeginEstimatingVelocity() : 一开始就开始计算力,无论该物体是否被抓取
- FinishEstimatingVelocity() : 结束抓取时,计算力
- GetVelocityEstimate() : 获取计算平均的速度力(返回 Vertor3 )
- GetAngularVelocityEstimate() : 获取计算平均的角力(返回 Vertor3 )
- GetAccelerationEstimate() : 获取计算的平均加速度(返回 Vertor3 )
自定一脚本:实现弹性球的变形与状态显示
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Valve.VR;
using Valve.VR.InteractionSystem;
public class SquishyBall : MonoBehaviour
{
public Interactable interactable; //交互组件
public new SkinnedMeshRenderer renderer; //模型的SkinnedMeshRenderer ,用来控制变形
public bool afftectMaterial; //是否变形后,调整材质
[SteamVR_DefaultAction("Squeeze")]
public SteamVR_Action_Single gripSqueeze; //握的手势操作
[SteamVR_DefaultAction("Squeeze")]
public SteamVR_Action_Single pinchSqueeze; //捏的手势操作
public TextMesh textMesh; //用于显示状态的 3D 文本
private float attachTime; //抓取的时长
private new Rigidbody rigidbody; //刚体
void Start()
{
if (interactable == null)
interactable = GetComponent();
if (renderer == null)
renderer = GetComponent();
if (rigidbody == null)
rigidbody = GetComponent();
textMesh.text = "无手悬停!";
}
void Update()
{
float grip = 0;
float pinch = 0;
if (interactable.attachedToHand)
{
grip = gripSqueeze.GetAxis(interactable.attachedToHand.handType);
pinch = pinchSqueeze.GetAxis(interactable.attachedToHand.handType);
}
renderer.SetBlendShapeWeight(0, Mathf.Lerp(renderer.GetBlendShapeWeight(0), grip * 150, Time.deltaTime * 10));
if (renderer.sharedMesh.blendShapeCount > 1)
{
renderer.SetBlendShapeWeight(1, Mathf.Lerp(renderer.GetBlendShapeWeight(1), pinch * 200, Time.deltaTime * 10));
}
if (afftectMaterial)
{
renderer.material.SetFloat("_Deform", Mathf.Pow(grip * 1.5f, 0.5f));
if (renderer.material.HasProperty("_PinchDeform"))
{
renderer.material.SetFloat("_PinchDeform", Mathf.Pow(pinch * 2.0f, 0.5f));
}
}
}
private void OnHandHoverBegin(Hand hand)
{
textMesh.text = "弹性球正被: " + hand.name + " 悬停!";
}
private void OnHandHoverEnd(Hand hand)
{
textMesh.text = "无手悬停!";
}
//-------------------------------------------------
// 当可交互物体刚被手抓取附着时,被调用一次
//-------------------------------------------------
private void OnAttachedToHand(Hand hand)
{
textMesh.text = "弹性球附着在:" + hand.name;
attachTime = Time.time;
}
//-------------------------------------------------
// 当可交互物体刚被手释放分离时,被调用一次
//-------------------------------------------------
private void OnDetachedFromHand(Hand hand)
{
textMesh.text = "弹性球从 " + hand.name + " 分离!";
}
//-------------------------------------------------
//当可交互物体刚被手一直抓取附着时,被每帧调用
//-------------------------------------------------
private void HandAttachedUpdate(Hand hand)
{
textMesh.text = "弹性球附着在:" + hand.name + "\n附着时间: " + (Time.time - attachTime).ToString("F2");
}
}