diff --git a/Game/Game.InputHandling.cs b/Game/Game.InputHandling.cs index 2c474abeb..5c60971c7 100644 --- a/Game/Game.InputHandling.cs +++ b/Game/Game.InputHandling.cs @@ -131,8 +131,7 @@ namespace ClassicalSharp { } } if( right ) { - if( SelectedPos.TranslatedPos == null ) return; - Vector3I pos = SelectedPos.TranslatedPos.Value; + Vector3I pos = SelectedPos.TranslatedPos; Block block = HeldBlock; byte oldBlock = 0; diff --git a/Physics/IntersectionUtils.cs b/Physics/IntersectionUtils.cs index 4d3923988..cd453b8a8 100644 --- a/Physics/IntersectionUtils.cs +++ b/Physics/IntersectionUtils.cs @@ -4,44 +4,12 @@ using OpenTK; namespace ClassicalSharp { - public struct Quad { - public Vector3 Normal; - public Vector3 Pos1, Pos2, Pos3, Pos4; - - public Quad( Vector3 norm, Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4 ) { - Pos1 = p1; - Pos2 = p2; - Pos3 = p3; - Pos4 = p4; - Normal = norm; - } - } - public static class IntersectionUtils { - public static IEnumerable GetFaces( Vector3 min, Vector3 max ) { - yield return new Quad( -Vector3.UnitY, // bottom - new Vector3( min.X, min.Y, min.Z ), new Vector3( max.X, min.Y, min.Z ), - new Vector3( max.X, min.Y, max.Z ), new Vector3( min.X, min.Y, max.Z ) ); - yield return new Quad( Vector3.UnitY, // top - new Vector3( min.X, max.Y, min.Z ), new Vector3( max.X, max.Y, min.Z ), - new Vector3( max.X, max.Y, max.Z ), new Vector3( min.X, max.Y, max.Z ) ); - yield return new Quad( -Vector3.UnitX, // left - new Vector3( min.X, min.Y, min.Z ), new Vector3( min.X, max.Y, min.Z ), - new Vector3( min.X, max.Y, max.Z ), new Vector3( min.X, min.Y, max.Z ) ); - yield return new Quad( Vector3.UnitX, // right - new Vector3( max.X, min.Y, min.Z ), new Vector3( max.X, max.Y, min.Z ), - new Vector3( max.X, max.Y, max.Z ), new Vector3( max.X, min.Y, max.Z ) ); - yield return new Quad( -Vector3.UnitZ, // front - new Vector3( min.X, min.Y, min.Z ), new Vector3( max.X, min.Y, min.Z ), - new Vector3( max.X, max.Y, min.Z ), new Vector3( min.X, max.Y, min.Z ) ); - yield return new Quad( Vector3.UnitZ, // back - new Vector3( min.X, min.Y, max.Z ), new Vector3( max.X, min.Y, max.Z ), - new Vector3( max.X, max.Y, max.Z ), new Vector3( min.X, max.Y, max.Z ) ); - } - //http://www.cs.utah.edu/~awilliam/box/box.pdf - public static bool RayIntersectsBox( Vector3 origin, Vector3 dir, Vector3 min, Vector3 max ) { + public static bool RayIntersectsBox( Vector3 origin, Vector3 dir, Vector3 min, Vector3 max, + out float t0, out float t1 ) { + t0 = t1 = 0; float tmin, tmax, tymin, tymax, tzmin, tzmax; float invDirX = 1 / dir.X; if( invDirX >= 0 ) { @@ -77,10 +45,16 @@ namespace ClassicalSharp { } if( tmin > tzmax || tzmin > tmax ) return false; + if( tzmin > tmin ) + tmin = tzmin; + if( tzmax < tmax ) + tmax = tzmax; + t0 = tmin; + t1 = tmax; return true; } - //http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/raytri/raytri.c + //http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/raytri/raytri.c public static bool RayTriangleIntersect( Vector3 orig, Vector3 dir, Vector3 p0, Vector3 p1, Vector3 p2, out Vector3 I ) { Vector3 edge1 = p1 - p0; Vector3 edge2 = p2 - p0; diff --git a/Physics/Picking.cs b/Physics/Picking.cs index a8a194fbc..9a3e78973 100644 --- a/Physics/Picking.cs +++ b/Physics/Picking.cs @@ -32,8 +32,9 @@ namespace ClassicalSharp { float height = info.BlockHeight( block ); Vector3 min = new Vector3( x, y, z ); Vector3 max = new Vector3( x + 1, y + height, z + 1 ); - if( IntersectionUtils.RayIntersectsBox( origin, dir, min, max ) ) { - return new PickedPos( min, max, origin, dir ); + float t0, t1; + if( IntersectionUtils.RayIntersectsBox( origin, dir, min, max, out t0, out t1 ) ) { + return new PickedPos( min, max, origin, dir, t0, t1 ); } } } @@ -123,54 +124,30 @@ namespace ClassicalSharp { public Vector3 Min, Max; public Vector3I BlockPos; - public Vector3I? TranslatedPos; + public Vector3I TranslatedPos; - struct QuadIntersection { - public Quad Quad; - public Vector3 Intersection; - - public QuadIntersection( Quad quad, Vector3 intersection ) { - Quad = quad; - Intersection = intersection; - } - } - - public PickedPos( Vector3 p1, Vector3 p2, Vector3 origin, Vector3 dir ) { + public PickedPos( Vector3 p1, Vector3 p2, Vector3 origin, Vector3 dir, float t0, float t1 ) { Min = Vector3.Min( p1, p2 ); Max = Vector3.Max( p1, p2 ); BlockPos = Vector3I.Truncate( Min ); - - Quad? closestQuad = null; - Vector3 closest = new Vector3( float.MaxValue, float.MaxValue, float.MaxValue ); - IEnumerable faces = IntersectionUtils.GetFaces( Min, Max ); - foreach( QuadIntersection result in FindIntersectingTriangles( origin, dir, faces ) ) { - Vector3 I = result.Intersection; - if( ( origin - I ).LengthSquared < ( origin - closest ).LengthSquared ) { - closest = I; - closestQuad = result.Quad; - } - } - if( closestQuad != null ) { - TranslatedPos = Vector3I.Truncate( Min + closestQuad.Value.Normal ); - } + + Vector3I normal = Vector3I.Zero; + Vector3 intersect = origin + dir * t0; + float dist = float.PositiveInfinity; + TestAxis( intersect.X - Min.X, ref dist, -Vector3I.UnitX, ref normal ); + TestAxis( intersect.X - Max.X, ref dist, Vector3I.UnitX, ref normal ); + TestAxis( intersect.Y - Min.Y, ref dist, -Vector3I.UnitY, ref normal ); + TestAxis( intersect.Y - Max.Y, ref dist, Vector3I.UnitY, ref normal ); + TestAxis( intersect.Z - Min.Z, ref dist, -Vector3I.UnitZ, ref normal ); + TestAxis( intersect.Z - Max.Z, ref dist, Vector3I.UnitZ, ref normal ); + TranslatedPos = BlockPos + normal; } - - static IEnumerable FindIntersectingTriangles( Vector3 origin, Vector3 dir, IEnumerable quads ) { - foreach( Quad quad in quads ) { - Vector3 p0 = quad.Pos1; // assumed to be min point - Vector3 p2 = quad.Pos3; // assumed to be max point - Vector3 I; - - Vector3 p1 = quad.Pos2; // triangle 1 - if( IntersectionUtils.RayTriangleIntersect( origin, dir, p0, p1, p2, out I ) ) { - yield return new QuadIntersection( quad, I ); - } - - p1 = quad.Pos4; // triangle 2 - if( IntersectionUtils.RayTriangleIntersect( origin, dir, p0, p1, p2, out I ) ) { - yield return new QuadIntersection( quad, I ); - } + static void TestAxis( float dAxis, ref float dist, Vector3I nAxis, ref Vector3I normal ) { + dAxis = Math.Abs( dAxis ); + if( dAxis < dist ) { + dist = dAxis; + normal = nAxis; } } } diff --git a/Utils/Utils.cs b/Utils/Utils.cs index 7f5beafce..3de4cbc87 100644 --- a/Utils/Utils.cs +++ b/Utils/Utils.cs @@ -251,6 +251,9 @@ namespace ClassicalSharp { public struct Vector3I { public static Vector3I Zero = new Vector3I( 0, 0, 0 ); + public static Vector3I UnitX = new Vector3I( 1, 0, 0 ); + public static Vector3I UnitY = new Vector3I( 0, 1, 0 ); + public static Vector3I UnitZ = new Vector3I( 0, 0, 1 ); public int X, Y, Z; @@ -287,6 +290,10 @@ namespace ClassicalSharp { return new Vector3I( left.X - right.X, left.Y - right.Y, left.Z - right.Z ); } + public static Vector3I operator - ( Vector3I left ) { + return new Vector3I( -left.X, -left.Y, -left.Z ); + } + public static explicit operator Vector3I( Vector3 value ) { return Truncate( value ); }