mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-11 16:45:48 -04:00
Replace ray-triangle intersection with much faster alternative.
This commit is contained in:
parent
c22874d4fc
commit
ba9d29b4cd
@ -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;
|
||||
|
||||
|
@ -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<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
|
||||
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;
|
||||
|
@ -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<Quad> 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<QuadIntersection> FindIntersectingTriangles( Vector3 origin, Vector3 dir, IEnumerable<Quad> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 );
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user