833 lines
22 KiB
GLSL
833 lines
22 KiB
GLSL
Shader "Hidden/VRCMarker Internal/Line Renderer"
|
|
{
|
|
Properties
|
|
{
|
|
[HideInInspector]_Color ("Color", Color) = (1,1,1,1)
|
|
[HideInInspector]_Scale ("Width", Range(0, 1)) = 0.5
|
|
_GradientPeriod ("Gradient Period", Float) = 256
|
|
|
|
//[NoScaleOffset] _MainTex("Albedo (RGB)", 2D) = "white" {}
|
|
////[NoScaleOffset] _MetallicGlossMap("Mask Map", 2D) = "white" {}
|
|
//[NoScaleOffset] _ColorMask("Color Mask Map", 2D) = "white" {}
|
|
//_Glossiness ("Smoothness", Range(0,1)) = 0.5
|
|
//_GradientLength ("Gradient Length", Float) = 2
|
|
[HideInInspector] _StencilRef ("", Float) = 0
|
|
_PositionData ("Data", 2D) = "white" {}
|
|
|
|
_SubdivideDistance ("Subdivide Distance", Float) = 3
|
|
[Toggle(_VRC_LIGHTVOLUMES)] _EnableLightVolumes ("VRC Light Volumes", Float) = 0
|
|
_LightVolumesInfluence ("VRC Light Volume Influence", Range(0,1)) = 0.9
|
|
}
|
|
|
|
CGINCLUDE
|
|
|
|
#pragma vertex vert
|
|
#pragma fragment frag
|
|
|
|
#ifdef SHADER_API_D3D11
|
|
#define USE_GEOM
|
|
#endif
|
|
|
|
#pragma multi_compile_instancing
|
|
|
|
#include "Line.cginc"
|
|
#include "UnityCG.cginc"
|
|
|
|
#pragma shader_feature_local_fragment _VRC_LIGHTVOLUMES
|
|
#ifdef _VRC_LIGHTVOLUMES
|
|
#include "Packages/red.sim.lightvolumes/Shaders/LightVolumes.cginc"
|
|
|
|
// fallback to 1.0
|
|
void LV_SampleLightProbe_1(out float3 L0, out float3 L1r, out float3 L1g, out float3 L1b) {
|
|
L0 = 1;
|
|
L1r = 1.0/3.0;
|
|
L1g = 1.0/3.0;
|
|
L1b = 1.0/3.0;
|
|
}
|
|
#define LV_SampleLightProbe LV_SampleLightProbe_1
|
|
#endif
|
|
|
|
half _LightVolumesInfluence;
|
|
half3 _Color;
|
|
half _OutlineValue;
|
|
half _OutlineHue;
|
|
|
|
half _Scale;
|
|
half _GradientPeriod;
|
|
half4 _Gradient[8];
|
|
uint _GradientLength;
|
|
uint _VertexCount;
|
|
float3 _LastPosition;
|
|
|
|
float _DummyZero;
|
|
float _OutlineWidth;
|
|
float _EraseDistance;
|
|
float3 _EraserPosition;
|
|
|
|
float _SubdivideDistance;
|
|
|
|
Texture2D<float4> _PositionData;
|
|
|
|
struct appdata
|
|
{
|
|
float4 vertex : POSITION; // not needed lol
|
|
uint vertexID : SV_VertexID;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
#ifdef USE_GEOM
|
|
struct v2g
|
|
{
|
|
float4 vertex : SV_POSITION;
|
|
uint vertexID : TEXCOORD0;
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
};
|
|
|
|
struct g2f
|
|
#else
|
|
struct v2f
|
|
#endif
|
|
{
|
|
float4 vertex : SV_POSITION;
|
|
float2 uv0 : TEXCOORD0;
|
|
nointerpolation bool isLine : TEXCOORD1;
|
|
half3 gradient : TEXCOORD2;
|
|
float3 position : TEXCOORD3;
|
|
|
|
UNITY_VERTEX_INPUT_INSTANCE_ID
|
|
UNITY_VERTEX_OUTPUT_STEREO
|
|
};
|
|
|
|
|
|
float3 centerEyePos()
|
|
{
|
|
// trail tube looks more convincing in vr without this
|
|
// #if defined(UNITY_STEREO_MULTIVIEW_ENABLED) || defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_SINGLE_PASS_STEREO)
|
|
// return 0.5 * (unity_StereoWorldSpaceCameraPos[0] + unity_StereoWorldSpaceCameraPos[1]);
|
|
// #else
|
|
return _WorldSpaceCameraPos;
|
|
// #endif
|
|
}
|
|
|
|
// thanks error.mdl for help
|
|
float3 billboardTriangle(float3 vertex, float3 triCenter)
|
|
{
|
|
vertex -= triCenter;
|
|
float3 head = centerEyePos();
|
|
float3 center2Head = head - triCenter;
|
|
float c2hLen = length(center2Head);
|
|
float c2hXZLen = length(center2Head.xz);
|
|
|
|
float sin1 = center2Head.y / c2hLen;
|
|
float cos1 = c2hXZLen / c2hLen;
|
|
float2x2 rot1 = float2x2(cos1, -sin1, -sin1, cos1);
|
|
vertex.zy = mul(rot1, vertex.zy);
|
|
|
|
float sin2 = center2Head.x / c2hXZLen;
|
|
float cos2 = center2Head.z / c2hXZLen;
|
|
float2x2 rot2 = float2x2(cos2, sin2, -sin2, cos2);
|
|
vertex.xz = mul(rot2, vertex.xz);
|
|
|
|
vertex += triCenter;
|
|
return vertex;
|
|
}
|
|
|
|
// vertices always set in this order, i hope
|
|
static const float2 offsets[7] =
|
|
{
|
|
float2(0, 0),
|
|
float2(0, 1),
|
|
float2(1, 1),
|
|
float2(1, 0),
|
|
float2(-0.077350269189625764509148780501f, 0),
|
|
float2(0.5f, 1),
|
|
float2(1.077350269189625764509148780501f, 0)
|
|
};
|
|
|
|
struct Gradient
|
|
{
|
|
int type;
|
|
int colorsLength;
|
|
half4 colors[8];
|
|
};
|
|
|
|
Gradient NewGradient(int type, int colorsLength, half4 colors[8])
|
|
{
|
|
Gradient output =
|
|
{
|
|
type, colorsLength, colors
|
|
};
|
|
return output;
|
|
}
|
|
|
|
half3 EvaluateGradient(Gradient gradient, half time)
|
|
{
|
|
half3 color = gradient.colors[0].rgb;
|
|
[unroll(6)]
|
|
for (int c = 1; c < gradient.colorsLength; c++)
|
|
{
|
|
half colorPos = saturate((time - gradient.colors[c - 1].w) / (gradient.colors[c].w - gradient.colors[c - 1].w)) * step(c, gradient.colorsLength - 1);
|
|
color = lerp(color, gradient.colors[c].rgb, lerp(colorPos, step(0.01, colorPos), gradient.type));
|
|
}
|
|
|
|
return color;
|
|
}
|
|
|
|
half evaluateTime(uint id, half frequency)
|
|
{
|
|
half t = (sin((float)id / frequency) + 1.0) / 2.0;
|
|
return t;
|
|
}
|
|
|
|
#ifdef USE_GEOM
|
|
v2g vert (appdata v)
|
|
{
|
|
v2g o;
|
|
UNITY_INITIALIZE_OUTPUT(v2g, o);
|
|
UNITY_SETUP_INSTANCE_ID(v);
|
|
UNITY_TRANSFER_INSTANCE_ID(v, o);
|
|
|
|
o.vertex = v.vertex;
|
|
o.vertexID = v.vertexID;
|
|
return o;
|
|
}
|
|
|
|
#else
|
|
|
|
v2f vert(appdata v)
|
|
{
|
|
v2f o;
|
|
UNITY_SETUP_INSTANCE_ID(v); //Insert
|
|
UNITY_INITIALIZE_OUTPUT(v2f, o); //Insert
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); //Insert
|
|
|
|
uint index = v.vertexID / 7;
|
|
uint type = v.vertexID % 7;
|
|
bool isLine = type <= 3;
|
|
|
|
// float3 originalPos = v.vertex.xyz;
|
|
|
|
//v.vertex.xyz = _PositionData[uint2(0, index)].xyz;
|
|
float4 data0 = _PositionData[IndexToCoords(index)];
|
|
float4 data1 = _PositionData[IndexToCoords(index - 1)];
|
|
float3 start = data0.xyz;
|
|
float3 end = data1.xyz;
|
|
|
|
float timestamp0 = data0.a;
|
|
float timestamp1 = data1.a;
|
|
float time = _Time.y;
|
|
|
|
bool shouldDiscard = false;
|
|
|
|
if (all(start.xyz == end.xyz))
|
|
{
|
|
start = 0;
|
|
shouldDiscard = true;
|
|
}
|
|
|
|
|
|
if (timestamp0 > 0)
|
|
{
|
|
float increment = 0.02f;
|
|
float timeScale = 1.0f / increment;
|
|
|
|
float nextTime = _PositionData[IndexToCoords(index + 1)].a;
|
|
if (nextTime == 0) nextTime = timestamp1;
|
|
float timeDistance = abs(timestamp0 - nextTime);
|
|
// if (timeDistance == 0) timeDistance = 0.04;
|
|
// if (timeDistance > 0.49) timeDistance = 0.02;
|
|
|
|
float timeOffset = _Time.y - timestamp0;
|
|
float lerpTime = saturate(timeOffset / timeDistance);
|
|
if (all(end == 0)) end = start;
|
|
start = lerp(end, start, lerpTime);
|
|
|
|
if (timeOffset <= 0 || (_Time.y - timestamp1) <= 0)
|
|
{
|
|
shouldDiscard = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
UNITY_BRANCH
|
|
if (shouldDiscard|| all(start.xyz == 0))
|
|
{
|
|
o.vertex = 0.0 / 0.0;
|
|
// o.vertex = asfloat(-1);
|
|
return o;
|
|
}
|
|
else
|
|
{
|
|
uint gradientTime = type <= 1 ? data1.a : data0.a;
|
|
|
|
float3 vertexPos = start;
|
|
float3 otherPos = end;
|
|
o.position = vertexPos;
|
|
|
|
if (isLine && type <= 1)
|
|
{
|
|
otherPos = start;
|
|
|
|
if (all(end != 0 && start == 0) || all(end == 0 && start != 0))
|
|
{
|
|
vertexPos = start;
|
|
}
|
|
else
|
|
{
|
|
vertexPos = end;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
float2 offset = offsets[type];
|
|
|
|
#ifdef OUTLINE_PASS
|
|
_Scale += _OutlineWidth;
|
|
#endif
|
|
|
|
UNITY_BRANCH
|
|
if (isLine)
|
|
{
|
|
gradientTime = data0.a;
|
|
float3 v1 = otherPos - vertexPos;
|
|
float3 v2 = centerEyePos() - vertexPos;
|
|
float3 scaleDir = normalize(cross(v1, v2));
|
|
scaleDir *= _Scale;
|
|
|
|
if (offset.x > 0) scaleDir = -scaleDir;
|
|
// scaleDir *= offset.x * 2 - 1;
|
|
|
|
vertexPos += scaleDir * offset.y;
|
|
vertexPos -= scaleDir * (1 - offset.y);
|
|
}
|
|
else
|
|
{
|
|
float scaleFactor = 1.5;
|
|
float2 triangleOffset = offset * 2 - 1;
|
|
triangleOffset *= _Scale * scaleFactor;
|
|
triangleOffset.y += _Scale * scaleFactor * UNITY_PI * 0.106;
|
|
|
|
float3 vertexOffset = float3(triangleOffset.x, triangleOffset.y, 0);
|
|
float3 triangleVertex = float3(vertexPos.xy + triangleOffset, vertexPos.z);
|
|
vertexPos = billboardTriangle(triangleVertex, vertexPos);
|
|
}
|
|
|
|
o.vertex = mul(UNITY_MATRIX_VP, float4(vertexPos, 1.0));
|
|
|
|
|
|
// o.vertex = UnityObjectToClipPos(float4(originalPos, 1));
|
|
|
|
o.uv0 = offset;
|
|
o.isLine = isLine;
|
|
|
|
UNITY_BRANCH
|
|
if (_GradientLength > 0)
|
|
{
|
|
// half t = evaluateTime((gradientTime * 7) + type , _GradientPeriod);
|
|
half t = evaluateTime(v.vertexID, 256);
|
|
Gradient g = NewGradient(0, _GradientLength, _Gradient);
|
|
o.gradient = EvaluateGradient(g,t);
|
|
}
|
|
|
|
return o;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
float3 CatmullRom(float3 p0, float3 p1, float3 p2, float3 p3, float t) {
|
|
|
|
float t2 = t * t;
|
|
float t3 = t2 * t;
|
|
|
|
float3 p = 0.5 * (
|
|
(2.0 * p1) +
|
|
(-p0 + p2) * t +
|
|
(2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2 +
|
|
(-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3
|
|
);
|
|
|
|
return p;
|
|
}
|
|
|
|
#ifdef USE_GEOM
|
|
[maxvertexcount(6)]
|
|
void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream)
|
|
{
|
|
g2f o1 = (g2f)0;
|
|
g2f o2[3] = { (g2f)0,(g2f)0,(g2f)0 };
|
|
|
|
#ifdef OUTLINE_PASS
|
|
_Scale += _OutlineWidth;
|
|
#endif
|
|
|
|
|
|
bool shouldSubvidide = false;
|
|
|
|
for(int i = 0; i < 3; i++)
|
|
{
|
|
UNITY_SETUP_INSTANCE_ID(IN[i]);
|
|
|
|
uint vertexID = IN[i].vertexID;
|
|
uint index = vertexID / 7;
|
|
uint type = vertexID % 7;
|
|
bool isLine = type <= 3;
|
|
|
|
// float3 originalPos = v.vertex.xyz;
|
|
|
|
//v.vertex.xyz = _PositionData[uint2(0, index)].xyz;
|
|
float4 data0 = _PositionData[IndexToCoords(index)];
|
|
float4 data1 = _PositionData[IndexToCoords(index - 1)];
|
|
float3 start = data0.xyz;
|
|
float3 end = data1.xyz;
|
|
// end = lerp(start.xyz, end.xyz, 0.5);
|
|
|
|
|
|
float timestamp0 = data0.a;
|
|
float timestamp1 = data1.a;
|
|
float time = _Time.y;
|
|
|
|
bool shouldDiscard = false;
|
|
|
|
if (all(start.xyz == end.xyz))
|
|
{
|
|
start = 0;
|
|
shouldDiscard = true;
|
|
}
|
|
|
|
|
|
|
|
if (timestamp0 > 0)
|
|
{
|
|
float increment = 0.02f;
|
|
float timeScale = 1.0f / increment;
|
|
|
|
float nextTime = _PositionData[IndexToCoords(index + 1)].a;
|
|
if (nextTime == 0) nextTime = timestamp1;
|
|
float timeDistance = abs(timestamp0 - nextTime);
|
|
// if (timeDistance == 0) timeDistance = 0.04;
|
|
// if (timeDistance > 0.49) timeDistance = 0.02;
|
|
|
|
float timeOffset = _Time.y - timestamp0;
|
|
float lerpTime = saturate(timeOffset / timeDistance);
|
|
if (all(end == 0)) end = start;
|
|
start = lerp(end, start, lerpTime);
|
|
|
|
if (timeOffset <= 0 || (_Time.y - timestamp1) <= 0)
|
|
{
|
|
shouldDiscard = true;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
UNITY_BRANCH
|
|
if (shouldDiscard|| all(start.xyz == 0))
|
|
{
|
|
// o.vertex = 0.0 / 0.0;
|
|
// o.vertex = asfloat(-1);
|
|
// triStream.RestartStrip();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
float3 subdivide = 0;
|
|
if (!all(end.xyz == 0))
|
|
{
|
|
float distanceToCam = distance(end, centerEyePos());
|
|
|
|
UNITY_BRANCH
|
|
if (distanceToCam < _SubdivideDistance)
|
|
{
|
|
float3 previousPoint = _PositionData[IndexToCoords(index-2)];
|
|
float3 nextPoint = _PositionData[IndexToCoords(index+1)];
|
|
|
|
if (all(previousPoint == 0) || all(nextPoint.xyz == 0))
|
|
{
|
|
previousPoint = start;
|
|
nextPoint = end;
|
|
}
|
|
|
|
float tt = mad(sin(_Time.y), 0.5, 0.5);
|
|
float d1 = distance(previousPoint, start);
|
|
float d2 = distance(start, end);
|
|
|
|
float maxDistance = distance(start, end) * 3.0;
|
|
if (distance(previousPoint, start) > maxDistance)
|
|
{
|
|
previousPoint = start;
|
|
}
|
|
if (distance(nextPoint, end) > maxDistance)
|
|
{
|
|
nextPoint = end;
|
|
}
|
|
|
|
subdivide = CatmullRom(previousPoint, start, end, nextPoint, 0.5);
|
|
subdivide = lerp((start + end) / 2.0, subdivide, saturate((_SubdivideDistance - distanceToCam) * 3.0));
|
|
shouldSubvidide = true;
|
|
}
|
|
}
|
|
|
|
|
|
uint gradientTime = type <= 1 ? data1.a : data0.a;
|
|
|
|
UNITY_BRANCH
|
|
if (_GradientLength > 0)
|
|
{
|
|
// half t = evaluateTime((gradientTime * 7) + type , _GradientPeriod);
|
|
half t = evaluateTime(vertexID, 256);
|
|
Gradient g = NewGradient(0, _GradientLength, _Gradient);
|
|
o1.gradient = EvaluateGradient(g, t);
|
|
o2[i].gradient = o1.gradient;
|
|
}
|
|
|
|
float3 start1 = start;
|
|
float3 end1 = end;
|
|
// o1
|
|
{
|
|
if (shouldSubvidide)
|
|
{
|
|
start = subdivide;
|
|
}
|
|
|
|
float3 vertexPos = start;
|
|
float3 otherPos = end;
|
|
|
|
if (isLine && type <= 1)
|
|
{
|
|
otherPos = start;
|
|
|
|
if (all(end != 0 && start == 0) || all(end == 0 && start != 0))
|
|
{
|
|
vertexPos = start;
|
|
}
|
|
else
|
|
{
|
|
vertexPos = end;
|
|
}
|
|
}
|
|
|
|
float2 offset = offsets[type];
|
|
|
|
UNITY_BRANCH
|
|
if (isLine)
|
|
{
|
|
gradientTime = data0.a;
|
|
float3 v1 = otherPos - vertexPos;
|
|
float3 v2 = centerEyePos() - vertexPos;
|
|
float3 scaleDir = normalize(cross(v1, v2));
|
|
scaleDir *= _Scale;
|
|
|
|
if (offset.x > 0) scaleDir = -scaleDir;
|
|
// scaleDir *= offset.x * 2 - 1;
|
|
|
|
vertexPos += scaleDir * offset.y;
|
|
vertexPos -= scaleDir * (1 - offset.y);
|
|
}
|
|
else
|
|
{
|
|
float scaleFactor = 1.5;
|
|
float2 triangleOffset = offset * 2 - 1;
|
|
triangleOffset *= _Scale * scaleFactor;
|
|
triangleOffset.y += _Scale * scaleFactor * UNITY_PI * 0.106;
|
|
|
|
float3 vertexOffset = float3(triangleOffset.x, triangleOffset.y, 0);
|
|
float3 triangleVertex = float3(vertexPos.xy + triangleOffset, vertexPos.z);
|
|
vertexPos = billboardTriangle(triangleVertex, vertexPos);
|
|
}
|
|
|
|
o1.vertex = mul(UNITY_MATRIX_VP, float4(vertexPos, 1.0));
|
|
o1.position = start;
|
|
o1.uv0 = offset;
|
|
o1.isLine = isLine;
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o1);
|
|
triStream.Append(o1);
|
|
}
|
|
|
|
// o2
|
|
UNITY_BRANCH
|
|
if (shouldSubvidide)
|
|
{
|
|
start = start1;
|
|
end = subdivide;
|
|
|
|
float3 vertexPos = start;
|
|
float3 otherPos = end;
|
|
|
|
if (isLine && type <= 1)
|
|
{
|
|
otherPos = start;
|
|
|
|
if (all(end != 0 && start == 0) || all(end == 0 && start != 0))
|
|
{
|
|
vertexPos = start;
|
|
}
|
|
else
|
|
{
|
|
vertexPos = end;
|
|
}
|
|
}
|
|
|
|
float2 offset = offsets[type];
|
|
|
|
UNITY_BRANCH
|
|
if (isLine)
|
|
{
|
|
gradientTime = data0.a;
|
|
float3 v1 = otherPos - vertexPos;
|
|
float3 v2 = centerEyePos() - vertexPos;
|
|
float3 scaleDir = normalize(cross(v1, v2));
|
|
scaleDir *= _Scale;
|
|
|
|
if (offset.x > 0) scaleDir = -scaleDir;
|
|
// scaleDir *= offset.x * 2 - 1;
|
|
|
|
vertexPos += scaleDir * offset.y;
|
|
vertexPos -= scaleDir * (1 - offset.y);
|
|
}
|
|
else
|
|
{
|
|
float scaleFactor = 1.5;
|
|
float2 triangleOffset = offset * 2 - 1;
|
|
triangleOffset *= _Scale * scaleFactor;
|
|
triangleOffset.y += _Scale * scaleFactor * UNITY_PI * 0.106;
|
|
|
|
float3 vertexOffset = float3(triangleOffset.x, triangleOffset.y, 0);
|
|
float3 triangleVertex = float3(vertexPos.xy + triangleOffset, vertexPos.z);
|
|
vertexPos = billboardTriangle(triangleVertex, vertexPos);
|
|
}
|
|
|
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o2[i]);
|
|
o2[i].vertex = mul(UNITY_MATRIX_VP, float4(vertexPos, 1.0));
|
|
o2[i].uv0 = offset;
|
|
o2[i].isLine = isLine;
|
|
}
|
|
}
|
|
}
|
|
|
|
o2[0].isLine = o1.isLine;
|
|
o2[1].isLine = o1.isLine;
|
|
o2[2].isLine = o1.isLine;
|
|
|
|
o2[0].position = o1.position;
|
|
o2[1].position = o1.position;
|
|
o2[2].position = o1.position;
|
|
|
|
if (shouldSubvidide)
|
|
{
|
|
triStream.RestartStrip();
|
|
triStream.Append(o2[0]);
|
|
triStream.Append(o2[1]);
|
|
triStream.Append(o2[2]);
|
|
}
|
|
triStream.RestartStrip();
|
|
}
|
|
#endif
|
|
|
|
half3 HueShift(float3 In, float Offset)
|
|
{
|
|
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
|
|
float4 P = lerp(float4(In.bg, K.wz), float4(In.gb, K.xy), step(In.b, In.g));
|
|
float4 Q = lerp(float4(P.xyw, In.r), float4(In.r, P.yzx), step(P.x, In.r));
|
|
float D = Q.x - min(Q.w, Q.y);
|
|
float E = 1e-10;
|
|
float3 hsv = float3(abs(Q.z + (Q.w - Q.y)/(6.0 * D + E)), D / (Q.x + E), Q.x);
|
|
|
|
float hue = hsv.x + Offset / 360;
|
|
hsv.x = (hue < 0)
|
|
? hue + 1
|
|
: (hue > 1)
|
|
? hue - 1
|
|
: hue;
|
|
|
|
float4 K2 = float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
|
float3 P2 = abs(frac(hsv.xxx + K2.xyz) * 6.0 - K2.www);
|
|
return hsv.z * lerp(K2.xxx, saturate(P2 - K2.xxx), hsv.y);
|
|
}
|
|
|
|
float TriangleInsideQuad(float2 uv, float2 p0, float2 p1, float2 p2)
|
|
{
|
|
float e0 = (p1.x - p0.x) * (uv.y - p0.y) - (p1.y - p0.y) * (uv.x - p0.x);
|
|
float e1 = (p2.x - p1.x) * (uv.y - p1.y) - (p2.y - p1.y) * (uv.x - p1.x);
|
|
float e2 = (p0.x - p2.x) * (uv.y - p2.y) - (p0.y - p2.y) * (uv.x - p2.x);
|
|
|
|
return (e0 >= 0 && e1 >= 0 && e2 >= 0) ? 1.0 : 0.0;
|
|
}
|
|
|
|
#ifdef USE_GEOM
|
|
half4 frag(g2f i) : SV_Target
|
|
#else
|
|
half4 frag(v2f i) : SV_Target
|
|
#endif
|
|
{
|
|
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(i); //Insert
|
|
|
|
half alpha = 1;
|
|
|
|
// uint samplecount = GetRenderTargetSampleCount();
|
|
bool inEraseRange = distance(_EraserPosition, i.position) < _EraseDistance;
|
|
|
|
bool eraseColor = false;
|
|
UNITY_BRANCH
|
|
if (!i.isLine)
|
|
{
|
|
float2 coord = i.uv0.xy;
|
|
coord.x -= 0.5;
|
|
coord.y -= 1./3.;
|
|
|
|
float circle = length(coord);
|
|
float size = 1.0 / 3.0;
|
|
|
|
float pwidth = max(fwidth(circle), 0.0001);
|
|
alpha = saturate((size - circle) / pwidth);
|
|
|
|
#ifndef OUTLINE_PASS
|
|
bool triangleOutline = 1 - TriangleInsideQuad(i.uv0, float2(0.5,0.94), float2(-0.02,0.03), float2(1.02,0.03));
|
|
if (inEraseRange && triangleOutline)
|
|
{
|
|
eraseColor = true;
|
|
alpha = 1;
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
float size = abs(i.uv0.y - 0.5) * 2;
|
|
size = 1-size;
|
|
float pwidth = max(fwidth(size), 0.0001);
|
|
|
|
alpha = saturate((size) / pwidth);
|
|
alpha = saturate(alpha + pwidth);
|
|
|
|
}
|
|
|
|
// alpha = alpha * samplecount + 0.5;
|
|
// cov = (1u << (uint)(alpha)) - 1u;
|
|
|
|
if (alpha < 0.1) discard;
|
|
|
|
|
|
half3 color = _GradientLength > 0 ? i.gradient : _Color;
|
|
|
|
#ifdef OUTLINE_PASS
|
|
color = HueShift(color, _OutlineHue);
|
|
color *= _OutlineValue;
|
|
#endif
|
|
|
|
if (eraseColor)
|
|
{
|
|
color = float3(1,0.1,0.1);
|
|
}
|
|
|
|
#ifdef _VRC_LIGHTVOLUMES
|
|
float3 up = float3(0,1,0);
|
|
float3 dir = normalize(_WorldSpaceCameraPos.xyz - i.position);
|
|
float3 L0, L1r, L1g, L1b;
|
|
LightVolumeSH(i.position, L0, L1r, L1g, L1b);
|
|
float3 sh9Dir = L1r.xyz * 0.333333 + L1g.xyz * 0.333333 + L1b.xyz * 0.333333;
|
|
float3 sh9DirAbs = float3(sh9Dir.x, abs(sh9Dir.y), sh9Dir.z);
|
|
|
|
half3 sh = LightVolumeEvaluate(sh9DirAbs, L0, L1r, L1g, L1b);
|
|
if (any(float3(unity_SHAr.w, unity_SHAg.w, unity_SHAb.w) != L0))
|
|
color.rgb *= lerp(1.0, sh, _LightVolumesInfluence);
|
|
#endif
|
|
|
|
return half4(color, alpha);
|
|
}
|
|
ENDCG
|
|
SubShader
|
|
{
|
|
|
|
Tags
|
|
{
|
|
"RenderType"="Opaque"
|
|
"DisableBatching" = "True"
|
|
}
|
|
|
|
// PC with Geometry shader
|
|
Pass
|
|
{
|
|
Cull Back
|
|
Tags { "LightMode" = "ForwardBase" "Queue"="AlphaTest" "RenderType"="TransparentCutout" }
|
|
|
|
AlphaToMask On
|
|
|
|
Stencil
|
|
{
|
|
Ref 128
|
|
Comp Always
|
|
Pass Replace
|
|
}
|
|
|
|
CGPROGRAM
|
|
#pragma target 5.0
|
|
#pragma require geometry
|
|
#pragma geometry geom
|
|
#pragma only_renderers d3d11
|
|
ENDCG
|
|
}
|
|
|
|
// Outline Pass PC only
|
|
Pass
|
|
{
|
|
Cull Back
|
|
Tags { "LightMode" = "Always" "Queue"="AlphaTest" "RenderType"="TransparentCutout" }
|
|
// ZWrite Off
|
|
// Blend SrcAlpha OneMinusSrcAlpha
|
|
AlphaToMask On
|
|
Stencil
|
|
{
|
|
Ref 128
|
|
Comp NotEqual
|
|
}
|
|
|
|
CGPROGRAM
|
|
#pragma target 5.0
|
|
#pragma require geometry
|
|
#pragma geometry geom
|
|
#pragma only_renderers d3d11
|
|
|
|
#pragma multi_compile OUTLINE_PASS
|
|
ENDCG
|
|
}
|
|
|
|
// Pass
|
|
// {
|
|
// Name "ShadowCaster"
|
|
// Tags { "LightMode" = "ShadowCaster" }
|
|
|
|
// ZWrite On ZTest LEqual Cull Off
|
|
|
|
// CGPROGRAM
|
|
// #pragma multi_compile_shadowcaster
|
|
// ENDCG
|
|
// }
|
|
}
|
|
|
|
SubShader
|
|
{
|
|
Tags
|
|
{
|
|
"RenderType"="Opaque"
|
|
"DisableBatching" = "True"
|
|
}
|
|
|
|
// quest
|
|
Pass
|
|
{
|
|
Cull Back
|
|
Tags { "LightMode" = "ForwardBase" "Queue"="AlphaTest" "RenderType"="TransparentCutout" }
|
|
|
|
AlphaToMask On
|
|
|
|
CGPROGRAM
|
|
#pragma exclude_renderers d3d11
|
|
ENDCG
|
|
}
|
|
}
|
|
}
|