252 lines
10 KiB
GLSL
252 lines
10 KiB
GLSL
// Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)
|
|
|
|
Shader "WansShader/Skybox/Video" {
|
|
Properties {
|
|
_Tint ("Tint Color", Color) = (.5, .5, .5, .5)
|
|
[Gamma] _Exposure ("Exposure", Range(0, 8)) = 1.0
|
|
_Rotation ("Rotation", Range(0, 360)) = 0
|
|
[NoScaleOffset] _MainTex ("Spherical (HDR)", 2D) = "grey" {}
|
|
[KeywordEnum(6 Frames Layout, Latitude Longitude Layout)] _Mapping("Mapping", Float) = 1
|
|
[Enum(360 Degrees, 0, 180 Degrees, 1)] _ImageType("Image Type", Float) = 0
|
|
[Toggle] _MirrorOnBack("Mirror on Back", Float) = 0
|
|
[Enum(None, 0, Side by Side, 1, Over Under, 2)] _Layout("3D Layout", Float) = 0
|
|
}
|
|
|
|
SubShader {
|
|
Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
|
|
Cull Off ZWrite Off
|
|
|
|
Pass {
|
|
|
|
CGPROGRAM
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
#pragma target 2.0
|
|
#pragma multi_compile_local __ _MAPPING_6_FRAMES_LAYOUT
|
|
|
|
#include "UnityCG.cginc"
|
|
|
|
sampler2D _MainTex;
|
|
float4 _MainTex_TexelSize;
|
|
float4 _MainTex_HDR;
|
|
float4 _Tint;
|
|
half _Exposure;
|
|
float _Rotation;
|
|
#ifndef _MAPPING_6_FRAMES_LAYOUT
|
|
bool _MirrorOnBack;
|
|
int _ImageType;
|
|
int _Layout;
|
|
#endif
|
|
|
|
#ifndef _MAPPING_6_FRAMES_LAYOUT
|
|
inline float2 ToRadialCoords(float3 coords)
|
|
{
|
|
float3 normalizedCoords = normalize(coords);
|
|
float latitude = acos(normalizedCoords.y);
|
|
float longitude = atan2(normalizedCoords.z, normalizedCoords.x);
|
|
float2 sphereCoords = float2(longitude, latitude) * float2(0.5/UNITY_PI, 1.0/UNITY_PI);
|
|
return float2(0.5,1.0) - sphereCoords;
|
|
}
|
|
#endif
|
|
|
|
#ifdef _MAPPING_6_FRAMES_LAYOUT
|
|
inline float2 ToCubeCoords(float3 coords, float3 layout, float4 edgeSize, float4 faceXCoordLayouts, float4 faceYCoordLayouts, float4 faceZCoordLayouts)
|
|
{
|
|
// Determine the primary axis of the normal
|
|
float3 absn = abs(coords);
|
|
float3 absdir = absn > float3(max(absn.y,absn.z), max(absn.x,absn.z), max(absn.x,absn.y)) ? 1 : 0;
|
|
// Convert the normal to a local face texture coord [-1,+1], note that tcAndLen.z==dot(coords,absdir)
|
|
// and thus its sign tells us whether the normal is pointing positive or negative
|
|
float3 tcAndLen = mul(absdir, float3x3(coords.zyx, coords.xzy, float3(-coords.xy,coords.z)));
|
|
tcAndLen.xy /= tcAndLen.z;
|
|
// Flip-flop faces for proper orientation and normalize to [-0.5,+0.5]
|
|
bool2 positiveAndVCross = float2(tcAndLen.z, layout.x) > 0;
|
|
tcAndLen.xy *= (positiveAndVCross[0] ? absdir.yx : (positiveAndVCross[1] ? float2(absdir[2],0) : float2(0,absdir[2]))) - 0.5;
|
|
// Clamp values which are close to the face edges to avoid bleeding/seams (ie. enforce clamp texture wrap mode)
|
|
tcAndLen.xy = clamp(tcAndLen.xy, edgeSize.xy, edgeSize.zw);
|
|
// Scale and offset texture coord to match the proper square in the texture based on layout.
|
|
float4 coordLayout = mul(float4(absdir,0), float4x4(faceXCoordLayouts, faceYCoordLayouts, faceZCoordLayouts, faceZCoordLayouts));
|
|
tcAndLen.xy = (tcAndLen.xy + (positiveAndVCross[0] ? coordLayout.xy : coordLayout.zw)) * layout.yz;
|
|
return tcAndLen.xy;
|
|
}
|
|
#endif
|
|
|
|
float3 RotateAroundYInDegrees (float3 vertex, float degrees)
|
|
{
|
|
float alpha = degrees * UNITY_PI / 180.0;
|
|
float sina, cosa;
|
|
sincos(alpha, sina, cosa);
|
|
float2x2 m = float2x2(cosa, -sina, sina, cosa);
|
|
return float3(mul(m, vertex.xz), vertex.y).xzy;
|
|
}
|
|
|
|
struct appdata_t {
|
|
float4 vertex : POSITION;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct v2f {
|
|
float4 vertex : SV_POSITION;
|
|
float3 texcoord : TEXCOORD0;
|
|
#ifdef _MAPPING_6_FRAMES_LAYOUT
|
|
float3 layout : TEXCOORD1;
|
|
float4 edgeSize : TEXCOORD2;
|
|
float4 faceXCoordLayouts : TEXCOORD3;
|
|
float4 faceYCoordLayouts : TEXCOORD4;
|
|
float4 faceZCoordLayouts : TEXCOORD5;
|
|
#else
|
|
float2 image180ScaleAndCutoff : TEXCOORD1;
|
|
float4 layout3DScaleAndOffset : TEXCOORD2;
|
|
#endif
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
v2f vert (appdata_t v)
|
|
{
|
|
v2f o;
|
|
UNITY_SETUP_INSTANCE_ID(v);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
|
float3 rotated = RotateAroundYInDegrees(v.vertex, _Rotation);
|
|
o.vertex = UnityObjectToClipPos(rotated);
|
|
o.texcoord = v.vertex.xyz;
|
|
#ifdef _MAPPING_6_FRAMES_LAYOUT
|
|
// layout and edgeSize are solely based on texture dimensions and can thus be precalculated in the vertex shader.
|
|
float sourceAspect = float(_MainTex_TexelSize.z) / float(_MainTex_TexelSize.w);
|
|
// Use the halfway point between the 1:6 and 3:4 aspect ratios of the strip and cross layouts to
|
|
// guess at the correct format.
|
|
bool3 aspectTest =
|
|
sourceAspect >
|
|
float3(1.0, 1.0f / 6.0f + (3.0f / 4.0f - 1.0f / 6.0f) / 2.0f, 6.0f / 1.0f + (4.0f / 3.0f - 6.0f / 1.0f) / 2.0f);
|
|
// For a given face layout, the coordinates of the 6 cube faces are fixed: build a compact representation of the
|
|
// coordinates of the center of each face where the first float4 represents the coordinates of the X axis faces,
|
|
// the second the Y, and the third the Z. The first two float componenents (xy) of each float4 represent the face
|
|
// coordinates on the positive axis side of the cube, and the second (zw) the negative.
|
|
// layout.x is a boolean flagging the vertical cross layout (for special handling of flip-flops later)
|
|
// layout.yz contains the inverse of the layout dimensions (ie. the scale factor required to convert from
|
|
// normalized face coords to full texture coordinates)
|
|
if (aspectTest[0]) // horizontal
|
|
{
|
|
if (aspectTest[2])
|
|
{ // horizontal strip
|
|
o.faceXCoordLayouts = float4(0.5,0.5,1.5,0.5);
|
|
o.faceYCoordLayouts = float4(2.5,0.5,3.5,0.5);
|
|
o.faceZCoordLayouts = float4(4.5,0.5,5.5,0.5);
|
|
o.layout = float3(-1,1.0/6.0,1.0/1.0);
|
|
}
|
|
else
|
|
{ // horizontal cross
|
|
o.faceXCoordLayouts = float4(2.5,1.5,0.5,1.5);
|
|
o.faceYCoordLayouts = float4(1.5,2.5,1.5,0.5);
|
|
o.faceZCoordLayouts = float4(1.5,1.5,3.5,1.5);
|
|
o.layout = float3(-1,1.0/4.0,1.0/3.0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (aspectTest[1])
|
|
{ // vertical cross
|
|
o.faceXCoordLayouts = float4(2.5,2.5,0.5,2.5);
|
|
o.faceYCoordLayouts = float4(1.5,3.5,1.5,1.5);
|
|
o.faceZCoordLayouts = float4(1.5,2.5,1.5,0.5);
|
|
o.layout = float3(1,1.0/3.0,1.0/4.0);
|
|
}
|
|
else
|
|
{ // vertical strip
|
|
o.faceXCoordLayouts = float4(0.5,5.5,0.5,4.5);
|
|
o.faceYCoordLayouts = float4(0.5,3.5,0.5,2.5);
|
|
o.faceZCoordLayouts = float4(0.5,1.5,0.5,0.5);
|
|
o.layout = float3(-1,1.0/1.0,1.0/6.0);
|
|
}
|
|
}
|
|
// edgeSize specifies the minimum (xy) and maximum (zw) normalized face texture coordinates that will be used for
|
|
// sampling in the texture. Setting these to the effective size of a half pixel horizontally and vertically
|
|
// effectively enforces clamp mode texture wrapping for each individual face.
|
|
o.edgeSize.xy = _MainTex_TexelSize.xy * 0.5 / o.layout.yz - 0.5;
|
|
o.edgeSize.zw = -o.edgeSize.xy;
|
|
#else // !_MAPPING_6_FRAMES_LAYOUT
|
|
// Calculate constant horizontal scale and cutoff for 180 (vs 360) image type
|
|
if (_ImageType == 0) // 360 degree
|
|
o.image180ScaleAndCutoff = float2(1.0, 1.0);
|
|
else // 180 degree
|
|
o.image180ScaleAndCutoff = float2(2.0, _MirrorOnBack ? 1.0 : 0.5);
|
|
// Calculate constant scale and offset for 3D layouts
|
|
if (_Layout == 0) // No 3D layout
|
|
o.layout3DScaleAndOffset = float4(0,0,1,1);
|
|
else if (_Layout == 1) // Side-by-Side 3D layout
|
|
o.layout3DScaleAndOffset = float4(unity_StereoEyeIndex,0,0.5,1);
|
|
else // Over-Under 3D layout
|
|
o.layout3DScaleAndOffset = float4(0, 1-unity_StereoEyeIndex,1,0.5);
|
|
#endif
|
|
return o;
|
|
}
|
|
|
|
float4 frag(v2f i) : SV_Target
|
|
{
|
|
#ifdef _MAPPING_6_FRAMES_LAYOUT
|
|
float2 tc = ToCubeCoords(i.texcoord, i.layout, i.edgeSize, i.faceXCoordLayouts, i.faceYCoordLayouts, i.faceZCoordLayouts);
|
|
#else
|
|
float3 texcoord = float3(i.texcoord.x, i.texcoord.y, -i.texcoord.z);
|
|
float2 tc = ToRadialCoords(texcoord);
|
|
if (tc.x > i.image180ScaleAndCutoff[1])
|
|
return float4(0,0,0,1);
|
|
tc.x = fmod(tc.x*i.image180ScaleAndCutoff[0], 1);
|
|
tc = (tc + i.layout3DScaleAndOffset.xy) * i.layout3DScaleAndOffset.zw;
|
|
#endif
|
|
|
|
float4 tex = tex2D (_MainTex, tc);
|
|
float3 c = DecodeHDR (tex, _MainTex_HDR);
|
|
c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;
|
|
c *= _Exposure;
|
|
return float4(c, 1);
|
|
}
|
|
ENDCG
|
|
}
|
|
Pass {
|
|
Tags
|
|
{
|
|
"LightMode" = "Mask"
|
|
}
|
|
CGPROGRAM
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
#pragma target 3.5
|
|
|
|
#include "UnityCG.cginc"
|
|
#define SamplerState_Trilinear SAMPLER(sampler_trilinear)
|
|
|
|
struct appdata_t {
|
|
float4 vertex : POSITION;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct v2f {
|
|
float4 vertex : SV_POSITION;
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
|
|
|
|
v2f vert (appdata_t v)
|
|
{
|
|
v2f o;
|
|
UNITY_SETUP_INSTANCE_ID(v);
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
|
|
o.vertex = UnityObjectToClipPos(v.vertex);
|
|
return o;
|
|
}
|
|
|
|
float4 frag (v2f i) : SV_Target
|
|
{
|
|
return float4(1,1,1,1);
|
|
}
|
|
ENDCG
|
|
|
|
}
|
|
}
|
|
|
|
|
|
CustomEditor "SkyboxPanoramicShaderGUI"
|
|
Fallback Off
|
|
|
|
}
|