Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Ablesons
three.js
提交
3f479a5b
T
three.js
项目概览
Ablesons
/
three.js
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
three.js
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
3f479a5b
编写于
2月 01, 2016
作者:
R
rNix
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Added example webvr_stereo_pano
上级
c6722d05
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
3785 addition
and
1 deletion
+3785
-1
examples/files.js
examples/files.js
+2
-1
examples/js/libs/webvr-polyfill.js
examples/js/libs/webvr-polyfill.js
+3331
-0
examples/textures/cube/sun_temple_stripe_stereo.jpg
examples/textures/cube/sun_temple_stripe_stereo.jpg
+0
-0
examples/webgl_stereo_pano.html
examples/webgl_stereo_pano.html
+226
-0
examples/webvr_stereo_pano.html
examples/webvr_stereo_pano.html
+226
-0
未找到文件。
examples/files.js
浏览文件 @
3f479a5b
...
@@ -227,7 +227,8 @@ var files = {
...
@@ -227,7 +227,8 @@ var files = {
],
],
"
webvr
"
:
[
"
webvr
"
:
[
"
webvr_cubes
"
,
"
webvr_cubes
"
,
"
webvr_video
"
"
webvr_video
"
,
"
webvr_stereo_pano
"
],
],
"
css3d
"
:
[
"
css3d
"
:
[
"
css3d_molecules
"
,
"
css3d_molecules
"
,
...
...
examples/js/libs/webvr-polyfill.js
0 → 100644
浏览文件 @
3f479a5b
(
function
e
(
t
,
n
,
r
){
function
s
(
o
,
u
){
if
(
!
n
[
o
]){
if
(
!
t
[
o
]){
var
a
=
typeof
require
==
"
function
"
&&
require
;
if
(
!
u
&&
a
)
return
a
(
o
,
!
0
);
if
(
i
)
return
i
(
o
,
!
0
);
var
f
=
new
Error
(
"
Cannot find module '
"
+
o
+
"
'
"
);
throw
f
.
code
=
"
MODULE_NOT_FOUND
"
,
f
}
var
l
=
n
[
o
]
=
{
exports
:{}};
t
[
o
][
0
].
call
(
l
.
exports
,
function
(
e
){
var
n
=
t
[
o
][
1
][
e
];
return
s
(
n
?
n
:
e
)},
l
,
l
.
exports
,
e
,
t
,
n
,
r
)}
return
n
[
o
].
exports
}
var
i
=
typeof
require
==
"
function
"
&&
require
;
for
(
var
o
=
0
;
o
<
r
.
length
;
o
++
)
s
(
r
[
o
]);
return
s
})({
1
:[
function
(
_dereq_
,
module
,
exports
){
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* The base class for all VR devices.
*/
function
VRDevice
()
{
this
.
hardwareUnitId
=
'
webvr-polyfill hardwareUnitId
'
;
this
.
deviceId
=
'
webvr-polyfill deviceId
'
;
this
.
deviceName
=
'
webvr-polyfill deviceName
'
;
}
/**
* The base class for all VR HMD devices.
*/
function
HMDVRDevice
()
{
}
HMDVRDevice
.
prototype
=
new
VRDevice
();
/**
* The base class for all VR position sensor devices.
*/
function
PositionSensorVRDevice
()
{
}
PositionSensorVRDevice
.
prototype
=
new
VRDevice
();
module
.
exports
.
VRDevice
=
VRDevice
;
module
.
exports
.
HMDVRDevice
=
HMDVRDevice
;
module
.
exports
.
PositionSensorVRDevice
=
PositionSensorVRDevice
;
},{}],
2
:[
function
(
_dereq_
,
module
,
exports
){
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var
HMDVRDevice
=
_dereq_
(
'
./base.js
'
).
HMDVRDevice
;
// Constants from vrtoolkit: https://github.com/googlesamples/cardboard-java.
var
DEFAULT_INTERPUPILLARY_DISTANCE
=
0.06
;
var
DEFAULT_FIELD_OF_VIEW
=
40
;
var
Eye
=
{
LEFT
:
'
left
'
,
RIGHT
:
'
right
'
};
/**
* The HMD itself, providing rendering parameters.
*/
function
CardboardHMDVRDevice
()
{
// From com/google/vrtoolkit/cardboard/FieldOfView.java.
this
.
setMonocularFieldOfView_
(
DEFAULT_FIELD_OF_VIEW
);
// Set display constants.
this
.
setInterpupillaryDistance
(
DEFAULT_INTERPUPILLARY_DISTANCE
);
}
CardboardHMDVRDevice
.
prototype
=
new
HMDVRDevice
();
CardboardHMDVRDevice
.
prototype
.
getEyeParameters
=
function
(
whichEye
)
{
var
eyeTranslation
;
var
fieldOfView
;
var
renderRect
;
if
(
whichEye
==
Eye
.
LEFT
)
{
eyeTranslation
=
this
.
eyeTranslationLeft
;
fieldOfView
=
this
.
fieldOfViewLeft
;
renderRect
=
this
.
renderRectLeft
;
}
else
if
(
whichEye
==
Eye
.
RIGHT
)
{
eyeTranslation
=
this
.
eyeTranslationRight
;
fieldOfView
=
this
.
fieldOfViewRight
;
renderRect
=
this
.
renderRectRight
;
}
else
{
console
.
error
(
'
Invalid eye provided: %s
'
,
whichEye
);
return
null
;
}
return
{
recommendedFieldOfView
:
fieldOfView
,
eyeTranslation
:
eyeTranslation
,
renderRect
:
renderRect
};
};
/**
* Sets the field of view for both eyes. This is according to WebVR spec:
*
* @param {FieldOfView} opt_fovLeft Field of view of the left eye.
* @param {FieldOfView} opt_fovRight Field of view of the right eye.
* @param {Number} opt_zNear The near plane.
* @param {Number} opt_zFar The far plane.
*
* http://mozvr.github.io/webvr-spec/webvr.html#dom-hmdvrdevice-setfieldofviewleftfov-rightfov-znear-zfar
*/
CardboardHMDVRDevice
.
prototype
.
setFieldOfView
=
function
(
opt_fovLeft
,
opt_fovRight
,
opt_zNear
,
opt_zFar
)
{
if
(
opt_fovLeft
)
{
this
.
fieldOfViewLeft
=
opt_fovLeft
;
}
if
(
opt_fovRight
)
{
this
.
fieldOfViewRight
=
opt_fovRight
;
}
if
(
opt_zNear
)
{
this
.
zNear
=
opt_zNear
;
}
if
(
opt_zFar
)
{
this
.
zFar
=
opt_zFar
;
}
};
/**
* Changes the interpupillary distance of the rendered scene. This is useful for
* changing Cardboard viewers.
*
* Possibly a useful addition to the WebVR spec?
*
* @param {Number} ipd Distance between eyes.
*/
CardboardHMDVRDevice
.
prototype
.
setInterpupillaryDistance
=
function
(
ipd
)
{
this
.
eyeTranslationLeft
=
{
x
:
ipd
*
-
0.5
,
y
:
0
,
z
:
0
};
this
.
eyeTranslationRight
=
{
x
:
ipd
*
0.5
,
y
:
0
,
z
:
0
};
};
/**
* Changes the render rect (ie. viewport) where each eye is rendered. Again,
* useful for changing Cardboard viewers.
*
* @param {Rect} opt_rectLeft Viewport for left eye.
* @param {Rect} opt_rectRight Viewport for right eye.
*/
CardboardHMDVRDevice
.
prototype
.
setRenderRect
=
function
(
opt_rectLeft
,
opt_rectRight
)
{
if
(
opt_rectLeft
)
{
this
.
renderRectLeft
=
opt_rectLeft
;
}
if
(
opt_rectRight
)
{
this
.
renderRectRight
=
opt_rectRight
;
}
};
/**
* Sets a symmetrical field of view for both eyes, with just one angle.
*
* @param {Number} angle Angle in degrees of left, right, top and bottom for
* both eyes.
*/
CardboardHMDVRDevice
.
prototype
.
setMonocularFieldOfView_
=
function
(
angle
)
{
this
.
setFieldOfView
(
this
.
createSymmetricalFieldOfView_
(
angle
),
this
.
createSymmetricalFieldOfView_
(
angle
));
};
CardboardHMDVRDevice
.
prototype
.
createSymmetricalFieldOfView_
=
function
(
angle
)
{
return
{
upDegrees
:
angle
,
downDegrees
:
angle
,
leftDegrees
:
angle
,
rightDegrees
:
angle
};
};
module
.
exports
=
CardboardHMDVRDevice
;
},{
"
./base.js
"
:
1
}],
3
:[
function
(
_dereq_
,
module
,
exports
){
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* TODO: Fix up all "new THREE" instantiations to improve performance.
*/
var
SensorSample
=
_dereq_
(
'
./sensor-sample.js
'
);
var
THREE
=
_dereq_
(
'
./three-math.js
'
);
var
Util
=
_dereq_
(
'
./util.js
'
);
var
DEBUG
=
false
;
/**
* An implementation of a simple complementary filter, which fuses gyroscope and
* accelerometer data from the 'devicemotion' event.
*
* Accelerometer data is very noisy, but stable over the long term.
* Gyroscope data is smooth, but tends to drift over the long term.
*
* This fusion is relatively simple:
* 1. Get orientation estimates from accelerometer by applying a low-pass filter
* on that data.
* 2. Get orientation estimates from gyroscope by integrating over time.
* 3. Combine the two estimates, weighing (1) in the long term, but (2) for the
* short term.
*/
function
ComplementaryFilter
(
kFilter
)
{
this
.
kFilter
=
kFilter
;
// Raw sensor measurements.
this
.
currentAccelMeasurement
=
new
SensorSample
();
this
.
currentGyroMeasurement
=
new
SensorSample
();
this
.
previousGyroMeasurement
=
new
SensorSample
();
// Current filter orientation
this
.
filterQ
=
new
THREE
.
Quaternion
();
this
.
previousFilterQ
=
new
THREE
.
Quaternion
();
// Orientation based on the accelerometer.
this
.
accelQ
=
new
THREE
.
Quaternion
();
// Whether or not the orientation has been initialized.
this
.
isOrientationInitialized
=
false
;
// Running estimate of gravity based on the current orientation.
this
.
estimatedGravity
=
new
THREE
.
Vector3
();
// Measured gravity based on accelerometer.
this
.
measuredGravity
=
new
THREE
.
Vector3
();
// Debug only quaternion of gyro-based orientation.
this
.
gyroIntegralQ
=
new
THREE
.
Quaternion
();
}
ComplementaryFilter
.
prototype
.
addAccelMeasurement
=
function
(
vector
,
timestampS
)
{
this
.
currentAccelMeasurement
.
set
(
vector
,
timestampS
);
};
ComplementaryFilter
.
prototype
.
addGyroMeasurement
=
function
(
vector
,
timestampS
)
{
this
.
currentGyroMeasurement
.
set
(
vector
,
timestampS
);
var
deltaT
=
timestampS
-
this
.
previousGyroMeasurement
.
timestampS
;
if
(
Util
.
isTimestampDeltaValid
(
deltaT
))
{
this
.
run_
();
}
this
.
previousGyroMeasurement
.
copy
(
this
.
currentGyroMeasurement
);
};
ComplementaryFilter
.
prototype
.
run_
=
function
()
{
if
(
!
this
.
isOrientationInitialized
)
{
this
.
accelQ
=
this
.
accelToQuaternion_
(
this
.
currentAccelMeasurement
.
sample
);
this
.
previousFilterQ
.
copy
(
this
.
accelQ
);
this
.
isOrientationInitialized
=
true
;
return
;
}
var
deltaT
=
this
.
currentGyroMeasurement
.
timestampS
-
this
.
previousGyroMeasurement
.
timestampS
;
// Convert gyro rotation vector to a quaternion delta.
var
gyroDeltaQ
=
this
.
gyroToQuaternionDelta_
(
this
.
currentGyroMeasurement
.
sample
,
deltaT
);
this
.
gyroIntegralQ
.
multiply
(
gyroDeltaQ
);
// filter_1 = K * (filter_0 + gyro * dT) + (1 - K) * accel.
this
.
filterQ
.
copy
(
this
.
previousFilterQ
);
this
.
filterQ
.
multiply
(
gyroDeltaQ
);
// Calculate the delta between the current estimated gravity and the real
// gravity vector from accelerometer.
var
invFilterQ
=
new
THREE
.
Quaternion
();
invFilterQ
.
copy
(
this
.
filterQ
);
invFilterQ
.
inverse
();
this
.
estimatedGravity
.
set
(
0
,
0
,
-
1
);
this
.
estimatedGravity
.
applyQuaternion
(
invFilterQ
);
this
.
estimatedGravity
.
normalize
();
this
.
measuredGravity
.
copy
(
this
.
currentAccelMeasurement
.
sample
);
this
.
measuredGravity
.
normalize
();
// Compare estimated gravity with measured gravity, get the delta quaternion
// between the two.
var
deltaQ
=
new
THREE
.
Quaternion
();
deltaQ
.
setFromUnitVectors
(
this
.
estimatedGravity
,
this
.
measuredGravity
);
deltaQ
.
inverse
();
if
(
DEBUG
)
{
console
.
log
(
'
Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)
'
,
THREE
.
Math
.
radToDeg
(
Util
.
getQuaternionAngle
(
deltaQ
)),
(
this
.
estimatedGravity
.
x
).
toFixed
(
1
),
(
this
.
estimatedGravity
.
y
).
toFixed
(
1
),
(
this
.
estimatedGravity
.
z
).
toFixed
(
1
),
(
this
.
measuredGravity
.
x
).
toFixed
(
1
),
(
this
.
measuredGravity
.
y
).
toFixed
(
1
),
(
this
.
measuredGravity
.
z
).
toFixed
(
1
));
}
// Calculate the SLERP target: current orientation plus the measured-estimated
// quaternion delta.
var
targetQ
=
new
THREE
.
Quaternion
();
targetQ
.
copy
(
this
.
filterQ
);
targetQ
.
multiply
(
deltaQ
);
// SLERP factor: 0 is pure gyro, 1 is pure accel.
this
.
filterQ
.
slerp
(
targetQ
,
1
-
this
.
kFilter
);
this
.
previousFilterQ
.
copy
(
this
.
filterQ
);
};
ComplementaryFilter
.
prototype
.
getOrientation
=
function
()
{
return
this
.
filterQ
;
};
ComplementaryFilter
.
prototype
.
accelToQuaternion_
=
function
(
accel
)
{
var
normAccel
=
new
THREE
.
Vector3
();
normAccel
.
copy
(
accel
);
normAccel
.
normalize
();
var
quat
=
new
THREE
.
Quaternion
();
quat
.
setFromUnitVectors
(
new
THREE
.
Vector3
(
0
,
0
,
-
1
),
normAccel
);
quat
.
inverse
();
return
quat
;
};
ComplementaryFilter
.
prototype
.
gyroToQuaternionDelta_
=
function
(
gyro
,
dt
)
{
// Extract axis and angle from the gyroscope data.
var
quat
=
new
THREE
.
Quaternion
();
var
axis
=
new
THREE
.
Vector3
();
axis
.
copy
(
gyro
);
axis
.
normalize
();
quat
.
setFromAxisAngle
(
axis
,
gyro
.
length
()
*
dt
);
return
quat
;
};
module
.
exports
=
ComplementaryFilter
;
},{
"
./sensor-sample.js
"
:
8
,
"
./three-math.js
"
:
9
,
"
./util.js
"
:
11
}],
4
:[
function
(
_dereq_
,
module
,
exports
){
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var
PositionSensorVRDevice
=
_dereq_
(
'
./base.js
'
).
PositionSensorVRDevice
;
var
ComplementaryFilter
=
_dereq_
(
'
./complementary-filter.js
'
);
var
PosePredictor
=
_dereq_
(
'
./pose-predictor.js
'
);
var
TouchPanner
=
_dereq_
(
'
./touch-panner.js
'
);
var
THREE
=
_dereq_
(
'
./three-math.js
'
);
var
Util
=
_dereq_
(
'
./util.js
'
);
/**
* The positional sensor, implemented using DeviceMotion APIs.
*/
function
FusionPositionSensorVRDevice
()
{
this
.
deviceId
=
'
webvr-polyfill:fused
'
;
this
.
deviceName
=
'
VR Position Device (webvr-polyfill:fused)
'
;
this
.
accelerometer
=
new
THREE
.
Vector3
();
this
.
gyroscope
=
new
THREE
.
Vector3
();
window
.
addEventListener
(
'
devicemotion
'
,
this
.
onDeviceMotionChange_
.
bind
(
this
));
window
.
addEventListener
(
'
orientationchange
'
,
this
.
onScreenOrientationChange_
.
bind
(
this
));
this
.
filter
=
new
ComplementaryFilter
(
WebVRConfig
.
K_FILTER
||
0.98
);
this
.
posePredictor
=
new
PosePredictor
(
WebVRConfig
.
PREDICTION_TIME_S
||
0.040
);
this
.
touchPanner
=
new
TouchPanner
();
this
.
filterToWorldQ
=
new
THREE
.
Quaternion
();
// Set the filter to world transform, depending on OS.
if
(
Util
.
isIOS
())
{
this
.
filterToWorldQ
.
setFromAxisAngle
(
new
THREE
.
Vector3
(
1
,
0
,
0
),
Math
.
PI
/
2
);
}
else
{
this
.
filterToWorldQ
.
setFromAxisAngle
(
new
THREE
.
Vector3
(
1
,
0
,
0
),
-
Math
.
PI
/
2
);
}
this
.
worldToScreenQ
=
new
THREE
.
Quaternion
();
this
.
setScreenTransform_
();
// Keep track of a reset transform for resetSensor.
this
.
resetQ
=
new
THREE
.
Quaternion
();
this
.
isFirefoxAndroid
=
Util
.
isFirefoxAndroid
();
this
.
isIOS
=
Util
.
isIOS
();
}
FusionPositionSensorVRDevice
.
prototype
=
new
PositionSensorVRDevice
();
/**
* Returns {orientation: {x,y,z,w}, position: null}.
* Position is not supported since we can't do 6DOF.
*/
FusionPositionSensorVRDevice
.
prototype
.
getState
=
function
()
{
return
{
hasOrientation
:
true
,
orientation
:
this
.
getOrientation
(),
hasPosition
:
false
,
position
:
null
}
};
FusionPositionSensorVRDevice
.
prototype
.
getOrientation
=
function
()
{
// Convert from filter space to the the same system used by the
// deviceorientation event.
var
orientation
=
this
.
filter
.
getOrientation
();
// Predict orientation.
this
.
predictedQ
=
this
.
posePredictor
.
getPrediction
(
orientation
,
this
.
gyroscope
,
this
.
previousTimestampS
);
// Convert to THREE coordinate system: -Z forward, Y up, X right.
var
out
=
new
THREE
.
Quaternion
();
out
.
copy
(
this
.
filterToWorldQ
);
out
.
multiply
(
this
.
resetQ
);
if
(
!
WebVRConfig
.
TOUCH_PANNER_DISABLED
)
{
out
.
multiply
(
this
.
touchPanner
.
getOrientation
());
}
out
.
multiply
(
this
.
predictedQ
);
out
.
multiply
(
this
.
worldToScreenQ
);
// Handle the yaw-only case.
if
(
WebVRConfig
.
YAW_ONLY
)
{
// Make a quaternion that only turns around the Y-axis.
out
.
x
=
0
;
out
.
z
=
0
;
out
.
normalize
();
}
return
out
;
};
FusionPositionSensorVRDevice
.
prototype
.
resetSensor
=
function
()
{
var
euler
=
new
THREE
.
Euler
();
euler
.
setFromQuaternion
(
this
.
filter
.
getOrientation
());
var
yaw
=
euler
.
y
;
console
.
log
(
'
resetSensor with yaw: %f
'
,
yaw
);
this
.
resetQ
.
setFromAxisAngle
(
new
THREE
.
Vector3
(
0
,
0
,
1
),
-
yaw
);
if
(
!
WebVRConfig
.
TOUCH_PANNER_DISABLED
)
{
this
.
touchPanner
.
resetSensor
();
}
};
FusionPositionSensorVRDevice
.
prototype
.
onDeviceMotionChange_
=
function
(
deviceMotion
)
{
var
accGravity
=
deviceMotion
.
accelerationIncludingGravity
;
var
rotRate
=
deviceMotion
.
rotationRate
;
var
timestampS
=
deviceMotion
.
timeStamp
/
1000
;
// Firefox Android timeStamp returns one thousandth of a millisecond.
if
(
this
.
isFirefoxAndroid
)
{
timestampS
/=
1000
;
}
var
deltaS
=
timestampS
-
this
.
previousTimestampS
;
if
(
deltaS
<=
Util
.
MIN_TIMESTEP
||
deltaS
>
Util
.
MAX_TIMESTEP
)
{
console
.
warn
(
'
Invalid timestamps detected. Time step between successive
'
+
'
gyroscope sensor samples is very small or not monotonic
'
);
this
.
previousTimestampS
=
timestampS
;
return
;
}
this
.
accelerometer
.
set
(
-
accGravity
.
x
,
-
accGravity
.
y
,
-
accGravity
.
z
);
this
.
gyroscope
.
set
(
rotRate
.
alpha
,
rotRate
.
beta
,
rotRate
.
gamma
);
// With iOS and Firefox Android, rotationRate is reported in degrees,
// so we first convert to radians.
if
(
this
.
isIOS
||
this
.
isFirefoxAndroid
)
{
this
.
gyroscope
.
multiplyScalar
(
Math
.
PI
/
180
);
}
this
.
filter
.
addAccelMeasurement
(
this
.
accelerometer
,
timestampS
);
this
.
filter
.
addGyroMeasurement
(
this
.
gyroscope
,
timestampS
);
this
.
previousTimestampS
=
timestampS
;
};
FusionPositionSensorVRDevice
.
prototype
.
onScreenOrientationChange_
=
function
(
screenOrientation
)
{
this
.
setScreenTransform_
();
};
FusionPositionSensorVRDevice
.
prototype
.
setScreenTransform_
=
function
()
{
this
.
worldToScreenQ
.
set
(
0
,
0
,
0
,
1
);
switch
(
window
.
orientation
)
{
case
0
:
break
;
case
90
:
this
.
worldToScreenQ
.
setFromAxisAngle
(
new
THREE
.
Vector3
(
0
,
0
,
1
),
-
Math
.
PI
/
2
);
break
;
case
-
90
:
this
.
worldToScreenQ
.
setFromAxisAngle
(
new
THREE
.
Vector3
(
0
,
0
,
1
),
Math
.
PI
/
2
);
break
;
case
180
:
// TODO.
break
;
}
};
module
.
exports
=
FusionPositionSensorVRDevice
;
},{
"
./base.js
"
:
1
,
"
./complementary-filter.js
"
:
3
,
"
./pose-predictor.js
"
:
7
,
"
./three-math.js
"
:
9
,
"
./touch-panner.js
"
:
10
,
"
./util.js
"
:
11
}],
5
:[
function
(
_dereq_
,
module
,
exports
){
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var
WebVRPolyfill
=
_dereq_
(
'
./webvr-polyfill.js
'
);
// Initialize a WebVRConfig just in case.
window
.
WebVRConfig
=
window
.
WebVRConfig
||
{};
new
WebVRPolyfill
();
},{
"
./webvr-polyfill.js
"
:
12
}],
6
:[
function
(
_dereq_
,
module
,
exports
){
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var
PositionSensorVRDevice
=
_dereq_
(
'
./base.js
'
).
PositionSensorVRDevice
;
var
THREE
=
_dereq_
(
'
./three-math.js
'
);
var
Util
=
_dereq_
(
'
./util.js
'
);
// How much to rotate per key stroke.
var
KEY_SPEED
=
0.15
;
var
KEY_ANIMATION_DURATION
=
80
;
// How much to rotate for mouse events.
var
MOUSE_SPEED_X
=
0.5
;
var
MOUSE_SPEED_Y
=
0.3
;
/**
* A virtual position sensor, implemented using keyboard and
* mouse APIs. This is designed as for desktops/laptops where no Device*
* events work.
*/
function
MouseKeyboardPositionSensorVRDevice
()
{
this
.
deviceId
=
'
webvr-polyfill:mouse-keyboard
'
;
this
.
deviceName
=
'
VR Position Device (webvr-polyfill:mouse-keyboard)
'
;
// Attach to mouse and keyboard events.
window
.
addEventListener
(
'
keydown
'
,
this
.
onKeyDown_
.
bind
(
this
));
window
.
addEventListener
(
'
mousemove
'
,
this
.
onMouseMove_
.
bind
(
this
));
window
.
addEventListener
(
'
mousedown
'
,
this
.
onMouseDown_
.
bind
(
this
));
window
.
addEventListener
(
'
mouseup
'
,
this
.
onMouseUp_
.
bind
(
this
));
this
.
phi
=
0
;
this
.
theta
=
0
;
// Variables for keyboard-based rotation animation.
this
.
targetAngle
=
null
;
// State variables for calculations.
this
.
euler
=
new
THREE
.
Euler
();
this
.
orientation
=
new
THREE
.
Quaternion
();
// Variables for mouse-based rotation.
this
.
rotateStart
=
new
THREE
.
Vector2
();
this
.
rotateEnd
=
new
THREE
.
Vector2
();
this
.
rotateDelta
=
new
THREE
.
Vector2
();
}
MouseKeyboardPositionSensorVRDevice
.
prototype
=
new
PositionSensorVRDevice
();
/**
* Returns {orientation: {x,y,z,w}, position: null}.
* Position is not supported for parity with other PositionSensors.
*/
MouseKeyboardPositionSensorVRDevice
.
prototype
.
getState
=
function
()
{
this
.
euler
.
set
(
this
.
phi
,
this
.
theta
,
0
,
'
YXZ
'
);
this
.
orientation
.
setFromEuler
(
this
.
euler
);
return
{
hasOrientation
:
true
,
orientation
:
this
.
orientation
,
hasPosition
:
false
,
position
:
null
}
};
MouseKeyboardPositionSensorVRDevice
.
prototype
.
onKeyDown_
=
function
(
e
)
{
// Track WASD and arrow keys.
if
(
e
.
keyCode
==
38
)
{
// Up key.
this
.
animatePhi_
(
this
.
phi
+
KEY_SPEED
);
}
else
if
(
e
.
keyCode
==
39
)
{
// Right key.
this
.
animateTheta_
(
this
.
theta
-
KEY_SPEED
);
}
else
if
(
e
.
keyCode
==
40
)
{
// Down key.
this
.
animatePhi_
(
this
.
phi
-
KEY_SPEED
);
}
else
if
(
e
.
keyCode
==
37
)
{
// Left key.
this
.
animateTheta_
(
this
.
theta
+
KEY_SPEED
);
}
};
MouseKeyboardPositionSensorVRDevice
.
prototype
.
animateTheta_
=
function
(
targetAngle
)
{
this
.
animateKeyTransitions_
(
'
theta
'
,
targetAngle
);
};
MouseKeyboardPositionSensorVRDevice
.
prototype
.
animatePhi_
=
function
(
targetAngle
)
{
// Prevent looking too far up or down.
targetAngle
=
Util
.
clamp
(
targetAngle
,
-
Math
.
PI
/
2
,
Math
.
PI
/
2
);
this
.
animateKeyTransitions_
(
'
phi
'
,
targetAngle
);
};
/**
* Start an animation to transition an angle from one value to another.
*/
MouseKeyboardPositionSensorVRDevice
.
prototype
.
animateKeyTransitions_
=
function
(
angleName
,
targetAngle
)
{
// If an animation is currently running, cancel it.
if
(
this
.
angleAnimation
)
{
clearInterval
(
this
.
angleAnimation
);
}
var
startAngle
=
this
[
angleName
];
var
startTime
=
new
Date
();
// Set up an interval timer to perform the animation.
this
.
angleAnimation
=
setInterval
(
function
()
{
// Once we're finished the animation, we're done.
var
elapsed
=
new
Date
()
-
startTime
;
if
(
elapsed
>=
KEY_ANIMATION_DURATION
)
{
this
[
angleName
]
=
targetAngle
;
clearInterval
(
this
.
angleAnimation
);
return
;
}
// Linearly interpolate the angle some amount.
var
percent
=
elapsed
/
KEY_ANIMATION_DURATION
;
this
[
angleName
]
=
startAngle
+
(
targetAngle
-
startAngle
)
*
percent
;
}.
bind
(
this
),
1000
/
60
);
};
MouseKeyboardPositionSensorVRDevice
.
prototype
.
onMouseDown_
=
function
(
e
)
{
this
.
rotateStart
.
set
(
e
.
clientX
,
e
.
clientY
);
this
.
isDragging
=
true
;
};
// Very similar to https://gist.github.com/mrflix/8351020
MouseKeyboardPositionSensorVRDevice
.
prototype
.
onMouseMove_
=
function
(
e
)
{
if
(
!
this
.
isDragging
&&
!
this
.
isPointerLocked_
())
{
return
;
}
// Support pointer lock API.
if
(
this
.
isPointerLocked_
())
{
var
movementX
=
e
.
movementX
||
e
.
mozMovementX
||
0
;
var
movementY
=
e
.
movementY
||
e
.
mozMovementY
||
0
;
this
.
rotateEnd
.
set
(
this
.
rotateStart
.
x
-
movementX
,
this
.
rotateStart
.
y
-
movementY
);
}
else
{
this
.
rotateEnd
.
set
(
e
.
clientX
,
e
.
clientY
);
}
// Calculate how much we moved in mouse space.
this
.
rotateDelta
.
subVectors
(
this
.
rotateEnd
,
this
.
rotateStart
);
this
.
rotateStart
.
copy
(
this
.
rotateEnd
);
// Keep track of the cumulative euler angles.
var
element
=
document
.
body
;
this
.
phi
+=
2
*
Math
.
PI
*
this
.
rotateDelta
.
y
/
element
.
clientHeight
*
MOUSE_SPEED_Y
;
this
.
theta
+=
2
*
Math
.
PI
*
this
.
rotateDelta
.
x
/
element
.
clientWidth
*
MOUSE_SPEED_X
;
// Prevent looking too far up or down.
this
.
phi
=
Util
.
clamp
(
this
.
phi
,
-
Math
.
PI
/
2
,
Math
.
PI
/
2
);
};
MouseKeyboardPositionSensorVRDevice
.
prototype
.
onMouseUp_
=
function
(
e
)
{
this
.
isDragging
=
false
;
};
MouseKeyboardPositionSensorVRDevice
.
prototype
.
isPointerLocked_
=
function
()
{
var
el
=
document
.
pointerLockElement
||
document
.
mozPointerLockElement
||
document
.
webkitPointerLockElement
;
return
el
!==
undefined
;
};
MouseKeyboardPositionSensorVRDevice
.
prototype
.
resetSensor
=
function
()
{
console
.
error
(
'
Not implemented yet.
'
);
};
module
.
exports
=
MouseKeyboardPositionSensorVRDevice
;
},{
"
./base.js
"
:
1
,
"
./three-math.js
"
:
9
,
"
./util.js
"
:
11
}],
7
:[
function
(
_dereq_
,
module
,
exports
){
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var
THREE
=
_dereq_
(
'
./three-math.js
'
);
var
DEBUG
=
false
;
/**
* Given an orientation and the gyroscope data, predicts the future orientation
* of the head. This makes rendering appear faster.
*
* Also see: http://msl.cs.uiuc.edu/~lavalle/papers/LavYerKatAnt14.pdf
*
* @param {Number} predictionTimeS time from head movement to the appearance of
* the corresponding image.
*/
function
PosePredictor
(
predictionTimeS
)
{
this
.
predictionTimeS
=
predictionTimeS
;
// The quaternion corresponding to the previous state.
this
.
previousQ
=
new
THREE
.
Quaternion
();
// Previous time a prediction occurred.
this
.
previousTimestampS
=
null
;
// The delta quaternion that adjusts the current pose.
this
.
deltaQ
=
new
THREE
.
Quaternion
();
// The output quaternion.
this
.
outQ
=
new
THREE
.
Quaternion
();
}
PosePredictor
.
prototype
.
getPrediction
=
function
(
currentQ
,
gyro
,
timestampS
)
{
if
(
!
this
.
previousTimestampS
)
{
this
.
previousQ
.
copy
(
currentQ
);
this
.
previousTimestampS
=
timestampS
;
return
currentQ
;
}
// Calculate axis and angle based on gyroscope rotation rate data.
var
axis
=
new
THREE
.
Vector3
();
axis
.
copy
(
gyro
);
axis
.
normalize
();
var
angularSpeed
=
gyro
.
length
();
// If we're rotating slowly, don't do prediction.
if
(
angularSpeed
<
THREE
.
Math
.
degToRad
(
20
))
{
if
(
DEBUG
)
{
console
.
log
(
'
Moving slowly, at %s deg/s: no prediction
'
,
THREE
.
Math
.
radToDeg
(
angularSpeed
).
toFixed
(
1
));
}
this
.
outQ
.
copy
(
currentQ
);
this
.
previousQ
.
copy
(
currentQ
);
return
this
.
outQ
;
}
// Get the predicted angle based on the time delta and latency.
var
deltaT
=
timestampS
-
this
.
previousTimestampS
;
var
predictAngle
=
angularSpeed
*
this
.
predictionTimeS
;
this
.
deltaQ
.
setFromAxisAngle
(
axis
,
predictAngle
);
this
.
outQ
.
copy
(
this
.
previousQ
);
this
.
outQ
.
multiply
(
this
.
deltaQ
);
this
.
previousQ
.
copy
(
currentQ
);
return
this
.
outQ
;
};
module
.
exports
=
PosePredictor
;
},{
"
./three-math.js
"
:
9
}],
8
:[
function
(
_dereq_
,
module
,
exports
){
function
SensorSample
(
sample
,
timestampS
)
{
this
.
set
(
sample
,
timestampS
);
};
SensorSample
.
prototype
.
set
=
function
(
sample
,
timestampS
)
{
this
.
sample
=
sample
;
this
.
timestampS
=
timestampS
;
};
SensorSample
.
prototype
.
copy
=
function
(
sensorSample
)
{
this
.
set
(
sensorSample
.
sample
,
sensorSample
.
timestampS
);
};
module
.
exports
=
SensorSample
;
},{}],
9
:[
function
(
_dereq_
,
module
,
exports
){
/*
* A subset of THREE.js, providing mostly quaternion and euler-related
* operations, manually lifted from
* https://github.com/mrdoob/three.js/tree/master/src/math, as of 9c30286b38df039fca389989ff06ea1c15d6bad1
*/
// Only use if the real THREE is not provided.
var
THREE
=
window
.
THREE
||
{};
// If some piece of THREE is missing, fill it in here.
if
(
!
THREE
.
Quaternion
||
!
THREE
.
Vector3
||
!
THREE
.
Vector2
||
!
THREE
.
Euler
||
!
THREE
.
Math
)
{
console
.
log
(
'
No THREE.js found.
'
);
/*** START Quaternion ***/
/**
* @author mikael emtinger / http://gomo.se/
* @author alteredq / http://alteredqualia.com/
* @author WestLangley / http://github.com/WestLangley
* @author bhouston / http://exocortex.com
*/
THREE
.
Quaternion
=
function
(
x
,
y
,
z
,
w
)
{
this
.
_x
=
x
||
0
;
this
.
_y
=
y
||
0
;
this
.
_z
=
z
||
0
;
this
.
_w
=
(
w
!==
undefined
)
?
w
:
1
;
};
THREE
.
Quaternion
.
prototype
=
{
constructor
:
THREE
.
Quaternion
,
_x
:
0
,
_y
:
0
,
_z
:
0
,
_w
:
0
,
get
x
()
{
return
this
.
_x
;
},
set
x
(
value
)
{
this
.
_x
=
value
;
this
.
onChangeCallback
();
},
get
y
()
{
return
this
.
_y
;
},
set
y
(
value
)
{
this
.
_y
=
value
;
this
.
onChangeCallback
();
},
get
z
()
{
return
this
.
_z
;
},
set
z
(
value
)
{
this
.
_z
=
value
;
this
.
onChangeCallback
();
},
get
w
()
{
return
this
.
_w
;
},
set
w
(
value
)
{
this
.
_w
=
value
;
this
.
onChangeCallback
();
},
set
:
function
(
x
,
y
,
z
,
w
)
{
this
.
_x
=
x
;
this
.
_y
=
y
;
this
.
_z
=
z
;
this
.
_w
=
w
;
this
.
onChangeCallback
();
return
this
;
},
copy
:
function
(
quaternion
)
{
this
.
_x
=
quaternion
.
x
;
this
.
_y
=
quaternion
.
y
;
this
.
_z
=
quaternion
.
z
;
this
.
_w
=
quaternion
.
w
;
this
.
onChangeCallback
();
return
this
;
},
setFromEuler
:
function
(
euler
,
update
)
{
if
(
euler
instanceof
THREE
.
Euler
===
false
)
{
throw
new
Error
(
'
THREE.Quaternion: .setFromEuler() now expects a Euler rotation rather than a Vector3 and order.
'
);
}
// http://www.mathworks.com/matlabcentral/fileexchange/
// 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
// content/SpinCalc.m
var
c1
=
Math
.
cos
(
euler
.
_x
/
2
);
var
c2
=
Math
.
cos
(
euler
.
_y
/
2
);
var
c3
=
Math
.
cos
(
euler
.
_z
/
2
);
var
s1
=
Math
.
sin
(
euler
.
_x
/
2
);
var
s2
=
Math
.
sin
(
euler
.
_y
/
2
);
var
s3
=
Math
.
sin
(
euler
.
_z
/
2
);
if
(
euler
.
order
===
'
XYZ
'
)
{
this
.
_x
=
s1
*
c2
*
c3
+
c1
*
s2
*
s3
;
this
.
_y
=
c1
*
s2
*
c3
-
s1
*
c2
*
s3
;
this
.
_z
=
c1
*
c2
*
s3
+
s1
*
s2
*
c3
;
this
.
_w
=
c1
*
c2
*
c3
-
s1
*
s2
*
s3
;
}
else
if
(
euler
.
order
===
'
YXZ
'
)
{
this
.
_x
=
s1
*
c2
*
c3
+
c1
*
s2
*
s3
;
this
.
_y
=
c1
*
s2
*
c3
-
s1
*
c2
*
s3
;
this
.
_z
=
c1
*
c2
*
s3
-
s1
*
s2
*
c3
;
this
.
_w
=
c1
*
c2
*
c3
+
s1
*
s2
*
s3
;
}
else
if
(
euler
.
order
===
'
ZXY
'
)
{
this
.
_x
=
s1
*
c2
*
c3
-
c1
*
s2
*
s3
;
this
.
_y
=
c1
*
s2
*
c3
+
s1
*
c2
*
s3
;
this
.
_z
=
c1
*
c2
*
s3
+
s1
*
s2
*
c3
;
this
.
_w
=
c1
*
c2
*
c3
-
s1
*
s2
*
s3
;
}
else
if
(
euler
.
order
===
'
ZYX
'
)
{
this
.
_x
=
s1
*
c2
*
c3
-
c1
*
s2
*
s3
;
this
.
_y
=
c1
*
s2
*
c3
+
s1
*
c2
*
s3
;
this
.
_z
=
c1
*
c2
*
s3
-
s1
*
s2
*
c3
;
this
.
_w
=
c1
*
c2
*
c3
+
s1
*
s2
*
s3
;
}
else
if
(
euler
.
order
===
'
YZX
'
)
{
this
.
_x
=
s1
*
c2
*
c3
+
c1
*
s2
*
s3
;
this
.
_y
=
c1
*
s2
*
c3
+
s1
*
c2
*
s3
;
this
.
_z
=
c1
*
c2
*
s3
-
s1
*
s2
*
c3
;
this
.
_w
=
c1
*
c2
*
c3
-
s1
*
s2
*
s3
;
}
else
if
(
euler
.
order
===
'
XZY
'
)
{
this
.
_x
=
s1
*
c2
*
c3
-
c1
*
s2
*
s3
;
this
.
_y
=
c1
*
s2
*
c3
-
s1
*
c2
*
s3
;
this
.
_z
=
c1
*
c2
*
s3
+
s1
*
s2
*
c3
;
this
.
_w
=
c1
*
c2
*
c3
+
s1
*
s2
*
s3
;
}
if
(
update
!==
false
)
this
.
onChangeCallback
();
return
this
;
},
setFromAxisAngle
:
function
(
axis
,
angle
)
{
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
// assumes axis is normalized
var
halfAngle
=
angle
/
2
,
s
=
Math
.
sin
(
halfAngle
);
this
.
_x
=
axis
.
x
*
s
;
this
.
_y
=
axis
.
y
*
s
;
this
.
_z
=
axis
.
z
*
s
;
this
.
_w
=
Math
.
cos
(
halfAngle
);
this
.
onChangeCallback
();
return
this
;
},
setFromRotationMatrix
:
function
(
m
)
{
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
var
te
=
m
.
elements
,
m11
=
te
[
0
],
m12
=
te
[
4
],
m13
=
te
[
8
],
m21
=
te
[
1
],
m22
=
te
[
5
],
m23
=
te
[
9
],
m31
=
te
[
2
],
m32
=
te
[
6
],
m33
=
te
[
10
],
trace
=
m11
+
m22
+
m33
,
s
;
if
(
trace
>
0
)
{
s
=
0.5
/
Math
.
sqrt
(
trace
+
1.0
);
this
.
_w
=
0.25
/
s
;
this
.
_x
=
(
m32
-
m23
)
*
s
;
this
.
_y
=
(
m13
-
m31
)
*
s
;
this
.
_z
=
(
m21
-
m12
)
*
s
;
}
else
if
(
m11
>
m22
&&
m11
>
m33
)
{
s
=
2.0
*
Math
.
sqrt
(
1.0
+
m11
-
m22
-
m33
);
this
.
_w
=
(
m32
-
m23
)
/
s
;
this
.
_x
=
0.25
*
s
;
this
.
_y
=
(
m12
+
m21
)
/
s
;
this
.
_z
=
(
m13
+
m31
)
/
s
;
}
else
if
(
m22
>
m33
)
{
s
=
2.0
*
Math
.
sqrt
(
1.0
+
m22
-
m11
-
m33
);
this
.
_w
=
(
m13
-
m31
)
/
s
;
this
.
_x
=
(
m12
+
m21
)
/
s
;
this
.
_y
=
0.25
*
s
;
this
.
_z
=
(
m23
+
m32
)
/
s
;
}
else
{
s
=
2.0
*
Math
.
sqrt
(
1.0
+
m33
-
m11
-
m22
);
this
.
_w
=
(
m21
-
m12
)
/
s
;
this
.
_x
=
(
m13
+
m31
)
/
s
;
this
.
_y
=
(
m23
+
m32
)
/
s
;
this
.
_z
=
0.25
*
s
;
}
this
.
onChangeCallback
();
return
this
;
},
setFromUnitVectors
:
function
()
{
// http://lolengine.net/blog/2014/02/24/quaternion-from-two-vectors-final
// assumes direction vectors vFrom and vTo are normalized
var
v1
,
r
;
var
EPS
=
0.000001
;
return
function
(
vFrom
,
vTo
)
{
if
(
v1
===
undefined
)
v1
=
new
THREE
.
Vector3
();
r
=
vFrom
.
dot
(
vTo
)
+
1
;
if
(
r
<
EPS
)
{
r
=
0
;
if
(
Math
.
abs
(
vFrom
.
x
)
>
Math
.
abs
(
vFrom
.
z
)
)
{
v1
.
set
(
-
vFrom
.
y
,
vFrom
.
x
,
0
);
}
else
{
v1
.
set
(
0
,
-
vFrom
.
z
,
vFrom
.
y
);
}
}
else
{
v1
.
crossVectors
(
vFrom
,
vTo
);
}
this
.
_x
=
v1
.
x
;
this
.
_y
=
v1
.
y
;
this
.
_z
=
v1
.
z
;
this
.
_w
=
r
;
this
.
normalize
();
return
this
;
}
}(),
inverse
:
function
()
{
this
.
conjugate
().
normalize
();
return
this
;
},
conjugate
:
function
()
{
this
.
_x
*=
-
1
;
this
.
_y
*=
-
1
;
this
.
_z
*=
-
1
;
this
.
onChangeCallback
();
return
this
;
},
dot
:
function
(
v
)
{
return
this
.
_x
*
v
.
_x
+
this
.
_y
*
v
.
_y
+
this
.
_z
*
v
.
_z
+
this
.
_w
*
v
.
_w
;
},
lengthSq
:
function
()
{
return
this
.
_x
*
this
.
_x
+
this
.
_y
*
this
.
_y
+
this
.
_z
*
this
.
_z
+
this
.
_w
*
this
.
_w
;
},
length
:
function
()
{
return
Math
.
sqrt
(
this
.
_x
*
this
.
_x
+
this
.
_y
*
this
.
_y
+
this
.
_z
*
this
.
_z
+
this
.
_w
*
this
.
_w
);
},
normalize
:
function
()
{
var
l
=
this
.
length
();
if
(
l
===
0
)
{
this
.
_x
=
0
;
this
.
_y
=
0
;
this
.
_z
=
0
;
this
.
_w
=
1
;
}
else
{
l
=
1
/
l
;
this
.
_x
=
this
.
_x
*
l
;
this
.
_y
=
this
.
_y
*
l
;
this
.
_z
=
this
.
_z
*
l
;
this
.
_w
=
this
.
_w
*
l
;
}
this
.
onChangeCallback
();
return
this
;
},
multiply
:
function
(
q
,
p
)
{
if
(
p
!==
undefined
)
{
console
.
warn
(
'
THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.
'
);
return
this
.
multiplyQuaternions
(
q
,
p
);
}
return
this
.
multiplyQuaternions
(
this
,
q
);
},
multiplyQuaternions
:
function
(
a
,
b
)
{
// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
var
qax
=
a
.
_x
,
qay
=
a
.
_y
,
qaz
=
a
.
_z
,
qaw
=
a
.
_w
;
var
qbx
=
b
.
_x
,
qby
=
b
.
_y
,
qbz
=
b
.
_z
,
qbw
=
b
.
_w
;
this
.
_x
=
qax
*
qbw
+
qaw
*
qbx
+
qay
*
qbz
-
qaz
*
qby
;
this
.
_y
=
qay
*
qbw
+
qaw
*
qby
+
qaz
*
qbx
-
qax
*
qbz
;
this
.
_z
=
qaz
*
qbw
+
qaw
*
qbz
+
qax
*
qby
-
qay
*
qbx
;
this
.
_w
=
qaw
*
qbw
-
qax
*
qbx
-
qay
*
qby
-
qaz
*
qbz
;
this
.
onChangeCallback
();
return
this
;
},
multiplyVector3
:
function
(
vector
)
{
console
.
warn
(
'
THREE.Quaternion: .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.
'
);
return
vector
.
applyQuaternion
(
this
);
},
slerp
:
function
(
qb
,
t
)
{
if
(
t
===
0
)
return
this
;
if
(
t
===
1
)
return
this
.
copy
(
qb
);
var
x
=
this
.
_x
,
y
=
this
.
_y
,
z
=
this
.
_z
,
w
=
this
.
_w
;
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
var
cosHalfTheta
=
w
*
qb
.
_w
+
x
*
qb
.
_x
+
y
*
qb
.
_y
+
z
*
qb
.
_z
;
if
(
cosHalfTheta
<
0
)
{
this
.
_w
=
-
qb
.
_w
;
this
.
_x
=
-
qb
.
_x
;
this
.
_y
=
-
qb
.
_y
;
this
.
_z
=
-
qb
.
_z
;
cosHalfTheta
=
-
cosHalfTheta
;
}
else
{
this
.
copy
(
qb
);
}
if
(
cosHalfTheta
>=
1.0
)
{
this
.
_w
=
w
;
this
.
_x
=
x
;
this
.
_y
=
y
;
this
.
_z
=
z
;
return
this
;
}
var
halfTheta
=
Math
.
acos
(
cosHalfTheta
);
var
sinHalfTheta
=
Math
.
sqrt
(
1.0
-
cosHalfTheta
*
cosHalfTheta
);
if
(
Math
.
abs
(
sinHalfTheta
)
<
0.001
)
{
this
.
_w
=
0.5
*
(
w
+
this
.
_w
);
this
.
_x
=
0.5
*
(
x
+
this
.
_x
);
this
.
_y
=
0.5
*
(
y
+
this
.
_y
);
this
.
_z
=
0.5
*
(
z
+
this
.
_z
);
return
this
;
}
var
ratioA
=
Math
.
sin
(
(
1
-
t
)
*
halfTheta
)
/
sinHalfTheta
,
ratioB
=
Math
.
sin
(
t
*
halfTheta
)
/
sinHalfTheta
;
this
.
_w
=
(
w
*
ratioA
+
this
.
_w
*
ratioB
);
this
.
_x
=
(
x
*
ratioA
+
this
.
_x
*
ratioB
);
this
.
_y
=
(
y
*
ratioA
+
this
.
_y
*
ratioB
);
this
.
_z
=
(
z
*
ratioA
+
this
.
_z
*
ratioB
);
this
.
onChangeCallback
();
return
this
;
},
equals
:
function
(
quaternion
)
{
return
(
quaternion
.
_x
===
this
.
_x
)
&&
(
quaternion
.
_y
===
this
.
_y
)
&&
(
quaternion
.
_z
===
this
.
_z
)
&&
(
quaternion
.
_w
===
this
.
_w
);
},
fromArray
:
function
(
array
,
offset
)
{
if
(
offset
===
undefined
)
offset
=
0
;
this
.
_x
=
array
[
offset
];
this
.
_y
=
array
[
offset
+
1
];
this
.
_z
=
array
[
offset
+
2
];
this
.
_w
=
array
[
offset
+
3
];
this
.
onChangeCallback
();
return
this
;
},
toArray
:
function
(
array
,
offset
)
{
if
(
array
===
undefined
)
array
=
[];
if
(
offset
===
undefined
)
offset
=
0
;
array
[
offset
]
=
this
.
_x
;
array
[
offset
+
1
]
=
this
.
_y
;
array
[
offset
+
2
]
=
this
.
_z
;
array
[
offset
+
3
]
=
this
.
_w
;
return
array
;
},
onChange
:
function
(
callback
)
{
this
.
onChangeCallback
=
callback
;
return
this
;
},
onChangeCallback
:
function
()
{},
clone
:
function
()
{
return
new
THREE
.
Quaternion
(
this
.
_x
,
this
.
_y
,
this
.
_z
,
this
.
_w
);
}
};
THREE
.
Quaternion
.
slerp
=
function
(
qa
,
qb
,
qm
,
t
)
{
return
qm
.
copy
(
qa
).
slerp
(
qb
,
t
);
}
/*** END Quaternion ***/
/*** START Vector2 ***/
/**
* @author mrdoob / http://mrdoob.com/
* @author philogb / http://blog.thejit.org/
* @author egraether / http://egraether.com/
* @author zz85 / http://www.lab4games.net/zz85/blog
*/
THREE
.
Vector2
=
function
(
x
,
y
)
{
this
.
x
=
x
||
0
;
this
.
y
=
y
||
0
;
};
THREE
.
Vector2
.
prototype
=
{
constructor
:
THREE
.
Vector2
,
set
:
function
(
x
,
y
)
{
this
.
x
=
x
;
this
.
y
=
y
;
return
this
;
},
setX
:
function
(
x
)
{
this
.
x
=
x
;
return
this
;
},
setY
:
function
(
y
)
{
this
.
y
=
y
;
return
this
;
},
setComponent
:
function
(
index
,
value
)
{
switch
(
index
)
{
case
0
:
this
.
x
=
value
;
break
;
case
1
:
this
.
y
=
value
;
break
;
default
:
throw
new
Error
(
'
index is out of range:
'
+
index
);
}
},
getComponent
:
function
(
index
)
{
switch
(
index
)
{
case
0
:
return
this
.
x
;
case
1
:
return
this
.
y
;
default
:
throw
new
Error
(
'
index is out of range:
'
+
index
);
}
},
copy
:
function
(
v
)
{
this
.
x
=
v
.
x
;
this
.
y
=
v
.
y
;
return
this
;
},
add
:
function
(
v
,
w
)
{
if
(
w
!==
undefined
)
{
console
.
warn
(
'
THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.
'
);
return
this
.
addVectors
(
v
,
w
);
}
this
.
x
+=
v
.
x
;
this
.
y
+=
v
.
y
;
return
this
;
},
addVectors
:
function
(
a
,
b
)
{
this
.
x
=
a
.
x
+
b
.
x
;
this
.
y
=
a
.
y
+
b
.
y
;
return
this
;
},
addScalar
:
function
(
s
)
{
this
.
x
+=
s
;
this
.
y
+=
s
;
return
this
;
},
sub
:
function
(
v
,
w
)
{
if
(
w
!==
undefined
)
{
console
.
warn
(
'
THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.
'
);
return
this
.
subVectors
(
v
,
w
);
}
this
.
x
-=
v
.
x
;
this
.
y
-=
v
.
y
;
return
this
;
},
subVectors
:
function
(
a
,
b
)
{
this
.
x
=
a
.
x
-
b
.
x
;
this
.
y
=
a
.
y
-
b
.
y
;
return
this
;
},
multiply
:
function
(
v
)
{
this
.
x
*=
v
.
x
;
this
.
y
*=
v
.
y
;
return
this
;
},
multiplyScalar
:
function
(
s
)
{
this
.
x
*=
s
;
this
.
y
*=
s
;
return
this
;
},
divide
:
function
(
v
)
{
this
.
x
/=
v
.
x
;
this
.
y
/=
v
.
y
;
return
this
;
},
divideScalar
:
function
(
scalar
)
{
if
(
scalar
!==
0
)
{
var
invScalar
=
1
/
scalar
;
this
.
x
*=
invScalar
;
this
.
y
*=
invScalar
;
}
else
{
this
.
x
=
0
;
this
.
y
=
0
;
}
return
this
;
},
min
:
function
(
v
)
{
if
(
this
.
x
>
v
.
x
)
{
this
.
x
=
v
.
x
;
}
if
(
this
.
y
>
v
.
y
)
{
this
.
y
=
v
.
y
;
}
return
this
;
},
max
:
function
(
v
)
{
if
(
this
.
x
<
v
.
x
)
{
this
.
x
=
v
.
x
;
}
if
(
this
.
y
<
v
.
y
)
{
this
.
y
=
v
.
y
;
}
return
this
;
},
clamp
:
function
(
min
,
max
)
{
// This function assumes min < max, if this assumption isn't true it will not operate correctly
if
(
this
.
x
<
min
.
x
)
{
this
.
x
=
min
.
x
;
}
else
if
(
this
.
x
>
max
.
x
)
{
this
.
x
=
max
.
x
;
}
if
(
this
.
y
<
min
.
y
)
{
this
.
y
=
min
.
y
;
}
else
if
(
this
.
y
>
max
.
y
)
{
this
.
y
=
max
.
y
;
}
return
this
;
},
clampScalar
:
(
function
()
{
var
min
,
max
;
return
function
(
minVal
,
maxVal
)
{
if
(
min
===
undefined
)
{
min
=
new
THREE
.
Vector2
();
max
=
new
THREE
.
Vector2
();
}
min
.
set
(
minVal
,
minVal
);
max
.
set
(
maxVal
,
maxVal
);
return
this
.
clamp
(
min
,
max
);
};
}
)(),
floor
:
function
()
{
this
.
x
=
Math
.
floor
(
this
.
x
);
this
.
y
=
Math
.
floor
(
this
.
y
);
return
this
;
},
ceil
:
function
()
{
this
.
x
=
Math
.
ceil
(
this
.
x
);
this
.
y
=
Math
.
ceil
(
this
.
y
);
return
this
;
},
round
:
function
()
{
this
.
x
=
Math
.
round
(
this
.
x
);
this
.
y
=
Math
.
round
(
this
.
y
);
return
this
;
},
roundToZero
:
function
()
{
this
.
x
=
(
this
.
x
<
0
)
?
Math
.
ceil
(
this
.
x
)
:
Math
.
floor
(
this
.
x
);
this
.
y
=
(
this
.
y
<
0
)
?
Math
.
ceil
(
this
.
y
)
:
Math
.
floor
(
this
.
y
);
return
this
;
},
negate
:
function
()
{
this
.
x
=
-
this
.
x
;
this
.
y
=
-
this
.
y
;
return
this
;
},
dot
:
function
(
v
)
{
return
this
.
x
*
v
.
x
+
this
.
y
*
v
.
y
;
},
lengthSq
:
function
()
{
return
this
.
x
*
this
.
x
+
this
.
y
*
this
.
y
;
},
length
:
function
()
{
return
Math
.
sqrt
(
this
.
x
*
this
.
x
+
this
.
y
*
this
.
y
);
},
normalize
:
function
()
{
return
this
.
divideScalar
(
this
.
length
()
);
},
distanceTo
:
function
(
v
)
{
return
Math
.
sqrt
(
this
.
distanceToSquared
(
v
)
);
},
distanceToSquared
:
function
(
v
)
{
var
dx
=
this
.
x
-
v
.
x
,
dy
=
this
.
y
-
v
.
y
;
return
dx
*
dx
+
dy
*
dy
;
},
setLength
:
function
(
l
)
{
var
oldLength
=
this
.
length
();
if
(
oldLength
!==
0
&&
l
!==
oldLength
)
{
this
.
multiplyScalar
(
l
/
oldLength
);
}
return
this
;
},
lerp
:
function
(
v
,
alpha
)
{
this
.
x
+=
(
v
.
x
-
this
.
x
)
*
alpha
;
this
.
y
+=
(
v
.
y
-
this
.
y
)
*
alpha
;
return
this
;
},
equals
:
function
(
v
)
{
return
(
(
v
.
x
===
this
.
x
)
&&
(
v
.
y
===
this
.
y
)
);
},
fromArray
:
function
(
array
,
offset
)
{
if
(
offset
===
undefined
)
offset
=
0
;
this
.
x
=
array
[
offset
];
this
.
y
=
array
[
offset
+
1
];
return
this
;
},
toArray
:
function
(
array
,
offset
)
{
if
(
array
===
undefined
)
array
=
[];
if
(
offset
===
undefined
)
offset
=
0
;
array
[
offset
]
=
this
.
x
;
array
[
offset
+
1
]
=
this
.
y
;
return
array
;
},
fromAttribute
:
function
(
attribute
,
index
,
offset
)
{
if
(
offset
===
undefined
)
offset
=
0
;
index
=
index
*
attribute
.
itemSize
+
offset
;
this
.
x
=
attribute
.
array
[
index
];
this
.
y
=
attribute
.
array
[
index
+
1
];
return
this
;
},
clone
:
function
()
{
return
new
THREE
.
Vector2
(
this
.
x
,
this
.
y
);
}
};
/*** END Vector2 ***/
/*** START Vector3 ***/
/**
* @author mrdoob / http://mrdoob.com/
* @author *kile / http://kile.stravaganza.org/
* @author philogb / http://blog.thejit.org/
* @author mikael emtinger / http://gomo.se/
* @author egraether / http://egraether.com/
* @author WestLangley / http://github.com/WestLangley
*/
THREE
.
Vector3
=
function
(
x
,
y
,
z
)
{
this
.
x
=
x
||
0
;
this
.
y
=
y
||
0
;
this
.
z
=
z
||
0
;
};
THREE
.
Vector3
.
prototype
=
{
constructor
:
THREE
.
Vector3
,
set
:
function
(
x
,
y
,
z
)
{
this
.
x
=
x
;
this
.
y
=
y
;
this
.
z
=
z
;
return
this
;
},
setX
:
function
(
x
)
{
this
.
x
=
x
;
return
this
;
},
setY
:
function
(
y
)
{
this
.
y
=
y
;
return
this
;
},
setZ
:
function
(
z
)
{
this
.
z
=
z
;
return
this
;
},
setComponent
:
function
(
index
,
value
)
{
switch
(
index
)
{
case
0
:
this
.
x
=
value
;
break
;
case
1
:
this
.
y
=
value
;
break
;
case
2
:
this
.
z
=
value
;
break
;
default
:
throw
new
Error
(
'
index is out of range:
'
+
index
);
}
},
getComponent
:
function
(
index
)
{
switch
(
index
)
{
case
0
:
return
this
.
x
;
case
1
:
return
this
.
y
;
case
2
:
return
this
.
z
;
default
:
throw
new
Error
(
'
index is out of range:
'
+
index
);
}
},
copy
:
function
(
v
)
{
this
.
x
=
v
.
x
;
this
.
y
=
v
.
y
;
this
.
z
=
v
.
z
;
return
this
;
},
add
:
function
(
v
,
w
)
{
if
(
w
!==
undefined
)
{
console
.
warn
(
'
THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.
'
);
return
this
.
addVectors
(
v
,
w
);
}
this
.
x
+=
v
.
x
;
this
.
y
+=
v
.
y
;
this
.
z
+=
v
.
z
;
return
this
;
},
addScalar
:
function
(
s
)
{
this
.
x
+=
s
;
this
.
y
+=
s
;
this
.
z
+=
s
;
return
this
;
},
addVectors
:
function
(
a
,
b
)
{
this
.
x
=
a
.
x
+
b
.
x
;
this
.
y
=
a
.
y
+
b
.
y
;
this
.
z
=
a
.
z
+
b
.
z
;
return
this
;
},
sub
:
function
(
v
,
w
)
{
if
(
w
!==
undefined
)
{
console
.
warn
(
'
THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.
'
);
return
this
.
subVectors
(
v
,
w
);
}
this
.
x
-=
v
.
x
;
this
.
y
-=
v
.
y
;
this
.
z
-=
v
.
z
;
return
this
;
},
subVectors
:
function
(
a
,
b
)
{
this
.
x
=
a
.
x
-
b
.
x
;
this
.
y
=
a
.
y
-
b
.
y
;
this
.
z
=
a
.
z
-
b
.
z
;
return
this
;
},
multiply
:
function
(
v
,
w
)
{
if
(
w
!==
undefined
)
{
console
.
warn
(
'
THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.
'
);
return
this
.
multiplyVectors
(
v
,
w
);
}
this
.
x
*=
v
.
x
;
this
.
y
*=
v
.
y
;
this
.
z
*=
v
.
z
;
return
this
;
},
multiplyScalar
:
function
(
scalar
)
{
this
.
x
*=
scalar
;
this
.
y
*=
scalar
;
this
.
z
*=
scalar
;
return
this
;
},
multiplyVectors
:
function
(
a
,
b
)
{
this
.
x
=
a
.
x
*
b
.
x
;
this
.
y
=
a
.
y
*
b
.
y
;
this
.
z
=
a
.
z
*
b
.
z
;
return
this
;
},
applyEuler
:
function
()
{
var
quaternion
;
return
function
(
euler
)
{
if
(
euler
instanceof
THREE
.
Euler
===
false
)
{
console
.
error
(
'
THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.
'
);
}
if
(
quaternion
===
undefined
)
quaternion
=
new
THREE
.
Quaternion
();
this
.
applyQuaternion
(
quaternion
.
setFromEuler
(
euler
)
);
return
this
;
};
}(),
applyAxisAngle
:
function
()
{
var
quaternion
;
return
function
(
axis
,
angle
)
{
if
(
quaternion
===
undefined
)
quaternion
=
new
THREE
.
Quaternion
();
this
.
applyQuaternion
(
quaternion
.
setFromAxisAngle
(
axis
,
angle
)
);
return
this
;
};
}(),
applyMatrix3
:
function
(
m
)
{
var
x
=
this
.
x
;
var
y
=
this
.
y
;
var
z
=
this
.
z
;
var
e
=
m
.
elements
;
this
.
x
=
e
[
0
]
*
x
+
e
[
3
]
*
y
+
e
[
6
]
*
z
;
this
.
y
=
e
[
1
]
*
x
+
e
[
4
]
*
y
+
e
[
7
]
*
z
;
this
.
z
=
e
[
2
]
*
x
+
e
[
5
]
*
y
+
e
[
8
]
*
z
;
return
this
;
},
applyMatrix4
:
function
(
m
)
{
// input: THREE.Matrix4 affine matrix
var
x
=
this
.
x
,
y
=
this
.
y
,
z
=
this
.
z
;
var
e
=
m
.
elements
;
this
.
x
=
e
[
0
]
*
x
+
e
[
4
]
*
y
+
e
[
8
]
*
z
+
e
[
12
];
this
.
y
=
e
[
1
]
*
x
+
e
[
5
]
*
y
+
e
[
9
]
*
z
+
e
[
13
];
this
.
z
=
e
[
2
]
*
x
+
e
[
6
]
*
y
+
e
[
10
]
*
z
+
e
[
14
];
return
this
;
},
applyProjection
:
function
(
m
)
{
// input: THREE.Matrix4 projection matrix
var
x
=
this
.
x
,
y
=
this
.
y
,
z
=
this
.
z
;
var
e
=
m
.
elements
;
var
d
=
1
/
(
e
[
3
]
*
x
+
e
[
7
]
*
y
+
e
[
11
]
*
z
+
e
[
15
]
);
// perspective divide
this
.
x
=
(
e
[
0
]
*
x
+
e
[
4
]
*
y
+
e
[
8
]
*
z
+
e
[
12
]
)
*
d
;
this
.
y
=
(
e
[
1
]
*
x
+
e
[
5
]
*
y
+
e
[
9
]
*
z
+
e
[
13
]
)
*
d
;
this
.
z
=
(
e
[
2
]
*
x
+
e
[
6
]
*
y
+
e
[
10
]
*
z
+
e
[
14
]
)
*
d
;
return
this
;
},
applyQuaternion
:
function
(
q
)
{
var
x
=
this
.
x
;
var
y
=
this
.
y
;
var
z
=
this
.
z
;
var
qx
=
q
.
x
;
var
qy
=
q
.
y
;
var
qz
=
q
.
z
;
var
qw
=
q
.
w
;
// calculate quat * vector
var
ix
=
qw
*
x
+
qy
*
z
-
qz
*
y
;
var
iy
=
qw
*
y
+
qz
*
x
-
qx
*
z
;
var
iz
=
qw
*
z
+
qx
*
y
-
qy
*
x
;
var
iw
=
-
qx
*
x
-
qy
*
y
-
qz
*
z
;
// calculate result * inverse quat
this
.
x
=
ix
*
qw
+
iw
*
-
qx
+
iy
*
-
qz
-
iz
*
-
qy
;
this
.
y
=
iy
*
qw
+
iw
*
-
qy
+
iz
*
-
qx
-
ix
*
-
qz
;
this
.
z
=
iz
*
qw
+
iw
*
-
qz
+
ix
*
-
qy
-
iy
*
-
qx
;
return
this
;
},
project
:
function
()
{
var
matrix
;
return
function
(
camera
)
{
if
(
matrix
===
undefined
)
matrix
=
new
THREE
.
Matrix4
();
matrix
.
multiplyMatrices
(
camera
.
projectionMatrix
,
matrix
.
getInverse
(
camera
.
matrixWorld
)
);
return
this
.
applyProjection
(
matrix
);
};
}(),
unproject
:
function
()
{
var
matrix
;
return
function
(
camera
)
{
if
(
matrix
===
undefined
)
matrix
=
new
THREE
.
Matrix4
();
matrix
.
multiplyMatrices
(
camera
.
matrixWorld
,
matrix
.
getInverse
(
camera
.
projectionMatrix
)
);
return
this
.
applyProjection
(
matrix
);
};
}(),
transformDirection
:
function
(
m
)
{
// input: THREE.Matrix4 affine matrix
// vector interpreted as a direction
var
x
=
this
.
x
,
y
=
this
.
y
,
z
=
this
.
z
;
var
e
=
m
.
elements
;
this
.
x
=
e
[
0
]
*
x
+
e
[
4
]
*
y
+
e
[
8
]
*
z
;
this
.
y
=
e
[
1
]
*
x
+
e
[
5
]
*
y
+
e
[
9
]
*
z
;
this
.
z
=
e
[
2
]
*
x
+
e
[
6
]
*
y
+
e
[
10
]
*
z
;
this
.
normalize
();
return
this
;
},
divide
:
function
(
v
)
{
this
.
x
/=
v
.
x
;
this
.
y
/=
v
.
y
;
this
.
z
/=
v
.
z
;
return
this
;
},
divideScalar
:
function
(
scalar
)
{
if
(
scalar
!==
0
)
{
var
invScalar
=
1
/
scalar
;
this
.
x
*=
invScalar
;
this
.
y
*=
invScalar
;
this
.
z
*=
invScalar
;
}
else
{
this
.
x
=
0
;
this
.
y
=
0
;
this
.
z
=
0
;
}
return
this
;
},
min
:
function
(
v
)
{
if
(
this
.
x
>
v
.
x
)
{
this
.
x
=
v
.
x
;
}
if
(
this
.
y
>
v
.
y
)
{
this
.
y
=
v
.
y
;
}
if
(
this
.
z
>
v
.
z
)
{
this
.
z
=
v
.
z
;
}
return
this
;
},
max
:
function
(
v
)
{
if
(
this
.
x
<
v
.
x
)
{
this
.
x
=
v
.
x
;
}
if
(
this
.
y
<
v
.
y
)
{
this
.
y
=
v
.
y
;
}
if
(
this
.
z
<
v
.
z
)
{
this
.
z
=
v
.
z
;
}
return
this
;
},
clamp
:
function
(
min
,
max
)
{
// This function assumes min < max, if this assumption isn't true it will not operate correctly
if
(
this
.
x
<
min
.
x
)
{
this
.
x
=
min
.
x
;
}
else
if
(
this
.
x
>
max
.
x
)
{
this
.
x
=
max
.
x
;
}
if
(
this
.
y
<
min
.
y
)
{
this
.
y
=
min
.
y
;
}
else
if
(
this
.
y
>
max
.
y
)
{
this
.
y
=
max
.
y
;
}
if
(
this
.
z
<
min
.
z
)
{
this
.
z
=
min
.
z
;
}
else
if
(
this
.
z
>
max
.
z
)
{
this
.
z
=
max
.
z
;
}
return
this
;
},
clampScalar
:
(
function
()
{
var
min
,
max
;
return
function
(
minVal
,
maxVal
)
{
if
(
min
===
undefined
)
{
min
=
new
THREE
.
Vector3
();
max
=
new
THREE
.
Vector3
();
}
min
.
set
(
minVal
,
minVal
,
minVal
);
max
.
set
(
maxVal
,
maxVal
,
maxVal
);
return
this
.
clamp
(
min
,
max
);
};
}
)(),
floor
:
function
()
{
this
.
x
=
Math
.
floor
(
this
.
x
);
this
.
y
=
Math
.
floor
(
this
.
y
);
this
.
z
=
Math
.
floor
(
this
.
z
);
return
this
;
},
ceil
:
function
()
{
this
.
x
=
Math
.
ceil
(
this
.
x
);
this
.
y
=
Math
.
ceil
(
this
.
y
);
this
.
z
=
Math
.
ceil
(
this
.
z
);
return
this
;
},
round
:
function
()
{
this
.
x
=
Math
.
round
(
this
.
x
);
this
.
y
=
Math
.
round
(
this
.
y
);
this
.
z
=
Math
.
round
(
this
.
z
);
return
this
;
},
roundToZero
:
function
()
{
this
.
x
=
(
this
.
x
<
0
)
?
Math
.
ceil
(
this
.
x
)
:
Math
.
floor
(
this
.
x
);
this
.
y
=
(
this
.
y
<
0
)
?
Math
.
ceil
(
this
.
y
)
:
Math
.
floor
(
this
.
y
);
this
.
z
=
(
this
.
z
<
0
)
?
Math
.
ceil
(
this
.
z
)
:
Math
.
floor
(
this
.
z
);
return
this
;
},
negate
:
function
()
{
this
.
x
=
-
this
.
x
;
this
.
y
=
-
this
.
y
;
this
.
z
=
-
this
.
z
;
return
this
;
},
dot
:
function
(
v
)
{
return
this
.
x
*
v
.
x
+
this
.
y
*
v
.
y
+
this
.
z
*
v
.
z
;
},
lengthSq
:
function
()
{
return
this
.
x
*
this
.
x
+
this
.
y
*
this
.
y
+
this
.
z
*
this
.
z
;
},
length
:
function
()
{
return
Math
.
sqrt
(
this
.
x
*
this
.
x
+
this
.
y
*
this
.
y
+
this
.
z
*
this
.
z
);
},
lengthManhattan
:
function
()
{
return
Math
.
abs
(
this
.
x
)
+
Math
.
abs
(
this
.
y
)
+
Math
.
abs
(
this
.
z
);
},
normalize
:
function
()
{
return
this
.
divideScalar
(
this
.
length
()
);
},
setLength
:
function
(
l
)
{
var
oldLength
=
this
.
length
();
if
(
oldLength
!==
0
&&
l
!==
oldLength
)
{
this
.
multiplyScalar
(
l
/
oldLength
);
}
return
this
;
},
lerp
:
function
(
v
,
alpha
)
{
this
.
x
+=
(
v
.
x
-
this
.
x
)
*
alpha
;
this
.
y
+=
(
v
.
y
-
this
.
y
)
*
alpha
;
this
.
z
+=
(
v
.
z
-
this
.
z
)
*
alpha
;
return
this
;
},
cross
:
function
(
v
,
w
)
{
if
(
w
!==
undefined
)
{
console
.
warn
(
'
THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.
'
);
return
this
.
crossVectors
(
v
,
w
);
}
var
x
=
this
.
x
,
y
=
this
.
y
,
z
=
this
.
z
;
this
.
x
=
y
*
v
.
z
-
z
*
v
.
y
;
this
.
y
=
z
*
v
.
x
-
x
*
v
.
z
;
this
.
z
=
x
*
v
.
y
-
y
*
v
.
x
;
return
this
;
},
crossVectors
:
function
(
a
,
b
)
{
var
ax
=
a
.
x
,
ay
=
a
.
y
,
az
=
a
.
z
;
var
bx
=
b
.
x
,
by
=
b
.
y
,
bz
=
b
.
z
;
this
.
x
=
ay
*
bz
-
az
*
by
;
this
.
y
=
az
*
bx
-
ax
*
bz
;
this
.
z
=
ax
*
by
-
ay
*
bx
;
return
this
;
},
projectOnVector
:
function
()
{
var
v1
,
dot
;
return
function
(
vector
)
{
if
(
v1
===
undefined
)
v1
=
new
THREE
.
Vector3
();
v1
.
copy
(
vector
).
normalize
();
dot
=
this
.
dot
(
v1
);
return
this
.
copy
(
v1
).
multiplyScalar
(
dot
);
};
}(),
projectOnPlane
:
function
()
{
var
v1
;
return
function
(
planeNormal
)
{
if
(
v1
===
undefined
)
v1
=
new
THREE
.
Vector3
();
v1
.
copy
(
this
).
projectOnVector
(
planeNormal
);
return
this
.
sub
(
v1
);
}
}(),
reflect
:
function
()
{
// reflect incident vector off plane orthogonal to normal
// normal is assumed to have unit length
var
v1
;
return
function
(
normal
)
{
if
(
v1
===
undefined
)
v1
=
new
THREE
.
Vector3
();
return
this
.
sub
(
v1
.
copy
(
normal
).
multiplyScalar
(
2
*
this
.
dot
(
normal
)
)
);
}
}(),
angleTo
:
function
(
v
)
{
var
theta
=
this
.
dot
(
v
)
/
(
this
.
length
()
*
v
.
length
()
);
// clamp, to handle numerical problems
return
Math
.
acos
(
THREE
.
Math
.
clamp
(
theta
,
-
1
,
1
)
);
},
distanceTo
:
function
(
v
)
{
return
Math
.
sqrt
(
this
.
distanceToSquared
(
v
)
);
},
distanceToSquared
:
function
(
v
)
{
var
dx
=
this
.
x
-
v
.
x
;
var
dy
=
this
.
y
-
v
.
y
;
var
dz
=
this
.
z
-
v
.
z
;
return
dx
*
dx
+
dy
*
dy
+
dz
*
dz
;
},
setEulerFromRotationMatrix
:
function
(
m
,
order
)
{
console
.
error
(
'
THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.
'
);
},
setEulerFromQuaternion
:
function
(
q
,
order
)
{
console
.
error
(
'
THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.
'
);
},
getPositionFromMatrix
:
function
(
m
)
{
console
.
warn
(
'
THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().
'
);
return
this
.
setFromMatrixPosition
(
m
);
},
getScaleFromMatrix
:
function
(
m
)
{
console
.
warn
(
'
THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().
'
);
return
this
.
setFromMatrixScale
(
m
);
},
getColumnFromMatrix
:
function
(
index
,
matrix
)
{
console
.
warn
(
'
THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().
'
);
return
this
.
setFromMatrixColumn
(
index
,
matrix
);
},
setFromMatrixPosition
:
function
(
m
)
{
this
.
x
=
m
.
elements
[
12
];
this
.
y
=
m
.
elements
[
13
];
this
.
z
=
m
.
elements
[
14
];
return
this
;
},
setFromMatrixScale
:
function
(
m
)
{
var
sx
=
this
.
set
(
m
.
elements
[
0
],
m
.
elements
[
1
],
m
.
elements
[
2
]
).
length
();
var
sy
=
this
.
set
(
m
.
elements
[
4
],
m
.
elements
[
5
],
m
.
elements
[
6
]
).
length
();
var
sz
=
this
.
set
(
m
.
elements
[
8
],
m
.
elements
[
9
],
m
.
elements
[
10
]
).
length
();
this
.
x
=
sx
;
this
.
y
=
sy
;
this
.
z
=
sz
;
return
this
;
},
setFromMatrixColumn
:
function
(
index
,
matrix
)
{
var
offset
=
index
*
4
;
var
me
=
matrix
.
elements
;
this
.
x
=
me
[
offset
];
this
.
y
=
me
[
offset
+
1
];
this
.
z
=
me
[
offset
+
2
];
return
this
;
},
equals
:
function
(
v
)
{
return
(
(
v
.
x
===
this
.
x
)
&&
(
v
.
y
===
this
.
y
)
&&
(
v
.
z
===
this
.
z
)
);
},
fromArray
:
function
(
array
,
offset
)
{
if
(
offset
===
undefined
)
offset
=
0
;
this
.
x
=
array
[
offset
];
this
.
y
=
array
[
offset
+
1
];
this
.
z
=
array
[
offset
+
2
];
return
this
;
},
toArray
:
function
(
array
,
offset
)
{
if
(
array
===
undefined
)
array
=
[];
if
(
offset
===
undefined
)
offset
=
0
;
array
[
offset
]
=
this
.
x
;
array
[
offset
+
1
]
=
this
.
y
;
array
[
offset
+
2
]
=
this
.
z
;
return
array
;
},
fromAttribute
:
function
(
attribute
,
index
,
offset
)
{
if
(
offset
===
undefined
)
offset
=
0
;
index
=
index
*
attribute
.
itemSize
+
offset
;
this
.
x
=
attribute
.
array
[
index
];
this
.
y
=
attribute
.
array
[
index
+
1
];
this
.
z
=
attribute
.
array
[
index
+
2
];
return
this
;
},
clone
:
function
()
{
return
new
THREE
.
Vector3
(
this
.
x
,
this
.
y
,
this
.
z
);
}
};
/*** END Vector3 ***/
/*** START Euler ***/
/**
* @author mrdoob / http://mrdoob.com/
* @author WestLangley / http://github.com/WestLangley
* @author bhouston / http://exocortex.com
*/
THREE
.
Euler
=
function
(
x
,
y
,
z
,
order
)
{
this
.
_x
=
x
||
0
;
this
.
_y
=
y
||
0
;
this
.
_z
=
z
||
0
;
this
.
_order
=
order
||
THREE
.
Euler
.
DefaultOrder
;
};
THREE
.
Euler
.
RotationOrders
=
[
'
XYZ
'
,
'
YZX
'
,
'
ZXY
'
,
'
XZY
'
,
'
YXZ
'
,
'
ZYX
'
];
THREE
.
Euler
.
DefaultOrder
=
'
XYZ
'
;
THREE
.
Euler
.
prototype
=
{
constructor
:
THREE
.
Euler
,
_x
:
0
,
_y
:
0
,
_z
:
0
,
_order
:
THREE
.
Euler
.
DefaultOrder
,
get
x
()
{
return
this
.
_x
;
},
set
x
(
value
)
{
this
.
_x
=
value
;
this
.
onChangeCallback
();
},
get
y
()
{
return
this
.
_y
;
},
set
y
(
value
)
{
this
.
_y
=
value
;
this
.
onChangeCallback
();
},
get
z
()
{
return
this
.
_z
;
},
set
z
(
value
)
{
this
.
_z
=
value
;
this
.
onChangeCallback
();
},
get
order
()
{
return
this
.
_order
;
},
set
order
(
value
)
{
this
.
_order
=
value
;
this
.
onChangeCallback
();
},
set
:
function
(
x
,
y
,
z
,
order
)
{
this
.
_x
=
x
;
this
.
_y
=
y
;
this
.
_z
=
z
;
this
.
_order
=
order
||
this
.
_order
;
this
.
onChangeCallback
();
return
this
;
},
copy
:
function
(
euler
)
{
this
.
_x
=
euler
.
_x
;
this
.
_y
=
euler
.
_y
;
this
.
_z
=
euler
.
_z
;
this
.
_order
=
euler
.
_order
;
this
.
onChangeCallback
();
return
this
;
},
setFromRotationMatrix
:
function
(
m
,
order
,
update
)
{
var
clamp
=
THREE
.
Math
.
clamp
;
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
var
te
=
m
.
elements
;
var
m11
=
te
[
0
],
m12
=
te
[
4
],
m13
=
te
[
8
];
var
m21
=
te
[
1
],
m22
=
te
[
5
],
m23
=
te
[
9
];
var
m31
=
te
[
2
],
m32
=
te
[
6
],
m33
=
te
[
10
];
order
=
order
||
this
.
_order
;
if
(
order
===
'
XYZ
'
)
{
this
.
_y
=
Math
.
asin
(
clamp
(
m13
,
-
1
,
1
)
);
if
(
Math
.
abs
(
m13
)
<
0.99999
)
{
this
.
_x
=
Math
.
atan2
(
-
m23
,
m33
);
this
.
_z
=
Math
.
atan2
(
-
m12
,
m11
);
}
else
{
this
.
_x
=
Math
.
atan2
(
m32
,
m22
);
this
.
_z
=
0
;
}
}
else
if
(
order
===
'
YXZ
'
)
{
this
.
_x
=
Math
.
asin
(
-
clamp
(
m23
,
-
1
,
1
)
);
if
(
Math
.
abs
(
m23
)
<
0.99999
)
{
this
.
_y
=
Math
.
atan2
(
m13
,
m33
);
this
.
_z
=
Math
.
atan2
(
m21
,
m22
);
}
else
{
this
.
_y
=
Math
.
atan2
(
-
m31
,
m11
);
this
.
_z
=
0
;
}
}
else
if
(
order
===
'
ZXY
'
)
{
this
.
_x
=
Math
.
asin
(
clamp
(
m32
,
-
1
,
1
)
);
if
(
Math
.
abs
(
m32
)
<
0.99999
)
{
this
.
_y
=
Math
.
atan2
(
-
m31
,
m33
);
this
.
_z
=
Math
.
atan2
(
-
m12
,
m22
);
}
else
{
this
.
_y
=
0
;
this
.
_z
=
Math
.
atan2
(
m21
,
m11
);
}
}
else
if
(
order
===
'
ZYX
'
)
{
this
.
_y
=
Math
.
asin
(
-
clamp
(
m31
,
-
1
,
1
)
);
if
(
Math
.
abs
(
m31
)
<
0.99999
)
{
this
.
_x
=
Math
.
atan2
(
m32
,
m33
);
this
.
_z
=
Math
.
atan2
(
m21
,
m11
);
}
else
{
this
.
_x
=
0
;
this
.
_z
=
Math
.
atan2
(
-
m12
,
m22
);
}
}
else
if
(
order
===
'
YZX
'
)
{
this
.
_z
=
Math
.
asin
(
clamp
(
m21
,
-
1
,
1
)
);
if
(
Math
.
abs
(
m21
)
<
0.99999
)
{
this
.
_x
=
Math
.
atan2
(
-
m23
,
m22
);
this
.
_y
=
Math
.
atan2
(
-
m31
,
m11
);
}
else
{
this
.
_x
=
0
;
this
.
_y
=
Math
.
atan2
(
m13
,
m33
);
}
}
else
if
(
order
===
'
XZY
'
)
{
this
.
_z
=
Math
.
asin
(
-
clamp
(
m12
,
-
1
,
1
)
);
if
(
Math
.
abs
(
m12
)
<
0.99999
)
{
this
.
_x
=
Math
.
atan2
(
m32
,
m22
);
this
.
_y
=
Math
.
atan2
(
m13
,
m11
);
}
else
{
this
.
_x
=
Math
.
atan2
(
-
m23
,
m33
);
this
.
_y
=
0
;
}
}
else
{
console
.
warn
(
'
THREE.Euler: .setFromRotationMatrix() given unsupported order:
'
+
order
)
}
this
.
_order
=
order
;
if
(
update
!==
false
)
this
.
onChangeCallback
();
return
this
;
},
setFromQuaternion
:
function
()
{
var
matrix
;
return
function
(
q
,
order
,
update
)
{
if
(
matrix
===
undefined
)
matrix
=
new
THREE
.
Matrix4
();
matrix
.
makeRotationFromQuaternion
(
q
);
this
.
setFromRotationMatrix
(
matrix
,
order
,
update
);
return
this
;
};
}(),
setFromVector3
:
function
(
v
,
order
)
{
return
this
.
set
(
v
.
x
,
v
.
y
,
v
.
z
,
order
||
this
.
_order
);
},
reorder
:
function
()
{
// WARNING: this discards revolution information -bhouston
var
q
=
new
THREE
.
Quaternion
();
return
function
(
newOrder
)
{
q
.
setFromEuler
(
this
);
this
.
setFromQuaternion
(
q
,
newOrder
);
};
}(),
equals
:
function
(
euler
)
{
return
(
euler
.
_x
===
this
.
_x
)
&&
(
euler
.
_y
===
this
.
_y
)
&&
(
euler
.
_z
===
this
.
_z
)
&&
(
euler
.
_order
===
this
.
_order
);
},
fromArray
:
function
(
array
)
{
this
.
_x
=
array
[
0
];
this
.
_y
=
array
[
1
];
this
.
_z
=
array
[
2
];
if
(
array
[
3
]
!==
undefined
)
this
.
_order
=
array
[
3
];
this
.
onChangeCallback
();
return
this
;
},
toArray
:
function
()
{
return
[
this
.
_x
,
this
.
_y
,
this
.
_z
,
this
.
_order
];
},
toVector3
:
function
(
optionalResult
)
{
if
(
optionalResult
)
{
return
optionalResult
.
set
(
this
.
_x
,
this
.
_y
,
this
.
_z
);
}
else
{
return
new
THREE
.
Vector3
(
this
.
_x
,
this
.
_y
,
this
.
_z
);
}
},
onChange
:
function
(
callback
)
{
this
.
onChangeCallback
=
callback
;
return
this
;
},
onChangeCallback
:
function
()
{},
clone
:
function
()
{
return
new
THREE
.
Euler
(
this
.
_x
,
this
.
_y
,
this
.
_z
,
this
.
_order
);
}
};
/*** END Euler ***/
/*** START Math ***/
/**
* @author alteredq / http://alteredqualia.com/
* @author mrdoob / http://mrdoob.com/
*/
THREE
.
Math
=
{
generateUUID
:
function
()
{
// http://www.broofa.com/Tools/Math.uuid.htm
var
chars
=
'
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
'
.
split
(
''
);
var
uuid
=
new
Array
(
36
);
var
rnd
=
0
,
r
;
return
function
()
{
for
(
var
i
=
0
;
i
<
36
;
i
++
)
{
if
(
i
==
8
||
i
==
13
||
i
==
18
||
i
==
23
)
{
uuid
[
i
]
=
'
-
'
;
}
else
if
(
i
==
14
)
{
uuid
[
i
]
=
'
4
'
;
}
else
{
if
(
rnd
<=
0x02
)
rnd
=
0x2000000
+
(
Math
.
random
()
*
0x1000000
)
|
0
;
r
=
rnd
&
0xf
;
rnd
=
rnd
>>
4
;
uuid
[
i
]
=
chars
[
(
i
==
19
)
?
(
r
&
0x3
)
|
0x8
:
r
];
}
}
return
uuid
.
join
(
''
);
};
}(),
// Clamp value to range <a, b>
clamp
:
function
(
x
,
a
,
b
)
{
return
(
x
<
a
)
?
a
:
(
(
x
>
b
)
?
b
:
x
);
},
// Clamp value to range <a, inf)
clampBottom
:
function
(
x
,
a
)
{
return
x
<
a
?
a
:
x
;
},
// Linear mapping from range <a1, a2> to range <b1, b2>
mapLinear
:
function
(
x
,
a1
,
a2
,
b1
,
b2
)
{
return
b1
+
(
x
-
a1
)
*
(
b2
-
b1
)
/
(
a2
-
a1
);
},
// http://en.wikipedia.org/wiki/Smoothstep
smoothstep
:
function
(
x
,
min
,
max
)
{
if
(
x
<=
min
)
return
0
;
if
(
x
>=
max
)
return
1
;
x
=
(
x
-
min
)
/
(
max
-
min
);
return
x
*
x
*
(
3
-
2
*
x
);
},
smootherstep
:
function
(
x
,
min
,
max
)
{
if
(
x
<=
min
)
return
0
;
if
(
x
>=
max
)
return
1
;
x
=
(
x
-
min
)
/
(
max
-
min
);
return
x
*
x
*
x
*
(
x
*
(
x
*
6
-
15
)
+
10
);
},
// Random float from <0, 1> with 16 bits of randomness
// (standard Math.random() creates repetitive patterns when applied over larger space)
random16
:
function
()
{
return
(
65280
*
Math
.
random
()
+
255
*
Math
.
random
()
)
/
65535
;
},
// Random integer from <low, high> interval
randInt
:
function
(
low
,
high
)
{
return
Math
.
floor
(
this
.
randFloat
(
low
,
high
)
);
},
// Random float from <low, high> interval
randFloat
:
function
(
low
,
high
)
{
return
low
+
Math
.
random
()
*
(
high
-
low
);
},
// Random float from <-range/2, range/2> interval
randFloatSpread
:
function
(
range
)
{
return
range
*
(
0.5
-
Math
.
random
()
);
},
degToRad
:
function
()
{
var
degreeToRadiansFactor
=
Math
.
PI
/
180
;
return
function
(
degrees
)
{
return
degrees
*
degreeToRadiansFactor
;
};
}(),
radToDeg
:
function
()
{
var
radianToDegreesFactor
=
180
/
Math
.
PI
;
return
function
(
radians
)
{
return
radians
*
radianToDegreesFactor
;
};
}(),
isPowerOfTwo
:
function
(
value
)
{
return
(
value
&
(
value
-
1
)
)
===
0
&&
value
!==
0
;
},
nextPowerOfTwo
:
function
(
value
)
{
value
--
;
value
|=
value
>>
1
;
value
|=
value
>>
2
;
value
|=
value
>>
4
;
value
|=
value
>>
8
;
value
|=
value
>>
16
;
value
++
;
return
value
;
}
};
/*** END Math ***/
}
module
.
exports
=
THREE
;
},{}],
10
:[
function
(
_dereq_
,
module
,
exports
){
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var
THREE
=
_dereq_
(
'
./three-math.js
'
);
var
Util
=
_dereq_
(
'
./util.js
'
);
var
ROTATE_SPEED
=
0.5
;
/**
* Provides a quaternion responsible for pre-panning the scene before further
* transformations due to device sensors.
*/
function
TouchPanner
()
{
window
.
addEventListener
(
'
touchstart
'
,
this
.
onTouchStart_
.
bind
(
this
));
window
.
addEventListener
(
'
touchmove
'
,
this
.
onTouchMove_
.
bind
(
this
));
window
.
addEventListener
(
'
touchend
'
,
this
.
onTouchEnd_
.
bind
(
this
));
this
.
isTouching
=
false
;
this
.
rotateStart
=
new
THREE
.
Vector2
();
this
.
rotateEnd
=
new
THREE
.
Vector2
();
this
.
rotateDelta
=
new
THREE
.
Vector2
();
this
.
theta
=
0
;
this
.
orientation
=
new
THREE
.
Quaternion
();
}
TouchPanner
.
prototype
.
getOrientation
=
function
()
{
this
.
orientation
.
setFromEuler
(
new
THREE
.
Euler
(
0
,
0
,
this
.
theta
));
return
this
.
orientation
;
};
TouchPanner
.
prototype
.
resetSensor
=
function
()
{
this
.
theta
=
0
;
};
TouchPanner
.
prototype
.
onTouchStart_
=
function
(
e
)
{
// Only respond if there is exactly one touch.
if
(
e
.
touches
.
length
!=
1
)
{
return
;
}
this
.
rotateStart
.
set
(
e
.
touches
[
0
].
pageX
,
e
.
touches
[
0
].
pageY
);
this
.
isTouching
=
true
;
};
TouchPanner
.
prototype
.
onTouchMove_
=
function
(
e
)
{
if
(
!
this
.
isTouching
)
{
return
;
}
this
.
rotateEnd
.
set
(
e
.
touches
[
0
].
pageX
,
e
.
touches
[
0
].
pageY
);
this
.
rotateDelta
.
subVectors
(
this
.
rotateEnd
,
this
.
rotateStart
);
this
.
rotateStart
.
copy
(
this
.
rotateEnd
);
// On iOS, direction is inverted.
if
(
Util
.
isIOS
())
{
this
.
rotateDelta
.
x
*=
-
1
;
}
var
element
=
document
.
body
;
this
.
theta
+=
2
*
Math
.
PI
*
this
.
rotateDelta
.
x
/
element
.
clientWidth
*
ROTATE_SPEED
;
};
TouchPanner
.
prototype
.
onTouchEnd_
=
function
(
e
)
{
this
.
isTouching
=
false
;
};
module
.
exports
=
TouchPanner
;
},{
"
./three-math.js
"
:
9
,
"
./util.js
"
:
11
}],
11
:[
function
(
_dereq_
,
module
,
exports
){
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var
Util
=
window
.
Util
||
{};
Util
.
MIN_TIMESTEP
=
0.001
;
Util
.
MAX_TIMESTEP
=
1
;
Util
.
clamp
=
function
(
value
,
min
,
max
)
{
return
Math
.
min
(
Math
.
max
(
min
,
value
),
max
);
};
Util
.
isIOS
=
function
()
{
return
/iPad|iPhone|iPod/
.
test
(
navigator
.
platform
);
};
Util
.
isFirefoxAndroid
=
function
()
{
return
navigator
.
userAgent
.
indexOf
(
'
Firefox
'
)
!==
-
1
&&
navigator
.
userAgent
.
indexOf
(
'
Android
'
)
!==
-
1
;
}
// Helper method to validate the time steps of sensor timestamps.
Util
.
isTimestampDeltaValid
=
function
(
timestampDeltaS
)
{
if
(
isNaN
(
timestampDeltaS
))
{
return
false
;
}
if
(
timestampDeltaS
<=
Util
.
MIN_TIMESTEP
)
{
return
false
;
}
if
(
timestampDeltaS
>
Util
.
MAX_TIMESTEP
)
{
return
false
;
}
return
true
;
}
module
.
exports
=
Util
;
},{}],
12
:[
function
(
_dereq_
,
module
,
exports
){
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var
CardboardHMDVRDevice
=
_dereq_
(
'
./cardboard-hmd-vr-device.js
'
);
//var OrientationPositionSensorVRDevice = require('./orientation-position-sensor-vr-device.js');
var
FusionPositionSensorVRDevice
=
_dereq_
(
'
./fusion-position-sensor-vr-device.js
'
);
var
MouseKeyboardPositionSensorVRDevice
=
_dereq_
(
'
./mouse-keyboard-position-sensor-vr-device.js
'
);
// Uncomment to add positional tracking via webcam.
//var WebcamPositionSensorVRDevice = require('./webcam-position-sensor-vr-device.js');
var
HMDVRDevice
=
_dereq_
(
'
./base.js
'
).
HMDVRDevice
;
var
PositionSensorVRDevice
=
_dereq_
(
'
./base.js
'
).
PositionSensorVRDevice
;
function
WebVRPolyfill
()
{
this
.
devices
=
[];
if
(
!
this
.
isWebVRAvailable
())
{
this
.
enablePolyfill
();
}
}
WebVRPolyfill
.
prototype
.
isWebVRAvailable
=
function
()
{
return
(
'
getVRDevices
'
in
navigator
)
||
(
'
mozGetVRDevices
'
in
navigator
);
};
WebVRPolyfill
.
prototype
.
enablePolyfill
=
function
()
{
// Initialize our virtual VR devices.
if
(
this
.
isCardboardCompatible
())
{
this
.
devices
.
push
(
new
CardboardHMDVRDevice
());
}
// Polyfill using the right position sensor.
if
(
this
.
isMobile
())
{
//this.devices.push(new OrientationPositionSensorVRDevice());
this
.
devices
.
push
(
new
FusionPositionSensorVRDevice
());
}
else
{
if
(
!
WebVRConfig
.
MOUSE_KEYBOARD_CONTROLS_DISABLED
)
{
this
.
devices
.
push
(
new
MouseKeyboardPositionSensorVRDevice
());
}
// Uncomment to add positional tracking via webcam.
//this.devices.push(new WebcamPositionSensorVRDevice());
}
// Provide navigator.getVRDevices.
navigator
.
getVRDevices
=
this
.
getVRDevices
.
bind
(
this
);
// Provide the CardboardHMDVRDevice and PositionSensorVRDevice objects.
window
.
HMDVRDevice
=
HMDVRDevice
;
window
.
PositionSensorVRDevice
=
PositionSensorVRDevice
;
};
WebVRPolyfill
.
prototype
.
getVRDevices
=
function
()
{
var
devices
=
this
.
devices
;
return
new
Promise
(
function
(
resolve
,
reject
)
{
try
{
resolve
(
devices
);
}
catch
(
e
)
{
reject
(
e
);
}
});
};
/**
* Determine if a device is mobile.
*/
WebVRPolyfill
.
prototype
.
isMobile
=
function
()
{
return
/Android/i
.
test
(
navigator
.
userAgent
)
||
/iPhone|iPad|iPod/i
.
test
(
navigator
.
userAgent
);
};
WebVRPolyfill
.
prototype
.
isCardboardCompatible
=
function
()
{
// For now, support all iOS and Android devices.
// Also enable the WebVRConfig.FORCE_VR flag for debugging.
return
this
.
isMobile
()
||
WebVRConfig
.
FORCE_ENABLE_VR
;
};
module
.
exports
=
WebVRPolyfill
;
},{
"
./base.js
"
:
1
,
"
./cardboard-hmd-vr-device.js
"
:
2
,
"
./fusion-position-sensor-vr-device.js
"
:
4
,
"
./mouse-keyboard-position-sensor-vr-device.js
"
:
6
}]},{},[
5
]);
examples/textures/cube/sun_temple_stripe_stereo.jpg
0 → 100644
浏览文件 @
3f479a5b
681.8 KB
examples/webgl_stereo_pano.html
0 → 100644
浏览文件 @
3f479a5b
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<title>
three.js webgl - stereo pano demo
</title>
<meta
charset=
"utf-8"
>
<meta
name=
"viewport"
content=
"width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
>
<meta
name=
"viewmode"
content=
"projection=stereo"
>
<style>
html
,
body
{
background-color
:
#000
;
margin
:
0
;
padding
:
0
;
overflow
:
hidden
;
}
#vrMode
{
position
:
absolute
;
top
:
0
;
left
:
0
;
margin
:
10px
;
padding
:
10px
;
border
:
0
;
background
:
#000
;
color
:
#fff
;
font-size
:
1rem
;
}
</style>
<script>
WebVRConfig
=
{
// Forces availability of VR mode.
FORCE_ENABLE_VR
:
true
,
// Default: false.
// Complementary filter coefficient. 0 for accelerometer, 1 for gyro.
//K_FILTER: 0.98, // Default: 0.98.
// How far into the future to predict during fast motion.
//PREDICTION_TIME_S: 0, // Default: 0.050s.
// Flag to disable touch panner. In case you have your own touch controls
//TOUCH_PANNER_DISABLED: true, // Default: false.
// Enable yaw panning only, disabling roll and pitch. This can be useful
// for panoramas with nothing interesting above or below.
//YAW_ONLY: true, // Default: false.
// To disable keyboard and mouse controls. If you implement your own.
//MOUSE_KEYBOARD_CONTROLS_DISABLED: true // Default: false
}
</script>
</head>
<body>
<button
id=
"vrMode"
>
VR MODE
</button>
<script
src=
"../build/three.min.js"
></script>
<script
src=
"js/libs/webvr-polyfill.js"
></script>
<script
src=
"js/controls/VRControls.js"
></script>
<script
src=
"js/effects/VREffect.js"
></script>
<script>
var
camera
;
var
vrControls
;
var
effect
;
var
renderer
;
var
scene
;
var
vrMode
=
false
;
function
init
()
{
renderer
=
new
THREE
.
WebGLRenderer
(
{
antialias
:
true
}
);
renderer
.
setPixelRatio
(
window
.
devicePixelRatio
?
window
.
devicePixelRatio
:
1
);
document
.
body
.
appendChild
(
renderer
.
domElement
);
scene
=
new
THREE
.
Scene
();
camera
=
new
THREE
.
PerspectiveCamera
(
90
,
window
.
innerWidth
/
window
.
innerHeight
,
1
,
10000
);
camera
.
layers
.
enable
(
1
);
effect
=
new
THREE
.
VREffect
(
renderer
);
vrControls
=
new
THREE
.
VRControls
(
camera
);
var
textures
=
getTexturesFromAtlasFile
(
"
textures/cube/sun_temple_stripe_stereo.jpg
"
,
12
);
var
materials
=
[];
for
(
var
i
=
0
;
i
<
6
;
i
++
)
{
materials
.
push
(
new
THREE
.
MeshBasicMaterial
(
{
map
:
textures
[
i
]
}
)
);
}
var
skyBox
=
new
THREE
.
Mesh
(
new
THREE
.
CubeGeometry
(
1024
,
1024
,
1024
),
new
THREE
.
MeshFaceMaterial
(
materials
)
);
skyBox
.
applyMatrix
(
new
THREE
.
Matrix4
().
makeScale
(
1
,
1
,
-
1
)
);
skyBox
.
layers
.
set
(
1
);
scene
.
add
(
skyBox
);
var
materialsR
=
[];
for
(
var
i
=
6
;
i
<
12
;
i
++
)
{
materialsR
.
push
(
new
THREE
.
MeshBasicMaterial
(
{
map
:
textures
[
i
]
}
)
);
}
var
skyBoxR
=
new
THREE
.
Mesh
(
new
THREE
.
CubeGeometry
(
1024
,
1024
,
1024
),
new
THREE
.
MeshFaceMaterial
(
materialsR
)
);
skyBoxR
.
applyMatrix
(
new
THREE
.
Matrix4
().
makeScale
(
1
,
1
,
-
1
)
);
skyBoxR
.
layers
.
set
(
2
);
scene
.
add
(
skyBoxR
);
animate
();
onWindowResize
();
}
function
getTexturesFromAtlasFile
(
atlasImgUrl
,
tilesNum
)
{
var
textures
=
[];
for
(
var
i
=
0
;
i
<
tilesNum
;
i
++
)
{
textures
[
i
]
=
new
THREE
.
Texture
();
}
var
imageObj
=
new
Image
();
imageObj
.
onload
=
function
()
{
var
canvas
,
context
;
var
tileWidth
=
imageObj
.
height
;
for
(
var
i
=
0
;
i
<
textures
.
length
;
i
++
)
{
canvas
=
document
.
createElement
(
'
canvas
'
);
context
=
canvas
.
getContext
(
'
2d
'
);
canvas
.
height
=
tileWidth
;
canvas
.
width
=
tileWidth
;
context
.
drawImage
(
imageObj
,
tileWidth
*
i
,
0
,
tileWidth
,
tileWidth
,
0
,
0
,
tileWidth
,
tileWidth
);
textures
[
i
].
image
=
canvas
textures
[
i
].
needsUpdate
=
true
;
}
};
imageObj
.
src
=
atlasImgUrl
;
return
textures
;
}
function
requestFullscreen
()
{
effect
.
setFullScreen
(
true
);
}
function
onWindowResize
()
{
camera
.
aspect
=
window
.
innerWidth
/
window
.
innerHeight
;
camera
.
updateProjectionMatrix
();
if
(
vrMode
)
{
effect
.
setSize
(
window
.
innerWidth
,
window
.
innerHeight
);
}
else
{
renderer
.
setSize
(
window
.
innerWidth
,
window
.
innerHeight
);
}
}
function
onFullscreenChange
(
e
)
{
var
fsElement
=
document
.
fullscreenElement
||
document
.
mozFullScreenElement
||
document
.
webkitFullscreenElement
;
if
(
!
fsElement
)
{
vrMode
=
false
;
}
else
{
window
.
screen
.
orientation
.
lock
(
'
landscape
'
);
}
}
function
animate
()
{
if
(
vrMode
)
{
effect
.
render
(
scene
,
camera
);
}
else
{
renderer
.
setViewport
(
0
,
0
,
window
.
innerWidth
,
window
.
innerHeight
);
renderer
.
render
(
scene
,
camera
);
}
vrControls
.
update
();
requestAnimationFrame
(
animate
);
}
document
.
querySelector
(
'
#vrMode
'
).
addEventListener
(
'
click
'
,
function
()
{
vrMode
=
vrMode
?
false
:
true
;
requestFullscreen
();
onWindowResize
();
}
);
document
.
addEventListener
(
'
fullscreenchange
'
,
onFullscreenChange
);
document
.
addEventListener
(
'
mozfullscreenchange
'
,
onFullscreenChange
);
window
.
addEventListener
(
'
resize
'
,
onWindowResize
,
false
);
init
();
</script>
</body>
</html>
examples/webvr_stereo_pano.html
0 → 100644
浏览文件 @
3f479a5b
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<title>
three.js webgl - stereo pano demo
</title>
<meta
charset=
"utf-8"
>
<meta
name=
"viewport"
content=
"width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"
>
<meta
name=
"viewmode"
content=
"projection=stereo"
>
<style>
html
,
body
{
background-color
:
#000
;
margin
:
0px
;
padding
:
0px
;
overflow
:
hidden
;
}
#VrMode
{
position
:
absolute
;
top
:
0
;
left
:
0
;
margin
:
10px
;
background
:
black
;
border
:
0
;
color
:
#fff
;
padding
:
10px
;
font-size
:
1rem
;
}
</style>
<script>
WebVRConfig
=
{
// Forces availability of VR mode.
FORCE_ENABLE_VR
:
true
,
// Default: false.
// Complementary filter coefficient. 0 for accelerometer, 1 for gyro.
//K_FILTER: 0.98, // Default: 0.98.
// How far into the future to predict during fast motion.
//PREDICTION_TIME_S: 0, // Default: 0.050s.
// Flag to disable touch panner. In case you have your own touch controls
//TOUCH_PANNER_DISABLED: true, // Default: false.
// Enable yaw panning only, disabling roll and pitch. This can be useful
// for panoramas with nothing interesting above or below.
//YAW_ONLY: true, // Default: false.
// To disable keyboard and mouse controls. If you implement your own.
//MOUSE_KEYBOARD_CONTROLS_DISABLED: true // Default: false
}
</script>
</head>
<body>
<button
id=
"VrMode"
>
VR MODE
</button>
<script
src=
"../build/three.min.js"
></script>
<script
src=
"js/libs/webvr-polyfill.js"
></script>
<script
src=
"js/controls/VRControls.js"
></script>
<script
src=
"js/effects/VREffect.js"
></script>
<script>
var
camera
;
var
vrControls
;
var
effect
;
var
renderer
;
var
scene
;
var
TwitchStream
=
false
;
function
init
()
{
renderer
=
new
THREE
.
WebGLRenderer
(
{
antialias
:
true
}
);
renderer
.
setPixelRatio
(
window
.
devicePixelRatio
?
window
.
devicePixelRatio
:
1
);
document
.
body
.
appendChild
(
renderer
.
domElement
);
scene
=
new
THREE
.
Scene
();
camera
=
new
THREE
.
PerspectiveCamera
(
90
,
window
.
innerWidth
/
window
.
innerHeight
,
1
,
10000
);
camera
.
layers
.
enable
(
1
);
effect
=
new
THREE
.
VREffect
(
renderer
);
vrControls
=
new
THREE
.
VRControls
(
camera
);
var
textures
=
getTexturesFromAtlasFile
(
"
textures/cube/sun_temple_stripe_stereo.jpg
"
,
12
);
var
materials
=
[];
for
(
var
i
=
0
;
i
<
6
;
i
++
)
{
materials
.
push
(
new
THREE
.
MeshBasicMaterial
(
{
map
:
textures
[
i
]
}
)
);
}
var
skyBox
=
new
THREE
.
Mesh
(
new
THREE
.
CubeGeometry
(
1024
,
1024
,
1024
),
new
THREE
.
MeshFaceMaterial
(
materials
)
);
skyBox
.
applyMatrix
(
new
THREE
.
Matrix4
().
makeScale
(
1
,
1
,
-
1
)
);
skyBox
.
layers
.
set
(
1
);
scene
.
add
(
skyBox
);
var
materialsR
=
[];
for
(
var
i
=
6
;
i
<
12
;
i
++
)
{
materialsR
.
push
(
new
THREE
.
MeshBasicMaterial
(
{
map
:
textures
[
i
]
}
)
);
}
var
skyBoxR
=
new
THREE
.
Mesh
(
new
THREE
.
CubeGeometry
(
1024
,
1024
,
1024
),
new
THREE
.
MeshFaceMaterial
(
materialsR
)
);
skyBoxR
.
applyMatrix
(
new
THREE
.
Matrix4
().
makeScale
(
1
,
1
,
-
1
)
);
skyBoxR
.
layers
.
set
(
2
);
scene
.
add
(
skyBoxR
);
animate
();
onWindowResize
();
}
function
getTexturesFromAtlasFile
(
atlasImgUrl
,
tilesNum
)
{
var
textures
=
[];
for
(
var
i
=
0
;
i
<
tilesNum
;
i
++
)
{
textures
[
i
]
=
new
THREE
.
Texture
();
}
var
imageObj
=
new
Image
();
imageObj
.
onload
=
function
()
{
var
canvas
,
context
;
var
tileWidth
=
imageObj
.
height
;
for
(
var
i
=
0
;
i
<
textures
.
length
;
i
++
)
{
canvas
=
document
.
createElement
(
'
canvas
'
);
context
=
canvas
.
getContext
(
'
2d
'
);
canvas
.
height
=
tileWidth
;
canvas
.
width
=
tileWidth
;
context
.
drawImage
(
imageObj
,
tileWidth
*
i
,
0
,
tileWidth
,
tileWidth
,
0
,
0
,
tileWidth
,
tileWidth
);
textures
[
i
].
image
=
canvas
textures
[
i
].
needsUpdate
=
true
;
}
};
imageObj
.
src
=
atlasImgUrl
;
return
textures
;
}
function
requestFullscreen
()
{
effect
.
setFullScreen
(
true
);
}
function
onWindowResize
()
{
camera
.
aspect
=
window
.
innerWidth
/
window
.
innerHeight
;
camera
.
updateProjectionMatrix
();
if
(
TwitchStream
)
{
effect
.
setSize
(
window
.
innerWidth
,
window
.
innerHeight
);
}
else
{
renderer
.
setSize
(
window
.
innerWidth
,
window
.
innerHeight
);
}
}
function
onFullscreenChange
(
e
)
{
var
fsElement
=
document
.
fullscreenElement
||
document
.
mozFullScreenElement
||
document
.
webkitFullscreenElement
;
if
(
!
fsElement
)
{
TwitchStream
=
false
;
}
else
{
window
.
screen
.
orientation
.
lock
(
'
landscape
'
);
}
}
function
animate
()
{
if
(
TwitchStream
)
{
effect
.
render
(
scene
,
camera
);
}
else
{
renderer
.
setViewport
(
0
,
0
,
window
.
innerWidth
,
window
.
innerHeight
);
renderer
.
render
(
scene
,
camera
);
}
vrControls
.
update
();
requestAnimationFrame
(
animate
);
}
document
.
querySelector
(
'
#VrMode
'
).
addEventListener
(
'
click
'
,
function
()
{
TwitchStream
=
TwitchStream
?
false
:
true
;
requestFullscreen
();
onWindowResize
();
}
);
document
.
addEventListener
(
'
fullscreenchange
'
,
onFullscreenChange
);
document
.
addEventListener
(
'
mozfullscreenchange
'
,
onFullscreenChange
);
window
.
addEventListener
(
'
resize
'
,
onWindowResize
,
false
);
init
();
</script>
</body>
</html>
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录