Skip to content
Permalink
Browse files
Merge pull request #9106 from jordan-woyak/wm-distance
WiimoteEmu: Increase camera FOV to match that of a real Wii remote.
  • Loading branch information
jordan-woyak committed Sep 28, 2020
2 parents 9607500 + 0295d47 commit 3655243
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 32 deletions.
@@ -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`
@@ -135,8 +135,12 @@ class RunningVariance

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<T> m_running_mean;
@@ -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<Vec3, NUM_POINTS> 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;

@@ -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
{
@@ -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);
@@ -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
@@ -196,6 +196,8 @@ Device::Device(std::unique_ptr<WiimoteReal::Wiimote> wiimote) : m_wiimote(std::m

AddInput(new UndetectableAnalogInput<bool>(&m_ir_state.is_hidden, "IR Hidden", 1));

AddInput(new UndetectableAnalogInput<float>(&m_ir_state.distance, "IR Distance", 1));

// Raw gyroscope.
static constexpr std::array<std::array<const char*, 2>, 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<WiimoteEmu::IRBasic, 2>& data

using IRObject = WiimoteEmu::IRBasic::IRObject;

Common::Vec2 point_total;
int point_count = 0;
MathUtil::RunningVariance<Common::Vec2> 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<WiimoteEmu::IRBasic, 2>& 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<WiimoteEmu::IRBasic, 2>& data
add_point(block.GetObject2());
}

is_hidden = !point_count;
is_hidden = !points.Count();

if (points.Count() >= 2)
{
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 (point_count)
if (points.Count())
{
center_position =
point_total / float(point_count) / Common::Vec2(camera_max) * 2.f - Common::Vec2(1, 1);
center_position = points.Mean() / Common::Vec2(camera_max) * 2.f - Common::Vec2(1, 1);
}
else
{
@@ -135,6 +135,8 @@ class Device final : public Core::Device
// Average of visible IR "objects".
Common::Vec2 center_position = {};

float distance = 0;

bool is_hidden = true;
};

0 comments on commit 3655243

Please sign in to comment.