Shader技巧之实现单/双鱼眼全景球转换
发表于2018-11-15
这篇文章给大家分享下使用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
}
}
}
