AR开发实战Vuforia项目之太阳系八大行星(实现涂涂乐功能)

一、框架视图

二、主要代码

Shader "Color/Special" (传说会写shader是大神)

Shader "Color/Special" {
//Shader的路径和名称
    Properties {
    //材质属性面板中所显示的Shader属性面板
        _MainTex ("Base (RGB)", 2D) = "white" {}
        //"_MainTex"在Shader中调用时所使用的名称
        //"Base (RGB)"在面板中显示的名称
        //"2D"2D纹理
        //"white"给这个属性的默认值

        //从C#中获取截图时 识别图四个点世界坐标
        _Uvpoint1("point1", Vector) = (0 , 0 , 0 , 0)
        //"_Uvpoint1"在Shader中调用时所使用的名称
        //"point1"在面板中所显示的名称
        //Vector 四个浮点数组成的类型 
        //"0 , 0 , 0 , 0"附的初始值
        _Uvpoint2("point2", Vector) = (0 , 0 , 0 , 0)
        _Uvpoint3("point3", Vector) = (0 , 0 , 0 , 0)
        _Uvpoint4("point4", Vector) = (0 , 0 , 0 , 0)

    }

    //“ SubShader”着色器方案 在Shader中至少有一个SubShader 显卡每次只选择一个SubShader 如果当前硬件不支持这个SubShader 就会选择一个针对较旧的硬件的SubShader
    SubShader {
        Tags { "Queue"="Transparent" "RenderType"="Transparent" }
        //加入透明渲染处理,没有这一段的话赋值透明贴图时就会出现问题。
        LOD 200
        //细致程度   Level of Details 也叫作 Level of Development
        //"200"是一个代号 限制Shader的级别到200为止

        Pass{
            Blend SrcAlpha OneMinusSrcAlpha
            //加入Alpha的混合渲染  不加的话Alpha值无用
            CGPROGRAM
            //CG开始的关键词
            #pragma vertex vert
            //编译指令 顶点程序
            #pragma fragment frag
            //编译指令 片段程序
            #include "UnityCG.cginc"
            //"UnityCG.cginc" 是使用unity中带的封装好的cg代码集合
            //有点类似于C#中命名空间的引用

            //C#中传递来的值的引用
            sampler2D _MainTex;
            float4 _MainTex_ST;
            float4 _Uvpoint1;
            float4 _Uvpoint2;
            float4 _Uvpoint3;
            float4 _Uvpoint4;
            float4x4 _VP;
            //C#在截取图像时 世界坐标到摄像机坐标以及相机坐标到屏幕坐标的两个矩阵值相乘

            //结构体 
            struct v2f {
                float4  pos : SV_POSITION;
                float2  uv : TEXCOORD0;
                float4  fixedPos : TEXCOORD2;
            } ;

            //顶点程序和片段程序中用来计算UV的匹配和最护模型效果的渲染
            v2f vert (appdata_base v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
                o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                
                float4 top = lerp(_Uvpoint1, _Uvpoint3, o.uv.x);
                float4 bottom = lerp(_Uvpoint2, _Uvpoint4, o.uv.x);
                float4 fixedPos = lerp(bottom, top, o.uv.y);
                o.fixedPos = ComputeScreenPos(mul(UNITY_MATRIX_VP, fixedPos));
                return o;
            }
            float4 frag (v2f i) : COLOR
            {
                
                float4 top = lerp(_Uvpoint1, _Uvpoint3, i.uv.x);
                float4 bottom = lerp(_Uvpoint2, _Uvpoint4, i.uv.x);
                float4 fixedPos = lerp(bottom, top, i.uv.y);
                fixedPos = ComputeScreenPos(mul(_VP, fixedPos));
                return tex2D(_MainTex, fixedPos.xy / fixedPos.w);
                
            }
            ENDCG
            //CG结束的关键词
            //释放内存 
        }
    }
    //FallBack "Diffuse"
}

AudioPlay

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

public class AudioPlay : MonoBehaviour {

    //定义一条射线的类型;
    private Ray ray;

    //定义一个射线碰撞信息的存贮;
    private RaycastHit hit;//类型: 射线检测碰撞(信息存贮)

    //播放地球的声音
    //private AudioSource mAudioSource;
    //public AudioSource earthAudioSource;
    //public AudioSource sunAudioSource;

