Skip to content

Commit

Permalink
Line clipping fix.
Browse files Browse the repository at this point in the history
  • Loading branch information
awgil committed Jul 15, 2024
1 parent d2fa96a commit 9ff4219
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 72 deletions.
2 changes: 1 addition & 1 deletion FFXIVClientStructs
Submodule FFXIVClientStructs updated 61 files
+1 −9 FFXIVClientStructs/FFXIV/Client/Game/Character/Character.cs
+8 −0 FFXIVClientStructs/FFXIV/Client/Game/Character/DrawDataContainer.cs
+14 −0 FFXIVClientStructs/FFXIV/Client/Game/Character/EffectContainer.cs
+17 −3 FFXIVClientStructs/FFXIV/Client/Game/Fate/FateContext.cs
+5 −5 FFXIVClientStructs/FFXIV/Client/Game/Gauge/JobGaugeEnums.cs
+11 −12 FFXIVClientStructs/FFXIV/Client/Game/Gauge/JobGauges.cs
+12 −5 FFXIVClientStructs/FFXIV/Client/Game/Group/PartyMember.cs
+1 −1 FFXIVClientStructs/FFXIV/Client/Game/MJI/MJIManager.cs
+5 −5 FFXIVClientStructs/FFXIV/Client/Game/UI/ContentsFinder.cs
+8 −1 FFXIVClientStructs/FFXIV/Client/Graphics/Render/Camera.cs
+3 −3 FFXIVClientStructs/FFXIV/Client/Graphics/Render/Material.cs
+20 −19 FFXIVClientStructs/FFXIV/Client/Graphics/Scene/CharacterBase.cs
+2 −2 FFXIVClientStructs/FFXIV/Client/System/Scheduler/Base/CutSceneController.cs
+3 −0 FFXIVClientStructs/FFXIV/Client/System/String/Utf8String.cs
+1 −1 FFXIVClientStructs/FFXIV/Client/UI/AddonCharacterClass.cs
+1 −1 FFXIVClientStructs/FFXIV/Client/UI/AddonCharacterInspect.cs
+83 −55 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudACN.cs
+23 −48 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudAST.cs
+95 −75 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudBLM.cs
+9 −4 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudBRD.cs
+5 −2 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudDNC.cs
+23 −43 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudDRG.cs
+6 −3 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudDRK.cs
+4 −1 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudGNB.cs
+2 −1 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudMCH.cs
+104 −47 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudMNK.cs
+13 −5 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudNIN.cs
+129 −2 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudPCT.cs
+3 −1 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudPLD.cs
+2 −1 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudRDM.cs
+4 −2 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudRPR.cs
+3 −2 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudSAM.cs
+3 −2 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudSGE.cs
+154 −2 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudVPR.cs
+3 −1 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudWAR.cs
+2 −1 FFXIVClientStructs/FFXIV/Client/UI/AddonJobHudWHM.cs
+19 −12 FFXIVClientStructs/FFXIV/Client/UI/AddonNamePlate.cs
+2 −2 FFXIVClientStructs/FFXIV/Client/UI/AddonNeedGreed.cs
+2 −1 FFXIVClientStructs/FFXIV/Client/UI/AddonPartyList.cs
+12 −5 FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentBannerEditor.cs
+21 −21 FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentCharaCard.cs
+25 −0 FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentConfigkey.cs
+1 −0 FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentGatheringNote.cs
+3 −0 FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentGearset.cs
+13 −0 FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentHUD.cs
+26 −16 FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentLobby.cs
+9 −9 FFXIVClientStructs/FFXIV/Client/UI/Agent/AgentSatisfactionSupply.cs
+1 −1 FFXIVClientStructs/FFXIV/Client/UI/Info/InfoProxyCrossRealm.cs
+11 −0 FFXIVClientStructs/FFXIV/Client/UI/Misc/RaptureGearsetModule.cs
+8 −0 FFXIVClientStructs/FFXIV/Client/UI/RaptureAtkModule.cs
+22 −2 FFXIVClientStructs/FFXIV/Client/UI/UIInputData.cs
+3 −0 FFXIVClientStructs/FFXIV/Component/Exd/ExdModule.cs
+23 −0 FFXIVClientStructs/FFXIV/Component/GUI/AtkClippingMaskNode.cs
+1 −1 FFXIVClientStructs/FFXIV/Component/GUI/AtkResNode.cs
+14 −2 FFXIVClientStructs/FFXIV/Component/GUI/AtkTextNode.cs
+8 −1 FFXIVClientStructs/FFXIV/Component/GUI/AtkUnitBase.cs
+1 −1 global.json
+178 −17 ida/data.yml
+107 −1 ida/ffxiv_idarename.py
+314 −13 ida/ffxiv_structimporter.py
+5,658 −3,124 ida/ffxiv_structs.yml
110 changes: 56 additions & 54 deletions vnavmesh/Debug/DebugDrawer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,14 @@ public unsafe class DebugDrawer : IDisposable
public RenderTarget? RenderTarget { get; private set; }
public EffectMesh? EffectMesh { get; init; }

