//截图赋值,移走图片,涂色还在,长方形识别图,UV是正方形
//模型使用shander-ScanTex
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
//加入UI命名空间
//扫描识别,脚本挂载在PlaneA上,planeA为ImageTarget子物体,大小一样,为长方形,纹理为Vuforia上传的长方形纹理,
public class Scanning_PlaneA : MonoBehaviour {
public GameObject Img_Scan;
//储存识别框图片
public GameObject Img_Sucess;
//储存识别成功图片
//public GameObject Model1;
//储存地球模型
//public GameObject Model2;
//储存地球框架模型
public GameObject PlaneB;
//储存面板B
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;
//记录面片的宽高
//面片为ImageTarget的子物体,大小和ImageTarget一样大,面片的纹理和ImageTarget一样。
public float ImageTargetScale;
//父级目标识别ImageTarget缩放系数
public float PlaneScale;
//Plane缩放系数
//脚本刚开始运行的时候调用一次
void Start () {
CanS = GameObject.Find ("Canvas").gameObject.GetComponent<CanvasScaler> ();
//获取控制屏幕自适度的组件
X_Sc = Screen.width / CanS.referenceResolution.x;
//获取实际的缩放比例
}
//每一帧都调用
void Update () {
//计算了扫描框四个点的坐标位置,“*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*1*0.1f,gameObject.GetComponent<MeshFilter>().mesh.bounds.size.z*1*0.064f)*0.5f;
PlaneWH = new Vector2(gameObject.GetComponent<MeshFilter>().mesh.bounds.size.x * ImageTargetScale * PlaneScale, gameObject.GetComponent<MeshFilter>().mesh.bounds.size.z * ImageTargetScale * PlaneScale) * 0.5f;
//获取面片的宽高的一半
//"gameObject.GetComponent<MeshFilter>().mesh.bounds.size.x"获取面片X方向的宽度
//"*5"是因为开始获取到的长宽是模型本身的长宽,而场景中我们有缩放因素,父级物体(ImageTarget)放大了1f倍,自身缩小到了0.1,因此获取实际宽高需要再乘以0.5
//获取面片四个点的世界坐标
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秒
Img_Sucess.SetActive(true);
//激活提示识别成功的图片
gameObject.GetComponent<Renderer>().material=Tran_Mate;
//给面片材质赋值为透明材质,除去截图时的影响
Img_Scan.SetActive(false);
//扫描框取消
}
//截图的延迟函数
IEnumerator ScreenShot(){
yield return new WaitForSeconds (2.0f);
//延迟2秒
if(HasRe==true){
//当处于识别状态的时候才执行截图函数
gameObject.GetComponent<Renderer>().material=Tran_Mate;
//给面片材质赋值为透明材质,除去截图时的影响
////Earth.SetActive(true);
//////地球模型显示出来
////EarthFrame.SetActive(true);
//////地球模型框架显示出来
//Earth.GetComponent<ScreenShot>().ScreenShot_Button();
//调用地球模型上截图脚本的截图函数
PlaneB.GetComponent<ScreenShot_PlaneB>().ScreenShot_Button();
}
}
}
///////////////////////////////////////////////////////////////////////////////////
using UnityEngine;
using System.Collections;
//屏幕截图,脚本挂载在PlaneB上,PlaneB,为ImageTarget子物体,为正方形,长与ImageTarget一样,纹理为3D模型(正方形)UV纹理,正方形=长方形+空白
public class ScreenShot_PlaneB : MonoBehaviour {
public GameObject Model1;
//申请公有变量储存要赋予贴图的模型
//public GameObject Model2;
//储存地球仪配件模型
public GameObject PlaneA;
//储存面片A,ImageTarget的子物体平面,和ImageTarget一样大小,识别时,显示红色,识别成功后,显示绿色
public GameObject PlaneB;
//储存面片B,ImageTarget的子物体平面,和ImageTarget一样的长,为正方形,和ImageTarget一样的(长方形)纹理贴图,
//屏幕截图,从他身上截图和Image一样的长方形纹理,正方形内(长方形以外部分为空)
private int ScreenWidth;
//申请私有int型变量 记录屏幕的宽
private int ScreenHeight;
//申请私有int型变量 记录屏幕的高
private Texture2D TextureShot;
//申请Texture2D型变量 用来储存屏幕截图
private Vector2 PlaneWH;
//记录面片A的宽高
//记录面片的世界坐标
private Vector3 TopLeft_Pl_W;
//记录面片左上角的世界坐标
private Vector3 BottomLeft_Pl_W;
//记录面片左下角的世界坐标
private Vector3 TopRight_Pl_W;
//记录面片右上角的世界坐标
private Vector3 BottomRight_Pl_W;
//记录面片右下角的世界坐标
public float ImageTargetScale;
//父级目标识别ImageTarget缩放系数
public float PlaneScale;
//Plane缩放系数
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是一种分级纹理 在屏幕中显示大小不同时候给予不同级别的纹理 这里不使用
Model1.GetComponent<Renderer>().enabled = false;
// Model2.GetComponent<Renderer>().enabled = false;
//隐藏模型
//??透明脚本不管用??
}
//截图函数
public void ScreenShot_Button(){
PlaneWH = new Vector2 (PlaneB.GetComponent<MeshFilter>().mesh.bounds.size.x* ImageTargetScale * PlaneScale, PlaneB.GetComponent<MeshFilter>().mesh.bounds.size.z* ImageTargetScale * PlaneScale) *0.5f;
//获取面片的宽高的一半;*0.5;
//"gameObject.GetComponent<MeshFilter>().mesh.bounds.size.x"获取面片X方向的宽度
//"*M*N"是因为开始获取到的长宽是模型本身的长宽,而场景中我们有缩放因素,父级物体(ImageTarget)放大了n倍,自身缩小到了m,因此获取实际宽高需要再乘以m*n
//获取面片四个点的世界坐标
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
Model1.GetComponent<Renderer>().material.SetVector("_Uvpoint1",new Vector4(TopLeft_Pl_W.x,TopLeft_Pl_W.y,TopLeft_Pl_W.z,1f));
//将左上角的世界坐标传递给Shader ,其中1f是否了凑齐四位浮点数 ,用来进行后续的矩阵变换操作
Model1.GetComponent<Renderer>().material.SetVector("_Uvpoint2",new Vector4(BottomLeft_Pl_W.x,BottomLeft_Pl_W.y,BottomLeft_Pl_W.z,1f));
Model1.GetComponent<Renderer>().material.SetVector("_Uvpoint3",new Vector4(TopRight_Pl_W.x,TopRight_Pl_W.y,TopRight_Pl_W.z,1f));
Model1.GetComponent<Renderer>().material.SetVector("_Uvpoint4",new Vector4(BottomRight_Pl_W.x,BottomRight_Pl_W.y,BottomRight_Pl_W.z,1f));
//将截图时识别图四个角的世界坐标信息传递给Shader
//Model2.GetComponent<Renderer>().material.SetVector("_Uvpoint1",new Vector4(TopLeft_Pl_W.x,TopLeft_Pl_W.y,TopLeft_Pl_W.z,1f));
//将左上角的世界坐标传递给Shader ,其中1f是否了凑齐四位浮点数 ,用来进行后续的矩阵变换操作
//Model2.GetComponent<Renderer>().material.SetVector("_Uvpoint2",new Vector4(BottomLeft_Pl_W.x,BottomLeft_Pl_W.y,BottomLeft_Pl_W.z,1f));
//Model2.GetComponent<Renderer>().material.SetVector("_Uvpoint3",new Vector4(TopRight_Pl_W.x,TopRight_Pl_W.y,TopRight_Pl_W.z,1f));
//Model2.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;
//储存两个矩阵的乘积
Model1.GetComponent<Renderer>().material.SetMatrix("_VP",VP);
//将截图时的矩阵转换信息传递给Shader
//Model2.GetComponent<Renderer>().material.SetMatrix("_VP",VP);
//将截图时的矩阵转换信息传递给Shader
TextureShot.ReadPixels (new Rect(0,0,ScreenWidth,ScreenHeight),0,0);
//获取屏幕的像素信息
//第一个"0,0"获取屏幕像素的起始点
//“ScreenWidth,ScreenHeight”获取屏幕像素的范围
//第二个“0,0” 填充texture2D时填充的坐标
TextureShot.Apply ();
//确认之前对Texture2D进行的修改
Model1.GetComponent<Renderer>().enabled = true;
//Model2.GetComponent<Renderer>().enabled = true;
//显示模型
Model1.GetComponent<Renderer> ().material.mainTexture = TextureShot;
//获取Earth的渲染组件中的材质的主纹理,并将Texture2D赋值给这个主纹理
//Model2.GetComponent<Renderer> ().material.mainTexture = TextureShot;
//获取Earth的渲染组件中的材质的主纹理,并将Texture2D赋值给这个主纹理
PlaneA.SetActive (false);
PlaneB.SetActive (false);
//取消面片的激活状态
}
}
///////////////////////////////////////////////////////////////
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,)' with 'UnityObjectToClipPos()'
Shader "Texture/ScanTex" {
//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 = UnityObjectToClipPos(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"
}
网友评论