    //将所有便签放进去
    public AudioSource[] mAudioSource;
    //贮存名称;
    //string strName;

    //贮存便签
    int intTag;

    //贮存太阳系的,太阳系消失,所有配音不播放;
   // public GameObject SolarSystem;
    void Start () {
        
    }
    

    void Update () {
        //执行射线的方法;
        CameraSendRay();
        //判断太阳系隐藏,所有声音都停止;
        //if (SolarSystem.activeInHierarchy==false)
        //{
        //    sunAudioSource.Stop();
        //    earthAudioSource.Stop();
        //}
    }
    //----------------------------------------------------------------
    /// <summary>
    ///执行播放声音的方法; 
    /// </summary>
    //void CameraSendRay() //第一种方法
    //{
    //    if (Input.GetMouseButtonDown(0)) //点击屏幕
    //    {
    //        ray = Camera.main.ScreenPointToRay(Input.mousePosition); //射线的位置就是鼠标点击的位置
    //        if (Physics.Raycast(ray, out hit))  //获取射线碰撞信息
    //        {
    //            strName = hit.transform.name;
    //            Debug.Log(strName);
    //            switch (strName) //分别播放不同声音的信息
    //            {
    //                case "Earth_A":
    //                    if (sunAudioSource.isPlaying)
    //                    {
    //                        sunAudioSource.Stop();
    //                    }
    //                    earthAudioSource.Play();
    //                    break;
    //                case "Sun_Modle":
    //                    if (earthAudioSource.isPlaying)
    //                    {
    //                        earthAudioSource.Stop();
    //                    }
    //                    sunAudioSource.Play();
    //                    break;
    //                default:
    //                    break;
    //            }
    //        }
    //    }
    //}
    //----------------------------------------------------------------

    /// <summary>
    ///执行播放声音的方法; 
    /// </summary>
    void CameraSendRay() //第二种方法
    {
        if (Input.GetMouseButtonDown(0)) //点击屏幕
        {
            ray = Camera.main.ScreenPointToRay(Input.mousePosition); //射线的位置就是鼠标点击的位置
            if (Physics.Raycast(ray, out hit))  //获取射线碰撞信息
            {
               intTag =int.Parse(hit.transform.tag);
                //Debug.Log(intTag);
                //mAudioSource[intTag].Play();
                for (int i = 0; i < mAudioSource.Length; i++)
                {
                    if (mAudioSource[i].isPlaying && i != intTag)
                    {
                        mAudioSource[i].Stop();
                    }
                    else
                    {
                        mAudioSource[intTag].Play();
                    }
                }
            }
        }
    }


    /// <summary>
    /// 停止所有播放音乐的方法 第一种方法
    /// </summary>
    //public void StopAudioPlay() {
    //    sunAudioSource.Stop();
    //    earthAudioSource.Stop();
    //}

    /// <summary>
    /// 停止所有播放音乐的方法 第二种方法
    /// </summary>
    public void StopAudioPlay()
    {
        for (int i = 0; i < mAudioSource.Length; i++)
        {
                mAudioSource[i].Stop();
        }
    }



}

EarthInSunA

using UnityEngine;
using System.Collections;

public class EarthInSunA : MonoBehaviour
{

    public GameObject Earth;
    //保存地球
    public GameObject SolarSystem;
    //保存太阳系

    //地球显示的标志位
    private bool isShow = false; 

    // Use this for initialization
    void Start()
    {
        //赋值给声效
        //mAudioSource = gameObject.transform.GetComponent<AudioSource>();
    }

    // Update is called once per frame
    void Update()
    {
     
    }

    void OnMouseDown()
    {
        if (isShow)
        {
            //Earth.GetComponent<Renderer>().enabled = true;
            Earth.SetActive(true);
            //激活地球渲染组件
            Earth.GetComponent<ScreenShot>().EarthFrame.SetActive(true);
            //通过截图脚本中地球仪配件的变量 来激活地球仪配件的显示
            //Earth.GetComponent<EarthTouchA>().SetState = 0;
            Earth.GetComponent<EarthTouchA>().SetState = 0;
            //将点击交互的状态设置为0
            GameObject.Find("Sun").SendMessage("StopAudioPlay");
           // Debug.Log("有没有发送方法------------------");
            SolarSystem.SetActive(false);
            //取消太阳系的显示
        }
        isShow = !isShow;
    }

    
}


