1/*
2 * Copyright (C) 2017 Igalia S.L. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25#include "config.h"
26#include "VRFrameData.h"
27
28#include "VREyeParameters.h"
29#include "VRPlatformDisplay.h"
30#include "VRPose.h"
31#include <JavaScriptCore/TypedArrayInlines.h>
32
33namespace WebCore {
34
35VRFrameData::VRFrameData()
36 : m_pose(VRPose::create())
37{
38}
39
40static Ref<Float32Array> matrixToArray(const TransformationMatrix& matrix)
41{
42 auto columnMajorMatrix = matrix.toColumnMajorFloatArray();
43 return Float32Array::create(columnMajorMatrix.data(), 16);
44}
45
46Ref<Float32Array> VRFrameData::leftProjectionMatrix() const
47{
48 return matrixToArray(m_leftProjectionMatrix);
49}
50
51Ref<Float32Array> VRFrameData::leftViewMatrix() const
52{
53 return matrixToArray(m_leftViewMatrix);
54}
55
56Ref<Float32Array> VRFrameData::rightProjectionMatrix() const
57{
58 return matrixToArray(m_rightProjectionMatrix);
59}
60
61Ref<Float32Array> VRFrameData::rightViewMatrix() const
62{
63 return matrixToArray(m_rightViewMatrix);
64}
65
66const VRPose& VRFrameData::pose() const
67{
68 return m_pose;
69}
70
71static TransformationMatrix projectionMatrixFromFieldOfView(const VRFieldOfView& fov, double depthNear, double depthFar)
72{
73 double upTan = tan(deg2rad(fov.upDegrees()));
74 double downTan = tan(deg2rad(fov.downDegrees()));
75 double leftTan = tan(deg2rad(fov.leftDegrees()));
76 double rightTan = tan(deg2rad(fov.rightDegrees()));
77
78 double xScale = 2 / (leftTan + rightTan);
79 double yScale = 2 / (upTan + downTan);
80
81 TransformationMatrix projectionMatrix;
82 projectionMatrix.setM11(xScale);
83 projectionMatrix.setM22(yScale);
84 projectionMatrix.setM32((upTan - downTan) * yScale * 0.5);
85 projectionMatrix.setM31(-((leftTan - rightTan) * xScale * 0.5));
86 projectionMatrix.setM33((depthNear + depthFar) / (depthNear - depthFar));
87 projectionMatrix.setM34(-1);
88 projectionMatrix.setM43((2 * depthFar * depthNear) / (depthNear - depthFar));
89 projectionMatrix.setM44(0);
90
91 return projectionMatrix;
92}
93
94// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToMatrix/index.htm
95static TransformationMatrix rotationMatrixFromQuaternion(const VRPlatformTrackingInfo::Quaternion& quaternion)
96{
97 double magnitude = (quaternion.x * quaternion.x) + (quaternion.y * quaternion.y) + (quaternion.z * quaternion.z) + (quaternion.w * quaternion.w);
98 VRPlatformTrackingInfo::Quaternion normalizedQuaternion(quaternion.x / magnitude, quaternion.y / magnitude, quaternion.z / magnitude, quaternion.w / magnitude);
99 double x2 = normalizedQuaternion.x * normalizedQuaternion.x;
100 double y2 = normalizedQuaternion.y * normalizedQuaternion.y;
101 double z2 = normalizedQuaternion.z * normalizedQuaternion.z;
102 double w2 = normalizedQuaternion.w * normalizedQuaternion.w;
103 double xy = normalizedQuaternion.x * normalizedQuaternion.y;
104 double zw = normalizedQuaternion.z * normalizedQuaternion.w;
105 double xz = normalizedQuaternion.x * normalizedQuaternion.z;
106 double yw = normalizedQuaternion.y * normalizedQuaternion.w;
107 double yz = normalizedQuaternion.y * normalizedQuaternion.z;
108 double xw = normalizedQuaternion.x * normalizedQuaternion.w;
109
110 return TransformationMatrix(
111 x2 - y2 - z2 + w2, 2.0 * (xy - zw), 2.0 * (xz + yw), 0,
112 2.0 * (xy + zw), -x2 + y2 - z2 + w2, 2.0 * (yz - xw), 0,
113 2.0 * (xz - yw), 2.0 * (yz + xw), -x2 - y2 + z2 + w2, 0,
114 0, 0, 0, 1);
115}
116
117static void applyHeadToEyeTransform(TransformationMatrix& matrix, const FloatPoint3D& translation)
118{
119 matrix.setM41(matrix.m41() - translation.x());
120 matrix.setM42(matrix.m42() - translation.y());
121 matrix.setM43(matrix.m43() - translation.z());
122}
123
124void VRFrameData::update(const VRPlatformTrackingInfo& trackingInfo, const VREyeParameters& leftEye, const VREyeParameters& rightEye, double depthNear, double depthFar)
125{
126 m_leftProjectionMatrix = projectionMatrixFromFieldOfView(leftEye.fieldOfView(), depthNear, depthFar);
127 m_rightProjectionMatrix = projectionMatrixFromFieldOfView(rightEye.fieldOfView(), depthNear, depthFar);
128
129 m_timestamp = trackingInfo.timestamp;
130 m_pose->update(trackingInfo);
131
132 auto rotationMatrix = rotationMatrixFromQuaternion(trackingInfo.orientation.valueOr(VRPlatformTrackingInfo::Quaternion(0, 0, 0, 1)));
133 FloatPoint3D position = trackingInfo.position.valueOr(FloatPoint3D(0, 0, 0));
134 rotationMatrix.translate3d(-position.x(), -position.y(), -position.z());
135
136 m_leftViewMatrix = rotationMatrix;
137 applyHeadToEyeTransform(m_leftViewMatrix, leftEye.rawOffset());
138
139 m_rightViewMatrix = rotationMatrix;
140 applyHeadToEyeTransform(m_rightViewMatrix, rightEye.rawOffset());
141}
142
143} // namespace WebCore
144