Nreal Light开发-lesson 6 Nreal Light平面检测

前段时间赶ddl,没时间做项目了,现在继续。

请在完成前几讲的基础上完成本讲内容。

本次实验我们将制作一个指挥小兔子吃胡萝卜的小游戏。

一、准备工作

首先要下载一些3D素材,为以下两个链接:
兔子萝卜,添加到我的资源后,在unity中打开,再下载并导入即可。


然后通过本链接下载我们要用的素材PlaneDetectionStarterPackage.unitypackage,然后通过unity资源>导入包导入。

二、平面检测

part1

像往常一样,新建一个场景,命名为PlaneDetection,并打开。将Assets>NRSDK>Prefabs中的NRCameraRigNRInput拖入,并删除Main Camera(下图忘删了)。点击NRInput,在检查器中找到Session Config一栏,双击点开NRKernalSessionConfig,确认Plane Finding ModeImage Tracking Mode是不是都启动了(见下图)。

确认一下NRInputRaycast ModeLaser

新建一个空的GameObject,并命名为PlaneDetector,添加Component(组件),搜索Plane Detector并添加。再将Assets>PlaneDetectionStarterPackage中的WoodenPlaneVisualizer拖拽到Detected Plane Prefab处。

接着我们创建一个光标,来给小兔子引路。将Assets>PlaneDetectionStarterPackage中的Reticle Prefab拖入场景中。

接下来我们要编写一个脚本,在Assets>Scripts(这是前几讲建的一个文件夹,如果没有的话可以再建一个)中新建脚本ReticleBehaviour,代码如下:

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

public class ReticleBehaviour : MonoBehaviour
{
    public GameObject Child;
    public GameObject CurrentPlane;
    void Start()
    {
        Child = transform.GetChild(0).gameObject;
    }
    void Update()
    {
        var handControllerAnchor=NRInput.DomainHand==ControllerHandEnum.Left?ControllerAnchorEnum.LeftLaserAnchor:ControllerAnchorEnum.RightLaserAnchor;
        Transform laserAnchor = NRInput.AnchorsHelper.GetAnchor(NRInput.RaycastMode == RaycastModeEnum.Gaze ? ControllerAnchorEnum.GazePoseTrackerAnchor : handControllerAnchor);
        RaycastHit hitResult;
        if(Physics.Raycast(new Ray(laserAnchor.transform.position,laserAnchor.transform.forward),out hitResult,10))
        {
            var hit = hitResult.collider.gameObject;
            if(hit != null&&
                hit.GetComponent<NRTrackableBehaviour>()?.Trackable.GetTrackableType()==TrackableType.TRACKABLE_PLANE)
            {
                CurrentPlane= hit;
                transform.position = hitResult.point;
                Child.SetActive(true);
            }
            else Child.SetActive(false);
        }
    }
}

将上述脚本拖给Reticle Prefab
在资产中搜索Demo White Rabbit,将其拖拽到Assets>PlaneDetectionStarterPackage文件夹中。

新建一个脚本RabbitBehaviour用来控制兔子的移动,代码如下:

using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Security.Cryptography;
using System.Threading;
using UnityEngine;

public class RabbitBehaviour : MonoBehaviour
{
    public GameObject playerctrl;
    public ReticleBehaviour Reticle;
    public float Speed;
    Animator m_Animator;
    void Update()
    {
        var trackingPosition = Reticle.transform.position;
        m_Animator = gameObject.GetComponent<Animator>();
        if(Vector3.Distance(trackingPosition,transform.position)<0.2)
        {
            m_Animator.SetBool("Run", false);
            return;
        }
        m_Animator.SetBool("Run", true);
        var lookRotation = Quaternion.LookRotation(trackingPosition - transform.position);
        transform.rotation =
            Quaternion.Lerp(transform.rotation, lookRotation, Time.deltaTime * 10f);
        transform.position =
            Vector3.MoveTowards(transform.position, trackingPosition, Speed * Time.deltaTime);
    }
}

接下来设计一下兔子的动作。首先在Assets创建一个Anim文件夹,然后在文件夹内新建一个Animator Controller(动画器控制器),命名为RabbitAnim

Assets>Rabbits>Animations中的Rabbit@IdleRabbit@Run依次拖入Base Layer中。

在方块上右击,点击创建过渡,就可以将一个块和另一个块相连。我们将IdleRun相互连起来,最终效果如下图。

点击参数,点击+,选择Bool,将其重命名为Run

我们分别点击两个箭头,对触发条件进行修改。首先,取消勾选Has Exit Time(有退出时间),修改过渡持续时间,添加Conditions,参数为Run,两个箭头的值分别为truefalse,具体见下面两图(注意不要搞错了)


打开Assets>PlaneDetectionStartedPackage>DemoWhiteRabbit,然后点击检查器右上角的锁锁住(记得之后要解锁),再将Assets>Anim>RabbitAnim拖入控制器处。