EarthTouchA

using UnityEngine;
using System.Collections;
using UnityEngine.UI; //引用命名空间

public class EarthTouchA : MonoBehaviour
{

    public GameObject EarthFrame;
    //储存地球仪配件

    public GameObject SolarSystem;
    //储存太阳系模块

    public int SetState = 0;
    //申请Int型变量来储存点击的次数

    //public Image UIArea;
    //扫描框隐藏

    void Start()
    {

    }


    void Update()
    {
       // if (SetState==1||SetState==2)
        if (SetState == 1 || SetState == 2)
        {
            //当第一次点击状态或第二次点击状态时
            transform.Rotate(0, 25 * Time.deltaTime, 0, Space.Self);
            //让地球沿着自身Y轴转动
        }
    }

    //点击函数
    void OnMouseDown()
    {
        //if(SetState==0)
        if (SetState == 0)
        {
           // SetState = 1;
            //设置为状态1
            // gameObject.SetActive(true);
           // UIArea.enabled = false;

        }
        else if (SetState == 1)
            //else if(SetState==1)
        {
            //SetState = 2;
            //状态设置为2
           // gameObject.SetActive(true);
            EarthFrame.SetActive(false);
            //取消地球仪配件

        }
        else if (SetState == 2)
            //else if(SetState==2)
        {
           // SetState = 3;
            //状态设置为3
            //gameObject.GetComponent<Renderer>().enabled = false;
            gameObject.SetActive(false);
            //取消地球的显示,此处仅仅是渲染方式上不渲染,而不取消模型的激活状态
            SolarSystem.SetActive(true);
            //显示太阳系
        }
        //else if (SetState == 13)
        //{
        //    // SetState = 0;
        //    SetState = -1;
        //    //状态设置为0
        //    // gameObject.GetComponent<Renderer>().enabled = true;
        //    gameObject.SetActive(true);
        //    //显示地球
        //    EarthFrame.SetActive(true);
        //    //显示地球仪配件
        //    SolarSystem.SetActive(false);
        //    //取消太阳系的显示
        //}
        SetState++;
    }

    /// <summary>
    /// 通过发送方法调用次函数,不过已经禁用了,没成功
    /// </summary>
    public void ResetAgain() {
        SetState = 0;
        //状态设置为0
        // gameObject.GetComponent<Renderer>().enabled = true;
        gameObject.SetActive(true);
        //显示地球
        EarthFrame.SetActive(true);
        //显示地球仪配件
        SolarSystem.SetActive(false);

    }


}


PageNotFound //脱卡

using UnityEngine;
using Vuforia;
public class PageNotFound : MonoBehaviour, ITrackableEventHandler
{
    //引用
    private TrackableBehaviour mTrackableBehaviour;
    public Transform Target;//识别物
    Vector3 imgPos = new Vector3(0, 0, 0);//识别图上的位置
    Vector3 camPos = new Vector3(0, -3f, 100f);//脱卡后在屏幕中的位置
                                                //这俩值,具体多少得自己调,模型尺寸、重心不同

    bool isFirstTime = true; //第一查找

    public GameObject sun;
    //控制太阳大小
    void Start()
    {
        mTrackableBehaviour = GetComponent<TrackableBehaviour>();
        if (mTrackableBehaviour)
        {
            //重置
            mTrackableBehaviour.RegisterTrackableEventHandler(this);
        }
        // Target.GetComponent<MeshRenderer>().enabled = false;//起始时不显示
        Target.gameObject.SetActive(false);

    }


