Log in or register to post comments

Vuforia Dominoes: native UWP adaption

December 3, 2018 - 2:55am #1

I've already asked about this on Stack Overflow (https://stackoverflow.com/questions/53542580/vuforia-dominoes-native-uwp-adaption), but I guess that wasn't the right forum. So to reiterate:

 

Working from Vuforia's native UWP sample for VuMarks I've been trying to implement functionality from the native Android Dominoes sample (both can be found here). Specifically, the option to click on the screen and get coordinates in the VuMark's target space.

Here is my code:

void VuMarkRenderer::OnScreenTapped(Point* pos, double logicalWidth, double logicalHeight) {
    // normalize coordinates
    float x = pos->X / logicalWidth;
    float y = pos->Y / logicalHeight;

    // normalized device coordinates
    Vuforia::Vec4F ndcNear(x, y, -1.0f, 1.0f);  // pn near plane
    Vuforia::Vec4F ndcFar(x, y, 1.0f, 1.0f);    // on far plane
    // to eye coordinates (i.e. multiplay with inverse projection matrix)
    auto nearPlanePoint = AppMathUtils::Vec4FTransform(ndcNear, m_currentInverseProjection);
    auto farPlanePoint = AppMathUtils::Vec4FTransform(ndcFar, m_currentInverseProjection);
    // normalize
    nearPlanePoint = AppMathUtils::Vec4FDiv(nearPlanePoint, nearPlanePoint.data[3]);
    farPlanePoint = AppMathUtils::Vec4FDiv(farPlanePoint, farPlanePoint.data[3]);

    // to object (world) coordinates
    Vuforia::Vec4F nearWorld = AppMathUtils::Vec4FTransform(nearPlanePoint, m_currentInverseModelView);
    Vuforia::Vec4F farWorld = AppMathUtils::Vec4FTransform(farPlanePoint, m_currentInverseModelView);
    // set up line (--> ray cast)
    Vuforia::Vec3F lineStart(
        nearWorld.data[0],
        nearWorld.data[1],
        nearWorld.data[2]);
    Vuforia::Vec3F lineEnd(
        farWorld.data[0],
        farWorld.data[1],
        farWorld.data[2]);

    // intersect with VuMark plane
    auto lineDir = AppMathUtils::Vec3FSub(lineEnd, lineStart);
    lineDir = AppMathUtils::Vec3FDiv(lineDir, lineDir.data[2]);
    Vuforia::Vec3F vuMarkPlaneCenter(0, 0, 0);
    auto planeDir = AppMathUtils::Vec3FSub(vuMarkPlaneCenter, lineStart);

    Vuforia::Vec3F vuMarkPlaneNormal(0, 0, 1);
    float n = AppMathUtils::Vec3FDot(vuMarkPlaneNormal, planeDir);
    float d = AppMathUtils::Vec3FDot(vuMarkPlaneNormal, lineDir);
    if (fabs(d) < 0.00001) {    // i.e. line is parallel to plane
         m_vuMarkView->UpdateDebugOutput("No intersection");
         return;
    }

    float dist = n / d;
    Vuforia::Vec3F offset = AppMathUtils::Vec3FScale(lineDir, dist);
    auto intersection = AppMathUtils::Vec3FAdd(lineStart, offset);
}

logicalWidth and logicalHeight are the UWP page's ActualWidth and ActualHeight respecively.

Here's where I get m_currentInverseProjection from:

[...]
// Calculate the DX Projection matrix using the current Vuforia state
auto projectionMatrix = Vuforia::Tool::convertPerspectiveProjection2GLMatrix(
    m_renderingPrimitives->getProjectionMatrix(Vuforia::VIEW_SINGULAR, state.getCameraCalibration()),
    m_near,
    m_far);

XMFLOAT4X4 dxProjection;
memcpy(dxProjection.m, projectionMatrix.data, sizeof(float) * 16);
XMStoreFloat4x4(&dxProjection, XMMatrixTranspose(XMLoadFloat4x4(&dxProjection)));
XMMATRIX xmProjection = XMLoadFloat4x4(&dxProjection);

bool gotVuMark = false;
for (size_t v = 0; v < viewList.getNumViews(); v++)
{
    Vuforia::VIEW viewId = viewList.getView(static_cast<int>(v));

    // Apply the appropriate eye adjustment to the raw projection matrix, and assign to the global variable
    Vuforia::Matrix44F eyeAdjustment44F = Vuforia::Tool::convert2GLMatrix(
        m_renderingPrimitives->getEyeDisplayAdjustmentMatrix(viewId));
    // get current inverse projection matrix
    Vuforia::Matrix44F currentProjection;
    AppMathUtils::multiplyMatrix(projectionMatrix, eyeAdjustment44F, currentProjection);
    m_currentInverseProjection = AppMathUtils::Matrix44FInverse(currentProjection);

    [...]

And here is m_currentInverseModelView:

[...]
// Set up the modelview matrix
auto poseGL = Vuforia::Tool::convertPose2GLMatrix(result->getPose());

// save the current inverse model-view matrix
m_currentInverseModelView = AppMathUtils::Matrix44FInverse(poseGL);

[...]

The functions from the AppMathUtils are just copied and pasted from the two sample projects.

However, the results are completely off. I am pretty sure that I'm misunderstanding something about the different coordinate systems, but I can absolutely not figure out what it is...

Does anyone have an idea, what I'm doing wrong? I'd appreciate any help!

 

Note:

I've also tried using Vuforia::Tool::projectPointToPlaneXY(*calib, m_vuMarkPose, videoXY) where m_vuMarkPose is the current TrackableResult->getPose() but that didn't give me any sensible results either.

Log in or register to post comments