diff --git a/util/Math/DirUtils.cs b/util/Math/DirUtils.cs index 64aa80240..c51135ede 100644 --- a/util/Math/DirUtils.cs +++ b/util/Math/DirUtils.cs @@ -82,5 +82,38 @@ namespace MCGalaxy { double z = -Math.Cos(yaw * packed2Rad); // e.g. 128 -> PI, result should be 1 return new Vec3F32((float)x, (float)y, (float)z); } + + public static Vec3F32 GetAdjDirVector(byte yaw, byte pitch) { + const double packed2Rad = (2 * Math.PI) / 256.0; + double x = Math.Sin(yaw * packed2Rad) * Math.Cos(pitch * packed2Rad); + double y = -Math.Sin(pitch * packed2Rad); + double z = -Math.Cos(yaw * packed2Rad) * Math.Cos(pitch * packed2Rad); + return new Vec3F32((float)x, (float)y, (float)z); + } + + public static void GetYawPitch(Vec3F32 dir, out byte yaw, out byte pitch) { + // y = -sin(pitch) -> pitch = arcsin(-y) + // x = sin(yaw) * cos(pitch) -> yaw = arcsin(x/cos(pitch)) + // z = -cos(yaw) * cos(pitch) -> yaw = arccos(-z/cos(pitch)) + const double rad2Packed = 256.0 / (2 * Math.PI); + // NOTE: This conversion method **does** lose information + // a) If pitch is 0, yaw cannot be properly recalculated + // b) Pitch will always be from 0-64 or 192-256, therefore flipped heads lost + // However since we have X/Z, this problem does not occur for yaw, + // as we can use both values to determine which side of unit circle yaw is in + // c) Resulting yaw/pitch may be 1 or 2 values off due to rounding + + double pitchRad = Math.Asin(-dir.Y); + double cosPitch = Math.Cos(pitchRad); + double yawRad = Math.Asin(dir.X / cosPitch); + yaw = (byte)(yawRad * rad2Packed); + pitch = (byte)(pitchRad * rad2Packed); + + // Other side of unit circle + if (dir.Z > 0) yaw = (byte)(128 - yaw); + // Almost exactly +X or -X + if (dir.Z >= 0 && dir.Z < +0.0000001) yaw = 192; + if (dir.Z <= 0 && dir.Z > -0.0000001) yaw = 64; + } } }