在场景中新建一个空的GameObject,重命名为Rabbit Spawner,再在Assets>Scripts文件夹中创建脚本RabbitManager,脚本代码如下:

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

public class RabbitManager : MonoBehaviour
{
    public GameObject WhiteRabbit;
    public ReticleBehaviour Reticle;
    public RabbitBehaviour Rabbit;
    private GameObject LockedPlane;

    private void Update()
    {
        if(Rabbit==null && WasTapped()&&Reticle.CurrentPlane!=null) 
        {
            var obj = Instantiate(WhiteRabbit);
            Rabbit = obj.GetComponent<RabbitBehaviour>();
            Rabbit.Reticle= Reticle;
            Rabbit.transform.position=Reticle.transform.position;
        }
    }
    private bool WasTapped()
    {
        return NRInput.GetButtonDown(ControllerButton.TRIGGER);
    }
}

把上述脚本添加到RabbitSpawner中,再将Assets>PlaneDetectionStartedPackage>DemoWhiteRabbit拖入White Rabbit,将场景中的Reticle Prefab拖入Reticle

Assets>RootVegetables>Prefabs中选择一个你喜欢的萝卜拖入Assets>PlaneDetectionStartedPackage中。

Scripts中新建脚本CarrotSpawner,代码如下:(写完之后有报错是正常现象)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using NRKernal;
using NRKernal.NRExamples;
using System.Net;

public class CarrotSpawner : MonoBehaviour
{
    public CarrotBehaviour carrot;
    public GameObject CarrotPrefab;
    public ReticleBehaviour Reticle;

    public static Vector3 RandomInTriangle(Vector3 v1,Vector3 v2)
    {
        float u = Random.Range(0.0f, 1.0f);
        float v = Random.Range(0.0f, 1.0f);
        if(v+u>1)
        {
            v = 1 - v;
            u=1- u;
        }
        return (v1*u) + (v2*v);
    }
    public Vector3 FindRandomLocation(GameObject plane)
    {
        var mesh = plane.GetComponent<PolygonPlaneVisualizer>().m_PlaneMesh;
        var triangles=mesh.triangles;
        var triangle = triangles[(int)Random.Range(0,triangles.Length-1)]/3*3;
        var vertices = mesh.vertices;
        var randomInTriangle = RandomInTriangle(vertices[triangle], vertices[triangle + 1]);
        var randomPoint = plane.transform.TransformPoint(randomInTriangle);
        randomPoint.y=Reticle.CurrentPlane.GetComponent<NRTrackableBehaviour>().Trackable.GetCenterPose().position.y;
        return randomPoint;
    }
    public void SpawnGem(GameObject plane)
    {
        var gemClone = Instantiate(CarrotPrefab);
        gemClone.transform.position=FindRandomLocation(plane);
        carrot = gemClone.GetComponent<CarrotBehaviour>();
    }
    private void Update()
    {
        if(Reticle.CurrentPlane != null)
        {
            if(carrot ==null)
            {
                SpawnGem(Reticle.CurrentPlane);
            }
        }
    }
}

再新建一个脚本CarrotBehaviour,不对这个脚本写任何代码。

在资产中寻找PolygonPlaneVisualizer脚本文件,打开后,将m_PlaneMesh修改为public。改完后,回到unity,应该就没有报错了。

将这个脚本与Assets>PlaneDetectionStartedPackage中的那个萝卜关联起来。

接着创建一个空的GameObject,命名成Carrot。然后将上面创建控制脚本文件CarrotSpawner与这个Object关联,并且把萝卜模型以及Reticle的模型拖拽到对应的位置。

最后需要将下面这段代码增加到RabbitBehaviour的脚本文件中,用来实现兔子吃萝卜的简单碰撞动作,当兔子靠近萝卜后,碰撞产生,萝卜消失。

	private void OnTriggerEnter(Collider other)
    {
        var Carrot = other.GetComponent<CarrotBehaviour>();
        if(Carrot != null)
        {
            Destroy(other.gameObject);
        }
    }

对兔子模型增加Rabbit BehaviourBox ColliderRigidbody三个组件,并修改参数到合适即可。然后,对萝卜模型也增加Box Collider组件。如下图所示。

至此,就可以导出运行了。

三、额外功能

根据先前所讲的内容,我们将额外添加手势识别和录屏的功能。

1、手势控制(该功能目前存在问题,之后有时间的时候将补档)

这里,我们想要不再使用手机作为控制器,而是使用手来控制,具体操作如下:
NRInputInput Source Type改为Hands

在资产中搜索NRHand,将NRHand_LNRHand_R分别拖入NRInput中作为其中RightLeft的子对象。

2、录屏

这个比较简单,可以参考之前的文章lesson 5。这里仅做简单说明。
首先要修改Assets>Plugins>Android>AndroidManifest(如果和之前用的同一个项目可以不用改了,详情见上一讲)。
搜索RGBCamera-Record场景并拖入,复制对象VideoCaptureExample,并粘贴在PlaneDetection场景中,再将RGBCamera-Record场景移除即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值