blob: a10025fe167933d9d4dea01e00902f1fd854ffc5 [file] [log] [blame]
/*
* Copyright (C) 2017 Igalia S.L. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "VRFrameData.h"
#include "VREyeParameters.h"
#include "VRPlatformDisplay.h"
#include "VRPose.h"
namespace WebCore {
VRFrameData::VRFrameData()
: m_pose(VRPose::create())
{
}
static Ref<Float32Array> matrixToArray(const TransformationMatrix& matrix)
{
TransformationMatrix::FloatMatrix4 columnMajorMatrix;
matrix.toColumnMajorFloatArray(columnMajorMatrix);
return Float32Array::create(columnMajorMatrix, 16).releaseNonNull();
}
Ref<Float32Array> VRFrameData::leftProjectionMatrix() const
{
return matrixToArray(m_leftProjectionMatrix);
}
Ref<Float32Array> VRFrameData::leftViewMatrix() const
{
return matrixToArray(m_leftViewMatrix);
}
Ref<Float32Array> VRFrameData::rightProjectionMatrix() const
{
return matrixToArray(m_rightProjectionMatrix);
}
Ref<Float32Array> VRFrameData::rightViewMatrix() const
{
return matrixToArray(m_rightViewMatrix);
}
const VRPose& VRFrameData::pose() const
{
return m_pose;
}
static TransformationMatrix projectionMatrixFromFieldOfView(const VRFieldOfView& fov, double depthNear, double depthFar)
{
double upTan = tan(deg2rad(fov.upDegrees()));
double downTan = tan(deg2rad(fov.downDegrees()));
double leftTan = tan(deg2rad(fov.leftDegrees()));
double rightTan = tan(deg2rad(fov.rightDegrees()));
double xScale = 2 / (leftTan + rightTan);
double yScale = 2 / (upTan + downTan);
TransformationMatrix projectionMatrix;
projectionMatrix.setM11(xScale);
projectionMatrix.setM22(yScale);
projectionMatrix.setM32((upTan - downTan) * yScale * 0.5);
projectionMatrix.setM31(-((leftTan - rightTan) * xScale * 0.5));
projectionMatrix.setM33((depthNear + depthFar) / (depthNear - depthFar));
projectionMatrix.setM34(-1);
projectionMatrix.setM43((2 * depthFar * depthNear) / (depthNear - depthFar));
projectionMatrix.setM44(0);
return projectionMatrix;
}
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm
static TransformationMatrix rotationMatrixFromQuaternion(const VRPlatformTrackingInfo::Quaternion& quaternion)
{
double magnitude = (quaternion.x * quaternion.x) + (quaternion.y * quaternion.y) + (quaternion.z * quaternion.z) + (quaternion.w * quaternion.w);
VRPlatformTrackingInfo::Quaternion normalizedQuaternion(quaternion.x / magnitude, quaternion.y / magnitude, quaternion.z / magnitude, quaternion.w / magnitude);
double x2 = normalizedQuaternion.x * normalizedQuaternion.x;
double y2 = normalizedQuaternion.y * normalizedQuaternion.y;
double z2 = normalizedQuaternion.z * normalizedQuaternion.z;
double w2 = normalizedQuaternion.w * normalizedQuaternion.w;
double xy = normalizedQuaternion.x * normalizedQuaternion.y;
double zw = normalizedQuaternion.z * normalizedQuaternion.w;
double xz = normalizedQuaternion.x * normalizedQuaternion.z;
double yw = normalizedQuaternion.y * normalizedQuaternion.w;
double yz = normalizedQuaternion.y * normalizedQuaternion.z;
double xw = normalizedQuaternion.x * normalizedQuaternion.w;
return TransformationMatrix(
x2 - y2 - z2 + w2, 2.0 * (xy - zw), 2.0 * (xz + yw), 0,
2.0 * (xy + zw), -x2 + y2 - z2 + w2, 2.0 * (yz - xw), 0,
2.0 * (xz - yw), 2.0 * (yz + xw), -x2 - y2 + z2 + w2, 0,
0, 0, 0, 1);
}
static void applyHeadToEyeTransform(TransformationMatrix& matrix, const FloatPoint3D& translation)
{
matrix.setM41(matrix.m41() - translation.x());
matrix.setM42(matrix.m42() - translation.y());
matrix.setM43(matrix.m43() - translation.z());
}
void VRFrameData::update(const VRPlatformTrackingInfo& trackingInfo, const VREyeParameters& leftEye, const VREyeParameters& rightEye, double depthNear, double depthFar)
{
m_leftProjectionMatrix = projectionMatrixFromFieldOfView(leftEye.fieldOfView(), depthNear, depthFar);
m_rightProjectionMatrix = projectionMatrixFromFieldOfView(rightEye.fieldOfView(), depthNear, depthFar);
m_timestamp = trackingInfo.timestamp;
m_pose->update(trackingInfo);
auto rotationMatrix = rotationMatrixFromQuaternion(trackingInfo.orientation.value_or(VRPlatformTrackingInfo::Quaternion(0, 0, 0, 1)));
FloatPoint3D position = trackingInfo.position.value_or(FloatPoint3D(0, 0, 0));
rotationMatrix.translate3d(-position.x(), -position.y(), -position.z());
m_leftViewMatrix = rotationMatrix;
applyHeadToEyeTransform(m_leftViewMatrix, leftEye.rawOffset());
m_rightViewMatrix = rotationMatrix;
applyHeadToEyeTransform(m_rightViewMatrix, rightEye.rawOffset());
}
} // namespace WebCore