涂涂乐 通过shader实现目标区域正交图片提取,移动端可用

来源:互联网 发布:java截取汉字字符串 编辑:程序博客网 时间:2024/06/03 23:03

      其实目的是从相机得到的透视图片中,得到目标图片的正交效果图。通过高通插件 shader实现透视变换(其实就是为了获得一张正交图片),也有多种实现方式,有些只能在pc端使用,这里只介绍一种可以在pc和移动端都正常实现的方式。

实现思路:

1、首先要有一个shader处理脚本传入的原始图片四个顶底坐标,在vert方法中通过UV坐标调整和差值运算得到目标位置,再通过一世界坐标-》裁剪坐标-》屏幕坐标的变换,最终得到视口坐标内的uv信息,在从frag方法中通过vert计算出来的uv信息从原始图片(相机得到的图片)获取像素, 从而获取识别图中所需区域的正交图。具体算法见 AdjustTextureShader 脚本。在项目中创建一个材质球命名为AdjustTextureMaterialshader选择为AdjustTextureShader 

2、通过在ImageTarget上挂四个空物体,位置拖放到需要截取区域的对应四个角,通过脚本传给shader作为uv变换的原始参数。

3、写一个脚本,用来传递ImageTarget上的四个位置信息给shader做处理。具体见GetTextureByShader脚本。

4、创建一个Plane 命名为TargetObj,翻转x轴翻转90度 调整合适的大小,因为需要整个画面固定在屏幕上固定位置,所以把这个TargetObj挂在ar相机下,并把ar相机的world center设置为camera

5、4步骤创建的TargetObj的材质球换成步骤1创建的材质球,挂上步骤3写的脚本,把ImageTarget下的四个顶点位置信息拖入脚本暴露出的对应接口中。

6、ImageTarget的脚本DefaultTrackableEventHandler脚本中添加一个公共变量TargetObj,用于相机识别状态改变的时候 显示和关闭这个物体,把步骤4创建的物体,拖入该公共变量。


Shader "Custom/AdjustTextureShader" {Properties{_MainTex("Base (RGB)", 2D) = "white" {}_UvpointTL("point1", Vector) = (0 , 0 , 0 , 0)_UvpointBL("point2", Vector) = (0 , 0 , 0 , 0)_UvpointTR("point3", Vector) = (0 , 0 , 0 , 0)_UvpointBR("point4", Vector) = (0 , 0 , 0 , 0)}SubShader{Tags{ "Queue" = "Transparent" "RenderType" = "Transparent" }LOD 200Pass{Blend SrcAlpha OneMinusSrcAlphaCGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"sampler2D _MainTex;//_MainTex_ST.xy存储的是缩放,_MainTex_ST.zw存储的是偏移float4 _MainTex_ST;float4 _UvpointTL;float4 _UvpointBL;float4 _UvpointTR;float4 _UvpointBR;struct v2f {float4 pos : SV_POSITION;//裁剪空间的顶点坐标float2 uv : TEXCOORD0;//第一组纹理坐标float4 fixedPos : TEXCOORD2;//第三组纹理坐标};/*默认顶点坐标参数结构体struct appdata_base {float4 vertex : POSITION;//位置float3 normal : NORMAL;//法线float4 texcoord : TEXCOORD0;//纹理坐标};*/v2f vert(appdata_base v){v2f o;o.pos = mul(UNITY_MATRIX_MVP,v.vertex);o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);o.uv.x = o.uv.x;o.uv.y = 1 - o.uv.y;float4 top = lerp(_UvpointTL, _UvpointTR, o.uv.x);float4 bottom = lerp(_UvpointBL, _UvpointBR, o.uv.x);float4 fixedPos = lerp(bottom, top, o.uv.y);//UNITY_MATRIX_VP:用于将顶点/矢量从世界空间变换到裁剪空间//ComputeScreenPos:裁剪空间坐标转换为屏幕空间坐标o.fixedPos = ComputeScreenPos(mul(UNITY_MATRIX_VP, fixedPos));return o;}float4 frag(v2f i) : COLOR{//i.fixedPos.xy / i.fixedPos.w得到视口空间中的坐标,视口坐标范围[(0,0),(1,1)]//i.fixedPos是屏幕坐标,齐次除法后得到视口坐标return tex2D(_MainTex, i.fixedPos.xy / i.fixedPos.w);}ENDCG}}}

using UnityEngine;using Vuforia;public class GetTextureByShader : MonoBehaviour{    public Transform posTL;    public Transform posTR;    public Transform posBL;    public Transform posBR;    Camera cam;    private RenderTexture renderTexture;    ImageTargetBehaviour targetBehaviour;    void Start()    {        targetBehaviour = GameObject.Find("ImageTarget").GetComponent<ImageTargetBehaviour>(); //GetComponentInParent<ImageTargetBehaviour>();        gameObject.layer = 31;    }    void Renderprepare()    {        if (!cam)        {            GameObject go = new GameObject("__cam");            cam = go.AddComponent<Camera>();            go.transform.parent = transform.parent;            cam.hideFlags = HideFlags.HideAndDontSave;        }        cam.CopyFrom(Camera.main);        cam.depth = 0;        cam.cullingMask = 31;        if (!renderTexture)        {            renderTexture = new RenderTexture(Screen.width, Screen.height,-50);        }        cam.targetTexture = renderTexture;        cam.Render();        GetComponent<Renderer>().material.SetTexture("_MainTex", renderTexture);    }    void OnWillRenderObject()    {        if (!targetBehaviour || targetBehaviour.ImageTarget == null)            return;        Vector3 targetAnglePointTL = posTL.position;        Vector3 targetAnglePointBL = posBL.position;        Vector3 targetAnglePointTR = posTR.position;        Vector3 targetAnglePointBR = posBR.position;        Renderprepare();        //设置Shader参数        GetComponent<Renderer>().material.SetVector("_UvpointTL", new Vector4(targetAnglePointTL.x, targetAnglePointTL.y, targetAnglePointTL.z, 1f));        GetComponent<Renderer>().material.SetVector("_UvpointBL", new Vector4(targetAnglePointBL.x, targetAnglePointBL.y, targetAnglePointBL.z, 1f));        GetComponent<Renderer>().material.SetVector("_UvpointTR", new Vector4(targetAnglePointTR.x, targetAnglePointTR.y, targetAnglePointTR.z, 1f));        GetComponent<Renderer>().material.SetVector("_UvpointBR", new Vector4(targetAnglePointBR.x, targetAnglePointBR.y, targetAnglePointBR.z, 1f));    }    void OnDestroy()    {        if (renderTexture)            DestroyImmediate(renderTexture);        if (cam)            DestroyImmediate(cam.gameObject);    }}


 

原创粉丝点击