Last active
August 29, 2015 14:09
-
-
Save gtk2k/8c479980729cb850a3a4 to your computer and use it in GitHub Desktop.
WebVR使ったコード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
ゲーム用フレームワークは使ったことがないため、ほぼナマなJSに書き換えました。 | |
FキーでOculusRift描画、Zキーでゼロポジションリセット。 | |
--> | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>sample</title> | |
<style type="text/css"> | |
body { | |
margin: 0; | |
padding: 0; | |
} | |
</style> | |
<script src="extlib/three.min.js"></script> | |
</head> | |
<body> | |
<video id="video" src="media/video/video-1920x960.mp4" autoplay loop style="display:none"></video> | |
<div id="webgl"></div> | |
<script> | |
var video = document.getElementById('video'); | |
var renderer = new THREE.WebGLRenderer(); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
webgl.appendChild(renderer.domElement); | |
var scene = new THREE.Scene(); | |
var cameraLeft = new THREE.PerspectiveCamera(75, 4 / 3, 0.1, 1000); | |
cameraLeft.position.set(0, 0, 0); | |
var cameraRight = new THREE.PerspectiveCamera(75, 4 / 3, 0.1, 1000); | |
cameraRight.position.set(0, 0, 0); | |
var camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.1, 1000); | |
camera.position.set(0, 0, 0); | |
var light = new THREE.DirectionalLight(0xffffff, 0.5); | |
light.position = new THREE.Vector3(100.0, 100.0, 100.0); | |
light.castShadow = true; | |
scene.add(light); | |
var light2 = new THREE.AmbientLight(0xffffff); | |
scene.add(light2); | |
var rotateBase = new THREE.Mesh(); | |
var material = new THREE.MeshPhongMaterial({ | |
color: 'gray', | |
ambient: 0x303030, | |
specular: 0xffffff, | |
shininess: 1, | |
metal: true | |
}); | |
var balls = []; | |
for (var i = 1; i <= 4; i++) { | |
for (var j = 1; j <= 4; j++) { | |
var ballGeometory = new THREE.SphereGeometry(10, 20, 20); | |
var ballMesh = new THREE.Mesh(ballGeometory, material); | |
ballMesh.position.set(i * 32, 0, j * 32 - 140); | |
ballMesh.r = i; | |
ballMesh.c = j; | |
ballMesh.i = 0.0; | |
ballMesh.rows = 4; | |
ballMesh.cols = 4; | |
ballMesh.org = (Math.sin(ballMesh.r / ballMesh.rows + ballMesh.i) + Math.sin(ballMesh.c / ballMesh.cols + ballMesh.i)) * 16; | |
rotateBase.add(ballMesh); | |
balls.push(ballMesh); | |
} | |
} | |
var wallGeometory = new THREE.BoxGeometry(640, 480, 1); | |
var wallMesh = new THREE.Mesh(wallGeometory, material); | |
wallMesh.position.set(400, 40, -400); | |
rotateBase.add(wallMesh); | |
var videoGeometory = new THREE.SphereGeometry(1000, 32, 32); | |
var videoTexture = new THREE.Texture(video); | |
var videoMaterial = new THREE.MeshBasicMaterial({ | |
map: videoTexture, | |
overdraw: true, | |
side: THREE.DoubleSide | |
}); | |
var videoMesh = new THREE.Mesh(videoGeometory, videoMaterial); | |
rotateBase.add(videoMesh); | |
scene.add(rotateBase); | |
// VR Device Setup | |
var sensorDevice = null; | |
var hmdDevice = null; | |
var vrMode = false; | |
var renderTargetWidth = window.innerWidth; | |
var renderTargetHeight = window.innerHeight; | |
function PerspectiveMatrixFromVRFieldOfView(fov, zNear, zFar) { | |
var outMat = new THREE.Matrix4(); | |
var out = outMat.elements; | |
var upTan, downTan, leftTan, rightTan; | |
if (fov == null) { | |
// If no FOV is given plug in some dummy values | |
upTan = Math.tan(50 * Math.PI / 180.0); | |
downTan = Math.tan(50 * Math.PI / 180.0); | |
leftTan = Math.tan(45 * Math.PI / 180.0); | |
rightTan = Math.tan(45 * Math.PI / 180.0); | |
} else { | |
upTan = Math.tan(fov.upDegrees * Math.PI / 180.0); | |
downTan = Math.tan(fov.downDegrees * Math.PI / 180.0); | |
leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0); | |
rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0); | |
} | |
var xScale = 2.0 / (leftTan + rightTan); | |
var yScale = 2.0 / (upTan + downTan); | |
out[0] = xScale; | |
out[4] = 0.0; | |
out[8] = -((leftTan - rightTan) * xScale * 0.5); | |
out[12] = 0.0; | |
out[1] = 0.0; | |
out[5] = yScale; | |
out[9] = ((upTan - downTan) * yScale * 0.5); | |
out[13] = 0.0; | |
out[2] = 0.0; | |
out[6] = 0.0; | |
out[10] = zFar / (zNear - zFar); | |
out[14] = (zFar * zNear) / (zNear - zFar); | |
out[3] = 0.0; | |
out[7] = 0.0; | |
out[11] = -1.0; | |
out[15] = 0.0; | |
return outMat; | |
} | |
var fovScale = 1.0; | |
function resizeFOV(amount) { | |
var fovLeft, fovRight; | |
if (!hmdDevice) { return; } | |
if (amount != 0 && 'setFieldOfView' in hmdDevice) { | |
fovScale += amount; | |
if (fovScale < 0.1) { fovScale = 0.1; } | |
fovLeft = hmdDevice.getRecommendedEyeFieldOfView("left"); | |
fovRight = hmdDevice.getRecommendedEyeFieldOfView("right"); | |
fovLeft.upDegrees *= fovScale; | |
fovLeft.downDegrees *= fovScale; | |
fovLeft.leftDegrees *= fovScale; | |
fovLeft.rightDegrees *= fovScale; | |
fovRight.upDegrees *= fovScale; | |
fovRight.downDegrees *= fovScale; | |
fovRight.leftDegrees *= fovScale; | |
fovRight.rightDegrees *= fovScale; | |
hmdDevice.setFieldOfView(fovLeft, fovRight); | |
} | |
//if ('getRecommendedEyeRenderRect' in hmdDevice) { | |
// var leftEyeViewport = hmdDevice.getRecommendedEyeRenderRect("left"); | |
// var rightEyeViewport = hmdDevice.getRecommendedEyeRenderRect("right"); | |
// renderTargetWidth = leftEyeViewport.width + rightEyeViewport.width; | |
// renderTargetHeight = Math.max(leftEyeViewport.height, rightEyeViewport.height); | |
//} | |
resize(); | |
if ('getCurrentEyeFieldOfView' in hmdDevice) { | |
fovLeft = hmdDevice.getCurrentEyeFieldOfView("left"); | |
fovRight = hmdDevice.getCurrentEyeFieldOfView("right"); | |
} else { | |
fovLeft = hmdDevice.getRecommendedEyeFieldOfView("left"); | |
fovRight = hmdDevice.getRecommendedEyeFieldOfView("right"); | |
} | |
cameraLeft.projectionMatrix = PerspectiveMatrixFromVRFieldOfView(fovLeft, 0.1, 1000); | |
cameraRight.projectionMatrix = PerspectiveMatrixFromVRFieldOfView(fovRight, 0.1, 1000); | |
} | |
function EnumerateVRDevices(devices) { | |
// First find an HMD device | |
for (var i = 0; i < devices.length; ++i) { | |
if (devices[i] instanceof HMDVRDevice) { | |
hmdDevice = devices[i]; | |
var eyeOffsetLeft = hmdDevice.getEyeTranslation("left"); | |
var eyeOffsetRight = hmdDevice.getEyeTranslation("right"); | |
cameraLeft.position.add(eyeOffsetLeft); | |
cameraRight.position.add(eyeOffsetRight); | |
console.log(cameraLeft.position.x, cameraRight.position.x); | |
resizeFOV(0.0); | |
} | |
} | |
// Next find a sensor that matches the HMD hardwareUnitId | |
for (var i = 0; i < devices.length; ++i) { | |
if (devices[i] instanceof PositionSensorVRDevice && | |
(!hmdDevice || devices[i].hardwareUnitId == hmdDevice.hardwareUnitId)) { | |
sensorDevice = devices[i]; | |
} | |
} | |
} | |
if (navigator.getVRDevices) { | |
navigator.getVRDevices().then(EnumerateVRDevices); | |
} else if (navigator.mozGetVRDevices) { | |
navigator.mozGetVRDevices(EnumerateVRDevices); | |
} | |
function resize() { | |
if (vrMode) { | |
camera.aspect = renderTargetWidth / renderTargetHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize(renderTargetWidth, renderTargetHeight); | |
} else { | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
} | |
} | |
resize(); | |
//window.addEventListener("resize", resize, false); | |
// Fullscreen VR mode handling | |
function onFullscreenChange() { | |
if (!document.webkitFullscreenElement && !document.mozFullScreenElement) { | |
vrMode = false; | |
} | |
resize(); | |
} | |
document.addEventListener("webkitfullscreenchange", onFullscreenChange, false); | |
document.addEventListener("mozfullscreenchange", onFullscreenChange, false); | |
function render() { | |
requestAnimationFrame(render); | |
videoTexture.needsUpdate = true; | |
for (var i = 0; i < balls.length; i++){ | |
var ball = balls[i]; | |
ball.position.y = (Math.sin(ball.r / ball.rows + ball.i) + Math.sin(ball.c / ball.cols + ball.i)) * 32; | |
ball.i += 0.1; | |
if (ball.position.y === ball.org) { | |
ball.i = 0.0; | |
} | |
} | |
if (vrMode) { | |
if (sensorDevice) { | |
var vrState = sensorDevice.getState(); | |
rotateBase.quaternion.x = vrState.orientation.x; | |
rotateBase.quaternion.y = vrState.orientation.y; | |
rotateBase.quaternion.z = vrState.orientation.z; | |
rotateBase.quaternion.w = -vrState.orientation.w; | |
} | |
// Render left eye | |
renderer.enableScissorTest(true); | |
renderer.setScissor(0, 0, renderTargetWidth / 2, renderTargetHeight); | |
renderer.setViewport(0, 0, renderTargetWidth / 2, renderTargetHeight); | |
renderer.render(scene, cameraLeft); | |
// Render right eye | |
renderer.setScissor(renderTargetWidth / 2, 0, renderTargetWidth / 2, renderTargetHeight); | |
renderer.setViewport(renderTargetWidth / 2, 0, renderTargetWidth / 2, renderTargetHeight); | |
renderer.render(scene, cameraRight); | |
} else { | |
// Render mono view | |
renderer.enableScissorTest(false); | |
renderer.setViewport(0, 0, window.innerWidth, window.innerHeight); | |
renderer.render(scene, camera); | |
} | |
} | |
render(); | |
document.addEventListener('keydown', function (e) { | |
if (e.keyCode == 'F'.charCodeAt(0)) { // 'F'キーが押された場合 | |
if (!hmdDevice) return; | |
var cnvs = document.getElementsByTagName('canvas'); | |
if (cnvs.length) { | |
for (var i = cnvs.length; i--;) { | |
var cnv = cnvs[i]; | |
if (cnv.parentNode.id === 'webgl') { | |
if (cnv.webkitRequestFullscreen) { | |
cnv.webkitRequestFullscreen({ vrDisplay: hmdDevice, /*vrDistortion: false*/ }); | |
vrMode = true; | |
} else if (cnv.mozRequestFullScreen) { | |
cnv.mozRequestFullScreen({ vrDisplay: hmdDevice }); | |
vrMode = true; | |
} | |
return; | |
} | |
} | |
} | |
} else if (e.keyCode == 'Z'.charCodeAt(0)) { | |
sensorDevice.zeroSensor(); | |
} | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment