Unity平台 + Vuforia SDK实现的AR程序开发

  • 追加部分
  • 思路简介
  • 【Turret对象】CannonSystem脚本
  • 【DiskProjectile对象】Projectile脚本
  • 【MIKU对象】Target脚本
  • 碰撞触发条件
  • UI动态按钮
  • 【BUG】关于Unity编辑器除选项卡外白屏的问题
  • 接触的功能区
  • 1.Vuforia Engine,AR插件
  • 2.UI,用户界面
  • 3.Audio,音源
  • 4.Shaders,Material材质渲染方法
  • 5.MMD插件,动作编辑器
  • 6.Effects,特效
  • 7.Collider,碰撞体
  • 8.RigidBody,刚体
  • 9.TrailRenderer,尾迹渲染器
  • 10.Animation/Animator,动画系统
  • 11.Switch Platform,平台发布系统
  • 没有涉及到的功能区
  • GameObject的灵魂——2D/3D Object
  • 模型的灵魂——Animation/Animator
  • Light、Camera——光线,摄像机对象
  • Video——录像机
  • Component选项卡
  • 追加篇总结


作者写在前面的话:
没啥好说的,这个追加篇,就是……嗯应老师要求抽空再搞了搞,增加了两物体碰撞。以及尝试进入UnityUI领域。操作上还是比较简单的。理解上也没啥难点。嗯…就是需要时间还有一点运气?

追加部分

思路简介

unity ar 手势识别 unity ar ui_Collider

【Turret对象】CannonSystem脚本

主要功用:限制Turret对象射击单位次数及力,及制造炮弹对象和控制Turret对应动画

此Turret模型来源于Unity官方教程,emmm国内翻译好的视频链接在下,包含下载link
bilibili Instaco栗课 [中英双字]Unity官方教程_使用Vuforia制作AR内容01-05

由于本系列教程重点不在3D模型上面故,大多数均采用现有大佬们的模型,每个模型我均会说明出处,以及在文件中ReadMe注明模型来源官网。

简单的就不说了,前面3个篇章,该讲的基础内容已经很全面了。直接上代码

//CannonSystem脚本如其名,主要功能是生成炮弹projectile对象并给force,从炮塔口
using UnityEngine;
using UnityEngine.Events;

public class CannonSystem : MonoBehaviour 
{
	[Header("Firing Properties")]
	public float maxProjectileForce = 18000f;   //炮弹的最大力限制
	public float cooldown = 1f;                 //发射冷却时间

	[Header("Projectile Properties")]
	public GameObject projectilePrefab;			//炮弹引用接口

	Transform projectileSpawnTransform;         //炮弹物体产生的初始位置
	bool canShoot = true;
	Animator anim;								//坦克动画组件


	void Awake()
	{
		//获取坦克发射的炮弹的生成点 通过坦克对象内炮嘴路径来提供, 虽然低效但实用
		projectileSpawnTransform = GameObject.Find("Geometry/Cockpit/Turret Elevation Pivot Point/Projectile Spawn Point").transform;

		//获取坦克动画控制器
		anim = GetComponent<Animator> ();
	}

	public void FireProjectile()
	{
		if (!canShoot)
			return;
        
        //生成炮弹实例
		GameObject go = (GameObject)Instantiate(projectilePrefab, projectileSpawnTransform.position, projectileSpawnTransform.rotation);
		Vector3 force = projectileSpawnTransform.transform.forward * maxProjectileForce;    //设置力的方向
		go.GetComponent<Rigidbody>().AddForce(force);                                       //给予物理动能
        anim.SetTrigger ("Fire");                                                           //设置坦克动画为Fire状态(自动会恢复,Animator设置)

		canShoot = false;
		Invoke("CoolDown", cooldown);                                                       //延迟调用CoolDown函数
    }

	void CoolDown()
	{
		canShoot = true;
	}
}

没什么难点步骤如下

  1. 获取Turret对象的Projectile Spawn Point模型区块的位置(作为炮弹的起始位置)
  2. 获取Turret对象的动画控制器Animator
  3. Fire生成炮弹projectile对象,并给予力使其运动。
  4. 设置Turrent动画状态为Fire(可在Animator中查看Fire状态)
  5. 增加延迟调用 Invoke() 。

【DiskProjectile对象】Projectile脚本

**此脚本设置炮弹自身的设定(存续时间爆炸持续时间等)、爆炸函数(包含自毁)

//这个脚本控制着我们射击射弹的行为。 它处理爆炸力以及销毁自己
using UnityEngine;
using UnityEngine.Events;

public class Projectile : MonoBehaviour
{
	[Header("Projectile Properties")]           //UnityAPI,在Unity界面添加大标题。Public的属性均可在Unity进行修改,且永久生效。
	public float lifeTime = 2.0f;               //炮弹存在时间,为零就自动爆炸,存在时间决定运动距离
	public float explosionDuration = 3f;        //爆炸持续时间
	public float explosionForce = 100f;			//Unity的碰撞系统含有力这一定义,用于计算被碰撞物体的速度
	public float explosionRadius = 4f;			//爆炸半径
	public LayerMask targetLayerMask;           //用于确定哪些图层蒙版中的对象受爆炸影响