public SharpDX.Matrix ViewProj { get; private set; }
public SharpDX.Matrix Proj { get; private set; }
public SharpDX.Matrix View { get; private set; }
public SharpDX.Matrix CameraWorld { get; private set; }
public float CameraAzimuth { get; private set; } // facing north = 0, facing west = pi/4, facing south = +-pi/2, facing east = -pi/4
public float CameraAltitude { get; private set; } // facing horizontally = 0, facing down = pi/4, facing up = -pi/4
public SharpDX.Vector2 ViewportSize { get; private set; }

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate nint GetEngineCoreSingletonDelegate();

private nint _engineCoreSingleton;
public Vector3 Origin;
public Matrix4x4 View;
public Matrix4x4 Proj;
public Matrix4x4 ViewProj;
public Vector4 NearPlane;
public float CameraAzimuth; // facing north = 0, facing west = pi/4, facing south = +-pi/2, facing east = -pi/4
public float CameraAltitude; // facing horizontally = 0, facing down = pi/4, facing up = -pi/4
public Vector2 ViewportSize;

private List<(Vector2 from, Vector2 to, uint col, int thickness)> _viewportLines = new();
private List<(Vector2 center, float radius, uint color)> _viewportCircles = new();
Expand All @@ -42,7 +38,6 @@ public DebugDrawer()
{
Service.Log.Error($"Failed to set up renderer; some debug visualization will be unavailable: {ex}");
}
_engineCoreSingleton = Marshal.GetDelegateForFunctionPointer<GetEngineCoreSingletonDelegate>(Service.SigScanner.ScanText("E8 ?? ?? ?? ?? 48 8D 4C 24 ?? 48 89 4C 24 ?? 4C 8D 4D ?? 4C 8D 44 24 ??"))();
}

public void Dispose()
Expand All @@ -54,15 +49,30 @@ public void Dispose()

