<!DOCTYPE html> <html lang="en"> <head> <title>three.js webgl - morphtargets - MD2 controls</title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> <style> body { color: #000; font-family:Monospace; font-size:13px; text-align:center; font-weight: bold; background-color: #fff; margin: 0px; overflow: hidden; } #info { color:#000; position: relative; margin: 0 auto -2.1em; top: 0px; padding: 5px; z-index:100; } a { color: skyblue; } #stats { position: absolute; top:0; left: 0 } #stats #fps { background: transparent !important } #stats #fps #fpsText { color: #aaa !important } #stats #fps #fpsGraph { display: none } </style> </head> <body> <div id="info"> <a href="http://threejs.org" target="_blank">three.js</a> - morphtargets - Ogro by <a href="http://planetquake.gamespy.com/View.php?view=Quake2.Detail&id=556">Magarnigal</a> - converted by <a href="https://twitter.com/#!/oosmoxiecode">@oosmoxiecode</a>'s <a href="http://oos.moxiecode.com/blog/2012/01/md2-to-json-converter/">MD2 converter</a> - use arrows to control characters, mouse for camera </div> <script src="../build/three.min.js"></script> <script src="js/controls/OrbitControls.js"></script> <script src='js/MD2CharacterComplex.js'></script> <script src='js/Detector.js'></script> <script src='js/libs/stats.min.js'></script> <script> if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); var SCREEN_WIDTH = window.innerWidth; var SCREEN_HEIGHT = window.innerHeight; var container, camera, scene, renderer; var characters = []; var nCharacters = 0; var cameraControls; var controls = { moveForward: false, moveBackward: false, moveLeft: false, moveRight: false }; var clock = new THREE.Clock(); init(); animate(); function init() { container = document.createElement( 'div' ); document.body.appendChild( container ); // CAMERA camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 4000 ); camera.position.set( 0, 150, 1300 ); // SCENE scene = new THREE.Scene(); scene.fog = new THREE.Fog( 0xffffff, 1000, 4000 ); scene.add( camera ); // LIGHTS scene.add( new THREE.AmbientLight( 0x222222 ) ); var light = new THREE.DirectionalLight( 0xffffff, 2.25 ); light.position.set( 200, 450, 500 ); light.castShadow = true; light.shadowMapWidth = 1024; light.shadowMapHeight = 1024; light.shadowMapDarkness = 0.95; // by turning on the frustum, you can see where the light's // shadow volume is located: //light.shadowCameraVisible = true; light.shadowCameraNear = 100; light.shadowCameraFar = 1200; light.shadowCameraTop = 400; light.shadowCameraBottom = -250; light.shadowCameraRight = 900; light.shadowCameraLeft = -1000; // cascaded shadows don't appear to be working, and add little // light.shadowCascade = true; //light.shadowCascadeCount = 3; //light.shadowCascadeNearZ = [ -1.000, 0.995, 0.998 ]; //light.shadowCascadeFarZ = [ 0.995, 0.998, 1.000 ]; //light.shadowCascadeWidth = [ 1024, 1024, 1024 ]; //light.shadowCascadeHeight = [ 1024, 1024, 1024 ]; scene.add( light ); // GROUND var gt = THREE.ImageUtils.loadTexture( "textures/terrain/grasslight-big.jpg" ); var gg = new THREE.PlaneBufferGeometry( 16000, 16000 ); var gm = new THREE.MeshPhongMaterial( { color: 0xffffff, map: gt } ); var ground = new THREE.Mesh( gg, gm ); ground.rotation.x = - Math.PI / 2; ground.material.map.repeat.set( 64, 64 ); ground.material.map.wrapS = ground.material.map.wrapT = THREE.RepeatWrapping; // note that because the ground does not cast a shadow, .castShadow is left false ground.receiveShadow = true; scene.add( ground ); // RENDERER renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setClearColor( scene.fog.color ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); container.appendChild( renderer.domElement ); // renderer.gammaInput = true; renderer.gammaOutput = true; renderer.shadowMapEnabled = true; //renderer.shadowMapCascade = true; //renderer.shadowMapType = THREE.PCFSoftShadowMap; //renderer.shadowMapDebug = true; // STATS stats = new Stats(); container.appendChild( stats.domElement ); // EVENTS window.addEventListener( 'resize', onWindowResize, false ); document.addEventListener( 'keydown', onKeyDown, false ); document.addEventListener( 'keyup', onKeyUp, false ); // CONTROLS cameraControls = new THREE.OrbitControls( camera, renderer.domElement ); cameraControls.target.set( 0, 50, 0 ); // CHARACTER var configOgro = { baseUrl: "models/animated/ogro/", body: "ogro-light.js", skins: [ "grok.jpg", "ogrobase.png", "arboshak.png", "ctf_r.png", "ctf_b.png", "darkam.png", "freedom.png", "gib.png", "gordogh.png", "igdosh.png", "khorne.png", "nabogro.png", "sharokh.png" ], weapons: [ [ "weapon-light.js", "weapon.jpg" ] ], animations: { move: "run", idle: "stand", jump: "jump", attack: "attack", crouchMove: "cwalk", crouchIdle: "cstand", crouchAttach: "crattack" }, walkSpeed: 350, crouchSpeed: 175 }; var nRows = 1; var nSkins = configOgro.skins.length; nCharacters = nSkins * nRows; for ( var i = 0; i < nCharacters; i ++ ) { var character = new THREE.MD2CharacterComplex(); character.scale = 3; character.controls = controls; characters.push( character ); } var baseCharacter = new THREE.MD2CharacterComplex(); baseCharacter.scale = 3; baseCharacter.onLoadComplete = function () { var k = 0; for ( var j = 0; j < nRows; j ++ ) { for ( var i = 0; i < nSkins; i ++ ) { var cloneCharacter = characters[ k ]; cloneCharacter.shareParts( baseCharacter ); // cast and receive shadows cloneCharacter.enableShadows( true ); cloneCharacter.setWeapon( 0 ); cloneCharacter.setSkin( i ); cloneCharacter.root.position.x = ( i - nSkins/2 ) * 150; cloneCharacter.root.position.z = j * 250; scene.add( cloneCharacter.root ); k ++; } } var gyro = new THREE.Gyroscope(); gyro.add( camera ); characters[ Math.floor( nSkins/2 ) ].root.add( gyro ); }; baseCharacter.loadParts( configOgro ); } // EVENT HANDLERS function onWindowResize( event ) { SCREEN_WIDTH = window.innerWidth; SCREEN_HEIGHT = window.innerHeight; renderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); camera.aspect = SCREEN_WIDTH/ SCREEN_HEIGHT; camera.updateProjectionMatrix(); } function onKeyDown ( event ) { switch( event.keyCode ) { case 38: /*up*/ case 87: /*W*/ controls.moveForward = true; break; case 40: /*down*/ case 83: /*S*/ controls.moveBackward = true; break; case 37: /*left*/ case 65: /*A*/ controls.moveLeft = true; break; case 39: /*right*/ case 68: /*D*/ controls.moveRight = true; break; //case 67: /*C*/ controls.crouch = true; break; //case 32: /*space*/ controls.jump = true; break; //case 17: /*ctrl*/ controls.attack = true; break; } }; function onKeyUp ( event ) { switch( event.keyCode ) { case 38: /*up*/ case 87: /*W*/ controls.moveForward = false; break; case 40: /*down*/ case 83: /*S*/ controls.moveBackward = false; break; case 37: /*left*/ case 65: /*A*/ controls.moveLeft = false; break; case 39: /*right*/ case 68: /*D*/ controls.moveRight = false; break; //case 67: /*C*/ controls.crouch = false; break; //case 32: /*space*/ controls.jump = false; break; //case 17: /*ctrl*/ controls.attack = false; break; } }; // function animate() { requestAnimationFrame( animate ); render(); stats.update(); } function render() { var delta = clock.getDelta(); cameraControls.update( delta ); for ( var i = 0; i < nCharacters; i ++ ) { characters[ i ].update( delta ); } renderer.render( scene, camera ); } </script> </body> </html>