diff --git a/Entities/Entity.cs b/Entities/Entity.cs index 776d5b49f..cdef459aa 100644 --- a/Entities/Entity.cs +++ b/Entities/Entity.cs @@ -42,23 +42,6 @@ namespace ClassicalSharp { } } - public virtual BoundingBox PickingBounds { - get { - BoundingBox bb = Model.PickingBounds; - float angle = YawRadians; - // TODO: This would be a lot simpler and more accurate if we just did ray-oobb intersection. - Vector3 x1z1 = Utils.RotateY( bb.Min.X, 0, bb.Min.Z, angle ); - Vector3 x1z2 = Utils.RotateY( bb.Min.X, 0, bb.Max.Z, angle ); - Vector3 x2z1 = Utils.RotateY( bb.Max.X, 0, bb.Min.Z, angle ); - Vector3 x2z2 = Utils.RotateY( bb.Max.X, 0, bb.Max.Z, angle ); - float minX = Math.Min( x1z1.X, Math.Min( x1z2.X, Math.Min( x2z2.X, x2z1.X ) ) ); - float maxX = Math.Max( x1z1.X, Math.Max( x1z2.X, Math.Max( x2z2.X, x2z1.X ) ) ); - float minZ = Math.Min( x1z1.Z, Math.Min( x1z2.Z, Math.Min( x2z2.Z, x2z1.Z ) ) ); - float maxZ = Math.Max( x1z1.Z, Math.Max( x1z2.Z, Math.Max( x2z2.Z, x2z1.Z ) ) ); - return new BoundingBox( minX, bb.Min.Y, minZ, maxX, bb.Max.Y, maxZ ).Offset( Position ); - } - } - public abstract void Despawn(); public abstract void Render( double deltaTime, float t ); diff --git a/Entities/EntityList.cs b/Entities/EntityList.cs index cc48a9441..96a172b76 100644 --- a/Entities/EntityList.cs +++ b/Entities/EntityList.cs @@ -33,17 +33,18 @@ namespace ClassicalSharp { } public byte GetClosetPlayer( Vector3 eyePos, Vector3 dir ) { - float dist = float.PositiveInfinity; + float closestDist = float.PositiveInfinity; byte targetId = 255; for( int i = 0; i < Players.Length - 1; i++ ) { // -1 because we don't want to pick against local player Player p = Players[i]; if( p == null ) continue; - BoundingBox bounds = p.PickingBounds; float t0, t1; - if( IntersectionUtils.RayIntersectsBox( eyePos, dir, bounds.Min, bounds.Max, out t0, out t1 ) ) { - dist = t0; - targetId = (byte)i; + if( Intersection.RayIntersectsRotatedBox( eyePos, dir, p, out t0, out t1 ) ) { + if( t0 < closestDist ) { + closestDist = t0; + targetId = (byte)i; + } } } return targetId; diff --git a/Physics/IntersectionUtils.cs b/Physics/IntersectionUtils.cs index cd453b8a8..2b28a05ab 100644 --- a/Physics/IntersectionUtils.cs +++ b/Physics/IntersectionUtils.cs @@ -4,7 +4,21 @@ using OpenTK; namespace ClassicalSharp { - public static class IntersectionUtils { + public static class Intersection { + + internal static bool RayIntersectsRotatedBox( Vector3 origin, Vector3 dir, Player target, out float tMin, out float tMax ) { + // This is the rotated AABB of the model + // * + // / \ we then perform a counter *---* and we can then do + // ====>* x * rotation to the rotated AABB | x | a standard AABB test + // \ / and ray origin and direction *---* with the rotated ray + // * / + // / + Vector3 rotatedOrigin = target.Position + Utils.RotateY( origin - target.Position, -target.YawRadians ); + Vector3 rotatedDir = Utils.RotateY( dir, -target.YawRadians ); + BoundingBox bb = target.Model.PickingBounds.Offset( target.Position ); + return RayIntersectsBox( rotatedOrigin, rotatedDir, bb.Min, bb.Max, out tMin, out tMax ); + } //http://www.cs.utah.edu/~awilliam/box/box.pdf public static bool RayIntersectsBox( Vector3 origin, Vector3 dir, Vector3 min, Vector3 max, diff --git a/Physics/Picking.cs b/Physics/Picking.cs index 3be2ee016..3c0b10743 100644 --- a/Physics/Picking.cs +++ b/Physics/Picking.cs @@ -90,7 +90,7 @@ namespace ClassicalSharp { // This cell falls on the path of the ray. Now perform an additional bounding box test, // since some blocks do not occupy a whole cell. float t0, t1; - if( IntersectionUtils.RayIntersectsBox( origin, dir, min, max, out t0, out t1 ) ) { + if( Intersection.RayIntersectsBox( origin, dir, min, max, out t0, out t1 ) ) { pickedPos.UpdateBlockPos( min, max, origin, dir, t0, t1 ); return; } diff --git a/Utils/Camera.cs b/Utils/Camera.cs index 1cc491243..64bb89954 100644 --- a/Utils/Camera.cs +++ b/Utils/Camera.cs @@ -44,7 +44,7 @@ namespace ClassicalSharp { } public override void GetPickedBlock( PickedPos pos ) { - Vector3 dir = Utils.GetDirectionVector( player.YawRadians, player.PitchRadians + Math.PI ); + Vector3 dir = Utils.GetDirVector( player.YawRadians, player.PitchRadians ); Vector3 eyePos = player.EyePosition; float reach = Window.LocalPlayer.ReachDistance; Picking.GetPickedBlockPos( Window, eyePos, dir, reach, pos ); @@ -108,7 +108,7 @@ namespace ClassicalSharp { public override Matrix4 GetView() { Vector3 eyePos = player.EyePosition; - Vector3 cameraPos = eyePos - Utils.GetDirectionVector( player.YawRadians, player.PitchRadians + Math.PI ) * distance; + Vector3 cameraPos = eyePos - Utils.GetDirVector( player.YawRadians, player.PitchRadians ) * distance; return Matrix4.LookAt( cameraPos, eyePos, Vector3.UnitY ); } @@ -124,7 +124,7 @@ namespace ClassicalSharp { public override Matrix4 GetView() { Vector3 eyePos = player.EyePosition; - Vector3 cameraDir = Utils.GetDirectionVector( player.YawRadians, player.PitchRadians + Math.PI ); + Vector3 cameraDir = Utils.GetDirVector( player.YawRadians, player.PitchRadians ); return Matrix4.LookAt( eyePos, eyePos + cameraDir, Vector3.UnitY ); } diff --git a/Utils/Utils.cs b/Utils/Utils.cs index 5f47c64da..5b730455e 100644 --- a/Utils/Utils.cs +++ b/Utils/Utils.cs @@ -111,6 +111,12 @@ namespace ClassicalSharp { return packed * 360.0 / 256.0; } + public static Vector3 RotateY( Vector3 v, float angle ) { + float cosA = (float)Math.Cos( angle ); + float sinA = (float)Math.Sin( angle ); + return new Vector3( cosA * v.X - sinA * v.Z, v.Y, sinA * v.X + cosA * v.Z ); + } + public static Vector3 RotateY( float x, float y, float z, float angle ) { float cosA = (float)Math.Cos( angle ); float sinA = (float)Math.Sin( angle ); @@ -138,10 +144,10 @@ namespace ClassicalSharp { return dx * dx + dy * dy + dz * dz; } - public static Vector3 GetDirectionVector( double yawRad, double pitchRad ) { - double x = Math.Cos( pitchRad ) * -Math.Sin( yawRad ); - double y = Math.Sin( pitchRad ); - double z = Math.Cos( pitchRad ) * Math.Cos( yawRad ); + public static Vector3 GetDirVector( double yawRad, double pitchRad ) { + double x = -Math.Cos( pitchRad ) * -Math.Sin( yawRad ); + double y = -Math.Sin( pitchRad ); + double z = -Math.Cos( pitchRad ) * Math.Cos( yawRad ); return new Vector3( (float)x, (float)y, (float)z ); }