diff options
| -rw-r--r-- | 2ner.shader | 1 | ||||
| -rw-r--r-- | cnlohr.cginc | 2 | ||||
| -rw-r--r-- | shatter_wave.cginc | 39 | ||||
| -rw-r--r-- | tessellation.cginc | 42 |
4 files changed, 64 insertions, 20 deletions
diff --git a/2ner.shader b/2ner.shader index a03b3d7..00a485f 100644 --- a/2ner.shader +++ b/2ner.shader @@ -549,6 +549,7 @@ Shader "yum_food/2ner" [HideInInspector] m_end_Tessellation_Heightmap("Heightmap", Float) = 0 [HideInInspector] m_start_Tessellation_Range_Factor("Range-based factor", Float) = 0 [ThryToggle(_TESSELLATION_RANGE_FACTOR)] _Tessellation_Range_Factor_Enabled("Enable", Float) = 0 + [Helpbox]_Tessellation_Range_Factor_Help("All distances are given in squared meters. For example, to set the far distance to 4 meters, enter 16.", Int) = 0 _Tessellation_Range_Factor_Distance_Near("Distance (near)", Float) = 1 _Tessellation_Range_Factor_Factor_Near("Factor (near)", Float) = 1 _Tessellation_Range_Factor_Distance_Far("Distance (far)", Float) = 1 diff --git a/cnlohr.cginc b/cnlohr.cginc index 52aca35..ce3e883 100644 --- a/cnlohr.cginc +++ b/cnlohr.cginc @@ -44,7 +44,7 @@ bool isMirror() { return _VRChatMirrorMode != 0; } // https://github.com/cnlohr/shadertrixx?tab=readme-ov-file#eye-center-position
float3 getCenterCamPos() {
#if defined(USING_STEREO_MATRICES) || defined(UNITY_SINGLE_PASS_STEREO)
- return (unity_StereoWorldSpaceCameraPos[0] + unity_StereoWorldSpaceCameraPos[1]) / 2;
+ return (unity_StereoWorldSpaceCameraPos[0] + unity_StereoWorldSpaceCameraPos[1]) * 0.5;
#else
return isMirror() ? _VRChatMirrorCameraPos : _WorldSpaceCameraPos.xyz;
#endif
diff --git a/shatter_wave.cginc b/shatter_wave.cginc index 8636df6..f86a6ac 100644 --- a/shatter_wave.cginc +++ b/shatter_wave.cginc @@ -15,11 +15,22 @@ void shatterWaveVert(inout float3 objPos, float3 objNormal, float3 objTangent) { float3 wave_axis2 = normalize(_Shatter_Wave_Direction2);
float3 wave_axis3 = normalize(_Shatter_Wave_Direction3);
float4x3 wave_axes = float4x3(wave_axis0, wave_axis1, wave_axis2, wave_axis3);
- float4x3 objPos_proj;
- objPos_proj[0] = dot(objPos, wave_axis0) * normalize(wave_axis0);
- objPos_proj[1] = dot(objPos, wave_axis1) * normalize(wave_axis1);
- objPos_proj[2] = dot(objPos, wave_axis2) * normalize(wave_axis2);
- objPos_proj[3] = dot(objPos, wave_axis3) * normalize(wave_axis3);
+
+ float4 projDots = mul(wave_axes, objPos);
+ // Equivalent code:
+ // float4 projDots = float4(
+ // dot(objPos, wave_axis0),
+ // dot(objPos, wave_axis1),
+ // dot(objPos, wave_axis2),
+ // dot(objPos, wave_axis3)
+ // );
+
+ float4x3 objPos_proj = float4x3(
+ projDots.x * wave_axis0,
+ projDots.y * wave_axis1,
+ projDots.z * wave_axis2,
+ projDots.w * wave_axis3
+ );
#if defined(_SHATTER_WAVE_AUDIOLINK)
float4 wave_t;
@@ -64,25 +75,23 @@ void shatterWaveVert(inout float3 objPos, float3 objNormal, float3 objTangent) { float4 wave_center = wave_t;
- // TODO calculate signed distance from wave center
- float4 distance_signed;
- for (uint i = 0; i < 4; i++) {
- float3 dist_to_center = objPos_proj[i] - wave_center[i] * wave_axes[i];
- distance_signed[i] = dot(dist_to_center, wave_axes[i]);
- }
+ float4 distance_signed = float4(
+ dot(objPos_proj[0] - wave_center.x * wave_axes[0], wave_axes[0]),
+ dot(objPos_proj[1] - wave_center.y * wave_axes[1], wave_axes[1]),
+ dot(objPos_proj[2] - wave_center.z * wave_axes[2], wave_axes[2]),
+ dot(objPos_proj[3] - wave_center.w * wave_axes[3], wave_axes[3])
+ );
#if defined(_SHATTER_WAVE_ROTATION)
float4 thetas = clamp(distance_signed * _Shatter_Wave_Rotation_Strength, -1, 1) * TAU;
+ [unroll]
for (uint i = 0; i < 4; i++) {
objPos = rotate_vector(objPos, get_quaternion(wave_axes[i], thetas[i]));
}
#endif
float4 offset = exp(-abs(distance_signed) * _Shatter_Wave_Power) * _Shatter_Wave_Amplitude;
- objPos += objNormal * offset[0];
- objPos += objNormal * offset[1];
- objPos += objNormal * offset[2];
- objPos += objNormal * offset[3];
+ objPos += objNormal * (offset.x + offset.y + offset.z + offset.w);
}
void shatterWaveFrag(inout float3 normal, float3 objPos) {
diff --git a/tessellation.cginc b/tessellation.cginc index 2725776..30c3c63 100644 --- a/tessellation.cginc +++ b/tessellation.cginc @@ -16,20 +16,54 @@ tess_factors patch_constant(InputPatch<v2f, 3> patch) { tess_factors f; #if defined(_TESSELLATION) #if defined(_TESSELLATION_RANGE_FACTOR) - float d = length(getCenterCamPos() - patch[0].worldPos.xyz); + float3 vec = getCenterCamPos() - patch[0].worldPos.xyz; + float d2 = dot(vec, vec); float factor = lerp( _Tessellation_Range_Factor_Factor_Near, _Tessellation_Range_Factor_Factor_Far, smoothstep( _Tessellation_Range_Factor_Distance_Near, _Tessellation_Range_Factor_Distance_Far, - d)); + d2)); #else float factor = _Tessellation_Factor; #endif + { + // Frustum culling - don't tessellate if the patch is outside the viewport + // (xy) or behind the camera (w). We approximate this by checking the + // un-transformed and maximally transformed locations. Technically we could + // miss an intersection in the middle, but I haven't noticed any visible + // popping with this approach. + float max_displacement = _Tessellation_Heightmap_Scale * 0.5 + _Tessellation_Heightmap_Offset; + float3 p0d = patch[0].objPos.xyz + patch[0].normal.xyz * max_displacement; + float3 p1d = patch[1].objPos.xyz + patch[1].normal.xyz * max_displacement; + float3 p2d = patch[2].objPos.xyz + patch[2].normal.xyz * max_displacement; + float4 p0_clipPos = UnityObjectToClipPos(float4(patch[0].objPos.xyz, 1)); + float4 p1_clipPos = UnityObjectToClipPos(float4(patch[1].objPos.xyz, 1)); + float4 p2_clipPos = UnityObjectToClipPos(float4(patch[2].objPos.xyz, 1)); + float4 p0d_clipPos = UnityObjectToClipPos(float4(p0d, 1)); + float4 p1d_clipPos = UnityObjectToClipPos(float4(p1d, 1)); + float4 p2d_clipPos = UnityObjectToClipPos(float4(p2d, 1)); + float3 p0_ndc = p0_clipPos.xyz / p0_clipPos.w; + float3 p1_ndc = p1_clipPos.xyz / p1_clipPos.w; + float3 p2_ndc = p2_clipPos.xyz / p2_clipPos.w; + float3 p0d_ndc = p0d_clipPos.xyz / p0d_clipPos.w; + float3 p1d_ndc = p1d_clipPos.xyz / p1d_clipPos.w; + float3 p2d_ndc = p2d_clipPos.xyz / p2d_clipPos.w; + + bool on_screen = + (p0_ndc.x > -1 && p0_ndc.x < 1 && p0_ndc.y > -1 && p0_ndc.y < 1 && p0_clipPos.w > 0) || + (p1_ndc.x > -1 && p1_ndc.x < 1 && p1_ndc.y > -1 && p1_ndc.y < 1 && p1_clipPos.w > 0) || + (p2_ndc.x > -1 && p2_ndc.x < 1 && p2_ndc.y > -1 && p2_ndc.y < 1 && p2_clipPos.w > 0) || + (p0d_ndc.x > -1 && p0d_ndc.x < 1 && p0d_ndc.y > -1 && p0d_ndc.y < 1 && p0d_clipPos.w > 0) || + (p1d_ndc.x > -1 && p1d_ndc.x < 1 && p1d_ndc.y > -1 && p1d_ndc.y < 1 && p1d_clipPos.w > 0) || + (p2d_ndc.x > -1 && p2d_ndc.x < 1 && p2d_ndc.y > -1 && p2d_ndc.y < 1 && p2d_clipPos.w > 0); + factor = lerp(0, factor, on_screen); + } #else float factor = 1; #endif + f.edge[0] = factor; f.edge[1] = factor; f.edge[2] = factor; @@ -40,7 +74,7 @@ tess_factors patch_constant(InputPatch<v2f, 3> patch) { [UNITY_domain("tri")] [UNITY_outputcontrolpoints(3)] [UNITY_outputtopology("triangle_cw")] -[UNITY_partitioning("fractional_odd")] +[UNITY_partitioning("integer")] [UNITY_patchconstantfunc("patch_constant")] v2f hull( InputPatch<v2f, 3> patch, @@ -55,7 +89,7 @@ v2f domain( OutputPatch<v2f, 3> patch, float3 baryc : SV_DomainLocation) { - v2f o; + v2f o = (v2f) 0; #define DOMAIN_INTERP(fieldName) \ patch[0].fieldName * baryc.x + \ patch[1].fieldName * baryc.y + \ |