    [Header("Object References")]
    public GameObject body;						//炮弹的网格部分(mesh renderer)
	public GameObject explosionParticles;       //爆炸粒子系统

    Rigidbody rigidBody;                        //炮弹的刚体
    Collider sphereCollider;					//炮弹的碰撞体
    bool exploded;								//是否爆炸


    void Awake()
    {
        //获取碰撞体和刚体的引用
        sphereCollider = GetComponent<Collider> ();
		rigidBody = GetComponent<Rigidbody>();
    }

	void Update()
	{
		//随时间减少炮弹存在时间
		lifeTime -= Time.deltaTime;
		//炮弹时间为0,自动爆炸
		if (lifeTime <= 0f)
		{
			Explode();
		}
        Debug.Log("炮弹自动爆炸,自毁结束");
    }

    void OnCollisionEnter( Collision collision )
    {
		//Unity提供的碰撞监测函数,当碰撞时,爆炸
		Explode();

        //尝试从炮弹击中的物体中获取目标脚本
        Target target = collision.gameObject.GetComponent<Target>();

		//如果从被炮弹碰撞到的物体中获取到脚本,则调用这个脚本的Hit函数
		if ( target != null )
			target.Hit();
        Debug.Log("获取到目标脚本Hit函数,碰撞结束");
    }

    void Explode()
    {
		//如果爆炸标识为已爆炸,则返回空(即是一个炮弹只能炸一回)要么是存在时间=0炸,要么是碰撞炸
        if (exploded) 
			return;
        //调用该函数即标识为已爆炸
		exploded = true;
        //禁用炮弹的所有组件,渲染器,碰撞器,刚体,脚本(Update)
		body.SetActive( false );
        rigidBody.isKinematic = true;           //运动学,力、碰撞或关节将不再影响刚体
        sphereCollider.enabled = false;         //碰撞关闭

		//开启爆炸粒子特效
		explosionParticles.SetActive(true);
		
		//获取,所有在爆炸半径并且在设定的影响图层中的碰撞体组
		Collider[] colliders = Physics.OverlapSphere(transform.position, explosionRadius, targetLayerMask);
		//循环操作获取到的碰撞体组
		for (int i = 0; i < colliders.Length; i++)
		{
			//获取某一碰撞体
			Rigidbody rb = colliders[i].GetComponent<Rigidbody>();
			//以爆炸力使物体起飞(位移)
			rb.AddExplosionForce(explosionForce, transform.position, explosionRadius, 2f);
		}
		Destroy(gameObject, explosionDuration); //在爆炸持续时间结束后,销毁炮弹
        Debug.Log("炮弹销毁,爆炸结束");
    }
}

两个重要函数
void OnCollisionEnter( Collision collision ) 这个函数是Unity内置碰撞检测函数,主要用途是,当Projectile对象碰撞到其他碰撞体后进行的操作。操作内容为:projectile物体调用自身的explode函数,然后获取Miku对象下Targe脚本,调用Target.Hit()函数令Miku自毁。
void Explode() 炮弹爆炸函数,将炮弹对象的所有组件关闭,即不再显示炮弹。再开启爆炸粒子特效,获取爆炸半径内提前设定被影响图层的碰撞体组,然后循环操作获取到的碰撞体组对象,以爆炸力来驱使碰撞组对象移动。执行完循环后炮弹对象自毁。

【MIKU对象】Target脚本

没东西。只是为了销毁自身

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Target : MonoBehaviour
{
	public float timeAfterHit = .5f;		//被碰撞后与消失间隔
	public void Hit()
	{
		Destroy(gameObject, timeAfterHit);
	}  
}

碰撞触发条件

1 碰撞双方必须都有Collider组件
2 碰撞的主动方必须有Rigidbody组件
3 刚体不能勾选IsKinematic
4 碰撞体不能够勾选IsTigger

相关概念:Collider Rigidbody 碰撞检测等

UI动态按钮

应用到Sprite精灵2D图形对象。主要功能是在一张大图中去截取一部分成为一个小精灵对象,然后给小精灵命名,通过精灵名称就能在场景中直接使用。其次,sprite还可以用来制作动画。将导入的图片类型设置为Sprite可直接拖到场景面板里,并带有随屏幕大小自动缩放功能,还可以加Collider进行射线检测。总的来说,Sprite2D图形对象是一个十分便捷的功能。
动态功能实现是由——Btn_Option动画控制器。动态体现为按钮向右平移并回复到初始位置及颜色进行更改(颜色更改是由Transition——Sprite Swap实现的)

【BUG】关于Unity编辑器除选项卡外白屏的问题

可能因素:你的显存崩了,
解决方法:改用以集成图形(图形处理器)启动就不会出现此问题 / 选项卡——重置布局
现象:我双开Unity使用高性能图形处理器再加谷歌浏览器多开页面,就会出现浏览器白屏+Unity白屏。emmm

