diff --git a/ClassicalSharp/Math/Matrix4.cs b/ClassicalSharp/Math/Matrix4.cs index 9e5930a7a..5d03dea0a 100644 --- a/ClassicalSharp/Math/Matrix4.cs +++ b/ClassicalSharp/Math/Matrix4.cs @@ -138,20 +138,15 @@ namespace OpenTK { a, b, c, -1, 0, 0, d, 0); } - - public static void LookAt(Vector3 eye, Vector3 target, Vector3 up, out Matrix4 result) { - Vector3 z = Vector3.Normalize(eye - target); - Vector3 x = Vector3.Normalize(Vector3.Cross(up, z)); - Vector3 y = Vector3.Normalize(Vector3.Cross(z, x)); - - Matrix4 rot = new Matrix4(new Vector4(x.X, y.X, z.X, 0.0f), - new Vector4(x.Y, y.Y, z.Y, 0.0f), - new Vector4(x.Z, y.Z, z.Z, 0.0f), - Vector4.UnitW); + + public static void LookRot(Vector3 pos, ClassicalSharp.Vector2 rot, out Matrix4 result) { + Matrix4 rotX, rotY, trans; + RotateX(out rotX, rot.Y); + RotateY(out rotY, rot.X); + Translate(out trans, -pos.X, -pos.Y, -pos.Z); - Matrix4 trans; - Translate(out trans, -eye.X, -eye.Y, -eye.Z); - Mult(out result, ref trans, ref rot); + Mult(out result, ref rotY, ref rotX); + Mult(out result, ref trans, ref result); } public static void Mult(out Matrix4 result, ref Matrix4 left, ref Matrix4 right) { diff --git a/ClassicalSharp/Math/Picking.cs b/ClassicalSharp/Math/Picking.cs index 03eaa9a83..aff2c16f1 100644 --- a/ClassicalSharp/Math/Picking.cs +++ b/ClassicalSharp/Math/Picking.cs @@ -50,25 +50,21 @@ namespace ClassicalSharp { } } + static Vector3 adjust = new Vector3(0.1f); static bool CameraClip(Game game, PickedPos pos) { if (BlockInfo.Draw[t.Block] == DrawType.Gas || BlockInfo.Collide[t.Block] != CollideType.Solid) return false; float t0, t1; - const float adjust = 0.1f; if (!Intersection.RayIntersectsBox(t.Origin, t.Dir, t.Min, t.Max, out t0, out t1)) return false; + + // Need to collide with slightly outside block, to avoid camera clipping issues + t.Min -= adjust; t.Max += adjust; + Intersection.RayIntersectsBox(t.Origin, t.Dir, t.Min, t.Max, out t0, out t1); + Vector3 I = t.Origin + t.Dir * t0; pos.SetAsValid(t.X, t.Y, t.Z, t.Min, t.Max, t.Block, I); - - switch (pos.Face) { - case BlockFace.XMin: pos.Intersect.X -= adjust; break; - case BlockFace.XMax: pos.Intersect.X += adjust; break; - case BlockFace.YMin: pos.Intersect.Y -= adjust; break; - case BlockFace.YMax: pos.Intersect.Y += adjust; break; - case BlockFace.ZMin: pos.Intersect.Z -= adjust; break; - case BlockFace.ZMax: pos.Intersect.Z += adjust; break; - } return true; } diff --git a/ClassicalSharp/Math/Vector3.cs b/ClassicalSharp/Math/Vector3.cs index a96c5d110..07a7232f6 100644 --- a/ClassicalSharp/Math/Vector3.cs +++ b/ClassicalSharp/Math/Vector3.cs @@ -61,26 +61,6 @@ namespace OpenTK { result.Y = blend * (b.Y - a.Y) + a.Y; result.Z = blend * (b.Z - a.Z) + a.Z; } - - public static float Dot(Vector3 left, Vector3 right) { - return left.X * right.X + left.Y * right.Y + left.Z * right.Z; - } - - public static void Dot(ref Vector3 left, ref Vector3 right, out float result) { - result = left.X * right.X + left.Y * right.Y + left.Z * right.Z; - } - - public static Vector3 Cross(Vector3 left, Vector3 right) { - return new Vector3(left.Y * right.Z - left.Z * right.Y, - left.Z * right.X - left.X * right.Z, - left.X * right.Y - left.Y * right.X); - } - - public static void Cross(ref Vector3 left, ref Vector3 right, out Vector3 result) { - result = new Vector3(left.Y * right.Z - left.Z * right.Y, - left.Z * right.X - left.X * right.Z, - left.X * right.Y - left.Y * right.X); - } public static Vector3 Normalize(Vector3 vec) { float scale = 1f / (float)Math.Sqrt(vec.LengthSquared); diff --git a/ClassicalSharp/Rendering/HeldBlockRenderer.cs b/ClassicalSharp/Rendering/HeldBlockRenderer.cs index 21030a6d0..bc1831ad4 100644 --- a/ClassicalSharp/Rendering/HeldBlockRenderer.cs +++ b/ClassicalSharp/Rendering/HeldBlockRenderer.cs @@ -90,10 +90,10 @@ namespace ClassicalSharp.Renderers { static Vector3 sOffset = new Vector3(0.46f, -0.52f, -0.72f); void SetMatrix() { Player p = game.LocalPlayer; - Vector3 eyePos = Vector3.Zero; eyePos.Y = p.EyeHeight; + Vector3 eye = Vector3.Zero; eye.Y = p.EyeHeight; - Matrix4 m, lookAt; - Matrix4.LookAt(eyePos, eyePos - Vector3.UnitZ, Vector3.UnitY, out lookAt); + Matrix4 lookAt, m; + Matrix4.Translate(out lookAt, -eye.X, -eye.Y, -eye.Z); Matrix4.Mult(out m, ref lookAt, ref Camera.tiltM); game.Graphics.View = m; } diff --git a/ClassicalSharp/Utils/Camera.cs b/ClassicalSharp/Utils/Camera.cs index e20299ece..ff6dad2ea 100644 --- a/ClassicalSharp/Utils/Camera.cs +++ b/ClassicalSharp/Utils/Camera.cs @@ -31,7 +31,6 @@ namespace ClassicalSharp { public abstract class PerspectiveCamera : Camera { protected static Vector2 rotOffset; - protected static Vector3 targetOffset; protected LocalPlayer player; public PerspectiveCamera(Game game) { @@ -40,18 +39,6 @@ namespace ClassicalSharp { tiltM = Matrix4.Identity; } - protected Vector3 GetDirVector() { - Vector2 rot = GetOrientation(); - Vector3 dir = Utils.GetDirVector(rot.X, rot.Y); - - // Adjusts pitch of the player to avoid looking straight up or down, - // as pitch parallel to camera up vector causes rendering issues - if (dir.Y > +0.999998f) dir.Y = +0.999998f; - if (dir.Y < -0.999998f) dir.Y = -0.999998f; - - return dir; - } - public override void GetProjection(out Matrix4 m) { float fov = game.Fov * Utils.Deg2Rad; float aspectRatio = (float)game.Width / game.Height; @@ -61,15 +48,13 @@ namespace ClassicalSharp { public override void GetView(out Matrix4 m) { Vector3 pos = game.CurrentCameraPos; - Vector3 target = pos + targetOffset; - - Matrix4.LookAt(pos, target, Vector3.UnitY, out m); + Vector2 rot = GetOrientation(); + Matrix4.LookRot(pos, rot, out m); Matrix4.Mult(out m, ref m, ref tiltM); } public override void GetPickedBlock(PickedPos pos) { Vector3 eyePos = player.EyePosition; - //Vector3 dir = GetDirVector(); Vector3 dir = Utils.GetDirVector(player.HeadYRadians, player.HeadXRadians); float reach = game.LocalPlayer.ReachDistance; @@ -134,7 +119,7 @@ namespace ClassicalSharp { // Need to make sure we don't cross the vertical axes, because that gets weird. if (update.HeadX >= 90 && update.HeadX <= 270) { - update.HeadX = player.interp.next.HeadX < 180 ? 89.9f : 270.1f; + update.HeadX = player.interp.next.HeadX < 180 ? 90.0f : 270.0f; } game.LocalPlayer.SetLocation(update, false); } @@ -193,12 +178,13 @@ namespace ClassicalSharp { Vector3 target = player.EyePosition; target.Y += bobbingVer; - Vector3 dir = -GetDirVector(); - Picking.ClipCameraPos(game, target, dir, dist, game.CameraClipPos); - Vector3 camPos = game.CameraClipPos.Intersect; + // cast ray from player position to camera position + // this way we can stop if we hit a block in the way + Vector2 rot = GetOrientation(); + Vector3 dir = -Utils.GetDirVector(rot.X, rot.Y); - targetOffset = target - camPos; - return camPos; + Picking.ClipCameraPos(game, target, dir, dist, game.CameraClipPos); + return game.CameraClipPos.Intersect; } } @@ -218,8 +204,6 @@ namespace ClassicalSharp { double headY = player.HeadYRadians; camPos.X += bobbingHor * (float)Math.Cos(headY); camPos.Z += bobbingHor * (float)Math.Sin(headY); - - targetOffset = GetDirVector(); return camPos; } } diff --git a/src/Client/Camera.c b/src/Client/Camera.c index d7158dc59..9f3d0acb9 100644 --- a/src/Client/Camera.c +++ b/src/Client/Camera.c @@ -9,23 +9,10 @@ #include "Input.h" Vector2 cam_rotOffset; -Vector3 cam_targetOffset; struct Camera Camera_Cameras[3]; Int32 Camera_ActiveIndex; #define Cam_IsForward_Third() (Camera_ActiveIndex == 2) -static Vector3 PerspectiveCamera_GetDirVector(void) { - Vector2 rot = Camera_Active->GetOrientation(); - Vector3 dir = Vector3_GetDirVector(rot.X, rot.Y); - - /* Adjusts pitch of the player to avoid looking straight up or down, */ - /* as pitch parallel to camera up vector causes rendering issues */ - if (dir.Y > +0.999998f) dir.Y = +0.999998f; - if (dir.Y < -0.999998f) dir.Y = -0.999998f; - - return dir; -} - static void PerspectiveCamera_GetProjection(struct Matrix* proj) { Real32 fovy = Game_Fov * MATH_DEG2RAD; Real32 aspectRatio = (Real32)Game_Width / (Real32)Game_Height; @@ -33,16 +20,14 @@ static void PerspectiveCamera_GetProjection(struct Matrix* proj) { } static void PerspectiveCamera_GetView(struct Matrix* mat) { - Vector3 pos = Game_CurrentCameraPos, target, up = Vector3_UnitY; - Vector3_Add(&target, &pos, &cam_targetOffset); - - Matrix_LookAt(mat, pos, target, up); + Vector3 pos = Game_CurrentCameraPos; + Vector2 rot = Camera_Active->GetOrientation(); + Matrix_LookRot(mat, pos, rot); Matrix_MulBy(mat, &Camera_TiltM); } static void PerspectiveCamera_GetPickedBlock(struct PickedPos* pos) { struct Entity* p = &LocalPlayer_Instance.Base; - /* Vector3 dir = PerspectiveCamera_GetDirVector(); */ Vector3 dir = Vector3_GetDirVector(p->HeadY * MATH_DEG2RAD, p->HeadX * MATH_DEG2RAD); Vector3 eyePos = Entity_GetEyePosition(p); Real32 reach = LocalPlayer_Instance.ReachDistance; @@ -104,7 +89,7 @@ static void PerspectiveCamera_UpdateMouseRotation(void) { /* Need to make sure we don't cross the vertical axes, because that gets weird. */ if (update.HeadX >= 90.0f && update.HeadX <= 270.0f) { - update.HeadX = player->Interp.Next.HeadX < 180.0f ? 89.9f : 270.1f; + update.HeadX = player->Interp.Next.HeadX < 180.0f ? 90.0f : 270.0f; } struct Entity* e = &player->Base; @@ -165,8 +150,6 @@ static Vector3 FirstPersonCamera_GetPosition(Real32 t) { Real32 headY = (p->HeadY * MATH_DEG2RAD); camPos.X += Camera_BobbingHor * Math_CosF(headY); camPos.Z += Camera_BobbingHor * Math_SinF(headY); - - cam_targetOffset = PerspectiveCamera_GetDirVector(); return camPos; } @@ -200,19 +183,19 @@ static Vector3 ThirdPersonCamera_GetPosition(Real32 t) { Vector3 target = Entity_GetEyePosition(p); target.Y += Camera_BobbingVer; - Vector3 dir = PerspectiveCamera_GetDirVector(); Vector3_Negate(&dir, &dir); - Picking_ClipCameraPos(target, dir, dist, &Game_CameraClipPos); - Vector3 camPos = Game_CameraClipPos.Intersect; + Vector2 rot = Camera_Active->GetOrientation(); + Vector3 dir = Vector3_GetDirVector(rot.X, rot.Y); + Vector3_Negate(&dir, &dir); - Vector3_Sub(&cam_targetOffset, &target, &camPos); - return camPos; + Picking_ClipCameraPos(target, dir, dist, &Game_CameraClipPos); + return Game_CameraClipPos.Intersect; } static bool ThirdPersonCamera_Zoom(Real32 amount) { Real32* dist = Cam_IsForward_Third() ? &dist_forward : &dist_third; Real32 newDist = *dist - amount; - newDist = min(newDist, 2.0f); *dist = newDist; + *dist = max(newDist, 2.0f); return true; } diff --git a/src/Client/HeldBlockRenderer.c b/src/Client/HeldBlockRenderer.c index 3a44719c4..b234c8002 100644 --- a/src/Client/HeldBlockRenderer.c +++ b/src/Client/HeldBlockRenderer.c @@ -51,12 +51,10 @@ static void HeldBlockRenderer_RenderModel(void) { static void HeldBlockRenderer_SetMatrix(void) { struct Entity* player = &LocalPlayer_Instance.Base; - Vector3 eyePos = VECTOR3_CONST(0.0f, Entity_GetEyeHeight(player), 0.0f); - Vector3 up = Vector3_UnitY; - Vector3 target = eyePos; target.Z -= 1.0f; /* Look straight down*/ + Vector3 eye = VECTOR3_CONST(0.0f, Entity_GetEyeHeight(player), 0.0f); struct Matrix m, lookAt; - Matrix_LookAt(&lookAt, eyePos, target, up); + Matrix_Translate(&lookAt, -eye.X, -eye.Y, -eye.Z); Matrix_Mul(&m, &lookAt, &Camera_TiltM); Gfx_View = m; } diff --git a/src/Client/Picking.c b/src/Client/Picking.c index d7b5cbac0..4904e6660 100644 --- a/src/Client/Picking.c +++ b/src/Client/Picking.c @@ -199,30 +199,21 @@ static bool Picking_ClipBlock(struct PickedPos* pos) { return true; } +static Vector3 picking_adjust = VECTOR3_CONST1(0.1f); static bool Picking_ClipCamera(struct PickedPos* pos) { - if (Block_Draw[tracer.Block] == DRAW_GAS || Block_Collide[tracer.Block] != COLLIDE_SOLID) { - return false; - } - + if (Block_Draw[tracer.Block] == DRAW_GAS || Block_Collide[tracer.Block] != COLLIDE_SOLID) return false; Real32 t0, t1; - if (!Intersection_RayIntersectsBox(tracer.Origin, tracer.Dir, tracer.Min, tracer.Max, &t0, &t1)) { - return false; - } + if (!Intersection_RayIntersectsBox(tracer.Origin, tracer.Dir, tracer.Min, tracer.Max, &t0, &t1)) return false; + + /* Need to collide with slightly outside block, to avoid camera clipping issues */ + Vector3_Sub(&tracer.Min, &tracer.Min, &picking_adjust); + Vector3_Add(&tracer.Max, &tracer.Max, &picking_adjust); + Intersection_RayIntersectsBox(tracer.Origin, tracer.Dir, tracer.Min, tracer.Max, &t0, &t1); Vector3 intersect; - Vector3_Mul1(&intersect, &tracer.Dir, t0); /* intersect = dir * t0 */ + Vector3_Mul1(&intersect, &tracer.Dir, t0); /* intersect = dir * t0 */ Vector3_Add(&intersect, &tracer.Origin, &intersect); /* intersect = origin + dir * t0 */ PickedPos_SetAsValid(pos, &tracer, intersect); - -#define PICKING_ADJUST 0.1f - switch (pos->ClosestFace) { - case FACE_XMIN: pos->Intersect.X -= PICKING_ADJUST; break; - case FACE_XMAX: pos->Intersect.X += PICKING_ADJUST; break; - case FACE_YMIN: pos->Intersect.Y -= PICKING_ADJUST; break; - case FACE_YMAX: pos->Intersect.Y += PICKING_ADJUST; break; - case FACE_ZMIN: pos->Intersect.Z -= PICKING_ADJUST; break; - case FACE_ZMAX: pos->Intersect.Z += PICKING_ADJUST; break; - } return true; } @@ -236,7 +227,7 @@ void Picking_ClipCameraPos(Vector3 origin, Vector3 dir, Real32 reach, struct Pic bool noClip = !Game_CameraClipping || LocalPlayer_Instance.Hacks.Noclip; if (noClip || !Picking_RayTrace(origin, dir, reach, pos, Picking_ClipCamera)) { PickedPos_SetAsInvalid(pos); - Vector3_Mul1(&pos->Intersect, &dir, reach); /* intersect = dir * reach */ + Vector3_Mul1(&pos->Intersect, &dir, reach); /* intersect = dir * reach */ Vector3_Add(&pos->Intersect, &origin, &pos->Intersect); /* intersect = origin + dir * reach */ } } diff --git a/src/Client/Vectors.c b/src/Client/Vectors.c index fd928c528..33010fcda 100644 --- a/src/Client/Vectors.c +++ b/src/Client/Vectors.c @@ -52,18 +52,6 @@ void Vector3_Lerp(Vector3* result, Vector3* a, Vector3* b, Real32 blend) { result->Z = blend * (b->Z - a->Z) + a->Z; } -Real32 Vector3_Dot(Vector3* a, Vector3* b) { - return a->X * b->X + a->Y * b->Y + a->Z * b->Z; -} - -void Vector3_Cross(Vector3* result, Vector3* a, Vector3* b) { - /* a or b could be pointing to result - can't directly assign X/Y/Z therefore */ - Real32 x = a->Y * b->Z - a->Z * b->Y; - Real32 y = a->Z * b->X - a->X * b->Z; - Real32 z = a->X * b->Y - a->Y * b->X; - result->X = x; result->Y = y; result->Z = z; -} - void Vector3_Normalize(Vector3* result, Vector3* a) { Real32 lenSquared = a->X * a->X + a->Y * a->Y + a->Z * a->Z; Real32 scale = 1.0f / Math_SqrtF(lenSquared); @@ -257,21 +245,14 @@ void Matrix_PerspectiveOffCenter(struct Matrix* result, Real32 left, Real32 rig result->Row2.W = -1.0f; } -void Matrix_LookAt(struct Matrix* result, Vector3 eye, Vector3 target, Vector3 up) { - /* Transposed, source https://msdn.microsoft.com/en-us/library/windows/desktop/bb281711(v=vs.85).aspx */ - Vector3 x, y, z; - Vector3_Sub(&z, &eye, &target); Vector3_Normalize(&z, &z); - Vector3_Cross(&x, &up, &z); Vector3_Normalize(&x, &x); - Vector3_Cross(&y, &z, &x); Vector3_Normalize(&y, &y); +void Matrix_LookRot(struct Matrix* result, Vector3 pos, Vector2 rot) { + struct Matrix rotX, rotY, trans; + Matrix_RotateX(&rotX, rot.Y); + Matrix_RotateY(&rotY, rot.X); + Matrix_Translate(&trans, -pos.X, -pos.Y, -pos.Z); - result->Row0.X = x.X; result->Row0.Y = y.X; result->Row0.Z = z.X; result->Row0.W = 0.0f; - result->Row1.X = x.Y; result->Row1.Y = y.Y; result->Row1.Z = z.Y; result->Row1.W = 0.0f; - result->Row2.X = x.Z; result->Row2.Y = y.Z; result->Row2.Z = z.Z; result->Row2.W = 0.0f; - - result->Row3.X = -Vector3_Dot(&x, &eye); - result->Row3.Y = -Vector3_Dot(&y, &eye); - result->Row3.Z = -Vector3_Dot(&z, &eye); - result->Row3.W = 1.0f; + Matrix_Mul(result, &rotY, &rotX); + Matrix_Mul(result, &trans, result); } Real32 diff --git a/src/Client/Vectors.h b/src/Client/Vectors.h index 1d990cf24..2a241bff2 100644 --- a/src/Client/Vectors.h +++ b/src/Client/Vectors.h @@ -41,7 +41,6 @@ void Vector3_Negate(Vector3* result, Vector3* a); void Vector3_Lerp(Vector3* result, Vector3* a, Vector3* b, Real32 blend); Real32 Vector3_Dot(Vector3* left, Vector3* right); -void Vector3_Cross(Vector3* result, Vector3* a, Vector3* b); void Vector3_Normalize(Vector3* result, Vector3* a); void Vector3_Transform(Vector3* result, Vector3* a, struct Matrix* mat); @@ -81,7 +80,7 @@ void Matrix_Orthographic(struct Matrix* result, Real32 width, Real32 height, Rea void Matrix_OrthographicOffCenter(struct Matrix* result, Real32 left, Real32 right, Real32 bottom, Real32 top, Real32 zNear, Real32 zFar); void Matrix_PerspectiveFieldOfView(struct Matrix* result, Real32 fovy, Real32 aspect, Real32 zNear, Real32 zFar); void Matrix_PerspectiveOffCenter(struct Matrix* result, Real32 left, Real32 right, Real32 bottom, Real32 top, Real32 zNear, Real32 zFar); -void Matrix_LookAt(struct Matrix* result, Vector3 eye, Vector3 target, Vector3 up); +void Matrix_LookRot(struct Matrix* result, Vector3 pos, Vector2 rot); bool FrustumCulling_SphereInFrustum(Real32 x, Real32 y, Real32 z, Real32 radius); void FrustumCulling_CalcFrustumEquations(struct Matrix* projection, struct Matrix* modelView);