Shader "The Decline Of Warriors/Space Warp Universal" { Properties { _BaseMap("Base Map", 2D) = "white" {} _LightMap("Light Map", 2D) = "white" {} _TextureArray("Texture Array", 2DArray) = "white" {} _BaseColor("Base Color", Color) = (1, 1, 1, 1) [ToggleUI] _UseBaseMap("Use Base Map", Float) = 1 [ToggleUI] _UseTextureArray("Use Texture Array", Float) = 0 [ToggleUI] _UseLightMap("Use Light Map", Float) = 0 [ToggleUI] _UseVertexColor("Use Vertex Color", Float) = 1 [ToggleUI] _UseFog("Use Fog", Float) = 1 [IntRange] _Mode("Warp Mode", Range(0, 9)) = 0 _J("Warp Scale", Float) = 16 _F5Distance("View Offset", Float) = 1 _AlphaClipThreshold("Alpha Clip Threshold", Range(0, 1)) = 0.001 [Enum(UnityEngine.Rendering.CullMode)] _Cull("Cull", Float) = 2 [Enum(Off, 0, On, 1)] _ZWrite("ZWrite", Float) = 1 [Enum(UnityEngine.Rendering.BlendMode)] _SrcBlend("Src Blend", Float) = 1 [Enum(UnityEngine.Rendering.BlendMode)] _DstBlend("Dst Blend", Float) = 0 } SubShader { Tags { "RenderPipeline"="UniversalPipeline" "RenderType"="Opaque" "Queue"="Geometry" } LOD 100 Pass { Name "Forward" Tags { "LightMode"="UniversalForward" } Cull [_Cull] ZWrite [_ZWrite] Blend [_SrcBlend] [_DstBlend] HLSLPROGRAM #pragma target 3.5 #pragma require 2darray #pragma vertex vert #pragma fragment frag #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); TEXTURE2D(_LightMap); SAMPLER(sampler_LightMap); TEXTURE2D_ARRAY(_TextureArray); SAMPLER(sampler_TextureArray); CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; float4 _LightMap_ST; half4 _BaseColor; float _UseBaseMap; float _UseTextureArray; float _UseLightMap; float _UseVertexColor; float _UseFog; float _Mode; float _J; float _F5Distance; float _AlphaClipThreshold; CBUFFER_END float4 _SpaceWarpCameraPosition; float4 _SpaceWarpPreviousCameraPosition; float4 _SpaceWarpCameraForward; float _SpaceWarpFrameTime; float _SpaceWarpTime; static const float kPi = 3.14159265359; static const float kMinEpsilon = 1e-5; struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; float2 uv2 : TEXCOORD1; half4 color : COLOR; }; struct Varyings { float4 positionHCS : SV_POSITION; float2 uv : TEXCOORD0; float2 lightUv : TEXCOORD1; float2 textureData : TEXCOORD2; half4 color : COLOR; float fogFactor : TEXCOORD3; }; float Dot2(float3 value) { return dot(value, value); } float2 Rotate2D(float2 value, float angle) { float s = sin(angle); float c = cos(angle); return float2(c * value.x + s * value.y, -s * value.x + c * value.y); } float3 WarpSafeNormalize(float3 value) { float lengthSquared = max(dot(value, value), kMinEpsilon); return value * rsqrt(lengthSquared); } float3 InvertSpace(float3 position, float3 offset) { float3 shifted = position + offset; float shiftedLength = max(length(shifted), kMinEpsilon); shifted = WarpSafeNormalize(shifted) * (Dot2(offset) / shiftedLength); shifted = reflect(shifted, WarpSafeNormalize(offset)); return shifted + offset; } float3x3 Inverse3x3(float3x3 matrixValue) { float3 a = matrixValue[0]; float3 b = matrixValue[1]; float3 c = matrixValue[2]; float3 r0 = cross(b, c); float3 r1 = cross(c, a); float3 r2 = cross(a, b); float determinant = dot(r2, c); float safeDeterminant = sign(determinant) * max(abs(determinant), kMinEpsilon); return transpose(float3x3(r0, r1, r2) / safeDeterminant); } float3 Torusify(float3 position, float3 cameraPosition, float warpScale) { float k = warpScale * 0.5; float safeK = max(abs(k), kMinEpsilon); position.y = tanh((position.y - cameraPosition.y) / safeK) * safeK; position.y -= k; position.xy = float2(-sin(position.x * kPi / warpScale) * position.y, cos(position.x * kPi / warpScale) * position.y) + float2(0.0, k); position.y += k; position.zy = float2(sin(position.z * kPi / warpScale) * position.y, cos(position.z * kPi / warpScale) * position.y) - float2(0.0, k); return position; } float3 Cust1(float3 position, float distance) { float3 viewPosition = mul((float3x3)UNITY_MATRIX_V, position); viewPosition.z -= distance / 1.1; return mul((float3x3)UNITY_MATRIX_I_V, viewPosition); } float3 Cust2(float3 position, float3 cameraPosition, float warpScale) { float3 torusLocal = Torusify(position + cameraPosition, cameraPosition, warpScale) - Torusify(cameraPosition, cameraPosition, warpScale); float3 vx = WarpSafeNormalize(Torusify(cameraPosition + float3(0.01, 0.0, 0.0), cameraPosition, warpScale) - Torusify(cameraPosition, cameraPosition, warpScale)); float3 vy = WarpSafeNormalize(Torusify(cameraPosition + float3(0.0, 0.01, 0.0), cameraPosition, warpScale) - Torusify(cameraPosition, cameraPosition, warpScale)); float3 vz = WarpSafeNormalize(Torusify(cameraPosition + float3(0.0, 0.0, 0.01), cameraPosition, warpScale) - Torusify(cameraPosition, cameraPosition, warpScale)); float3x3 directionMatrix = float3x3(vx, vy, vz); return mul(Inverse3x3(directionMatrix), torusLocal); } float3 Cust3(float3 position, float distance, float warpScale, float timeValue) { float angle = (sin(timeValue / 6.0) * distance) / warpScale; float s = sin(angle); float c = cos(angle); float3x3 rotation = float3x3( c, 0.0, -s, 0.0, 1.0, 0.0, s, 0.0, c ); return mul(position, rotation); } float3 WarpPosition(float3 worldPosition) { float warpScale = max(_J, 1.0); float3 cameraPosition = _SpaceWarpCameraPosition.w > 0.5 ? _SpaceWarpCameraPosition.xyz : GetCameraPositionWS(); float3 previousCameraPosition = _SpaceWarpPreviousCameraPosition.w > 0.5 ? _SpaceWarpPreviousCameraPosition.xyz : cameraPosition; float frameTime = max(_SpaceWarpFrameTime, 0.0001); float timeValue = _SpaceWarpTime > 0.0 ? _SpaceWarpTime : _Time.y; float3 position = worldPosition - cameraPosition; float3 cameraVelocity = (cameraPosition - previousCameraPosition) / frameTime; float distance = length(position) / warpScale; float x = position.x; float y = position.y; float z = position.z; float2 orbit = Rotate2D(float2(warpScale, 0.0), timeValue); float3x3 solv = float3x3( pow(2.0, -y / warpScale), 0.0, 0.0, x / warpScale, 1.0, -z / warpScale, 0.0, 0.0, pow(2.0, y / warpScale) ); int mode = (int)round(_Mode); if (mode == 0) { position = InvertSpace(position, float3(orbit.y, 0.0, orbit.x)); } else if (mode == 1) { position = InvertSpace(position, float3(orbit.x, orbit.y, 0.0)); } else if (mode == 2) { position = InvertSpace(position, float3(0.0, orbit.x, orbit.y)); } else if (mode == 3) { position += cameraVelocity * distance / warpScale; } else if (mode == 4) { position = InvertSpace(position, float3(0.0, warpScale, 0.0)); } else if (mode == 5) { position = InvertSpace(position, float3(0.0, -warpScale, 0.0)); } else if (mode == 6) { position = mul(position, solv); } else if (mode == 7) { position = Cust1(position, length(position)); } else if (mode == 8) { position = Cust2(position, cameraPosition, warpScale); } else if (mode == 9) { position = Cust3(position, length(position), warpScale, timeValue); } float3 cameraForward = _SpaceWarpCameraForward.w > 0.5 ? WarpSafeNormalize(_SpaceWarpCameraForward.xyz) : WarpSafeNormalize(GetWorldSpaceViewDir(worldPosition) * -1.0); return cameraPosition + position - cameraForward * _F5Distance; } Varyings vert(Attributes input) { Varyings output; float3 positionWS = TransformObjectToWorld(input.positionOS.xyz); positionWS = WarpPosition(positionWS); output.positionHCS = TransformWorldToHClip(positionWS); output.uv = TRANSFORM_TEX(input.uv, _BaseMap); output.lightUv = TRANSFORM_TEX(input.uv2, _LightMap); output.textureData = input.uv2; output.color = input.color; output.fogFactor = ComputeFogFactor(output.positionHCS.z); return output; } half4 frag(Varyings input) : SV_Target { half4 baseSample = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv); half4 arraySample = SAMPLE_TEXTURE2D_ARRAY(_TextureArray, sampler_TextureArray, frac(input.uv), input.textureData.x); half4 lightSample = SAMPLE_TEXTURE2D(_LightMap, sampler_LightMap, input.lightUv); half4 vertexColor = input.color; baseSample = lerp(half4(1, 1, 1, 1), baseSample, saturate(_UseBaseMap)); baseSample = lerp(baseSample, arraySample, saturate(_UseTextureArray)); lightSample = lerp(half4(1, 1, 1, 1), lightSample, saturate(_UseLightMap)); vertexColor = lerp(half4(1, 1, 1, 1), vertexColor, saturate(_UseVertexColor)); half4 color = baseSample * lightSample * vertexColor * _BaseColor; clip(color.a - _AlphaClipThreshold); if (_UseFog > 0.5) { color.rgb = MixFog(color.rgb, input.fogFactor); } return color; } ENDHLSL } } }