Replace ray-triangle intersection with much faster alternative.

This commit is contained in:
UnknownShadow200 2015-02-27 17:07:11 +11:00
parent c22874d4fc
commit ba9d29b4cd
4 changed files with 39 additions and 82 deletions

View File

@ -131,8 +131,7 @@ namespace ClassicalSharp {
} }
} }
if( right ) { if( right ) {
if( SelectedPos.TranslatedPos == null ) return; Vector3I pos = SelectedPos.TranslatedPos;
Vector3I pos = SelectedPos.TranslatedPos.Value;
Block block = HeldBlock; Block block = HeldBlock;
byte oldBlock = 0; byte oldBlock = 0;

View File

@ -4,44 +4,12 @@ using OpenTK;
namespace ClassicalSharp { 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 class IntersectionUtils {
public static IEnumerable<Quad> 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 //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 tmin, tmax, tymin, tymax, tzmin, tzmax;
float invDirX = 1 / dir.X; float invDirX = 1 / dir.X;
if( invDirX >= 0 ) { if( invDirX >= 0 ) {
@ -77,10 +45,16 @@ namespace ClassicalSharp {
} }
if( tmin > tzmax || tzmin > tmax ) if( tmin > tzmax || tzmin > tmax )
return false; return false;
if( tzmin > tmin )
tmin = tzmin;
if( tzmax < tmax )
tmax = tzmax;
t0 = tmin;
t1 = tmax;
return true; 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 ) { public static bool RayTriangleIntersect( Vector3 orig, Vector3 dir, Vector3 p0, Vector3 p1, Vector3 p2, out Vector3 I ) {
Vector3 edge1 = p1 - p0; Vector3 edge1 = p1 - p0;
Vector3 edge2 = p2 - p0; Vector3 edge2 = p2 - p0;

View File

@ -32,8 +32,9 @@ namespace ClassicalSharp {
float height = info.BlockHeight( block ); float height = info.BlockHeight( block );
Vector3 min = new Vector3( x, y, z ); Vector3 min = new Vector3( x, y, z );
Vector3 max = new Vector3( x + 1, y + height, z + 1 ); Vector3 max = new Vector3( x + 1, y + height, z + 1 );
if( IntersectionUtils.RayIntersectsBox( origin, dir, min, max ) ) { float t0, t1;
return new PickedPos( min, max, origin, dir ); 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 Vector3 Min, Max;
public Vector3I BlockPos; public Vector3I BlockPos;
public Vector3I? TranslatedPos; public Vector3I TranslatedPos;
struct QuadIntersection { public PickedPos( Vector3 p1, Vector3 p2, Vector3 origin, Vector3 dir, float t0, float t1 ) {
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 ) {
Min = Vector3.Min( p1, p2 ); Min = Vector3.Min( p1, p2 );
Max = Vector3.Max( p1, p2 ); Max = Vector3.Max( p1, p2 );
BlockPos = Vector3I.Truncate( Min ); BlockPos = Vector3I.Truncate( Min );
Quad? closestQuad = null; Vector3I normal = Vector3I.Zero;
Vector3 closest = new Vector3( float.MaxValue, float.MaxValue, float.MaxValue ); Vector3 intersect = origin + dir * t0;
IEnumerable<Quad> faces = IntersectionUtils.GetFaces( Min, Max ); float dist = float.PositiveInfinity;
foreach( QuadIntersection result in FindIntersectingTriangles( origin, dir, faces ) ) { TestAxis( intersect.X - Min.X, ref dist, -Vector3I.UnitX, ref normal );
Vector3 I = result.Intersection; TestAxis( intersect.X - Max.X, ref dist, Vector3I.UnitX, ref normal );
if( ( origin - I ).LengthSquared < ( origin - closest ).LengthSquared ) { TestAxis( intersect.Y - Min.Y, ref dist, -Vector3I.UnitY, ref normal );
closest = I; TestAxis( intersect.Y - Max.Y, ref dist, Vector3I.UnitY, ref normal );
closestQuad = result.Quad; 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;
if( closestQuad != null ) {
TranslatedPos = Vector3I.Truncate( Min + closestQuad.Value.Normal );
}
} }
static void TestAxis( float dAxis, ref float dist, Vector3I nAxis, ref Vector3I normal ) {
static IEnumerable<QuadIntersection> FindIntersectingTriangles( Vector3 origin, Vector3 dir, IEnumerable<Quad> quads ) { dAxis = Math.Abs( dAxis );
foreach( Quad quad in quads ) { if( dAxis < dist ) {
Vector3 p0 = quad.Pos1; // assumed to be min point dist = dAxis;
Vector3 p2 = quad.Pos3; // assumed to be max point normal = nAxis;
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 );
}
} }
} }
} }

View File

@ -251,6 +251,9 @@ namespace ClassicalSharp {
public struct Vector3I { public struct Vector3I {
public static Vector3I Zero = new Vector3I( 0, 0, 0 ); 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; 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 ); 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 ) { public static explicit operator Vector3I( Vector3 value ) {
return Truncate( value ); return Truncate( value );
} }