<!DOCTYPE HTML> <html lang="en"> <head> <title>three.js webgl - deferred rendering [morphing + skinning]</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 { background-color: #000; margin: 0px; overflow: hidden; } #info { position: absolute; top: 20px; width: 100%; color: #ffffff; padding: 5px; font-family: Monospace; font-size: 13px; text-align: center; } a { color: #ff0080; text-decoration: none; } a:hover { color: #0080ff; } #stats { position: absolute; top:10px; left: 5px } #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> - webgl deferred rendering with morphing and skinning animations - characters from <a href="http://www.sintel.org/">Sintel</a> and by <a href="http://opengameart.org/content/walk-cycles">Clint Bellanger</a> </div> <div id="container"></div> <script src="js/libs/stats.min.js"></script> <script src="../build/three.min.js"></script> <script src="js/Detector.js"></script> <script src="js/renderers/WebGLDeferredRenderer.js"></script> <script src="js/ShaderDeferred.js"></script> <script src="js/shaders/CopyShader.js"></script> <script src="js/shaders/FXAAShader.js"></script> <script src="js/postprocessing/EffectComposer.js"></script> <script src="js/postprocessing/RenderPass.js"></script> <script src="js/postprocessing/ShaderPass.js"></script> <script src="js/postprocessing/MaskPass.js"></script> <script> if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); var SCALE = 0.75; var WIDTH = window.innerWidth; var HEIGHT = window.innerHeight; var NEAR = 1.0, FAR = 350.0; var VIEW_ANGLE = 45; // controls var mouseX = 0; var mouseY = 0; var targetX = 0, targetY = 0; var angle = 0; var target = new THREE.Vector3( 0, 0, 0 ); var windowHalfX = window.innerWidth / 2; var windowHalfY = window.innerHeight / 2; // core var renderer, camera, scene, controls, stats, clock; // lights var numLights = 50; var lights = []; // morphs var morphs = []; // skins var skins = []; // init(); animate(); // ----------------------------- function init() { // renderer renderer = new THREE.WebGLDeferredRenderer( { width: WIDTH, height: HEIGHT, scale: SCALE, brightness: 2, antialias: true } ); var container = document.getElementById( 'container' ); container.appendChild( renderer.domElement ); // camera camera = new THREE.PerspectiveCamera( VIEW_ANGLE, WIDTH / HEIGHT, NEAR, FAR ); camera.position.z = 150; // scene scene = new THREE.Scene(); scene.add( camera ); // stats stats = new Stats(); stats.domElement.style.position = 'absolute'; stats.domElement.style.top = '8px'; stats.domElement.style.zIndex = 100; container.appendChild( stats.domElement ); // clock clock = new THREE.Clock(); // add lights initLights(); // add objects initObjects(); // events document.addEventListener( 'mousemove', onDocumentMouseMove, false ); window.addEventListener( 'resize', onWindowResize, false ); } // ----------------------------- function initLights() { var distance = 40; // front light var light = new THREE.PointLight( 0xffffff, 1.5, 1.5 * distance ); scene.add( light ); lights.push( light ); // random lights var c = new THREE.Vector3(); for ( var i = 1; i < numLights; i ++ ) { var light = new THREE.PointLight( 0xffffff, 2.0, distance ); c.set( Math.random(), Math.random(), Math.random() ).normalize(); light.color.setRGB( c.x, c.y, c.z ); scene.add( light ); lights.push( light ); } var geometry = new THREE.SphereGeometry( 0.7, 7, 7 ); for ( var i = 0; i < numLights; i ++ ) { var light = lights[ i ]; var material = new THREE.MeshBasicMaterial(); material.color = light.color; var emitter = new THREE.Mesh( geometry, material ); light.add( emitter ); } } function ensureLoop( animation ) { for ( var i = 0; i < animation.hierarchy.length; i ++ ) { var bone = animation.hierarchy[ i ]; var first = bone.keys[ 0 ]; var last = bone.keys[ bone.keys.length - 1 ]; last.pos = first.pos; last.rot = first.rot; last.scl = first.scl; } } function initObjects() { // add animated model var loader = new THREE.JSONLoader(); loader.load( "models/animated/elderlyWalk.js", function( geometry ) { geometry.computeMorphNormals(); var material = new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x333333, shininess: 20, wrapAround: true, morphTargets: true, morphNormals: true, vertexColors: THREE.NoColors, shading: THREE.FlatShading } ); var meshAnim = new THREE.MorphAnimMesh( geometry, material ); meshAnim.duration = 3000; meshAnim.userData.delta = -13; meshAnim.scale.multiplyScalar( 50 ); meshAnim.position.set( 180, -48, -10 ); meshAnim.rotation.y = -Math.PI/2; scene.add( meshAnim ); morphs.push( meshAnim ); } ); loader.load( "models/skinned/human_walk_0_female.js", function ( geometry, materials ) { geometry.computeVertexNormals(); geometry.computeBoundingBox(); ensureLoop( geometry.animation ); for ( var i = 0, il = materials.length; i < il; i ++ ) { var originalMaterial = materials[ i ]; originalMaterial.skinning = true; originalMaterial.map = undefined; originalMaterial.shading = THREE.SmoothShading; originalMaterial.color.setHSL( 0.01, 0.3, 0.3 ); originalMaterial.specular.setHSL( 0, 0, 0.1 ); originalMaterial.shininess = 75; originalMaterial.wrapAround = true; originalMaterial.wrapRGB.set( 1, 0.5, 0.5 ); } var s = 18.5; var material = new THREE.MeshFaceMaterial( materials ); var mesh = new THREE.SkinnedMesh( geometry, material, false ); mesh.scale.set( s, s, s ); mesh.rotation.y = Math.PI/2; mesh.position.x = -100; mesh.position.y = -geometry.boundingBox.min.y * s - 48; mesh.position.z = 18; mesh.userData.delta = 25; scene.add( mesh ); skins.push( mesh ); animation = new THREE.Animation( mesh, geometry.animation ); animation.play(); animation.update( 0 ); } ); // add box var box = generateBox(); box.scale.multiplyScalar( 8 ); scene.add( box ); } // ----------------------------- function generateBox() { var object = new THREE.Object3D(); var mapHeight2 = THREE.ImageUtils.loadTexture( "obj/lightmap/rocks.jpg" ); mapHeight2.repeat.set( 3, 1.5 ); mapHeight2.wrapS = mapHeight2.wrapT = THREE.RepeatWrapping; mapHeight2.anisotropy = 4; mapHeight2.format = THREE.RGBFormat; var mapHeight3 = THREE.ImageUtils.loadTexture( "textures/water.jpg" ); mapHeight3.repeat.set( 16, 8 ); mapHeight3.wrapS = mapHeight3.wrapT = THREE.RepeatWrapping; mapHeight3.anisotropy = 4; mapHeight3.format = THREE.RGBFormat; var geoPlane = new THREE.PlaneBufferGeometry( 40, 20 ); var matPlaneSide = new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x222222, shininess: 75, bumpMap: mapHeight2, bumpScale: 0.5 } ); var matPlaneBottom = new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x222222, shininess: 75, bumpMap: mapHeight3, bumpScale: 0.5 } ); var matPlaneTop = new THREE.MeshPhongMaterial( { color: 0x000000, specular: 0x222222, shininess: 75, bumpMap: mapHeight3, bumpScale: 1 } ); // bottom var mesh = new THREE.Mesh( geoPlane, matPlaneBottom ); mesh.position.z = -2; mesh.position.y = -6; mesh.rotation.x = -Math.PI/2; object.add( mesh ); // top var mesh = new THREE.Mesh( geoPlane, matPlaneTop ); mesh.position.z = -2; mesh.position.y = 7; mesh.rotation.x = Math.PI/2; object.add( mesh ); // back var mesh = new THREE.Mesh( geoPlane, matPlaneSide ); mesh.position.z = -4; mesh.position.y = 0; object.add( mesh ); // right var mesh = new THREE.Mesh( geoPlane, matPlaneSide ); mesh.position.z = 0; mesh.position.y = 0; mesh.position.x = 13; mesh.rotation.y = -Math.PI/2; //object.add( mesh ); // left var mesh = new THREE.Mesh( geoPlane, matPlaneSide ); mesh.position.z = 0; mesh.position.y = 0; mesh.position.x = -13; mesh.rotation.y = Math.PI/2; //object.add( mesh ); return object; } // ----------------------------- function onWindowResize( event ) { windowHalfX = window.innerWidth / 2; windowHalfY = window.innerHeight / 2; WIDTH = window.innerWidth; HEIGHT = window.innerHeight - 2 * MARGIN; renderer.setSize( WIDTH, HEIGHT ); camera.aspect = WIDTH / HEIGHT; camera.updateProjectionMatrix(); } function onDocumentMouseMove( event ) { mouseX = ( event.clientX - windowHalfX ) * 1; mouseY = ( event.clientY - windowHalfY ) * 1; } // ----------------------------- function animate() { requestAnimationFrame( animate ); render(); stats.update(); } function render() { var delta = clock.getDelta(); var time = Date.now() * 0.0005; // update lights var x, y, z; for ( var i = 0, il = lights.length; i < il; i ++ ) { var light = lights[ i ]; if ( i > 0 ) { x = Math.sin( time + i * 1.7 ) * 80; y = Math.cos( time + i * 1.5 ) * 40; z = Math.cos( time + i * 1.3 ) * 30; } else { x = Math.sin( time * 3 ) * 20; y = 15; z = Math.cos( time * 3 ) * 25 + 10; } light.position.set( x, y, z ); } // update morphs for ( var i = 0; i < morphs.length; i ++ ) { var morph = morphs[ i ]; morph.updateAnimation( 1000 * delta ); morph.position.x += morph.userData.delta * delta; if ( morph.position.x < -50 ) morph.position.x = 200; } // update skins THREE.AnimationHandler.update( 0.4 * delta ); for ( var i = 0; i < skins.length; i ++ ) { var skin = skins[ i ]; skin.position.x += skin.userData.delta * delta; if ( skin.position.x > 200 ) skin.position.x = -200; } // update controls targetX = mouseX * .001; targetY = mouseY * .001; angle += 0.05 * ( targetX - angle ); camera.position.x = -Math.sin( angle ) * 150; camera.position.z = Math.cos( angle ) * 150; camera.lookAt( target ); // render renderer.render( scene, camera ); } </script> </body> </html>