接触的功能区

总结一下这个项目接触到的功能模块,并附加复杂性排序

1.Vuforia Engine,AR插件

安装时勾选选项获取的Unity编辑器AR插件,给与开发者GameObject选项卡下增加Vuforia Engine物体集群。

Vuforia Engine物体集群

主要分两大类,第一个目标:单图目标,六面体多图目标,圆柱形目标,二维码目标,模型目标等。第二个辅助:3D扫描快速建模,地平线、中空识别并依托其构建AR对象。AR Camera为AR应用必备的组件,取代默认Camera。

unity ar 手势识别 unity ar ui_Unity_02


VirtualButton增强现实按钮

是ImageTarget物体的ImageTargetBehaviour提供的。【Add V B】模拟出人类在现实空间中触碰按钮的行为(当然现在的实现原理只是简单的图像碰撞域的识别)

unity ar 手势识别 unity ar ui_Collider_03

2.UI,用户界面

Canvas画布
Canvas是所有UI Component的父节点没错是最基础的节点,用于提供渲染着色显示等背景。在这里主要是承载Vuforia VB的图像Image和文本Text。
Image图像组件
按钮的蓝色,按钮的红色,其实是图片的切换。
Text文本组件
按钮的文字显示。

3.Audio,音源

Audio Source音源组件
在本程序中,主要是用于物体被跟踪发现时和物体跟踪消失时(这是ImageTarget下Default Trackable Event脚本设置的)开启进场声源,退场声源。以及DanceVB被触碰后开启背景音乐(其实这个在MIku物体的Animator是可以设置且正常播放的,但我可惜不行,不知道原因,后来为了在Android端进行开发后从Animator动画系统转为了Animation动画系统也就没有背景音乐设定的地方了)。

4.Shaders,Material材质渲染方法

Shaders渲染是在Miku模型从Windows平台转换到Android平台时遇到的,原因是Android端不支持MMD渲染方式,需要选择Mobile材质渲染方式。

5.MMD插件,动作编辑器

mmd只是一个动作编辑器,并不能制作模型或是编辑模型,也就是要在已有的模型基础上,自动化编辑产生一系列动作按时间顺序——>动画。而且……emmm不管是模型还是插件都是有版权的,hhhh慎用。先了解一下规则。建议用国外的模型。

6.Effects,特效

本程序引入了一个自发光Effects包,用于MIKU模型的自发光特效,主要是区别被射线法选定前后的区别。还有炮弹引入的爆炸粒子(Particle System)特效。

unity ar 手势识别 unity ar ui_Unity_04

7.Collider,碰撞体

在本应用中主要是用于,坦克产生的炮弹碰撞MIKU模型完成一次碰撞,然后调用Miku模型挂载的Target脚本中的Hit函数,进行MIku对象销毁Destroy()。

8.RigidBody,刚体

这个是构成碰撞行为的必要条件之一。刚体是启用一个物体物理行为的主要组件。一旦附加刚体组件,物体将受重力影响。如果刚体附加了Collider,则可以检测碰撞。 刚体可以接受力和扭矩,但Transform不能。

9.TrailRenderer,尾迹渲染器

创建材质球,添加材质,并修改shaders渲染器方法。

10.Animation/Animator,动画系统

在Miku模型动画设置的时候涉及过一点点,嗯,就是简单的文件拖拽。哈哈哈哈

11.Switch Platform,平台发布系统

安卓平台需要下载其配套的发布功能包,你只需要安装到Unity根目录后,选择安卓平台Building即可,苹果/主机等等都是如此操作,哎,真的是太方便了,以至于我都忘记有这个东西了。优秀的厂商在不断进步,减低开发者的成本,真的是令人喜爱。
也就是说你使用Unity平台开发安卓程序,不需要懂任何的Android知识,嘻嘻嘻unityNB

没有涉及到的功能区

GameObject的灵魂——2D/3D Object

模型这个方面基本是拿来主义,也没有细细深入,不过我觉得这个是大坑…告辞

模型的灵魂——Animation/Animator

动画系统和模型一样粗略的有了解,但不全面也不精细,简单的使用还是会一点。制作完不动的模型,那么就是怎么让模型动起来,欸……又一个大坑。告辞

Light、Camera——光线,摄像机对象

emmm这个地方,涉及的不多,细节了解的更不多,只有射线法选中对象试验过。光是一点没涉及过。

Video——录像机

emmm完全没用过。

Component选项卡

unity ar 手势识别 unity ar ui_Collider_05


告辞

追加篇总结

一直没搞懂,那个PlayOnStateChange脚本到底,怎么能够在其他文件夹下引入到Vuforia工程来,而不需要将这个脚本放到Vufoira/Script/目录下。emmm……恼火
还有关于追加的代码就不更新了,如果有需要评论留言吧,或者私聊。因为我需要修改下目标识别数据库,懒得改了,就不commit了。