CodeWalker/CodeWalker.Core/Utils/Vectors.cs

431 lines
13 KiB
C#
Raw Normal View History

2017-09-21 18:33:05 +08:00
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
2018-06-08 00:42:41 +08:00
using CodeWalker.GameFiles;
2017-09-21 18:33:05 +08:00
namespace CodeWalker
{
public static class Vectors
{
public static Vector3 XYZ(this Vector4 v)
{
return new Vector3(v.X, v.Y, v.Z);
}
2018-02-25 20:30:29 +08:00
public static Vector3 Round(this Vector3 v)
{
return new Vector3((float)Math.Round(v.X), (float)Math.Round(v.Y), (float)Math.Round(v.Z));
}
2019-12-03 21:52:22 +08:00
public static Vector3 GetPerpVec(this Vector3 n)
{
//make a vector perpendicular to the given one
float nx = Math.Abs(n.X);
float ny = Math.Abs(n.Y);
float nz = Math.Abs(n.Z);
if ((nx < ny) && (nx < nz))
{
return Vector3.Cross(n, Vector3.Right);
}
else if (ny < nz)
{
return Vector3.Cross(n, Vector3.Up);
}
else
{
return Vector3.Cross(n, Vector3.ForwardLH);
}
}
2020-01-06 19:17:51 +08:00
public static Vector3 Floor(this Vector3 v)
{
return new Vector3((float)Math.Floor(v.X), (float)Math.Floor(v.Y), (float)Math.Floor(v.Z));
}
public static Vector3 Ceiling(this Vector3 v)
{
return new Vector3((float)Math.Ceiling(v.X), (float)Math.Ceiling(v.Y), (float)Math.Ceiling(v.Z));
}
public static Vector3 Abs(this Vector3 v)
{
return new Vector3(Math.Abs(v.X), Math.Abs(v.Y), Math.Abs(v.Z));
}
2020-01-06 19:17:51 +08:00
public static int CompareTo(this Vector3 a, Vector3 b)
{
int c;
c = a.X.CompareTo(b.X); if (c != 0) return c;
c = a.Y.CompareTo(b.Y); if (c != 0) return c;
c = a.Z.CompareTo(b.Z); if (c != 0) return c;
return 0;
}
2019-12-03 21:52:22 +08:00
2017-09-21 18:33:05 +08:00
public static Vector4 Floor(this Vector4 v)
{
return new Vector4((float)Math.Floor(v.X), (float)Math.Floor(v.Y), (float)Math.Floor(v.Z), (float)Math.Floor(v.W));
}
2020-01-06 19:17:51 +08:00
public static Vector4 Ceiling(this Vector4 v)
{
return new Vector4((float)Math.Ceiling(v.X), (float)Math.Ceiling(v.Y), (float)Math.Ceiling(v.Z), (float)Math.Ceiling(v.W));
}
Ability to edit YTYP files and MLO Entity Defintions + Revisions to grass brush (#33) * - Add ability to edit/add ytyp files to project. - Add ability to edit/add ytyp archetype files to ytyp. - Add ability to add/remove entities from mlo archetype defs. - Add ability to save ytyp files. - Add dialog popup before optimizing grass batches. - Fix grass batches not being selected when chaning selection in project explorer. - Merged with upstream/master. - Squashed last 4 commits for PR cleanliness. * Fixed windows forms reference error. * - Added error checking to deleting mlo entities. - Fixed various bugs with deleting mlo entities. - Fixed edit archetype panel Asset Type box. - Removed redundant/unnecessary. - Removed backwards references between MCEntityDef and YmapEntityDef. All ymap entity to mcentity references are grabbed using indecies in the MloInstanceData class. - Fixed "YmapMenu" not showing when selecting entities/mlo entities in project form. Current bugs: - Loading a ytyp file -- mlo entities are not editiable, and are created in the world. - entitysets are not editable (properly). - Removing an mloinstancedef from a ymap does not delete the mlo instance's gizmo from the world, and it's still selectable. (Although all references are lost, and I believe collected by the GC?) * - Moved archetype initialization methods YmapFile.InitYmapEntityArchetypes(GameFileCache gfc) and MloInstanceData.InitYmapEntityArchetypes(GameFileCache gfc) - Added ability to load mlo instance defs through ymap files. - Fixed add method for mlo archetypes. * - Removed SetOrientationInv. - Removed unreachable code + updated comment. - Renamed CreateEntity to CreateYmapEntity, and renamed params for consistency. * Split calls to CreateYmapEntity() and MloArchetype.AddEntity(). * Fixed redundant rotation inversions. * - Added ability to select rooms. - Changed tree view grouping for mlo entities. - Fixed projectexplorer selection bugs. - Added ability to toggle mlo entity sets. - Fixed some change events when editing archetypes.
2018-12-03 16:54:04 +08:00
2019-01-26 18:00:13 +08:00
public static Vector4 Abs(this Vector4 v)
{
return new Vector4(Math.Abs(v.X), Math.Abs(v.Y), Math.Abs(v.Z), Math.Abs(v.W));
}
Ability to edit YTYP files and MLO Entity Defintions + Revisions to grass brush (#33) * - Add ability to edit/add ytyp files to project. - Add ability to edit/add ytyp archetype files to ytyp. - Add ability to add/remove entities from mlo archetype defs. - Add ability to save ytyp files. - Add dialog popup before optimizing grass batches. - Fix grass batches not being selected when chaning selection in project explorer. - Merged with upstream/master. - Squashed last 4 commits for PR cleanliness. * Fixed windows forms reference error. * - Added error checking to deleting mlo entities. - Fixed various bugs with deleting mlo entities. - Fixed edit archetype panel Asset Type box. - Removed redundant/unnecessary. - Removed backwards references between MCEntityDef and YmapEntityDef. All ymap entity to mcentity references are grabbed using indecies in the MloInstanceData class. - Fixed "YmapMenu" not showing when selecting entities/mlo entities in project form. Current bugs: - Loading a ytyp file -- mlo entities are not editiable, and are created in the world. - entitysets are not editable (properly). - Removing an mloinstancedef from a ymap does not delete the mlo instance's gizmo from the world, and it's still selectable. (Although all references are lost, and I believe collected by the GC?) * - Moved archetype initialization methods YmapFile.InitYmapEntityArchetypes(GameFileCache gfc) and MloInstanceData.InitYmapEntityArchetypes(GameFileCache gfc) - Added ability to load mlo instance defs through ymap files. - Fixed add method for mlo archetypes. * - Removed SetOrientationInv. - Removed unreachable code + updated comment. - Renamed CreateEntity to CreateYmapEntity, and renamed params for consistency. * Split calls to CreateYmapEntity() and MloArchetype.AddEntity(). * Fixed redundant rotation inversions. * - Added ability to select rooms. - Changed tree view grouping for mlo entities. - Fixed projectexplorer selection bugs. - Added ability to toggle mlo entity sets. - Fixed some change events when editing archetypes.
2018-12-03 16:54:04 +08:00
public static Quaternion ToQuaternion(this Vector4 v)
{
return new Quaternion(v);
}
2017-09-21 18:33:05 +08:00
}
public struct Vector2I
{
public int X;
public int Y;
public Vector2I(int x, int y)
{
X = x;
Y = y;
}
public Vector2I(Vector2 v)
{
X = (int)Math.Floor(v.X);
Y = (int)Math.Floor(v.Y);
}
public override string ToString()
{
return X.ToString() + ", " + Y.ToString();
}
public static Vector2I operator +(Vector2I a, Vector2I b)
{
return new Vector2I(a.X + b.X, a.Y + b.Y);
}
public static Vector2I operator -(Vector2I a, Vector2I b)
{
return new Vector2I(a.X - b.X, a.Y - b.Y);
}
}
public static class BoundingBoxMath
{
public static BoundingBox Transform(this BoundingBox b, Vector3 position, Quaternion orientation, Vector3 scale)
{
var mat = Matrix.Transformation(Vector3.Zero, Quaternion.Identity, scale, Vector3.Zero, orientation, position);
2023-07-29 00:55:26 +08:00
return b.Transform(mat);
}
public static BoundingBox Transform(this BoundingBox b, Matrix mat)
{
var matabs = mat;
matabs.Column1 = mat.Column1.Abs();
matabs.Column2 = mat.Column2.Abs();
matabs.Column3 = mat.Column3.Abs();
matabs.Column4 = mat.Column4.Abs();
var bbcenter = (b.Maximum + b.Minimum) * 0.5f;
var bbextent = (b.Maximum - b.Minimum) * 0.5f;
var ncenter = Vector3.TransformCoordinate(bbcenter, mat);
var nextent = Vector3.TransformNormal(bbextent, matabs).Abs();
return new BoundingBox(ncenter - nextent, ncenter + nextent);
}
}
public struct BoundingCapsule
{
public Vector3 PointA;
public Vector3 PointB;
public float Radius;
}
public static class BoundingCapsuleMath
{
public static bool Intersects(this Ray r, ref BoundingCapsule capsule, out float dist)
{
// intersect capsule : http://www.iquilezles.org/www/articles/intersectors/intersectors.htm
Vector3 ba = capsule.PointB - capsule.PointA;
Vector3 oa = r.Position - capsule.PointA;
float baba = Vector3.Dot(ba,ba);
float bard = Vector3.Dot(ba,r.Direction);
float baoa = Vector3.Dot(ba,oa);
float rdoa = Vector3.Dot(r.Direction,oa);
float oaoa = Vector3.Dot(oa,oa);
float r2 = capsule.Radius * capsule.Radius;
float a = baba - bard*bard;
float b = baba*rdoa - baoa*bard;
float c = baba*oaoa - baoa*baoa - r2*baba;
float h = b*b - a*c;
if( h>=0.0f )
{
float t = (-b-(float)Math.Sqrt(h))/a;
float y = baoa + t*bard;
// body
if (y > 0.0f && y < baba)
{
dist = t;
return true;
}
// caps
Vector3 oc = (y<=0.0f) ? oa : r.Position - capsule.PointB;
b = Vector3.Dot(r.Direction,oc);
c = Vector3.Dot(oc,oc) - r2;
h = b*b - c;
if( h>0.0f )
{
dist = -b - (float)Math.Sqrt(h);
return true;
}
}
dist = -1.0f;
return false;
}
public static Vector3 Normal(this BoundingCapsule c, ref Vector3 position)
{
Vector3 ba = c.PointB - c.PointA;
Vector3 pa = position - c.PointA;
float h = Math.Min(Math.Max(Vector3.Dot(pa, ba) / Vector3.Dot(ba, ba), 0.0f), 1.0f);
return Vector3.Normalize((pa - h * ba) / c.Radius);
}
public static bool Intersects(this BoundingSphere sph, ref BoundingCapsule capsule, out Vector3 norm)
{
var dist = LineMath.PointSegmentDistance(ref sph.Center, ref capsule.PointA, ref capsule.PointB);
var rads = sph.Radius + capsule.Radius;
if (dist <= rads)
{
norm = LineMath.PointSegmentNormal(ref sph.Center, ref capsule.PointA, ref capsule.PointB);
return true;
}
else
{
norm = Vector3.Up;
return false;
}
}
}
public struct BoundingCylinder
{
public Vector3 PointA;
public Vector3 PointB;
public float Radius;
}
public static class BoundingCylinderMath
{
public static bool Intersects(this Ray r, ref BoundingCylinder cylinder, out float dist, out Vector3 norm)
{
// intersect cylinder : https://www.shadertoy.com/view/4lcSRn
Vector3 ba = cylinder.PointB - cylinder.PointA;
Vector3 oc = r.Position - cylinder.PointA;
float baba = Vector3.Dot(ba, ba);
float bard = Vector3.Dot(ba, r.Direction);
float baoc = Vector3.Dot(ba, oc);
float r2 = cylinder.Radius * cylinder.Radius;
float k2 = baba - bard * bard;
float k1 = baba * Vector3.Dot(oc, r.Direction) - baoc * bard;
float k0 = baba * Vector3.Dot(oc, oc) - baoc * baoc - r2 * baba;
float h = k1 * k1 - k2 * k0;
if (h < 0.0f)
{
dist = -1.0f;
norm = Vector3.Up;
return false;
}
h = (float)Math.Sqrt(h);
float t = (-k1 - h) / k2;
// body
float y = baoc + t * bard;
if (y > 0.0f && y < baba)
{
dist = t;
norm = Vector3.Normalize((oc + t * r.Direction - ba * y / baba) / cylinder.Radius);
return true;
}
// caps
t = (((y < 0.0f) ? 0.0f : baba) - baoc) / bard;
if (Math.Abs(k1 + k2 * t) < h)
{
dist = t;
norm = Vector3.Normalize(ba * Math.Sign(y) / baba);
return true;
}
dist = -1.0f;
norm = Vector3.Up;
return false;
}
}
public static class LineMath
{
public static float PointSegmentDistance(ref Vector3 v, ref Vector3 a, ref Vector3 b)
{
//https://stackoverflow.com/questions/4858264/find-the-distance-from-a-3d-point-to-a-line-segment
Vector3 ab = b - a;
Vector3 av = v - a;
if (Vector3.Dot(av, ab) <= 0.0f)// Point is lagging behind start of the segment, so perpendicular distance is not viable.
{
return av.Length(); // Use distance to start of segment instead.
}
Vector3 bv = v - b;
if (Vector3.Dot(bv, ab) >= 0.0f)// Point is advanced past the end of the segment, so perpendicular distance is not viable.
{
return bv.Length(); // Use distance to end of the segment instead.
}
return Vector3.Cross(ab, av).Length() / ab.Length();// Perpendicular distance of point to segment.
}
public static Vector3 PointSegmentNormal(ref Vector3 v, ref Vector3 a, ref Vector3 b)
{
Vector3 ab = b - a;
Vector3 av = v - a;
if (Vector3.Dot(av, ab) <= 0.0f)
{
return Vector3.Normalize(av);
}
Vector3 bv = v - b;
if (Vector3.Dot(bv, ab) >= 0.0f)
{
return Vector3.Normalize(bv);
}
return Vector3.Normalize(Vector3.Cross(Vector3.Cross(ab, av), ab));
}
2020-01-13 20:31:27 +08:00
public static float PointRayDist(ref Vector3 p, ref Vector3 ro, ref Vector3 rd)
{
return Vector3.Cross(rd, p - ro).Length();
}
public static float DistanceFieldTest(in Vector2 s, in Vector2 p1, in Vector2 p2, out int winding)
{
//utility function to help in calculating distance field textures.
//finds the distance from a sample point to a line segment,
//outputting a winding value for use to determine if the sample point is inside or outside a shape.
var d = PointSegmentDistance(s, p1, p2);
winding = 0;
var d1 = p1 - s;
var d2 = p2 - s;
if ((d1.Y > 0) != (d2.Y > 0))//this segment crosses the y-axis (relative to s)
{
var yr = (0 - d1.Y) / (d2.Y - d1.Y);//how far along the line is the intersection?
var xr = d1.X + (d2.X - d1.X) * yr;//where on the x axis is the intersection?
if (xr > 0)
{
winding = (d2.Y > d1.Y) ? 1 : -1;
}
}
return d;
}
public static float PointSegmentDistance(in Vector2 v, in Vector2 a, in Vector2 b)
{
var ab = b - a;
var av = v - a;
var l2 = ab.LengthSquared();
if (l2 == 0) return av.Length();
var t = FloatUtil.Saturate(Vector2.Dot(av, ab) / l2);
var p = a + t * ab;
return (p - v).Length();
}
2020-01-13 20:31:27 +08:00
}
public static class TriangleMath
{
public static float AreaPart(ref Vector3 v1, ref Vector3 v2, ref Vector3 v3, out float angle)
{
var va = v2 - v1;
var vb = v3 - v1;
var na = Vector3.Normalize(va);
var nb = Vector3.Normalize(vb);
var a = va.Length();
var b = vb.Length();
var c = Math.Acos(Vector3.Dot(na, nb));
var area = (float)(0.5 * a * b * Math.Sin(c));
angle = (float)Math.Abs(c);
return area;
}
public static float Area(ref Vector3 v1, ref Vector3 v2, ref Vector3 v3)
{
var a1 = AreaPart(ref v1, ref v2, ref v3, out float t1);
var a2 = AreaPart(ref v2, ref v3, ref v1, out float t2);
var a3 = AreaPart(ref v3, ref v1, ref v2, out float t3);
var fp = (float)Math.PI;
var d1 = Math.Min(t1, Math.Abs(t1 - fp));
var d2 = Math.Min(t2, Math.Abs(t2 - fp));
var d3 = Math.Min(t3, Math.Abs(t3 - fp));
if ((d1 >= d2) && (a1 != 0))
{
if ((d1 >= d3) || (a3 == 0))
{
return a1;
}
else
{
return a3;
}
}
else
{
if ((d2 >= d3) || (a3 == 0))
{
return a2;
}
else
{
return a3;
}
}
}
}
2017-09-21 18:33:05 +08:00
}