    //接口实现 公开的
    public void OnTrackableStateChanged(
            TrackableBehaviour.Status previousStatus,
            TrackableBehaviour.Status newStatus)
    {
        if (newStatus == TrackableBehaviour.Status.DETECTED ||
                newStatus == TrackableBehaviour.Status.TRACKED ||
                newStatus == TrackableBehaviour.Status.EXTENDED_TRACKED)
        {
            //视野内发现识别图时
            //Target.GetComponent<MeshRenderer>().enabled = true;
            Target.gameObject.SetActive(true);
            Target.parent = this.transform;
            Target.localPosition = imgPos;
            Target.localRotation = Quaternion.identity;
            //Target.localRotation = Quaternion.Euler(90, 0, 0);
            isFirstTime = false;
        }
        else
        {
            //视野内没有识别图时,这里我是把位置和旋转都归零了,如果不做处理,可以
            if (!isFirstTime)
            {
                // Target.parent = Camera.main.transform;
                Target.parent = GameObject.FindGameObjectWithTag("MainCamera").transform;
                Target.localPosition = camPos;
                //Target.localRotation = Quaternion.identity;
                Target.localRotation = Quaternion.Euler(-30, 0, 0);
                //Debug.Log("3333333333333");

                //控制太阳大小
                sun.GetComponent<ParticleScaler>().particleScale = 1f;
            }
        }
    }
}

Sun_Rotate

using UnityEngine;
using System.Collections;

public class Sun_Rotate : MonoBehaviour {

    public float speed=8.0f;

    // Use this for initialization
    void Start () {
    
    }
    
    // Update is called once per frame
    void Update () {
        transform.Rotate(0,speed*Time.deltaTime,0,Space.Self );
    }
}

Area

//命名空间
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
//加入UI命名空间

public class Area : MonoBehaviour
{
    //"Area"类名 ,需要和外部脚本名称保持一致
    public GameObject SuccessPlane_Image;
    //储存识别成功图片
    public GameObject Scan_Image;
    //将用于隐藏扫描框
    public GameObject Earth;
    //储存地球模型
    public Material Green_Mate;
    //申请材质变量储存绿色的材质
    public Material Red_Mate;
    //申请材质变量储存红色材质
    public Material Tran_Mate;
    //申请材质变量储存透明材质

    private bool HasRe = false;
    //申请布尔变量来确定是否已经识别
    private CanvasScaler CanS;
    //申请变脸储存UI屏幕自适度的缩放组件

    private float X_Sc;
    //申请浮点型类型的变量储存实际的缩放比例

    //记录扫描框的范围
    private Vector2 TopLeft_UI;
    //记录扫描框左上角的坐标
    //“private”申请类型为私有
    private Vector2 BottomLeft_UI;
    //记录扫描框左下角的坐标
    private Vector2 TopRight_UI;
    //记录扫描框右上角的坐标
    private Vector2 BottomRight_UI;
    //记录扫描框右下角的坐标

    //记录面片的世界坐标
    private Vector3 TopLeft_Pl_W;
    //记录面片左上角的世界坐标
    private Vector3 BottomLeft_Pl_W;
    //记录面片左下角的世界坐标
    private Vector3 TopRight_Pl_W;
    //记录面片右上角的世界坐标
    private Vector3 BottomRight_Pl_W;
    //记录面片右下角的世界坐标

    //记录面片的屏幕坐标
    private Vector2 TopLeft_Pl_Sc;
    //记录面片左上角的屏幕坐标
    private Vector2 BottomLeft_Pl_Sc;
    //记录面片坐下角的屏幕坐标
    private Vector2 TopRight_Pl_Sc;
    //记录面片右上角的屏幕坐标
    private Vector2 BottomRight_Pl_Sc;
    //记录面片右下角的屏幕坐标

    private Vector2 PlaneWH;
    //记录面片的宽高


