diff --git a/Data/Sys/Profiles/Wiimote/Wii Remote with MotionPlus Pointing.ini b/Data/Sys/Profiles/Wiimote/Wii Remote with MotionPlus Pointing.ini index c13df04105..408c2ed0b4 100644 --- a/Data/Sys/Profiles/Wiimote/Wii Remote with MotionPlus Pointing.ini +++ b/Data/Sys/Profiles/Wiimote/Wii Remote with MotionPlus Pointing.ini @@ -21,7 +21,6 @@ IMUGyroscope/Roll Right = `Gyro Roll Right` IMUGyroscope/Yaw Left = `Gyro Yaw Left` IMUGyroscope/Yaw Right = `Gyro Yaw Right` IMUIR/Enabled = True -IMUIR/Total Yaw = 20 Extension/Attach MotionPlus = `Attached MotionPlus` Extension = `Attached Extension` Nunchuk/Buttons/C = `Nunchuk C` diff --git a/Source/Core/Common/MathUtil.h b/Source/Core/Common/MathUtil.h index c616b3d74d..5ad9ee0dcd 100644 --- a/Source/Core/Common/MathUtil.h +++ b/Source/Core/Common/MathUtil.h @@ -135,8 +135,12 @@ public: constexpr size_t Count() const { return m_running_mean.Count(); } constexpr T Mean() const { return m_running_mean.Mean(); } + constexpr T Variance() const { return m_variance / (Count() - 1); } - constexpr T StandardDeviation() const { return std::sqrt(Variance()); } + T StandardDeviation() const { return std::sqrt(Variance()); } + + constexpr T PopulationVariance() const { return m_variance / Count(); } + T PopulationStandardDeviation() const { return std::sqrt(PopulationVariance()); } private: RunningMean m_running_mean; diff --git a/Source/Core/Core/HW/WiimoteEmu/Camera.cpp b/Source/Core/Core/HW/WiimoteEmu/Camera.cpp index 05e28c7930..46ec87f672 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Camera.cpp +++ b/Source/Core/Core/HW/WiimoteEmu/Camera.cpp @@ -75,9 +75,6 @@ void CameraLogic::Update(const Common::Matrix44& transform) using Common::Vec3; using Common::Vec4; - constexpr auto CAMERA_FOV_Y = float(CAMERA_FOV_Y_DEG * MathUtil::TAU / 360); - constexpr auto CAMERA_ASPECT_RATIO = float(CAMERA_FOV_X_DEG) / CAMERA_FOV_Y_DEG; - // FYI: A real wiimote normally only returns 1 point for each LED cluster (2 total). // Sending all 4 points can actually cause some stuttering issues. constexpr int NUM_POINTS = 2; @@ -86,16 +83,12 @@ void CameraLogic::Update(const Common::Matrix44& transform) // This is reduced based on distance from sensor bar. constexpr int MAX_POINT_SIZE = 15; - // Sensor bar: - // Distance in meters between LED clusters. - constexpr float SENSOR_BAR_LED_SEPARATION = 0.2f; - const std::array leds{ Vec3{-SENSOR_BAR_LED_SEPARATION / 2, 0, 0}, Vec3{SENSOR_BAR_LED_SEPARATION / 2, 0, 0}, }; - const auto camera_view = Matrix44::Perspective(CAMERA_FOV_Y, CAMERA_ASPECT_RATIO, 0.001f, 1000) * + const auto camera_view = Matrix44::Perspective(CAMERA_FOV_Y, CAMERA_AR, 0.001f, 1000) * Matrix44::FromMatrix33(Matrix33::RotateX(float(MathUtil::TAU / 4))) * transform; diff --git a/Source/Core/Core/HW/WiimoteEmu/Camera.h b/Source/Core/Core/HW/WiimoteEmu/Camera.h index 4a98d33325..6d07d720da 100644 --- a/Source/Core/Core/HW/WiimoteEmu/Camera.h +++ b/Source/Core/Core/HW/WiimoteEmu/Camera.h @@ -91,13 +91,17 @@ static_assert(sizeof(IRFull) == 9, "Wrong size"); class CameraLogic : public I2CSlave { public: + // OEM sensor bar distance between LED clusters in meters. + static constexpr float SENSOR_BAR_LED_SEPARATION = 0.2f; + static constexpr int CAMERA_RES_X = 1024; static constexpr int CAMERA_RES_Y = 768; - // Wiibrew claims the camera FOV is about 33 deg by 23 deg. - // Unconfirmed but it seems to work well enough. - static constexpr int CAMERA_FOV_X_DEG = 33; - static constexpr int CAMERA_FOV_Y_DEG = 23; + // Jordan: I calculate the FOV at 42 degrees horizontally and having a 4:3 aspect ratio. + // This is 31.5 degrees vertically. + static constexpr float CAMERA_AR = 4.f / 3; + static constexpr float CAMERA_FOV_X = 42 * float(MathUtil::TAU) / 360; + static constexpr float CAMERA_FOV_Y = CAMERA_FOV_X / CAMERA_AR; enum : u8 { diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp index 1c5f48a148..fa379624db 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/Cursor.cpp @@ -33,8 +33,7 @@ Cursor::Cursor(std::string name_, std::string ui_name_) AddInput(Translate, _trans("Relative Input Hold")); - // Default values are optimized for "Super Mario Galaxy 2". - // This seems to be acceptable for a good number of games. + // Default values chosen to reach screen edges in most games including the Wii Menu. AddSetting(&m_vertical_offset_setting, // i18n: Refers to a positional offset applied to an emulated wiimote. @@ -50,7 +49,7 @@ Cursor::Cursor(std::string name_, std::string ui_name_) _trans("°"), // i18n: Refers to emulated wii remote movements. _trans("Total rotation about the yaw axis.")}, - 15, 0, 360); + 25, 0, 360); AddSetting(&m_pitch_setting, // i18n: Refers to an amount of rotational movement about the "pitch" axis. @@ -59,7 +58,7 @@ Cursor::Cursor(std::string name_, std::string ui_name_) _trans("°"), // i18n: Refers to emulated wii remote movements. _trans("Total rotation about the pitch axis.")}, - 15, 0, 360); + 20, 0, 360); AddSetting(&m_relative_setting, {_trans("Relative Input")}, false); AddSetting(&m_autohide_setting, {_trans("Auto-Hide")}, false); diff --git a/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUCursor.cpp b/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUCursor.cpp index 25df9772da..429cd18880 100644 --- a/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUCursor.cpp +++ b/Source/Core/InputCommon/ControllerEmu/ControlGroup/IMUCursor.cpp @@ -29,8 +29,7 @@ IMUCursor::IMUCursor(std::string name_, std::string ui_name_) { AddInput(Translate, _trans("Recenter")); - // Default values are optimized for "Super Mario Galaxy 2". - // This seems to be acceptable for a good number of games. + // Default values chosen to reach screen edges in most games including the Wii Menu. AddSetting(&m_yaw_setting, // i18n: Refers to an amount of rotational movement about the "yaw" axis. @@ -39,7 +38,7 @@ IMUCursor::IMUCursor(std::string name_, std::string ui_name_) _trans("°"), // i18n: Refers to emulated wii remote movements. _trans("Total rotation about the yaw axis.")}, - 15, 0, 360); + 25, 0, 360); } ControlState IMUCursor::GetTotalYaw() const diff --git a/Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.cpp b/Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.cpp index 6398bfa9e4..ef0d15090b 100644 --- a/Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.cpp +++ b/Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.cpp @@ -196,6 +196,8 @@ Device::Device(std::unique_ptr wiimote) : m_wiimote(std::m AddInput(new UndetectableAnalogInput(&m_ir_state.is_hidden, "IR Hidden", 1)); + AddInput(new UndetectableAnalogInput(&m_ir_state.distance, "IR Distance", 1)); + // Raw gyroscope. static constexpr std::array, 3> gyro_names = {{ {"Gyro Pitch Down", "Gyro Pitch Up"}, @@ -1198,9 +1200,9 @@ void Device::UpdateOrientation() // FYI: We could do some roll correction from multiple IR objects. const auto ir_rotation = - Common::Vec3(m_ir_state.center_position.y * WiimoteEmu::CameraLogic::CAMERA_FOV_Y_DEG, 0, - m_ir_state.center_position.x * WiimoteEmu::CameraLogic::CAMERA_FOV_X_DEG) / - 2 * float(MathUtil::TAU) / 360; + Common::Vec3(m_ir_state.center_position.y * WiimoteEmu::CameraLogic::CAMERA_FOV_Y, 0, + m_ir_state.center_position.x * WiimoteEmu::CameraLogic::CAMERA_FOV_X) / + 2; const auto ir_normal = Common::Vec3(0, 1, 0); const auto ir_vector = WiimoteEmu::GetMatrixFromGyroscope(-ir_rotation) * ir_normal; @@ -1226,8 +1228,7 @@ void Device::IRState::ProcessData(const std::array& data using IRObject = WiimoteEmu::IRBasic::IRObject; - Common::Vec2 point_total; - int point_count = 0; + MathUtil::RunningVariance points; const auto camera_max = IRObject(WiimoteEmu::CameraLogic::CAMERA_RES_X - 1, WiimoteEmu::CameraLogic::CAMERA_RES_Y - 1); @@ -1237,8 +1238,7 @@ void Device::IRState::ProcessData(const std::array& data if (point.y > camera_max.y) return; - point_total += Common::Vec2(point); - ++point_count; + points.Push(Common::Vec2(point)); }; for (auto& block : data) @@ -1247,12 +1247,25 @@ void Device::IRState::ProcessData(const std::array& data add_point(block.GetObject2()); } - is_hidden = !point_count; + is_hidden = !points.Count(); - if (point_count) + if (points.Count() >= 2) { - center_position = - point_total / float(point_count) / Common::Vec2(camera_max) * 2.f - Common::Vec2(1, 1); + const auto variance = points.PopulationVariance(); + // Adjusts Y coorinate to match horizontal FOV. + const auto separation = + Common::Vec2(std::sqrt(variance.x), std::sqrt(variance.y)) / + Common::Vec2(WiimoteEmu::CameraLogic::CAMERA_RES_X, + WiimoteEmu::CameraLogic::CAMERA_RES_Y * WiimoteEmu::CameraLogic::CAMERA_AR) * + 2; + + distance = WiimoteEmu::CameraLogic::SENSOR_BAR_LED_SEPARATION / separation.Length() / 2 / + std::tan(WiimoteEmu::CameraLogic::CAMERA_FOV_X / 2); + } + + if (points.Count()) + { + center_position = points.Mean() / Common::Vec2(camera_max) * 2.f - Common::Vec2(1, 1); } else { diff --git a/Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.h b/Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.h index 7615a92940..75a5c447e7 100644 --- a/Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.h +++ b/Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.h @@ -135,6 +135,8 @@ private: // Average of visible IR "objects". Common::Vec2 center_position = {}; + float distance = 0; + bool is_hidden = true; };