Created
August 29, 2013 12:39
-
-
Save edom18/6377548 to your computer and use it in GitHub Desktop.
[THREE.js] ジプシー・デンジャーを操作できるようにする
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
#ジプシー・デンジャーを歩けるようにしていきます。 | |
まずはキー押下時に歩くモーション、なにもしていないときは待機モーションになるようにしました。 | |
モデルの移動方向については、ヨモツ先生のこちらを参考にしました → http://yomotsu.github.io/threejs-examples/tps/ |
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
@import "compass/reset"; | |
img, canvas { | |
vertical-align: top; | |
} | |
#gui { | |
position: absolute; | |
left: 5px; | |
top: 5px; | |
padding: 10px; | |
background: rgba(0, 0, 0, 0.5); | |
border: solid 1px rgba(255, 255, 255, 0.5); | |
color: #fff; | |
} |
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
<div id="gui"> | |
<p>A key: move to left.</p> | |
<p>S key: move to back.</p> | |
<p>D key: move to right.</p> | |
<p>W key: move to front.</p> | |
</div> |
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
(function (win, doc) { | |
'use strict'; | |
var container, camera, scene, renderer, model, | |
globalLight, clock, | |
//for skybox. | |
sceneCube, cameraCube, textureCube, meshCube; | |
var offsetX = 0, | |
offsetY = 100, | |
offsetZ = 220; | |
//for model information. | |
var modelUrl = 'http://resources.edo-m18.me/models/gips-danger/gips-danger_rig_animation.js'; | |
var modelFrames = { | |
stand: [ 0, 32, 0, {state: 'stand', action: false}], | |
walk : [33, 65, 1.6, {state: 'stand', action: false}], | |
run : [66, 98, 3.2, {state: 'stand', action: false}] | |
}; | |
var player = { | |
position: { | |
x: 0, | |
y: 0, | |
z: 0, | |
distance: 0 | |
}, | |
camera: { | |
speed: 300, | |
distance: 400, | |
x: 0, | |
y: 100, | |
z: 0 | |
} | |
}; | |
var groundTextureUrl = 'http://jsrun.it/assets/h/M/n/q/hMnqT.jpg'; | |
// | |
function createModel(geometry, materials) { | |
var facematerial; | |
var scale = 17; | |
if (materials) { | |
for (var i = 0; i < materials.length; i++) { | |
materials[i].morphTargets = true; | |
} | |
facematerial = new THREE.MeshFaceMaterial(materials); | |
} | |
else { | |
facematerial = new THREE.MeshLambertMaterial({color: 0xcccccc}); | |
facematerial.morphTargets = true; | |
} | |
win.model = model = new THREE.MorphAnimMesh(geometry, facematerial); | |
model.scale.set(scale, scale, scale); | |
model.position.set(0, 0, 0); | |
model.castShadow = true; | |
model.receiveShadow = true; | |
model.setFrameRange(modelFrames.stand[0], modelFrames.stand[1]); | |
//model.add(camera); | |
scene.add(model); | |
animate(); | |
} | |
/** | |
* Initialize sky box. | |
*/ | |
function initSkybox() { | |
//Skyebox用のシーン、カメラを生成 | |
sceneCube = new THREE.Scene(); | |
cameraCube = new THREE.PerspectiveCamera(25, window.innerWidth / window.innerHeight, 1, 10000); | |
cameraCube.position.y = 20; | |
sceneCube.add(cameraCube); | |
//p = positive, n = negative | |
var urls = [ | |
'/assets/k/z/5/Y/kz5YB.jpg', | |
'/assets/x/P/8/J/xP8JV.jpg', | |
'/assets/p/S/A/e/pSAes.jpg', | |
'/assets/4/v/3/x/4v3xz.jpg', | |
'/assets/g/a/G/S/gaGSG.jpg', | |
'/assets/x/z/w/I/xzwIo.jpg' | |
]; | |
//キューブマップ用にテクスチャをロード | |
textureCube = THREE.ImageUtils.loadTextureCube(urls); | |
// | |
var shader, material; | |
//Skyebox用にデフォルトで準備されているシェーダを読み込み | |
shader = THREE.ShaderLib.cube; | |
//キューブマップ用テクスチャを、uniform変数「tCube」にアップロード | |
shader.uniforms.tCube.value = textureCube; | |
//上記のシェーダを、ShaderMaterialとしてマテリアルを生成 | |
material = new THREE.ShaderMaterial({ | |
fragmentShader: shader.fragmentShader, | |
vertexShader : shader.vertexShader, | |
uniforms : shader.uniforms, | |
depthWrite : false, | |
side : THREE.BackSide | |
}); | |
//Skyboxメッシュを生成 | |
meshCube = new THREE.Mesh(new THREE.CubeGeometry(1000, 1000, 1000), material); | |
//生成したメッシュをSkybox用シーンに追加 | |
sceneCube.add(meshCube); | |
} | |
/** | |
* Initialize ground plane. | |
*/ | |
function initGround() { | |
var initColor, initTexture, | |
groundMaterial, groundTexture, | |
mesh; | |
initColor = new THREE.Color(0xaea893); | |
initTexture = THREE.ImageUtils.generateDataTexture(1, 1, initColor); | |
groundMaterial = new THREE.MeshPhongMaterial({color: 0xffffff, specular: 0x111111, map: initTexture}); | |
groundTexture = THREE.ImageUtils.loadTexture(groundTextureUrl, undefined, function () { groundMaterial.map = groundTexture; }); | |
groundTexture.wrapS = groundTexture.wrapT = THREE.RepeatWrapping; | |
groundTexture.repeat.set(500, 500); | |
groundTexture.anisotropy = 6; | |
mesh = new THREE.Mesh(new THREE.PlaneGeometry(20000, 20000), groundMaterial); | |
mesh.rotation.x = -Math.PI / 2; | |
mesh.receiveShadow = true; | |
mesh.castShadow = true; | |
scene.add(mesh); | |
} | |
/** | |
* All of initialize to the WebGL scene. | |
*/ | |
function init() { | |
container = doc.createElement('div'); | |
doc.body.appendChild(container); | |
clock = new THREE.Clock(); | |
//Create a main scene. | |
scene = new THREE.Scene(); | |
win.camera = camera = new THREE.PerspectiveCamera(50, win.innerWidth / win.innerHeight, 1, 10000); | |
camera.position.set(offsetX, offsetY, -offsetZ); | |
scene.add(camera); | |
// | |
var d = 1000; | |
var pos = d / 5; | |
globalLight = new THREE.DirectionalLight(0xefefff, 2); | |
globalLight.position.set(-pos, pos, pos);//.normalize(); | |
globalLight.castShadow = true; | |
globalLight.shadowMapWidth = 2048; | |
globalLight.shadowMapHeight = 2048; | |
globalLight.shadowCameraLeft = -d; | |
globalLight.shadowCameraRight = d; | |
globalLight.shadowCameraTop = d; | |
globalLight.shadowCameraBottom = -d; | |
globalLight.shadowCameraNear = 0.1; | |
globalLight.shadowCameraFar = d; | |
globalLight.shadowCameraFov = 40; | |
//globalLight.shadowCameraVisible = true; | |
globalLight.shadowBias = 0.0001; | |
globalLight.shadowDarkness = 0.5; | |
scene.add(globalLight); | |
var light2 = new THREE.DirectionalLight(0xffefef, 0.4); | |
light2.position.set(0, d, 0).normalize(); | |
scene.add(light2); | |
var light3 = new THREE.DirectionalLight(0xffefef, 0.2); | |
light3.position.set(d, d, d).normalize(); | |
//scene.add(light3); | |
var ambLight = new THREE.AmbientLight(0x666666); | |
scene.add(ambLight); | |
//load a gips-danger | |
var loader = new THREE.JSONLoader(); | |
loader.load(modelUrl, createModel); | |
//load buildings. | |
loader.load('http://resources.edo-m18.me/models/gips-danger/building.js', function (geometry, materials) { | |
var face_material, | |
s = 100; | |
if (materials) { | |
face_material = new THREE.MeshFaceMaterial(materials); | |
} | |
else { | |
face_material = new THREE.MeshLambertMaterial({color: 0xcccccc}); | |
} | |
var building = new THREE.Mesh(geometry, face_material); | |
building.scale.set(s, s, s); | |
building.position.x += 70; | |
building.position.y += 28; | |
building.castShadow = true; | |
building.receiveShadow = true; | |
scene.add(building); | |
}); | |
// | |
initGround(); | |
initSkybox(); | |
// | |
renderer = new THREE.WebGLRenderer({antialias: true}); | |
renderer.sortObjects = false; | |
renderer.setSize(win.innerWidth, win.innerHeight); | |
renderer.setClearColor(0x000000, 1); | |
renderer.shadowMapEnabled = true; | |
renderer.shadowMapType = THREE.PCFShadowMap; | |
renderer.autoClear = false; | |
container.appendChild(renderer.domElement); | |
// | |
win.addEventListener('resize', onWindowResize, false); | |
} | |
// | |
function onWindowResize() { | |
camera.aspect = win.innerWidth / win.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize(win.innerWidth, win.innerHeight); | |
} | |
// | |
function animate() { | |
requestAnimationFrame(animate); | |
render(); | |
} | |
// | |
//var duration = 5000, | |
// keyframes = 30, | |
// lastKeyframe = 0, | |
// currentKeyframe = 0, | |
// interpolation = duration / keyframes; | |
function render() { | |
if (model) { | |
var delta = clock.getDelta(); | |
model.updateAnimation(700 * delta); | |
//if (model.morphTargetInfluences) { | |
// // Alternate morph targets | |
// var time = Date.now() % duration; | |
// var keyframe = Math.floor(time / interpolation); | |
// if (keyframe != currentKeyframe) { | |
// model.morphTargetInfluences[lastKeyframe] = 0; | |
// model.morphTargetInfluences[currentKeyframe] = 1; | |
// model.morphTargetInfluences[keyframe] = 0; | |
// lastKeyframe = currentKeyframe; | |
// currentKeyframe = keyframe; | |
// } | |
// model.morphTargetInfluences[keyframe] = (time % interpolation) / interpolation; | |
// model.morphTargetInfluences[lastKeyframe] = 1 - model.morphTargetInfluences[keyframe]; | |
//} | |
} | |
renderer.clear(); | |
renderer.render(sceneCube, cameraCube); | |
renderer.render(scene, camera); | |
var distance = player.camera.distance, | |
position = player.position; | |
model.position.x = player.position.x; | |
model.position.y = player.position.y; | |
model.position.z = player.position.z; | |
//カメラのpositionを決める | |
camera.position.x = position.x + distance * Math.sin((player.camera.x) * Math.PI / 180); | |
camera.position.z = position.z + distance * Math.cos((player.camera.x) * Math.PI / 180); | |
camera.position.y = position.y + distance * Math.sin((player.camera.y) * Math.PI / 360); | |
camera.position.y += 1; | |
var vec3 = new THREE.Vector3(player.position.x, player.position.y + 100, player.position.z); | |
camera.lookAt(vec3); | |
} | |
var moveState = { | |
moving : false, | |
front : false, | |
Backwards : false, | |
left : false, | |
right : false, | |
speed : .1, | |
angle : 0 | |
}; | |
var pointer = {x: 0, y: 0}; | |
doc.addEventListener('mousemove', function (e) { | |
var mouseX = e.clientX, | |
mouseY = e.clientY; | |
pointer.x = (mouseX / renderer.domElement.width) * 2 - 1; | |
pointer.y = -(mouseY / renderer.domElement.height) * 2 + 1; | |
}, false); | |
var oldPointerX = 0, | |
oldPointerY = 0; | |
function rotateStart() { | |
oldPointerX = pointer.x; | |
oldPointerY = pointer.y; | |
renderer.domElement.addEventListener('mousemove', rotate, false); | |
renderer.domElement.addEventListener('mouseup', rotateStop, false); | |
} | |
function rotateStop() { | |
renderer.domElement.removeEventListener('mousemove', rotate, false); | |
renderer.domElement.removeEventListener('mouseup', rotateStop, false); | |
} | |
function rotate() { | |
player.camera.x += (oldPointerX - pointer.x) * player.camera.speed; | |
player.camera.y += (oldPointerY - pointer.y) * player.camera.speed; | |
if (player.camera.y > 150) { | |
player.camera.y = 150; | |
} | |
if (player.camera.y < -150) { | |
player.camera.y = -150; | |
} | |
moveState.angle = player.camera.x % 360; | |
oldPointerX = pointer.x; | |
oldPointerY = pointer.y; | |
} | |
doc.addEventListener('mousedown', rotateStart, false); | |
doc.addEventListener('mousewheel', function (e) { | |
player.camera.distance += e.wheelDelta / 100; | |
}, false); | |
doc.addEventListener('DOMMouseScroll', function (e) { | |
player.camera.distance += e.detail / 10; | |
}, false); | |
//A = left, S = back, D = right, W = front | |
var A = 65, S = 83, D = 68, W = 87, sp = 0; | |
function move(e) { | |
if (!new RegExp(A + '|' + S + '|' + D + '|' + W).test(e.keyCode)) { | |
return; | |
} | |
if (e.shiftKey) { | |
setAction('run'); | |
} | |
else { | |
setAction('walk'); | |
} | |
var direction = moveState.angle; | |
switch (e.keyCode) { | |
case A: | |
direction += 270; | |
break; | |
case S: | |
direction += 0; | |
break; | |
case D: | |
direction += 90; | |
break; | |
case W: | |
direction += 180; | |
break; | |
} | |
model.rotation.y = direction * Math.PI / 180; | |
player.position.x += Math.sin(direction * Math.PI / 180) * sp; | |
player.position.z += Math.cos(direction * Math.PI / 180) * sp; | |
} | |
doc.addEventListener('keydown', move, false); | |
function setAction(actionName) { | |
var action = modelFrames[actionName]; | |
if (!action || !model) { | |
return; | |
} | |
model.setFrameRange(action[0], action[1]); | |
sp = action[2]; | |
} | |
doc.addEventListener('keyup', function () { | |
setAction('stand'); | |
}, false); | |
// | |
doc.addEventListener('DOMContentLoaded', init, false); | |
}(window, document)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment