Skip to content

WebXR Controls Improvements#1076

Closed
BlaiseRideout wants to merge 4 commits into
facebookresearch:masterfrom
BlaiseRideout:webxr
Closed

WebXR Controls Improvements#1076
BlaiseRideout wants to merge 4 commits into
facebookresearch:masterfrom
BlaiseRideout:webxr

Conversation

@BlaiseRideout

@BlaiseRideout BlaiseRideout commented Feb 3, 2021

Copy link
Copy Markdown
Contributor

Motivation and Context

Existing WebXR has limited unintuitive controls and this diff seeks to improve them.

How Has This Been Tested

Tested locally with a Rift S on Chrome 88.0.4324.104

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have completed my CLA (see CONTRIBUTING)
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@facebook-github-bot facebook-github-bot added the CLA Signed Do not delete this pull request or issue due to inactivity. label Feb 3, 2021
@BlaiseRideout BlaiseRideout changed the title Webxr WebXR Controls Improvements Feb 3, 2021
return spaces;
}

template <class T, typename... Targs>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mosra You are probably the best person to review this part. Do we really not have any better bindings exposed via Magnum?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

¯\_(ツ)_/¯

Magnum has no JS bindings on its own. Everything has been happening organically here so far, on an as-needed basis.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, I've reached out to Blaise about making some refactors here. The JS code uses Eigen types (vec4f, etc.), perhaps for legacy reasons.

@Skylion007 Skylion007 Feb 4, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@morsa does Magnum::Quaternion really not have a constructor for Vec4f though? Or at least a util for conversion?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah nvm, @eundersander posted the answer below.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a conversion from/to Eigen's Quaternion class, and possibly Eigen itself could have some way to convert to a 4-component vector on its own.

I'm not providing a conversion to a 4-component vector because it's not clear whether it should be xyzw or wxyz -- each math library uses something else, so it's better to be explicit. Which means doing a conversion using data()[i] also might not be 100% safe -- I don't know what order is the vec4f expected to be in and if it matches the order inside Magnum's Quaternion.

&Agent::getSensorSuite))
.function("getState", &Agent::getState)
.function("setState", &Agent::setState)
.function("setRotation", &Agent_setRotation)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So for consistency, rotation is a part of AgentState on the Python side Is it not the on C++ side, @bigbike ?

@Skylion007 Skylion007 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Javascript looks pretty good. I just want to make sure we are leveraging as much C++ code as possible. I don't think those Quaternion utility functions are necessary since I bet they exist inside of Magnum and can be easily accessed. @mosra knows more.

Also on the Python side, rotation is a part of AgentState, so we should make that consistent here as well. @vauduong and @bigbike are currently looking into the C++ agent code

@Skylion007 Skylion007 requested review from bigbike and mosra February 4, 2021 01:03
node.setRotation(Magnum::Quaternion(quatf(rot)).normalized());
}

void Agent_setRotation(Agent& agent, const Magnum::Quaternion& rot) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid introducing this new binding? How about implementing in JS:

  setAgentRotation(rotAngle) {
    let state = this.sim.getAgentState();
    state.rotation = WebAssembly.Module.eulerToQuaternion([0, rotAngle, 0])
    this.sim.setAgentState(state);
  }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used that approach originally, but switched to this one because I didn't need to set the whole agent state, so fetching the whole thing and then setting the whole thing when I only need to update one parameter seemed overkill and potentially less performant.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but that former approach is consistent with our Python AgentState APIs. I'd be surprised if it was a performance bottleneck, do you have benchmarks?

return Magnum::Quaternion(quatf(rot)).normalized();
}

Magnum::Quaternion Quaternion_mul(const Magnum::Quaternion& q1,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we need a quaternion multiply. But can we avoid introducing Magnum::Quaternion in the bindings interface? So far, for legacy reasons, we use the eigen vec4f. So I'm suggesting:

vec4f quaternionMultiply(const vec4f& q1, const vec4f& q2) {
  auto product = Magnum::Quaternion(quatf(q1)) * Magnum::Quaternion(quatf(q2));
  return vec4f(product.data()[0], product.data()[1], product.data()[2],
               product.data()[3]);
}

.function("inverted", &Magnum::Quaternion::inverted)
.function("transformVector", &Magnum::Quaternion::transformVector)
.function("mul", &Quaternion_mul)
.class_function("fromVec4f", &Quaternion_fromVec4f)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be defined as custom embind factory constructor, not a static method.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to push for another direction here. A nice, easy philosophy to apply everywhere here is: the Javascript class should have the same interface as the C++ class. Or a subset that grows as necessary (but remains a subset). My thinking is that @mosra already put some thought into this class's interface so why second-guess. It also avoids confusion for users learning to use both the Javascript and C++ versions of the class.

This means making fromVec4f a free function, called quaternionFromVec4f or similar.

mul is a special case because Javascript doesn't support operator overloading. I'm okay making that a member, since q1.mul(q2) would closely resemble q1 * q2.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with all that except the fact that it should be a static function like above.

@eundersander eundersander Feb 10, 2021

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it should be a static function like above.

Can you clarify? which function are we talking about (fromVec4f or mul)? And by static do you mean a static method on the javascript type?

I would argue that Module.Quaternion.fromVec4f (static method on Javascript Quaternion class) is confusing because Magnum::Quaternion::fromVec4f doesn't exist in C++.

If you're advocating that mul should be a static method (not a regular/non-static method), sure, I'm fine with that.

@mosra

mosra commented Feb 4, 2021

Copy link
Copy Markdown
Contributor

Vaguely (un)related and just FYI -- from what I know, it should be technically possible to create a WebXR application using just C++, without having to replicate a lot of code in JS and plain WebGL (as i saw in #984).

Of course depends on what the target audience is here -- If the WebXR app is meant to be developed, used & extended primarily by JS devs, then having it written in C++ would only add unnecessary roadblocks :)

const sensor = agent.sensorSuite.get(VIEW_SENSORS[iView]);

const pos = pointToArray(view.transform.position).slice(0, -1); // don't need w for position
sensor.setLocalTransform(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setLocalTransform takes a vec4f but you're passing a Quaternion. And the scary thing is that this builds and runs without error. I realize now that Emscripten/Embind/Javascript is not doing full type-checking. You can pass any object to setLocalTransform that happens to get storage as a 4-tuple of floats and you get no runtime error/warning.

@eundersander eundersander mentioned this pull request Mar 13, 2021
11 tasks
@eundersander

Copy link
Copy Markdown
Contributor

Cleaning this up a bit at a new PR: #1139

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed Do not delete this pull request or issue due to inactivity.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants