Shader技巧之实现单/双鱼眼全景球转换

发表于2018-11-15
评论0 4.1k浏览
这篇文章给大家分享下使用shader的技巧,利用shader实现单/双鱼眼到全景图转换。

单鱼眼最终效果:

思路

将x坐标当作弧度取tan,y坐标为半径转换

源代码:
Shader "QQ/TexConvert/SingleFishEyeSimple"
{
	Properties
	{
		_MainTex("Texture", 2D) = "white" {}
		_Lerp("lerp",Range(0,1)) = 1
		_Radius("radius",Range(0.0,1.0)) = 0.5
		[Toggle] _Hint("show hint", float) = 0
	}
		SubShader
		{
			Tags { "RenderType" = "Opaque" }
			LOD 100
			Pass
			{
				CGPROGRAM
				#pragma vertex vert
				#pragma fragment frag
				#include "UnityCG.cginc"
				struct appdata
				{
					float4 vertex : POSITION;
					float2 uv : TEXCOORD0;
				};
				struct v2f
				{
					float2 uv : TEXCOORD0;
					float4 vertex : SV_POSITION;
				};
				uniform sampler2D _MainTex;
				uniform float4 _MainTex_ST;
				uniform float _Lerp;
				uniform float _Radius;
				uniform float _Hint;
				v2f vert(appdata v)
				{
					v2f o;
					o.vertex = UnityObjectToClipPos(v.vertex);
					o.uv = TRANSFORM_TEX(v.uv, _MainTex);
					return o;
				}
				fixed4 frag(v2f i) : SV_Target
				{
					i.uv = abs(i.uv) % 1.0;
					float th = i.uv.x *  UNITY_PI * 2;
					float ta = tan(th);
					float2 uv0 = float2(cos(th)*ta*_Radius, sin(th) / ta*_Radius)*(1 - i.uv.y) + 0.5;
					fixed4 col = tex2D(_MainTex, lerp(i.uv, uv0, _Lerp), 0, 0);
					if (_Hint > 0)
					{
						if (length(i.uv - float2(0.5, 0.5)) < _Radius)
							col += fixed4(uv0, 0, 1);
					}
					return col;
				}
				ENDCG
			}
		}
}

双鱼眼最终效果

思路

将平面坐标转换到球面坐标
将球面坐标转换为经纬度
取经纬度的二维坐标

源代码:
Shader"QQ/DoubleFishEyeSimple"  
{  
	Properties  
	{  
		_MainTex("Texture",2D)="white"{}  
		_Lerp("lerp",Range(0,1))=1  
		_Radius("radius",Range(0.0,1.0))=0.5  
		_Blend("blend",Range(0,1))=0.1  
		[Toggle]_Hint("showhint",float)=0  
	}  
	SubShader  
	{  
		Tags{"RenderType"="Opaque"}  
		LOD100  
		Pass  
		{  
			CGPROGRAM  
			#pragmavertexvert  
			#pragmafragmentfrag  
			#include"UnityCG.cginc"  
			structappdata  
			{  
				float4vertex:POSITION;  
				float2uv:TEXCOORD0;  
			};  
			structv2f  
			{  
				float2uv:TEXCOORD0;  
				float4vertex:SV_POSITION;  
			};  
			uniformsampler2D_MainTex;  
			uniformfloat4_MainTex_ST;  
			uniformfloat_Lerp;  
			uniformfloat_Radius;  
			uniformfloat_Blend;  
			uniformfloat_Hint;  
			v2fvert(appdatav)  
			{  
				v2fo;  
				o.vertex=UnityObjectToClipPos(v.vertex);  
				o.uv=TRANSFORM_TEX(v.uv,_MainTex);  
				returno;  
			}  
			float3pts(float2uv,floatr)  
			{  
				uv=(uv/1.0-0.5)*UNITY_PI;  
				returnr*float3(sin(uv.x)*cos(uv.y),sin(uv.y),cos(uv.x)*cos(uv.y));  
			}  
			float2stp(float3s,floatr)  
			{  
				floatt=atan2(s.y,s.x);  
				floatp=atan2(sqrt(s.x*s.x+s.y*s.y),s.z);  
				float_r=r*2*p/UNITY_PI;  
				return_r*float2(cos(t),sin(t));  
			}  
			float2ptstp(float2uv,floatr,float2o)  
			{  
				float3s=pts(uv,_Radius);  
				float2_uv=stp(s,_Radius);  
				_uv.x/=2;  
				return_uv+=o;  
			}  
			fixed4frag(v2fi):SV_Target  
			{  
				i.uv=abs(i.uv)%1.0;  
				float2uv=float2((i.uv.x%0.5)/0.5,i.uv.y);  
				floatm=_Blend+1;  
				float2_uv=float2(uv.x/m,uv.y);  
				float2uv0=ptstp(_uv,_Radius,float2(i.uv.x>0.5?0.75:0.25,0.5));  
				fixed4col=tex2D(_MainTex,lerp(i.uv,uv0,_Lerp),0,0);  
				if(_Blend>0.0)  
				{  
					m=1-1/m;  
					if(_uv.x<m)  
					{  
						float2uv1=ptstp(_uv-float2(1+m,0),_Radius,float2(i.uv.x>0.5?0.25:0.75,0.5));  
						fixed4_col=tex2D(_MainTex,lerp(i.uv,uv1,_Lerp),0,0);  
						col=lerp(col,_col,(m-_uv.x)/m);  
					}  
				}  
				if(_Hint>0)  
				{  
					float2s0=uv-float2(0.5,0.5);  
					if(length(s0)<_Radius)  
						col+=fixed4(0.5,0,0,1);  
				}  
				returncol;  
			}  
			ENDCG  
		}  
	}  
}  

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引

标签: