summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--2ner.shader1
-rw-r--r--cnlohr.cginc2
-rw-r--r--shatter_wave.cginc39
-rw-r--r--tessellation.cginc42
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 + \