    //脚本刚开始运行的时候调用一次
    void Start()
    {

        CanS = GameObject.Find("Canvas").gameObject.GetComponent<CanvasScaler>();
        //获取控制屏幕自适度的组件

        X_Sc = Screen.width / CanS.referenceResolution.x;
        //获取实际的缩放比例

        //计算了扫描框四个点的坐标位置,“*X_Sc"是屏幕自适度的缩放比例,这样才能获取真正运行时UI图片的宽高
        TopLeft_UI = new Vector2(Screen.width - 400 * X_Sc, Screen.height + 300 * X_Sc) * 0.5f;
        //给扫描框左上角的坐标赋值
        //"Screen.width-400,Screen.height+300" 屏幕的宽度减去扫描框的宽度,屏幕的高度减去扫描框的高度
        BottomLeft_UI = new Vector2(Screen.width - 400 * X_Sc, Screen.height - 300 * X_Sc) * 0.5f;
        //给扫描框左下角的坐标赋值
        TopRight_UI = new Vector2(Screen.width + 400 * X_Sc, Screen.height + 300 * X_Sc) * 0.5f;
        //给扫描框右上角的坐标赋值
        BottomRight_UI = new Vector2(Screen.width + 400 * X_Sc, Screen.height - 300 * X_Sc) * 0.5f;
        //给扫描框右下角的坐标赋值

        PlaneWH = new Vector2(gameObject.GetComponent<MeshFilter>().mesh.bounds.size.x * 50 * 0.1f, gameObject.GetComponent<MeshFilter>().mesh.bounds.size.z * 50 * 0.0646f) * 0.5f;
        //获取面片的宽高的一半
        //"gameObject.GetComponent<MeshFilter>().mesh.bounds.size.x"获取面片X方向的宽度
        //"*5"是因为开始获取到的长宽是模型本身的长宽,而场景中我们有缩放因素,父级物体放大了50倍,自身缩小到了0.1,因此获取实际宽高需要再乘以5
    }

    //每一帧都调用
    void Update()
    {      
        //获取面片四个点的世界坐标
        TopLeft_Pl_W = gameObject.transform.parent.position + new Vector3(-PlaneWH.x, 0, PlaneWH.y);
        //获取面片左上角的世界坐标
        //"gameObject.transform.parent.position"物体的父级物体的世界坐标
        //"new Vector2 (-PlaneWH.x,PlaneWH.y)"向左上方偏移的量
        BottomLeft_Pl_W = gameObject.transform.parent.position + new Vector3(-PlaneWH.x, 0, -PlaneWH.y);
        //获取面片左下角的世界坐标
        TopRight_Pl_W = gameObject.transform.parent.position + new Vector3(PlaneWH.x, 0, PlaneWH.y);
        //获取面片右上角的世界坐标
        BottomRight_Pl_W = gameObject.transform.parent.position + new Vector3(PlaneWH.x, 0, -PlaneWH.y);
        //获取面片右下角的世界坐标


        //获取面片的屏幕坐标
        TopLeft_Pl_Sc = Camera.main.WorldToScreenPoint(TopLeft_Pl_W);
        //获取面片左上角的屏幕坐标
        //Camera.main.WorldToScreenPoint(Vector3()); 将世界坐标转化为屏幕坐标
        BottomLeft_Pl_Sc = Camera.main.WorldToScreenPoint(BottomLeft_Pl_W);
        //获取面片左下角的屏幕坐标
        TopRight_Pl_Sc = Camera.main.WorldToScreenPoint(TopRight_Pl_W);
        //获取面片右上角的屏幕坐标
        BottomRight_Pl_Sc = Camera.main.WorldToScreenPoint(BottomRight_Pl_W);
        //获取面片右下角的屏幕坐标

        //判断面片是否在扫描框范围内
        if (TopLeft_Pl_Sc.x > TopLeft_UI.x && TopLeft_Pl_Sc.y < TopLeft_UI.y && BottomLeft_Pl_Sc.x > BottomLeft_UI.x && BottomLeft_Pl_Sc.y > BottomLeft_UI.y && TopRight_Pl_Sc.x < TopRight_UI.x && TopRight_Pl_Sc.y < TopLeft_UI.y && BottomRight_Pl_Sc.x < BottomRight_UI.x && BottomRight_Pl_Sc.y > BottomRight_UI.y)
        {
            //当面片完全处于扫描框范围内时 执行以下代码
            if (HasRe == false)
            {
                //如果尚未识别
                gameObject.GetComponent<Renderer>().material = Green_Mate;
                //将脚本所附着的物体(面片)的材质变为绿色材质
                StartCoroutine("SuccessUI");
                //调用显示识别成功图片的延迟函数
                StartCoroutine("ScreenShot");
                //调用截图的延迟函数
                HasRe = true;
                //已经识别
            }

        }
        else
        {
            //当面片并非完全处于扫描框范围内时  执行以下代码
            gameObject.GetComponent<Renderer>().material = Red_Mate;
            //将脚本所附着的物体(面片)的材质变为红色材质
            HasRe = false;
            //识别状态设置为未识别
        }



    }

