涂涂乐 通过shader实现目标区域正交图片提取,移动端可用
来源:互联网 发布:java截取汉字字符串 编辑:程序博客网 时间:2024/06/03 23:03
其实目的是从相机得到的透视图片中,得到目标图片的正交效果图。通过高通插件和 shader实现透视变换(其实就是为了获得一张正交图片),也有多种实现方式,有些只能在pc端使用,这里只介绍一种可以在pc和移动端都正常实现的方式。
实现思路:
1、首先要有一个shader处理脚本传入的原始图片四个顶底坐标,在vert方法中通过UV坐标调整和差值运算得到目标位置,再通过一世界坐标-》裁剪坐标-》屏幕坐标的变换,最终得到视口坐标内的uv信息,在从frag方法中通过vert计算出来的uv信息从原始图片(相机得到的图片)获取像素, 从而获取识别图中所需区域的正交图。具体算法见 AdjustTextureShader 脚本。在项目中创建一个材质球命名为AdjustTextureMaterial,shader选择为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); }}
- 涂涂乐 通过shader实现目标区域正交图片提取,移动端可用
- 一个图像目标区域提取的问题
- 通过 css3 实现鼠标划过图片移动
- js事件实现通过键盘移动图片
- shader实现图片阴影
- 移动端车牌识别可通过计算机视觉提取字符
- 提取图片中任意形状的区域
- 提取图片中任意形状的区域
- 提取图片中任意形状的区域
- 提取图片中任意形状的区域
- 【C#】身份证识别(二):提取目标区域图像
- shader之——移动端阴影实现
- Android通过手势实现图片按照指定路径移动
- Android通过手势实现图片按照指定路径移动
- Android实现 通过手势随意缩放、移动ImageView图片
- Android实现 通过手势随意缩放、移动ImageView图片
- 区域提取
- 【shader】Unity 移动端海面
- 基于运放和三极管的恒流源电路
- Java观察者模式以及与订阅发布者模式区别
- 强化学习
- SSH入门--员工管理系统
- iotop命令监控磁盘io
- 涂涂乐 通过shader实现目标区域正交图片提取,移动端可用
- AndroidStudio上打开之前的项目报错但是能运行
- [CDH--安装]--关于Spark版本的支持
- iOS 内省方法浅谈
- mybatis 传入null值解决方法
- 深入理解Java中的final关键字
- java设计模式汇总
- STM32时钟配置方法详解
- js 把线性的数据结构改成树形结构