void GetBestLights( float Channel, inout int orificeType, inout float3 orificePositionTracker, inout float3 orificeNormalTracker, inout float3 penetratorPositionTracker, inout float penetratorLength ) {
	float ID = step( 0.5 , Channel );
	float baseID = ( ID * 0.02 );
	float holeID = ( baseID + 0.01 );
	float ringID = ( baseID + 0.02 );
	float normalID = ( 0.05 + ( ID * 0.01 ) );
	float penetratorID = ( 0.09 + ( ID * -0.01 ) );
	float4 orificeWorld;
	float4 orificeNormalWorld;
	float4 penetratorWorld;
	float penetratorDist=100;
	for (int i=0;i<4;i++) {
		float range = (0.005 * sqrt(1000000 - unity_4LightAtten0[i])) / sqrt(unity_4LightAtten0[i]);
		if (length(unity_LightColor[i].rgb) < 0.01) {
			if (abs(fmod(range,0.1)-holeID)<0.005) {
				orificeType=0;
				orificeWorld = float4(unity_4LightPosX0[i], unity_4LightPosY0[i], unity_4LightPosZ0[i], 1);
				orificePositionTracker = mul( unity_WorldToObject, orificeWorld ).xyz;
			}
			if (abs(fmod(range,0.1)-ringID)<0.005) {
				orificeType=1;
				orificeWorld = float4(unity_4LightPosX0[i], unity_4LightPosY0[i], unity_4LightPosZ0[i], 1);
				orificePositionTracker = mul( unity_WorldToObject, orificeWorld ).xyz;
			}
			if (abs(fmod(range,0.1)-normalID)<0.005) {
				orificeNormalWorld = float4(unity_4LightPosX0[i], unity_4LightPosY0[i], unity_4LightPosZ0[i], 1);
				orificeNormalTracker = mul( unity_WorldToObject, orificeNormalWorld ).xyz;
			}
			if (abs(fmod(range,0.1)-penetratorID)<0.005) {
				float3 tempPenetratorPositionTracker = penetratorPositionTracker;
				penetratorWorld = float4(unity_4LightPosX0[i], unity_4LightPosY0[i], unity_4LightPosZ0[i], 1);
				penetratorPositionTracker = mul( unity_WorldToObject, penetratorWorld ).xyz;
				if (length(penetratorPositionTracker)>length(tempPenetratorPositionTracker)) {
					penetratorPositionTracker = tempPenetratorPositionTracker;
				} else {
					penetratorLength=unity_LightColor[i].a;
				}
			}
		}
	}
}
VertexOutput vert (VertexInput v)
{
			float orificeType = 0;
			float3 orificePositionTracker = float3(0,0,100);
			float3 orificeNormalTracker = float3(0,0,99);
			float3 penetratorPositionTracker = float3(0,0,1);
			float pl=0;
			GetBestLights(_OrificeChannel, orificeType, orificePositionTracker, orificeNormalTracker, penetratorPositionTracker, pl);
			float3 orificeNormal = normalize( lerp( ( orificePositionTracker - orificeNormalTracker ) , orificePositionTracker , max( _EntranceStiffness , 0.01 )) );
			float3 PhysicsNormal = normalize(penetratorPositionTracker.xyz) * _Length * 0.3;
			float wriggleTime = _Time.y * _WriggleSpeed;
			float temp_output_257_0 = ( _Length * ( ( cos( wriggleTime ) * _Wriggle ) + _Curvature ) );
			float wiggleTime = _Time.y * ( _WriggleSpeed * 0.39 );
			float distanceToOrifice = length( orificePositionTracker );
			float enterFactor = smoothstep( ( _Length + -0.05 ) , _Length , distanceToOrifice);
			float3 finalOrificeNormal = normalize( lerp( orificeNormal , ( PhysicsNormal + ( ( float3(0,1,0) * ( temp_output_257_0 + ( _Length * ( _ReCurvature + ( ( sin( wriggleTime ) * 0.3 ) * _Wriggle ) ) * 2.0 ) ) ) + ( float3(0.5,0,0) * ( cos( wiggleTime ) * _Wriggle ) ) ) ) , enterFactor) );
			float smoothstepResult186 = smoothstep( _Length , ( _Length + 0.05 ) , distanceToOrifice);
			float3 finalOrificePosition = lerp( orificePositionTracker , ( ( normalize(penetratorPositionTracker) * _Length ) + ( float3(0,0.2,0) * ( sin( ( wriggleTime + UNITY_PI ) ) * _Wriggle ) * _Length ) + ( float3(0.2,0,0) * _Length * ( sin( ( wiggleTime + UNITY_PI ) ) * _Wriggle ) ) ) , smoothstepResult186);
			float finalOrificeDistance = length( finalOrificePosition );
			float3 bezierBasePosition = float3(0,0,0);
			float temp_output_59_0 = ( finalOrificeDistance / 3.0 );
			float3 lerpResult274 = lerp( float3( 0,0,0 ) , ( float3(0,1,0) * ( temp_output_257_0 * -0.2 ) ) , saturate( ( distanceToOrifice / _Length ) ));
			float3 temp_output_267_0 = ( ( temp_output_59_0 * float3(0,0,1) ) + lerpResult274 );
			float3 bezierBaseNormal = temp_output_267_0;
			float3 temp_output_63_0 = ( finalOrificePosition - ( temp_output_59_0 * finalOrificeNormal ) );
			float3 bezierOrificeNormal = temp_output_63_0;
			float3 bezierOrificePosition = finalOrificePosition;
			float vertexBaseTipPosition = ( v.vertex.z / finalOrificeDistance );
			float t = saturate(vertexBaseTipPosition);
			float oneMinusT = 1 - t;
			float3 bezierPoint = oneMinusT * oneMinusT * oneMinusT * bezierBasePosition + 3 * oneMinusT * oneMinusT * t * bezierBaseNormal + 3 * oneMinusT * t * t * bezierOrificeNormal + t * t * t * bezierOrificePosition;
			float3 straightLine = (float3(0.0 , 0.0 , v.vertex.z));
			float baseFactor = smoothstep( 0.05 , -0.05 , v.vertex.z);
			bezierPoint = lerp( bezierPoint , straightLine , baseFactor);
			bezierPoint = lerp( ( ( finalOrificeNormal * ( v.vertex.z - finalOrificeDistance ) ) + finalOrificePosition ) , bezierPoint , step( vertexBaseTipPosition , 1.0 ));
			float3 bezierDerivitive = 3 * oneMinusT * oneMinusT * (bezierBaseNormal - bezierBasePosition) + 6 * oneMinusT * t * (bezierOrificeNormal - bezierBaseNormal) + 3 * t * t * (bezierOrificePosition - bezierOrificeNormal);
			bezierDerivitive = normalize( lerp( bezierDerivitive , float3(0,0,1) , baseFactor) );
			float bezierUpness = dot( bezierDerivitive , float3( 0,1,0 ) );
			float3 bezierUp = lerp( float3(0,1,0) , float3( 0,0,-1 ) , saturate( bezierUpness ));
			float bezierDownness = dot( bezierDerivitive , float3( 0,-1,0 ) );
			bezierUp = normalize( lerp( bezierUp , float3( 0,0,1 ) , saturate( bezierDownness )) );
			float3 bezierSpaceX = normalize( cross( bezierDerivitive , bezierUp ) );
			float3 bezierSpaceY = normalize( cross( bezierDerivitive , -bezierSpaceX ) );
			float3 bezierSpaceVertexOffset = ( ( v.vertex.y * bezierSpaceY ) + ( v.vertex.x * -bezierSpaceX ) );
			float3 bezierSpaceVertexOffsetNormal = normalize( bezierSpaceVertexOffset );
			float distanceFromTip = ( finalOrificeDistance - v.vertex.z );
			float squeezeFactor = smoothstep( 0.0 , _SqueezeDist , -distanceFromTip);
			squeezeFactor = max( squeezeFactor , smoothstep( 0.0 , _SqueezeDist , distanceFromTip));
			float3 bezierSpaceVertexOffsetSqueezed = lerp( ( bezierSpaceVertexOffsetNormal * min( length( bezierSpaceVertexOffset ) , _squeeze ) ) , bezierSpaceVertexOffset , squeezeFactor);
			float bulgeFactor = smoothstep( 0.0 , _BulgeOffset , abs( ( finalOrificeDistance - v.vertex.z ) ));
			float bulgeFactorBaseClip = smoothstep( 0.0 , 0.05 , v.vertex.z);
			float bezierSpaceVertexOffsetBulged = lerp( 1.0 , ( 1.0 + _BulgePower ) , ( ( 1.0 - bulgeFactor ) * 100.0 * bulgeFactorBaseClip ));
			float3 bezierSpaceVertexOffsetFinal = lerp( ( bezierSpaceVertexOffsetSqueezed * bezierSpaceVertexOffsetBulged ) , bezierSpaceVertexOffset , enterFactor);
			float3 bezierConstructedVertex = ( bezierPoint + bezierSpaceVertexOffsetFinal );
			float3 sphereifyDistance = ( bezierConstructedVertex - finalOrificePosition );
			float3 sphereifyNormal = normalize( sphereifyDistance );
			float sphereifyFactor = smoothstep( 0.05 , -0.05 , distanceFromTip);
			float killSphereifyForRing = lerp( sphereifyFactor , 0.0 , orificeType);
			bezierConstructedVertex = lerp( bezierConstructedVertex , ( ( min( length( sphereifyDistance ) , _squeeze ) * sphereifyNormal ) + finalOrificePosition ) , killSphereifyForRing);
			float3 ase_worldPos = mul( unity_ObjectToWorld, v.vertex );
			float3 ase_worldViewDir = normalize( UnityWorldSpaceViewDir( ase_worldPos ) );
			bezierConstructedVertex = lerp( bezierConstructedVertex , ( -ase_worldViewDir * float3( 10000,10000,10000 ) ) , _WorldSpaceLightPos0.w);
			v.normal = normalize( ( ( -bezierSpaceX * v.normal.x ) + ( bezierSpaceY * v.normal.y ) + ( bezierDerivitive * v.normal.z ) ) );
			v.vertex.xyz = bezierConstructedVertex;
			v.vertex.w = 1;

    VertexOutput o = (VertexOutput)0;
    float3 wnormal = UnityObjectToWorldNormal(v.normal);
    float3 tangent = UnityObjectToWorldDir(v.tangent.xyz);
    half tangentSign = v.tangent.w * unity_WorldTransformParams.w;
    float3 bitangent = cross(wnormal, tangent) * tangentSign;

    #if defined(Geometry)
        o.vertex = v.vertex;
    #endif

    o.pos = UnityObjectToClipPos(v.vertex);
    o.worldPos = mul(unity_ObjectToWorld, v.vertex);
    o.ntb[0] = wnormal;
    o.ntb[1] = tangent;
    o.ntb[2] = bitangent;
    o.uv = v.uv;
    o.uv1 = v.uv1;
    o.color = float4(v.color.rgb, 0); // store if outline in alpha channel of vertex colors | 0 = not an outline
    o.normal = v.normal;
    o.screenPos = ComputeScreenPos(o.pos);
    o.objPos = normalize(v.vertex);

    #if !defined(UNITY_PASS_SHADOWCASTER)
        UNITY_TRANSFER_SHADOW(o, o.uv);
        UNITY_TRANSFER_FOG(o, o.pos);
    #else
        TRANSFER_SHADOW_CASTER_NOPOS(o, o.pos);
    #endif
    return o;
}