    //显示识别成功图片的延迟函数
    IEnumerator SuccessUI()
    {
        yield return new WaitForSeconds(0.5f);
        //延迟0.5秒
        SuccessPlane_Image.SetActive(true);
        //激活提示识别成功的图片
        gameObject.GetComponent<Renderer>().material = Tran_Mate;
        //给面片材质赋值为透明材质,出去截图时的影响
        Scan_Image.SetActive(false);
        //识别成功后隐藏扫描框;
    }

    //截图的延迟函数
    IEnumerator ScreenShot()
    {
        yield return new WaitForSeconds(2.0f);
        //延迟2秒
        if (HasRe == true)
        {
            //当处于识别状态的时候才执行截图函数
            gameObject.GetComponent<Renderer>().material = Tran_Mate;
            //给面片材质赋值为透明材质,出去截图时的影响
            Earth.GetComponent<ScreenShot>().ScreenShot_Button();
            //调用地球模型上截图脚本的截图函数
        }
    }
}

ResetExitUI

using UnityEngine;
using System.Collections;

public class ResetExitUI : MonoBehaviour {

    // Use this for initialization
    void Start () {
    
    }
    
    // Update is called once per frame
    void Update () {
    
    }

    /// <summary>
    /// 退出游戏的方法
    /// </summary>
    public void QuitUI(){
        //点击退出按钮 退出页面
        Application.Quit ();
        //退出app
    }

    /// <summary>
    /// 重置游戏方法
    /// </summary>
    public void ResetUI() {
        GameObject.Find("Earth_A").SendMessage("OnMouseDown");
    }
}

ScreenShot

using UnityEngine;
using System.Collections;

public class ScreenShot : MonoBehaviour
{
    public GameObject Earth;
    //申请公有变量储存要赋予贴图的模型
    public GameObject EarthFrame;
    //储存地球仪配件模型
    public GameObject EarthA;
    //储存太阳系中的地球
    //地球公开的引用
    public GameObject PlaneA;
    public GameObject PlaneB;
    //储存面片B

    private int ScreenWidth;
    //申请私有int型变量 记录屏幕的宽
    private int ScreenHeight;
    //申请私有int型变量 记录屏幕的高
    private Texture2D TextureShot;
    //申请Texture2D型变量 用来储存屏幕截图

    private Vector2 PlaneWH;
    //记录面片的宽高

    //记录面片的世界坐标
    private Vector3 TopLeft_Pl_W;
    //记录面片左上角的世界坐标
    private Vector3 BottomLeft_Pl_W;
    //记录面片左下角的世界坐标
    private Vector3 TopRight_Pl_W;
    //记录面片右上角的世界坐标
    private Vector3 BottomRight_Pl_W;
    //记录面片右下角的世界坐标

    // Use this for initialization
    void Start()
    {
        ScreenWidth = Screen.width;
        //获取屏幕的宽
        ScreenHeight = Screen.height;
        //获取屏幕的高

        TextureShot = new Texture2D(ScreenWidth, ScreenHeight, TextureFormat.RGB24, false);
        // 标准格式 : Texture2D(int width,int height,TextureFormat format,bool mipmap);
        // “int width,int height,” 纹理的宽高
        //"TextureFormat format" 纹理的模式 RGB24 RGBA32等模式 
        //"bool mipmap"mipmap是一种分级纹理  在屏幕中显示大小不同时候给予不同级别的纹理 这里不使用

    }

    // Update is called once per frame
    void Update()
    {

    }

