From f8e19afe651c0eebca35a3471bb0e6963020bb2c Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 31 Dec 2015 11:09:53 +1100 Subject: [PATCH] Implement clipping for third person camera, also fix sound selection method for blocks being wrong (Thanks 123DontMessWitMe) --- .../2D/Screens/Menu/HacksSettingsScreen.cs | 6 +++ ClassicalSharp/Entities/LocalPlayer.cs | 20 ++++----- ClassicalSharp/Game/Game.Properties.cs | 7 ++- ClassicalSharp/Game/Game.cs | 7 ++- ClassicalSharp/Physics/PickedPos.cs | 4 ++ ClassicalSharp/Physics/Picking.cs | 44 ++++++++++++++----- .../Rendering/MapBordersRenderer.cs | 3 +- ClassicalSharp/Rendering/MapRenderer.cs | 3 +- ClassicalSharp/Rendering/PickingRenderer.cs | 3 +- .../Rendering/StandardEnvRenderer.cs | 3 +- ClassicalSharp/Rendering/WeatherRenderer.cs | 3 +- ClassicalSharp/Selections/SelectionManager.cs | 3 +- ClassicalSharp/Utils/Camera.cs | 19 +++++--- ClassicalSharp/Utils/Options.cs | 1 + Launcher2/Launcher2.csproj | 2 +- 15 files changed, 86 insertions(+), 42 deletions(-) diff --git a/ClassicalSharp/2D/Screens/Menu/HacksSettingsScreen.cs b/ClassicalSharp/2D/Screens/Menu/HacksSettingsScreen.cs index 07f00a7a6..9724cf878 100644 --- a/ClassicalSharp/2D/Screens/Menu/HacksSettingsScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/HacksSettingsScreen.cs @@ -27,6 +27,11 @@ namespace ClassicalSharp { (g, v) => { g.LocalPlayer.SpeedMultiplier = Single.Parse( v ); Options.Set( OptionsKey.Speed, v ); } ), + Make( -140, 0, "Camera clipping", OnWidgetClick, + g => g.CameraClipping ? "yes" : "no", + (g, v) => { g.CameraClipping = v == "yes"; + Options.Set( OptionsKey.CameraClipping, v == "yes" ); } ), + // Column 2 Make( 140, -100, "Liquids breakable", OnWidgetClick, g => g.LiquidsBreakable ? "yes" : "no", @@ -56,6 +61,7 @@ namespace ClassicalSharp { validators = new MenuInputValidator[] { new BooleanValidator(), new RealValidator( 0.1f, 50 ), + new BooleanValidator(), new BooleanValidator(), new BooleanValidator(), diff --git a/ClassicalSharp/Entities/LocalPlayer.cs b/ClassicalSharp/Entities/LocalPlayer.cs index da5b33e4c..d9ffaaa04 100644 --- a/ClassicalSharp/Entities/LocalPlayer.cs +++ b/ClassicalSharp/Entities/LocalPlayer.cs @@ -142,16 +142,7 @@ namespace ClassicalSharp { SoundType type = SoundType.None; bool nonAir = false; - // first check block standing on - byte blockUnder = (byte)BlockUnderFeet; - SoundType typeUnder = game.BlockInfo.StepSounds[blockUnder]; - BlockCollideType collideType = game.BlockInfo.CollideType[blockUnder]; - if( collideType == BlockCollideType.Solid && typeUnder != SoundType.None ) { - nonAir = true; - return typeUnder; - } - - // then check surrounding liquids/gas for sounds + // first check surrounding liquids/gas for sounds TouchesAny( bounds, b => { SoundType newType = game.BlockInfo.StepSounds[b]; BlockCollideType collide = game.BlockInfo.CollideType[b]; @@ -163,6 +154,15 @@ namespace ClassicalSharp { if( type != SoundType.None ) return type; + // then check block standing on + byte blockUnder = (byte)BlockUnderFeet; + SoundType typeUnder = game.BlockInfo.StepSounds[blockUnder]; + BlockCollideType collideType = game.BlockInfo.CollideType[blockUnder]; + if( collideType == BlockCollideType.Solid && typeUnder != SoundType.None ) { + nonAir = true; + return typeUnder; + } + // then check all solid blocks at feet pos.Y -= 0.01f; bounds.Max.Y = bounds.Min.Y = pos.Y; diff --git a/ClassicalSharp/Game/Game.Properties.cs b/ClassicalSharp/Game/Game.Properties.cs index 458c5f742..41f4fd33a 100644 --- a/ClassicalSharp/Game/Game.Properties.cs +++ b/ClassicalSharp/Game/Game.Properties.cs @@ -55,6 +55,9 @@ namespace ClassicalSharp { /// Accumulator for the number of chunk updates performed. Reset every second. public int ChunkUpdates; + /// Whether the third person camera should have their camera position clipped so as to not intersect blocks. + public bool CameraClipping = true; + public MapRenderer MapRenderer; public MapBordersRenderer MapBordersRenderer; public EnvRenderer EnvRenderer; @@ -66,7 +69,7 @@ namespace ClassicalSharp { public SelectionManager SelectionManager; public ParticleManager ParticleManager; public PickingRenderer Picking; - public PickedPos SelectedPos = new PickedPos(); + public PickedPos SelectedPos = new PickedPos(), CameraClipPos = new PickedPos(); public ModelCache ModelCache; internal string skinServer, chatInInputBuffer = null; internal int defaultIb; @@ -126,6 +129,8 @@ namespace ClassicalSharp { public bool ViewBobbing, ShowBlockInHand; public bool UseSound, UseMusic, LiquidsBreakable; + public Vector3 CurrentCameraPos; + public Animations Animations; internal int CloudsTexId, RainTexId, SnowTexId, GuiTexId; internal bool screenshotRequested; diff --git a/ClassicalSharp/Game/Game.cs b/ClassicalSharp/Game/Game.cs index f0b3132a4..ede2c2a6e 100644 --- a/ClassicalSharp/Game/Game.cs +++ b/ClassicalSharp/Game/Game.cs @@ -44,6 +44,7 @@ namespace ClassicalSharp { Options.Load(); AcceptedUrls.Load(); ViewDistance = Options.GetInt( OptionsKey.ViewDist, 16, 4096, 512 ); + CameraClipping = Options.GetBool( OptionsKey.CameraClipping, true ); InputHandler = new InputHandler( this ); Chat = new ChatLog( this ); ParticleManager = new ParticleManager( this ); @@ -185,10 +186,12 @@ namespace ClassicalSharp { Culling.CalcFrustumEquations( ref Projection, ref modelView ); bool visible = activeScreen == null || !activeScreen.BlocksWorld; - if( visible ) { + if( visible ) { AxisLinesRenderer.Render( e.Time ); Players.RenderModels( Graphics, e.Time, t ); Players.RenderNames( Graphics, e.Time, t ); + CurrentCameraPos = Camera.GetCameraPos( LocalPlayer.EyePosition ); + ParticleManager.Render( e.Time, t ); Camera.GetPickedBlock( SelectedPos ); // TODO: only pick when necessary EnvRenderer.Render( e.Time ); @@ -351,7 +354,7 @@ namespace ClassicalSharp { PerspectiveCamera oldCam = (PerspectiveCamera)Camera; if( Camera == firstPersonCam ) Camera = thirdPersonCam; else if( Camera == thirdPersonCam ) Camera = forwardThirdPersonCam; - else if( Camera == forwardThirdPersonCam ) Camera = firstPersonZoomCam; + //else if( Camera == forwardThirdPersonCam ) Camera = firstPersonZoomCam; else Camera = firstPersonCam; if( !LocalPlayer.CanUseThirdPersonCamera ) diff --git a/ClassicalSharp/Physics/PickedPos.cs b/ClassicalSharp/Physics/PickedPos.cs index be4e8005e..cae6a9ce5 100644 --- a/ClassicalSharp/Physics/PickedPos.cs +++ b/ClassicalSharp/Physics/PickedPos.cs @@ -12,6 +12,9 @@ namespace ClassicalSharp { /// Maximum world coordinates of the block's bounding box. public Vector3 Max; + /// Exact world coordinates at which the ray intersected this block. + public Vector3 IntersectPoint; + /// Integer world coordinates of the block. public Vector3I BlockPos; @@ -36,6 +39,7 @@ namespace ClassicalSharp { BlockPos = new Vector3I( x, y, z ); Valid = true; BlockType = block; + IntersectPoint = intersect; Vector3I normal = Vector3I.Zero; float dist = float.PositiveInfinity; diff --git a/ClassicalSharp/Physics/Picking.cs b/ClassicalSharp/Physics/Picking.cs index 65a75e0a3..3a09f3a1a 100644 --- a/ClassicalSharp/Physics/Picking.cs +++ b/ClassicalSharp/Physics/Picking.cs @@ -10,7 +10,7 @@ namespace ClassicalSharp { /// Determines the picked block based on the given origin and direction vector.
/// Marks pickedPos as invalid if a block could not be found due to going outside map boundaries /// or not being able to find a suitable candiate within the given reach distance.
- public static void CalculatePickedBlock( Game window, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos ) { + public static void CalculatePickedBlock( Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos ) { // Implementation based on: "A Fast Voxel Traversal Algorithm for Ray Tracing" // John Amanatides, Andrew Woo // http://www.cse.yorku.ca/~amana/research/grid.pdf @@ -21,10 +21,10 @@ namespace ClassicalSharp { int x = start.X, y = start.Y, z = start.Z; Vector3I step, cellBoundary; Vector3 tMax, tDelta; - CalculateTimes( origin, dir, out step, out cellBoundary, out tMax, out tDelta ); + CalcVectors( origin, dir, out step, out cellBoundary, out tMax, out tDelta ); - Map map = window.Map; - BlockInfo info = window.BlockInfo; + Map map = game.Map; + BlockInfo info = game.BlockInfo; float reachSquared = reach * reach; int iterations = 0; @@ -44,7 +44,7 @@ namespace ClassicalSharp { return; } - if( window.CanPick( block ) ) { + if( game.CanPick( block ) ) { // 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; @@ -61,15 +61,20 @@ namespace ClassicalSharp { "Something has gone wrong. (dir: " + dir + ")" ); } - public static void ClipCameraPos( Game window, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos ) { + public static void ClipCameraPos( Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos ) { + if( !game.CameraClipping ) { + pickedPos.SetAsInvalid(); + pickedPos.IntersectPoint = origin + dir * reach; + return; + } Vector3I start = Vector3I.Floor( origin ); int x = start.X, y = start.Y, z = start.Z; Vector3I step, cellBoundary; Vector3 tMax, tDelta; - CalculateTimes( origin, dir, out step, out cellBoundary, out tMax, out tDelta ); + CalcVectors( origin, dir, out step, out cellBoundary, out tMax, out tDelta ); - Map map = window.Map; - BlockInfo info = window.BlockInfo; + Map map = game.Map; + BlockInfo info = game.BlockInfo; float reachSquared = reach * reach; int iterations = 0; @@ -84,25 +89,42 @@ namespace ClassicalSharp { if( dx * dx + dy * dy + dz * dz > reachSquared ) { pickedPos.SetAsInvalid(); + pickedPos.IntersectPoint = origin + dir * reach; return; } if( info.CollideType[block] == BlockCollideType.Solid && !info.IsAir[block] ) { float t0, t1; + const float adjust = 0.1f; if( Intersection.RayIntersectsBox( origin, dir, min, max, out t0, out t1 ) ) { Vector3 intersect = origin + dir * t0; pickedPos.SetAsValid( x, y, z, min, max, block, intersect ); + + switch( pickedPos.BlockFace) { + case CpeBlockFace.XMin: + pickedPos.IntersectPoint.X -= adjust; break; + case CpeBlockFace.XMax: + pickedPos.IntersectPoint.X += adjust; break; + case CpeBlockFace.YMin: + pickedPos.IntersectPoint.Y -= adjust; break; + case CpeBlockFace.YMax: + pickedPos.IntersectPoint.Y += adjust; break; + case CpeBlockFace.ZMin: + pickedPos.IntersectPoint.Z -= adjust; break; + case CpeBlockFace.ZMax: + pickedPos.IntersectPoint.Z += adjust; break; + } return; } } Step( ref tMax, ref tDelta, ref step, ref x, ref y, ref z ); iterations++; } - throw new InvalidOperationException( "did over 10000 iterations in GetPickedBlockPos(). " + + throw new InvalidOperationException( "did over 10000 iterations in ClipCameraPos(). " + "Something has gone wrong. (dir: " + dir + ")" ); } - static void CalculateTimes( Vector3 origin, Vector3 dir, out Vector3I step, + static void CalcVectors( Vector3 origin, Vector3 dir, out Vector3I step, out Vector3I cellBoundary, out Vector3 tMax, out Vector3 tDelta ) { Vector3I start = Vector3I.Floor( origin ); // Determine which way we go. diff --git a/ClassicalSharp/Rendering/MapBordersRenderer.cs b/ClassicalSharp/Rendering/MapBordersRenderer.cs index 147b1a3fd..9bcfda4db 100644 --- a/ClassicalSharp/Rendering/MapBordersRenderer.cs +++ b/ClassicalSharp/Rendering/MapBordersRenderer.cs @@ -57,9 +57,8 @@ namespace ClassicalSharp { // Do not draw water when we cannot see it. // Fixes some 'depth bleeding through' issues with 16 bit depth buffers on large maps. - Vector3 eyePos = game.LocalPlayer.EyePosition; float yVisible = Math.Min( 0, map.SidesHeight ); - if( game.Map.EdgeBlock != Block.Air && game.Camera.GetCameraPos( eyePos ).Y >= yVisible ) { + if( game.Map.EdgeBlock != Block.Air && game.CurrentCameraPos.Y >= yVisible ) { graphics.DrawIndexedVb_TrisT2fC4b( edgesVertices * 6 / 4, 0 ); } graphics.AlphaBlending = false; diff --git a/ClassicalSharp/Rendering/MapRenderer.cs b/ClassicalSharp/Rendering/MapRenderer.cs index 8880379cc..fc3d6582a 100644 --- a/ClassicalSharp/Rendering/MapRenderer.cs +++ b/ClassicalSharp/Rendering/MapRenderer.cs @@ -224,8 +224,7 @@ namespace ClassicalSharp { int[] distances; void UpdateSortOrder() { - Player p = game.LocalPlayer; - Vector3 cameraPos = game.Camera.GetCameraPos( p.EyePosition ); + Vector3 cameraPos = game.CurrentCameraPos; Vector3I newChunkPos = Vector3I.Floor( cameraPos ); newChunkPos.X = (newChunkPos.X & ~0x0F) + 8; newChunkPos.Y = (newChunkPos.Y & ~0x0F) + 8; diff --git a/ClassicalSharp/Rendering/PickingRenderer.cs b/ClassicalSharp/Rendering/PickingRenderer.cs index 0c96291c9..6fcaffda0 100644 --- a/ClassicalSharp/Rendering/PickingRenderer.cs +++ b/ClassicalSharp/Rendering/PickingRenderer.cs @@ -24,8 +24,7 @@ namespace ClassicalSharp.Renderers { public void Render( double delta, PickedPos pickedPos ) { index = 0; - Player player = game.LocalPlayer; - Vector3 camPos = game.Camera.GetCameraPos( player.EyePosition ); + Vector3 camPos = game.CurrentCameraPos; float dist = (camPos - pickedPos.Min).LengthSquared; float size = dist < 12 * 12 ? 1/64f : 1/32f; diff --git a/ClassicalSharp/Rendering/StandardEnvRenderer.cs b/ClassicalSharp/Rendering/StandardEnvRenderer.cs index 46c3e8dde..6fcc563f5 100644 --- a/ClassicalSharp/Rendering/StandardEnvRenderer.cs +++ b/ClassicalSharp/Rendering/StandardEnvRenderer.cs @@ -23,8 +23,7 @@ namespace ClassicalSharp.Renderers { public override void Render( double deltaTime ) { if( skyVb == -1 || cloudsVb == -1 ) return; - Vector3 eyePos = game.LocalPlayer.EyePosition; - Vector3 pos = game.Camera.GetCameraPos( eyePos ); + Vector3 pos = game.CurrentCameraPos; float normalY = map.Height + 8; float skyY = Math.Max( pos.Y + 8, normalY ); diff --git a/ClassicalSharp/Rendering/WeatherRenderer.cs b/ClassicalSharp/Rendering/WeatherRenderer.cs index 053453ef5..5138b553e 100644 --- a/ClassicalSharp/Rendering/WeatherRenderer.cs +++ b/ClassicalSharp/Rendering/WeatherRenderer.cs @@ -32,8 +32,7 @@ namespace ClassicalSharp { graphics.Texturing = true; graphics.BindTexture( weather == Weather.Rainy ? game.RainTexId : game.SnowTexId ); - Vector3 eyePos = game.LocalPlayer.EyePosition; - Vector3 camPos = game.Camera.GetCameraPos( eyePos ); + Vector3 camPos = game.CurrentCameraPos; Vector3I pos = Vector3I.Floor( camPos ); bool moved = pos != lastPos; lastPos = pos; diff --git a/ClassicalSharp/Selections/SelectionManager.cs b/ClassicalSharp/Selections/SelectionManager.cs index a545ffd13..24d945a00 100644 --- a/ClassicalSharp/Selections/SelectionManager.cs +++ b/ClassicalSharp/Selections/SelectionManager.cs @@ -38,12 +38,11 @@ namespace ClassicalSharp.Selections { SelectionBoxComparer comparer = new SelectionBoxComparer(); public void Render( double delta ) { - Player player = game.LocalPlayer; if( selections.Count == 0 ) return; // TODO: Proper selection box sorting. But this is very difficult because // we can have boxes within boxes, intersecting boxes, etc. Probably not worth it. - Vector3 camPos = game.Camera.GetCameraPos( player.EyePosition ); + Vector3 camPos = game.CurrentCameraPos; for( int i = 0; i < selections.Count; i++ ) comparer.Intersect( selections[i], camPos ); selections.Sort( comparer ); diff --git a/ClassicalSharp/Utils/Camera.cs b/ClassicalSharp/Utils/Camera.cs index 871d24d08..60d21efbf 100644 --- a/ClassicalSharp/Utils/Camera.cs +++ b/ClassicalSharp/Utils/Camera.cs @@ -143,8 +143,10 @@ namespace ClassicalSharp { CalcViewBobbing( delta ); Vector3 eyePos = player.EyePosition; eyePos.Y += bobYOffset; - Vector3 cameraPos = eyePos - Utils.GetDirVector( player.YawRadians, player.PitchRadians ) * distance; - //Vector3 cameraPos = Picking.ClipCameraPos( game, eyePos, -Utils.GetDirVector( player.YawRadians, player.PitchRadians ), distance ); + + Vector3 dir = -Utils.GetDirVector( player.YawRadians, player.PitchRadians ); + Picking.ClipCameraPos( game, eyePos, dir, distance, game.CameraClipPos ); + Vector3 cameraPos = game.CameraClipPos.IntersectPoint; return Matrix4.LookAt( cameraPos, eyePos, Vector3.UnitY ) * tiltMatrix; } @@ -153,7 +155,9 @@ namespace ClassicalSharp { } public override Vector3 GetCameraPos( Vector3 eyePos ) { - return eyePos - Utils.GetDirVector( player.YawRadians, player.PitchRadians ) * distance; + Vector3 dir = -Utils.GetDirVector( player.YawRadians, player.PitchRadians ); + Picking.ClipCameraPos( game, eyePos, dir, distance, game.CameraClipPos ); + return game.CameraClipPos.IntersectPoint; } } @@ -173,7 +177,10 @@ namespace ClassicalSharp { CalcViewBobbing( delta ); Vector3 eyePos = player.EyePosition; eyePos.Y += bobYOffset; - Vector3 cameraPos = eyePos + Utils.GetDirVector( player.YawRadians, player.PitchRadians ) * distance; + + Vector3 dir = Utils.GetDirVector( player.YawRadians, player.PitchRadians ); + Picking.ClipCameraPos( game, eyePos, dir, distance, game.CameraClipPos ); + Vector3 cameraPos = game.CameraClipPos.IntersectPoint; return Matrix4.LookAt( cameraPos, eyePos, Vector3.UnitY ) * tiltMatrix; } @@ -182,7 +189,9 @@ namespace ClassicalSharp { } public override Vector3 GetCameraPos( Vector3 eyePos ) { - return eyePos + Utils.GetDirVector( player.YawRadians, player.PitchRadians ) * distance; + Vector3 dir = Utils.GetDirVector( player.YawRadians, player.PitchRadians ); + Picking.ClipCameraPos( game, eyePos, dir, distance, game.CameraClipPos ); + return game.CameraClipPos.IntersectPoint; } } diff --git a/ClassicalSharp/Utils/Options.cs b/ClassicalSharp/Utils/Options.cs index 33338a590..9069fc72d 100644 --- a/ClassicalSharp/Utils/Options.cs +++ b/ClassicalSharp/Utils/Options.cs @@ -36,6 +36,7 @@ namespace ClassicalSharp { public const string PushbackPlacing = "pushbackplacing"; public const string InvertMouse = "invertmouse"; public const string NoclipSlide = "noclipslide"; + public const string CameraClipping = "cameraclipping"; } // TODO: implement this diff --git a/Launcher2/Launcher2.csproj b/Launcher2/Launcher2.csproj index 020d45cca..5bd5daedb 100644 --- a/Launcher2/Launcher2.csproj +++ b/Launcher2/Launcher2.csproj @@ -20,7 +20,7 @@ icon.ico - x86 + AnyCPU 4194304 False Auto