From fa66aacf2ea1a5b9a1073222a2e1595f352e4745 Mon Sep 17 00:00:00 2001 From: 0thElement Date: Tue, 2 Apr 2024 23:47:11 +0900 Subject: [PATCH] Gameplay: Implement rendering for 0ms arcs --- .../Gameplay/Data/Events/Arc.Rendering.cs | 28 +++++- .../Gameplay/Data/Events/ArcSegmentData.cs | 96 ++++++++++++++++++- .../Scripts/Gameplay/Render/IRenderService.cs | 2 +- .../Scripts/Gameplay/Render/RenderService.cs | 6 +- Assets/Shaders/Shadow.shader | 9 +- 5 files changed, 131 insertions(+), 10 deletions(-) diff --git a/Assets/Scripts/Gameplay/Data/Events/Arc.Rendering.cs b/Assets/Scripts/Gameplay/Data/Events/Arc.Rendering.cs index b1c5d83c..66962655 100644 --- a/Assets/Scripts/Gameplay/Data/Events/Arc.Rendering.cs +++ b/Assets/Scripts/Gameplay/Data/Events/Arc.Rendering.cs @@ -206,10 +206,22 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr continue; } - var (bodyMatrix, shadowMatrix) = segment.GetMatrices(currentFloorPosition, groupProperties.FallDirection, z, pos.y); Vector3 midpoint = pos + ((segment.StartPosition + segment.EndPosition) / 2); midpoint.z = (zPos + endZPos) / 2; float depth = Services.Camera.CalculateDepthSquared(midpoint); + + var (bodyMatrix, shadowMatrix, cornerOffset) = + (EndTiming > Timing || IsTrace) ? + segment.GetMatrices(currentFloorPosition, groupProperties.FallDirection, z, pos.y) : + segment.GetMatricesSlam( + currentFloorPosition, + groupProperties.FallDirection, + z, + pos, + TimingGroupInstance, + NextArc, + Values.ArcMeshOffset); + if (IsTrace) { Services.Render.DrawTraceSegment(matrix * bodyMatrix, color, IsSelected, depth); @@ -223,7 +235,7 @@ public void UpdateRender(int currentTiming, double currentFloorPosition, GroupPr Services.Render.DrawArcSegment(Color, highlight, matrix * bodyMatrix, color, IsSelected, redArcValue, basePos.y + segment.EndPosition.y, depth); if (!groupProperties.NoShadow) { - Services.Render.DrawArcShadow(matrix * shadowMatrix, color); + Services.Render.DrawArcShadow(matrix * shadowMatrix, color, cornerOffset); } } } @@ -315,6 +327,18 @@ public float ArcYAt(int timing) return ArcFormula.Y(YStart, YEnd, p, LineType); } + public bool TryGetFirstSegement(out ArcSegmentData segment) + { + if (segments.Count >= 1) + { + segment = segments[0]; + return true; + } + + segment = default; + return false; + } + private void RebuildSegments() { if (Values.EnableArcRebuildSegment || segments.Count == 0) diff --git a/Assets/Scripts/Gameplay/Data/Events/ArcSegmentData.cs b/Assets/Scripts/Gameplay/Data/Events/ArcSegmentData.cs index 7eaabe36..b910c386 100644 --- a/Assets/Scripts/Gameplay/Data/Events/ArcSegmentData.cs +++ b/Assets/Scripts/Gameplay/Data/Events/ArcSegmentData.cs @@ -1,4 +1,4 @@ -using System; +using ArcCreate.Gameplay.Chart; using UnityEngine; namespace ArcCreate.Gameplay.Data @@ -25,7 +25,7 @@ public float CalculateZPos(double currentFloorPosition) public float CalculateEndZPos(double currentFloorPosition) => ArcFormula.FloorPositionToZ(EndFloorPosition - currentFloorPosition); - public (Matrix4x4 body, Matrix4x4 shadow) GetMatrices(double floorPosition, Vector3 fallDirection, float baseZ, float baseY) + public (Matrix4x4 body, Matrix4x4 shadow, Vector4 cornerOffset) GetMatrices(double floorPosition, Vector3 fallDirection, float baseZ, float baseY) { float startZ = ArcFormula.FloorPositionToZ(FloorPosition - floorPosition); float endZ = ArcFormula.FloorPositionToZ(EndFloorPosition - floorPosition); @@ -46,7 +46,97 @@ public float CalculateEndZPos(double currentFloorPosition) new Vector4(dir.x, 0, dir.z, 0), new Vector4(startPos.x, -baseY, startPos.z, 1)); - return (bodyMatrix, shadowMatrix); + return (bodyMatrix, shadowMatrix, Vector4.zero); + } + + public (Matrix4x4 body, Matrix4x4 shadow, Vector4 cornerOffset) + GetMatricesSlam(double floorPosition, Vector3 fallDirection, float baseZ, Vector3 basePos, TimingGroup group, Arc next, float offset) + { + if (From > 0) + { + return (Matrix4x4.zero, Matrix4x4.zero, Vector4.zero); + } + + float startZ = ArcFormula.FloorPositionToZ(FloorPosition - floorPosition); + Vector3 startPos = StartPosition + ((startZ - baseZ) * fallDirection); + Vector3 endPos = EndPosition + ((startZ - baseZ) * fallDirection); + Vector3 dir = endPos - startPos; + + Matrix4x4 bodyMatrix = new Matrix4x4( + new Vector4(1, 0, 0, 0), + new Vector4(0, 1, 0, 0), + new Vector4(dir.x, dir.y, dir.z, 0), + new Vector4(startPos.x, startPos.y, startPos.z, 1)); + + // Accounting for angled arcs being less wide than straight arcs + float zLength = offset * 2; + if (next != null && next.TryGetFirstSegement(out ArcSegmentData nextFirstSeg) + && nextFirstSeg.EndTiming > nextFirstSeg.Timing) + { + float dz = Mathf.Abs(ArcFormula.FloorPositionToZ(nextFirstSeg.EndFloorPosition - nextFirstSeg.FloorPosition)); + float dx = Mathf.Abs(nextFirstSeg.StartPosition.x - nextFirstSeg.EndPosition.x); + zLength = Mathf.Sqrt(4 * offset * offset * dz * dz / ((dz * dz) + (dx * dx))); + } + + double fpOffset = ArcFormula.ZToFloorPosition(zLength); + + // Arc might go backward or forward in time, need to check both direction. + int slamForwardTiming = group.GetTimingFromFloorPosition(FloorPosition + fpOffset); + int slamBackwardTiming = group.GetTimingFromFloorPosition(FloorPosition - fpOffset); + int endOfSlamTiming = Mathf.Max(slamForwardTiming, slamBackwardTiming); + + // Likely speed=0. Do not render shadow. + if (endOfSlamTiming <= Timing) + { + return (bodyMatrix, Matrix4x4.zero, Vector4.zero); + } + + bool isPositiveSpeed = slamForwardTiming > slamBackwardTiming; + + // Get the necessary coords. + // nf ^ Z axis + // + x +flx - - - - - - - - +frx | + // | | | shadow . | + // | next arc | pf . | + // +----x-----+nlx - - +-----x----+nrx | + // nn | prev arc | | + // | | | | + // | x | | + // pn | + // ----------------------------------> X axis + float pf = startPos.x; + float nn = endPos.x; + float nf = (next == null || next.EndTiming <= next.Timing) ? nn : next.WorldXAt(endOfSlamTiming) - basePos.x; + + float nrx, nlx, frx, flx = 0; + if (nn < pf) + { + nrx = pf + offset; + nlx = nn + offset; + flx = Mathf.Min(nf + offset, nrx); + frx = Mathf.Max(nf + offset, nrx); + } + else + { + nlx = pf - offset; + nrx = nn - offset; + flx = Mathf.Min(nf - offset, nlx); + frx = Mathf.Max(nf - offset, nlx); + } + + zLength *= isPositiveSpeed ? 1 : -1; + float zn = startPos.z; + float zf = zn + zLength; + + float width = (nrx - nlx) / (offset * 2); + Matrix4x4 shadowMatrix = new Matrix4x4( + new Vector4(width, 0, 0, 0), + new Vector4(0, 1, 0, 0), + new Vector4(0, 0, zLength, 0), + new Vector4((nlx + nrx) / 2, -basePos.y, 0, 1)); + + Vector4 cornerOffset = new Vector4(0, frx - nrx, 0, flx - nlx) / width; + return (bodyMatrix, shadowMatrix, cornerOffset); } } } \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/Render/IRenderService.cs b/Assets/Scripts/Gameplay/Render/IRenderService.cs index 43e53edb..c42fd4b0 100644 --- a/Assets/Scripts/Gameplay/Render/IRenderService.cs +++ b/Assets/Scripts/Gameplay/Render/IRenderService.cs @@ -19,7 +19,7 @@ public interface IRenderService void DrawArcSegment(int colorId, bool highlight, Matrix4x4 matrix, Color color, bool selected, float redValue, float y, float depth); - void DrawArcShadow(Matrix4x4 matrix, Color color); + void DrawArcShadow(Matrix4x4 matrix, Color color, Vector4 cornerOffset); void DrawArcTap(bool sfx, Texture texture, Matrix4x4 matrix, Color color, bool selected); diff --git a/Assets/Scripts/Gameplay/Render/RenderService.cs b/Assets/Scripts/Gameplay/Render/RenderService.cs index f6832462..187211e0 100644 --- a/Assets/Scripts/Gameplay/Render/RenderService.cs +++ b/Assets/Scripts/Gameplay/Render/RenderService.cs @@ -124,9 +124,9 @@ public void DrawTraceSegment(Matrix4x4 matrix, Color color, bool selected, float }); } - public void DrawArcShadow(Matrix4x4 matrix, Color color) + public void DrawArcShadow(Matrix4x4 matrix, Color color, Vector4 cornerOffset) { - arcShadowDrawer.RegisterInstance(matrix, color); + arcShadowDrawer.RegisterInstance(matrix, color, cornerOffset); } public void DrawTraceShadow(Matrix4x4 matrix, Color color) @@ -280,7 +280,7 @@ public void SetShadowMaterial(Material material) arcShadowDrawer = new InstancedRendererPool( material, ArcMeshGenerator.GetShadowMesh(false), - false); + true); traceShadowDrawer?.Dispose(); traceShadowDrawer = new InstancedRendererPool( diff --git a/Assets/Shaders/Shadow.shader b/Assets/Shaders/Shadow.shader index bba92471..5223b3d5 100644 --- a/Assets/Shaders/Shadow.shader +++ b/Assets/Shaders/Shadow.shader @@ -44,6 +44,7 @@ UNITY_INSTANCING_BUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(half4, _Color) + UNITY_DEFINE_INSTANCED_PROP(float4, _Properties) UNITY_INSTANCING_BUFFER_END(Props) float4 _ShadowColor; @@ -56,9 +57,15 @@ UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); + o.uv = TRANSFORM_TEX(v.uv, _MainTex); + float4 offset = UNITY_ACCESS_INSTANCED_PROP(Props, _Properties); + v.vertex.x += ((o.uv.x < 0.5) && (o.uv.y < 0.5)) * offset.x; + v.vertex.x += ((o.uv.x < 0.5) && (o.uv.y > 0.5)) * offset.y; + v.vertex.x += ((o.uv.x > 0.5) && (o.uv.y < 0.5)) * offset.z; + v.vertex.x += ((o.uv.x > 0.5) && (o.uv.y > 0.5)) * offset.w; + o.worldpos = mul(unity_ObjectToWorld, v.vertex); o.vertex = UnityObjectToClipPos(v.vertex); - o.uv = TRANSFORM_TEX(v.uv, _MainTex); return o; }