    public void ScreenShot_Button()
    {

        PlaneWH = new Vector2(PlaneB.GetComponent<MeshFilter>().mesh.bounds.size.x, PlaneB.GetComponent<MeshFilter>().mesh.bounds.size.z) * 5 * 0.5f;
        //获取面片的宽高的一半
        //"gameObject.GetComponent<MeshFilter>().mesh.bounds.size.x"获取面片X方向的宽度
        //"*5"是因为开始获取到的长宽是模型本身的长宽,而场景中我们有缩放因素,父级物体放大了50倍,自身缩小到了0.1,因此获取实际宽高需要再乘以5

        //获取面片四个点的世界坐标
        TopLeft_Pl_W = PlaneB.transform.parent.position + new Vector3(-PlaneWH.x, 0, PlaneWH.y);
        //获取面片左上角的世界坐标
        //"gameObject.transform.parent.position"物体的父级物体的世界坐标
        //"new Vector2 (-PlaneWH.x,PlaneWH.y)"向左上方偏移的量
        BottomLeft_Pl_W = PlaneB.transform.parent.position + new Vector3(-PlaneWH.x, 0, -PlaneWH.y);
        //获取面片左下角的世界坐标
        TopRight_Pl_W = PlaneB.transform.parent.position + new Vector3(PlaneWH.x, 0, PlaneWH.y);
        //获取面片右上角的世界坐标
        BottomRight_Pl_W = PlaneB.transform.parent.position + new Vector3(PlaneWH.x, 0, -PlaneWH.y);
        //获取面片右下角的世界坐标

        //将截图时识别图四个角的世界坐标信息传递给Shader
        Earth.GetComponent<Renderer>().material.SetVector("_Uvpoint1", new Vector4(TopLeft_Pl_W.x, TopLeft_Pl_W.y, TopLeft_Pl_W.z, 1f));
        //将左上角的世界坐标传递给Shader ,其中1f是否了凑齐四位浮点数 ,用来进行后续的矩阵变换操作
        Earth.GetComponent<Renderer>().material.SetVector("_Uvpoint2", new Vector4(BottomLeft_Pl_W.x, BottomLeft_Pl_W.y, BottomLeft_Pl_W.z, 1f));
        Earth.GetComponent<Renderer>().material.SetVector("_Uvpoint3", new Vector4(TopRight_Pl_W.x, TopRight_Pl_W.y, TopRight_Pl_W.z, 1f));
        Earth.GetComponent<Renderer>().material.SetVector("_Uvpoint4", new Vector4(BottomRight_Pl_W.x, BottomRight_Pl_W.y, BottomRight_Pl_W.z, 1f));

        //将截图时识别图四个角的世界坐标信息传递给Shader
        EarthFrame.GetComponent<Renderer>().material.SetVector("_Uvpoint1", new Vector4(TopLeft_Pl_W.x, TopLeft_Pl_W.y, TopLeft_Pl_W.z, 1f));
        //将左上角的世界坐标传递给Shader ,其中1f是否了凑齐四位浮点数 ,用来进行后续的矩阵变换操作
        EarthFrame.GetComponent<Renderer>().material.SetVector("_Uvpoint2", new Vector4(BottomLeft_Pl_W.x, BottomLeft_Pl_W.y, BottomLeft_Pl_W.z, 1f));
        EarthFrame.GetComponent<Renderer>().material.SetVector("_Uvpoint3", new Vector4(TopRight_Pl_W.x, TopRight_Pl_W.y, TopRight_Pl_W.z, 1f));
        EarthFrame.GetComponent<Renderer>().material.SetVector("_Uvpoint4", new Vector4(BottomRight_Pl_W.x, BottomRight_Pl_W.y, BottomRight_Pl_W.z, 1f));

        //将截图时识别图四个角的世界坐标信息传递给Shader
        EarthA.GetComponent<Renderer>().material.SetVector("_Uvpoint1",new Vector4(TopLeft_Pl_W.x,TopLeft_Pl_W.y,TopLeft_Pl_W.z,1f));
        //将左上角的世界坐标传递给Shader ,其中1f是否了凑齐四位浮点数 ,用来进行后续的矩阵变换操作
        EarthA.GetComponent<Renderer>().material.SetVector("_Uvpoint2",new Vector4(BottomLeft_Pl_W.x,BottomLeft_Pl_W.y,BottomLeft_Pl_W.z,1f));
        EarthA.GetComponent<Renderer>().material.SetVector("_Uvpoint3",new Vector4(TopRight_Pl_W.x,TopRight_Pl_W.y,TopRight_Pl_W.z,1f));
        EarthA.GetComponent<Renderer>().material.SetVector("_Uvpoint4",new Vector4(BottomRight_Pl_W.x,BottomRight_Pl_W.y,BottomRight_Pl_W.z,1f));


        Matrix4x4 P = GL.GetGPUProjectionMatrix(Camera.main.projectionMatrix, false);
        //获取截图时GPU的投影矩阵
        Matrix4x4 V = Camera.main.worldToCameraMatrix;
        //获取截图时世界坐标到相机的矩阵
        Matrix4x4 VP = P * V;
        //储存两个矩阵的乘积
        Earth.GetComponent<Renderer>().material.SetMatrix("_VP", VP);
        //将截图时的矩阵转换信息传递给Shader
        EarthFrame.GetComponent<Renderer>().material.SetMatrix("_VP", VP);
        //将截图时的矩阵转换信息传递给Shader
        EarthA.GetComponent<Renderer>().material.SetMatrix("_VP",VP);
        //将截图时的矩阵转换信息传递给Shader

       // Debug.Log("----------错误前");
        TextureShot.ReadPixels(new Rect(0, 0, ScreenWidth, ScreenHeight), 0, 0);
      //  Debug.Log("错误后--------------");
        //获取屏幕的像素信息 
        //第一个"0,0"获取屏幕像素的起始点
        //“ScreenWidth,ScreenHeight”获取屏幕像素的范围
        //第二个“0,0” 填充texture2D时填充的坐标

        TextureShot.Apply();
        //确认之前对Texture2D进行的修改

        Earth.GetComponent<Renderer>().material.mainTexture = TextureShot;
        //获取Earth的渲染组件中的材质的主纹理,并将Texture2D赋值给这个主纹理
        EarthFrame.GetComponent<Renderer>().material.mainTexture = TextureShot;
        //获取Earth的渲染组件中的材质的主纹理,并将Texture2D赋值给这个主纹理
        EarthA.GetComponent<Renderer> ().material.mainTexture = TextureShot;
        //获取Earth的渲染组件中的材质的主纹理,并将Texture2D赋值给这个主纹理

        //状态隐藏
        PlaneA.SetActive(false);
        PlaneB.SetActive(false);
        //取消面片的激活状态
    }


}


