mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-15 10:35:11 -04:00
Do more accurate model picking with rotated AABBs, make sure to only return closest player in model picking.
This commit is contained in:
parent
e23b5aeda5
commit
43a7e35d64
@ -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 Despawn();
|
||||||
|
|
||||||
public abstract void Render( double deltaTime, float t );
|
public abstract void Render( double deltaTime, float t );
|
||||||
|
@ -33,19 +33,20 @@ namespace ClassicalSharp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public byte GetClosetPlayer( Vector3 eyePos, Vector3 dir ) {
|
public byte GetClosetPlayer( Vector3 eyePos, Vector3 dir ) {
|
||||||
float dist = float.PositiveInfinity;
|
float closestDist = float.PositiveInfinity;
|
||||||
byte targetId = 255;
|
byte targetId = 255;
|
||||||
|
|
||||||
for( int i = 0; i < Players.Length - 1; i++ ) { // -1 because we don't want to pick against local player
|
for( int i = 0; i < Players.Length - 1; i++ ) { // -1 because we don't want to pick against local player
|
||||||
Player p = Players[i];
|
Player p = Players[i];
|
||||||
if( p == null ) continue;
|
if( p == null ) continue;
|
||||||
BoundingBox bounds = p.PickingBounds;
|
|
||||||
float t0, t1;
|
float t0, t1;
|
||||||
if( IntersectionUtils.RayIntersectsBox( eyePos, dir, bounds.Min, bounds.Max, out t0, out t1 ) ) {
|
if( Intersection.RayIntersectsRotatedBox( eyePos, dir, p, out t0, out t1 ) ) {
|
||||||
dist = t0;
|
if( t0 < closestDist ) {
|
||||||
|
closestDist = t0;
|
||||||
targetId = (byte)i;
|
targetId = (byte)i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return targetId;
|
return targetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,21 @@ using OpenTK;
|
|||||||
|
|
||||||
namespace ClassicalSharp {
|
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
|
//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,
|
||||||
|
@ -90,7 +90,7 @@ namespace ClassicalSharp {
|
|||||||
// This cell falls on the path of the ray. Now perform an additional bounding box test,
|
// 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.
|
// since some blocks do not occupy a whole cell.
|
||||||
float t0, t1;
|
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 );
|
pickedPos.UpdateBlockPos( min, max, origin, dir, t0, t1 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ namespace ClassicalSharp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override void GetPickedBlock( PickedPos pos ) {
|
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;
|
Vector3 eyePos = player.EyePosition;
|
||||||
float reach = Window.LocalPlayer.ReachDistance;
|
float reach = Window.LocalPlayer.ReachDistance;
|
||||||
Picking.GetPickedBlockPos( Window, eyePos, dir, reach, pos );
|
Picking.GetPickedBlockPos( Window, eyePos, dir, reach, pos );
|
||||||
@ -108,7 +108,7 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
public override Matrix4 GetView() {
|
public override Matrix4 GetView() {
|
||||||
Vector3 eyePos = player.EyePosition;
|
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 );
|
return Matrix4.LookAt( cameraPos, eyePos, Vector3.UnitY );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
public override Matrix4 GetView() {
|
public override Matrix4 GetView() {
|
||||||
Vector3 eyePos = player.EyePosition;
|
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 );
|
return Matrix4.LookAt( eyePos, eyePos + cameraDir, Vector3.UnitY );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +111,12 @@ namespace ClassicalSharp {
|
|||||||
return packed * 360.0 / 256.0;
|
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 ) {
|
public static Vector3 RotateY( float x, float y, float z, float angle ) {
|
||||||
float cosA = (float)Math.Cos( angle );
|
float cosA = (float)Math.Cos( angle );
|
||||||
float sinA = (float)Math.Sin( angle );
|
float sinA = (float)Math.Sin( angle );
|
||||||
@ -138,10 +144,10 @@ namespace ClassicalSharp {
|
|||||||
return dx * dx + dy * dy + dz * dz;
|
return dx * dx + dy * dy + dz * dz;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Vector3 GetDirectionVector( double yawRad, double pitchRad ) {
|
public static Vector3 GetDirVector( double yawRad, double pitchRad ) {
|
||||||
double x = Math.Cos( pitchRad ) * -Math.Sin( yawRad );
|
double x = -Math.Cos( pitchRad ) * -Math.Sin( yawRad );
|
||||||
double y = Math.Sin( pitchRad );
|
double y = -Math.Sin( pitchRad );
|
||||||
double z = Math.Cos( pitchRad ) * Math.Cos( yawRad );
|
double z = -Math.Cos( pitchRad ) * Math.Cos( yawRad );
|
||||||
return new Vector3( (float)x, (float)y, (float)z );
|
return new Vector3( (float)x, (float)y, (float)z );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user