public void StartFrame()
{
ViewProj = ReadMatrix(_engineCoreSingleton + 0x1B4);
Proj = ReadMatrix(_engineCoreSingleton + 0x174);
View = ViewProj * SharpDX.Matrix.Invert(Proj);
CameraWorld = SharpDX.Matrix.Invert(View);
CameraAzimuth = MathF.Atan2(View.Column3.X, View.Column3.Z);
CameraAltitude = MathF.Asin(View.Column3.Y);
ViewportSize = ReadVec2(_engineCoreSingleton + 0x1F4);
var controlCamera = FFXIVClientStructs.FFXIV.Client.Game.Control.CameraManager.Instance()->GetActiveCamera();
var renderCamera = controlCamera != null ? controlCamera->SceneCamera.RenderCamera : null;
if (renderCamera != null)
{
Origin = renderCamera->Origin;
View = renderCamera->ViewMatrix;
View.M44 = 1; // for whatever reason, game doesn't initialize it...
Proj = renderCamera->ProjectionMatrix;
ViewProj = View * Proj;

// note that game uses reverse-z by default, so we can't just get full plane equation by reading column 3 of vp matrix
// so just calculate it manually: column 3 of view matrix is plane equation for a plane equation going through origin
// proof:
// plane equation p is such that p.dot(Q, 1) = 0 if Q lines on the plane => pw = -Q.dot(n); for view matrix, V43 is -origin.dot(forward)
// plane equation for near plane has Q.dot(n) = O.dot(n) - near => pw = V43 + near
NearPlane = new(View.M13, View.M23, View.M33, View.M43 + renderCamera->NearPlane);

CameraAzimuth = MathF.Atan2(View.M13, View.M33);
CameraAltitude = MathF.Asin(View.M23);
var device = FFXIVClientStructs.FFXIV.Client.Graphics.Kernel.Device.Instance();
ViewportSize = new(device->Width, device->Height);
}

EffectMesh?.UpdateConstants(RenderContext, new() { ViewProj = ViewProj, CameraPos = new(CameraWorld.M41, CameraWorld.M42, CameraWorld.M43), LightingWorldYThreshold = 55.Degrees().Cos() });
EffectMesh?.UpdateConstants(RenderContext, new() { ViewProj = ViewProj, CameraPos = Origin, LightingWorldYThreshold = 55.Degrees().Cos() });

if (RenderTarget == null || RenderTarget.Size != ViewportSize)
{
Expand Down Expand Up @@ -101,10 +111,8 @@ public void EndFrame()

public void DrawWorldLine(Vector3 start, Vector3 end, uint color, int thickness = 1)
{
var p1 = start.ToSharpDX();
var p2 = end.ToSharpDX();
if (ClipLineToNearPlane(ref p1, ref p2))
_viewportLines.Add((WorldToScreen(p1), WorldToScreen(p2), color, thickness));
if (ClipLineToNearPlane(ref start, ref end))
_viewportLines.Add((WorldToScreen(start), WorldToScreen(end), color, thickness));
}

public void DrawWorldPolygon(IEnumerable<Vector3> points, uint color, int thickness = 1)
Expand Down Expand Up @@ -170,37 +178,30 @@ public void DrawWorldTriangle(Vector3 v1, Vector3 v2, Vector3 v3, uint color, in

public void DrawWorldPoint(Vector3 p, float radius, uint color, int thickness = 1)
{
var pw = p.ToSharpDX();
var nearPlane = ViewProj.Column3;
if (SharpDX.Vector4.Dot(new(pw, 1), nearPlane) <= 0)
if (Vector4.Dot(new(p, 1), NearPlane) >= 0)
return;

var ps = WorldToScreen(pw);
var ps = WorldToScreen(p);
foreach (var (from, to) in AdjacentPairs(CurveApprox.Circle(ps, radius, 1)))
_viewportLines.Add((from, to, color, thickness));
}

public void DrawWorldPointFilled(Vector3 p, float radius, uint color)
{
var pw = p.ToSharpDX();
var nearPlane = ViewProj.Column3;
if (SharpDX.Vector4.Dot(new(pw, 1), nearPlane) <= 0)
if (Vector4.Dot(new(p, 1), NearPlane) >= 0)
return;
_viewportCircles.Add((WorldToScreen(pw), radius, color));
_viewportCircles.Add((WorldToScreen(p), radius, color));
}

// arrow with pointer at p coming from the direction of q
public void DrawWorldArrowPoint(Vector3 p, Vector3 q, float l, uint color, int thickness = 1)
{
var pw = p.ToSharpDX();
var nearPlane = ViewProj.Column3;
if (SharpDX.Vector4.Dot(new(pw, 1), nearPlane) <= 0)
if (Vector4.Dot(new(p, 1), NearPlane) >= 0)
return;

var qw = q.ToSharpDX();
ClipLineToNearPlane(ref pw, ref qw);
var ps = WorldToScreen(pw);
var qs = WorldToScreen(qw);
ClipLineToNearPlane(ref p, ref q);
var ps = WorldToScreen(p);
var qs = WorldToScreen(q);
var d = Vector2.Normalize(qs - ps) * l;
var n = new Vector2(-d.Y, d.X) * 0.5f;
_viewportLines.Add((ps, ps + d + n, color, thickness));
Expand Down Expand Up @@ -254,31 +255,32 @@ private unsafe SharpDX.Vector2 ReadVec2(nint address)
return new(p[0], p[1]);
}

private bool ClipLineToNearPlane(ref SharpDX.Vector3 a, ref SharpDX.Vector3 b)
private bool ClipLineToNearPlane(ref Vector3 a, ref Vector3 b)
{
var n = ViewProj.Column3; // near plane
var an = SharpDX.Vector4.Dot(new(a, 1), n);
var bn = SharpDX.Vector4.Dot(new(b, 1), n);
if (an <= 0 && bn <= 0)
return false;
var an = Vector4.Dot(new(a, 1), NearPlane);
var bn = Vector4.Dot(new(b, 1), NearPlane);
if (an >= 0 && bn >= 0)
return false; // line fully behind near plane

if (an < 0 || bn < 0)
if (an > 0 || bn > 0)
{
var ab = b - a;
var abn = SharpDX.Vector3.Dot(ab, new(n.X, n.Y, n.Z));
var abn = Vector3.Dot(ab, new(NearPlane.X, NearPlane.Y, NearPlane.Z));
var t = -an / abn;
if (an < 0)
a = a + t * ab;
var p = a + t * ab;
if (an > 0)
a = p;
else
b = a + t * ab;
b = p;
}
return true;
}

private Vector2 WorldToScreen(SharpDX.Vector3 w)
private Vector2 WorldToScreen(Vector3 w)
{
var p = SharpDX.Vector3.TransformCoordinate(w, ViewProj);
return new Vector2(0.5f * ViewportSize.X * (1 + p.X), 0.5f * ViewportSize.Y * (1 - p.Y)) + ImGuiHelpers.MainViewport.Pos;
var pp = Vector4.Transform(w, ViewProj);
var iw = 1 / pp.W;
return new Vector2(0.5f * ViewportSize.X * (1 + pp.X * iw), 0.5f * ViewportSize.Y * (1 - pp.Y * iw)) + ImGuiHelpers.MainViewport.Pos;
}

private static IEnumerable<(T, T)> AdjacentPairs<T>(IEnumerable<T> v) where T : struct
Expand Down
25 changes: 13 additions & 12 deletions vnavmesh/Debug/DebugGameCollision.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
using Dalamud.Hooking;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Memory;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Client.LayoutEngine;
using FFXIVClientStructs.FFXIV.Client.System.Framework;
using FFXIVClientStructs.FFXIV.Common.Component.BGCollision;
using FFXIVClientStructs.FFXIV.Common.Component.BGCollision.Math;
using FFXIVClientStructs.FFXIV.Common.Math;
using ImGuiNET;
using Navmesh.Render;
using System;
using System.Collections.Generic;
using System.Text;
using Matrix4x4 = System.Numerics.Matrix4x4;
using Vector3 = System.Numerics.Vector3;
using Vector4 = System.Numerics.Vector4;

namespace Navmesh.Debug;
Expand Down Expand Up @@ -276,26 +276,27 @@ private void DrawSceneRaycasts(SceneWrapper* s, int index)
return;
}

var clipPos = new SharpDX.Vector3(2 * screenPos.X / _dd.ViewportSize.X - 1, 1 - 2 * screenPos.Y / _dd.ViewportSize.Y, 1);
var invViewProj = SharpDX.Matrix.Invert(_dd.ViewProj);
var cameraWorldPos = _dd.CameraWorld.Row4.ToSystem();
var cameraPosAtPlane = SharpDX.Vector3.TransformCoordinate(clipPos, invViewProj).ToSystem();
var dir = System.Numerics.Vector3.Normalize(cameraPosAtPlane - new System.Numerics.Vector3(cameraWorldPos.X, cameraWorldPos.Y, cameraWorldPos.Z));
var clipPos = new Vector3(2 * screenPos.X / _dd.ViewportSize.X - 1, 1 - 2 * screenPos.Y / _dd.ViewportSize.Y, 1);
Matrix4x4.Invert(_dd.ViewProj, out var invViewProj);
var cameraPosAtPlaneP = Vector4.Transform(clipPos, invViewProj);
var cameraPosAtPlane = new Vector3(cameraPosAtPlaneP.X / cameraPosAtPlaneP.W, cameraPosAtPlaneP.Y / cameraPosAtPlaneP.W, cameraPosAtPlaneP.Z / cameraPosAtPlaneP.W);
var dir = Vector3.Normalize(cameraPosAtPlane - _dd.Origin);
_tree.LeafNode($"Mouse pos: screen={screenPos}, clip={clipPos}, dir={dir}");
float maxDist = 100000;
var filter = new RaycastMaterialFilter() { Mask = _materialMask.Raw, Value = _materialId.Raw };
var res = new RaycastHit();
var arg = new RaycastParams() { Origin = &cameraWorldPos, Direction = &dir, MaxDistance = &maxDist, MaterialFilter = &filter };
var sphere = new Vector4(_dd.Origin, 1);
var arg = new RaycastParams() { Origin = &sphere, Direction = &dir, MaxDistance = &maxDist, MaterialFilter = &filter };
if (s->Raycast(&res, _shownLayers.Raw, &arg))
{
_tree.LeafNode($"Raycast: {cameraWorldPos} + {res.Distance} = {res.Point}");
_tree.LeafNode($"Raycast: {_dd.Origin} + {res.Distance} = {res.Point}");
var ab = res.V2 - res.V1;
var ac = res.V3 - res.V1;
var normal = Vector3.Cross(ab, ac).Normalized;
var normal = Vector3.Normalize(Vector3.Cross(ab, ac));
_tree.LeafNode($"Normal: {normal} (slope={Angle.Acos(normal.Y)})");
_tree.LeafNode($"Material: {res.Material:X}");
DrawCollider((Collider*)res.Object);
VisualizeCollider((Collider*)res.Object, _materialId, _materialMask);
DrawCollider(res.Object);
VisualizeCollider(res.Object, _materialId, _materialMask);
_dd.DrawWorldLine(res.V1, res.V2, 0xff0000ff, 2);
_dd.DrawWorldLine(res.V2, res.V3, 0xff0000ff, 2);
_dd.DrawWorldLine(res.V3, res.V1, 0xff0000ff, 2);
Expand Down
6 changes: 3 additions & 3 deletions vnavmesh/Render/EffectMesh.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using FFXIVClientStructs.FFXIV.Common.Component.BGCollision.Math;
using SharpDX;
using SharpDX.D3DCompiler;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
Expand All @@ -8,6 +7,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using Matrix4x4 = System.Numerics.Matrix4x4;
using Vector3 = System.Numerics.Vector3;
using Vector4 = System.Numerics.Vector4;

Expand All @@ -20,7 +20,7 @@ public record struct Mesh(int FirstVertex, int FirstPrimitive, int NumPrimitives
[StructLayout(LayoutKind.Sequential)]
public struct Constants
{
public Matrix ViewProj;
public Matrix4x4 ViewProj;
public Vector3 CameraPos;
public float LightingWorldYThreshold; // to match recast demo, this should be equal to cos of max walkable angle
}
Expand Down Expand Up @@ -260,7 +260,7 @@ public void Dispose()

public void UpdateConstants(RenderContext ctx, Constants consts)
{
consts.ViewProj.Transpose();
consts.ViewProj = Matrix4x4.Transpose(consts.ViewProj);
ctx.Context.UpdateSubresource(ref consts, _constantBuffer);
}

Expand Down
4 changes: 2 additions & 2 deletions vnavmesh/Render/RenderTarget.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Numerics;

namespace Navmesh.Render;

Expand Down

0 comments on commit 9ff4219

Please sign in to comment.