SecUI

using UnityEngine;
using System.Collections;

public class SecUI : MonoBehaviour {

    private float CancelTime=0;
    //申请浮点类型的变量来记录 识别成功提示所存在的时间

    // Use this for initialization
    void Start () {
    
    }
    
    // Update is called once per frame
    void Update () {
        CancelTime += Time.deltaTime;
        //记录识别成功提示所存在的时间
        //每一帧运行都加经过一帧所使用的键

        if(CancelTime>1.3f){  
        //当识别成功的提示存在时间大于1.3秒时
            CancelTime=0;
            //记录存在时间归零
            gameObject.SetActive(false);
            //取消识别成功提示面板
        }
    }
}

Duijiao

using UnityEngine;
using System.Collections;
using Vuforia;

/// <summary>
/// 相机对焦
/// </summary>
public class Duijiao : MonoBehaviour
{


    // Use this for initialization
    //void Start()
    //{
    //   //通过Find寻找Ar摄像机
    //    GameObject ARCamera = GameObject.Find("ARCamera");

    //    //实例化摄像机时候自动对焦
    //    Vuforia.CameraDevice.Instance.SetFocusMode(Vuforia.CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO);
    //}

    //// Update is called once per frame
    //void Update()
    //{
    //    //运行过程中实行对焦功能
    //    Vuforia.CameraDevice.Instance.SetFocusMode(Vuforia.CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO);
    //}



    //-----------------------------------------------------
    //第二种对焦方法
    void Start()
    {
        //一开始自动对焦
        //Vuforia.CameraDevice.Instance.SetFocusMode(Vuforia.CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO);
        VuforiaARController.Instance.RegisterVuforiaStartedCallback(OnVuforiaStarted);
        VuforiaARController.Instance.RegisterOnPauseCallback(OnPaused);
    }


    private void OnVuforiaStarted()
    {
        CameraDevice.Instance.SetFocusMode(
        CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO);
    }

    private void OnPaused(bool paused)
    {
        if (!paused)
        { // resumed
            // Set again autofocus mode when app is resumed
            CameraDevice.Instance.SetFocusMode(
            CameraDevice.FocusMode.FOCUS_MODE_CONTINUOUSAUTO);
        }
    }

}



三、效果展示

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,816评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,729评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,300评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,780评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,890评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,084评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,151评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,912评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,355评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,666评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,809评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,504评论 4 334
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,150评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,882评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,121评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,628评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,724评论 2 351

推荐阅读更多精彩内容