1(function(){ 2 // 3D PERSON ------------ 3 // Set our main variables 4 let scene, 5 renderer, 6 camera, 7 model, // Our character 8 neck, // Reference to the neck bone in the skeleton 9 waist, // Reference to the waist bone in the skeleton 10 possibleAnims, // Animations found in our file 11 mixer, // THREE.js animations mixer 12 idle, // Idle, the default state our character returns to 13 clock = new THREE.Clock(), // Used for anims, which run to a clock instead of frame rate 14 currentlyAnimating = false, // Used to check whether characters neck is being used in another anim 15 raycaster = new THREE.Raycaster(), // Used to detect the click on our character 16 loaderAnim = document.getElementById('js-loader'); 17 18 init(); 19 20 function init() { 21 const MODEL_PATH = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/1376484/stacy_lightweight.glb'; 22 23 const canvas = document.querySelector('#c'); 24 const backgroundColor = 0x00000000; 25 26 // Init the scene 27 scene = new THREE.Scene(); 28 // scene.background = new THREE.Color(backgroundColor); 29 // scene.fog = new THREE.Fog(backgroundColor, 60, 100); 30 31 // Init the renderer 32 renderer = new THREE.WebGLRenderer({ canvas, antialias: true }); 33 renderer.shadowMap.enabled = true; 34 renderer.setPixelRatio(devicePixelRatio); 35 document.body.appendChild(renderer.domElement); 36 37 // Add a camera 38 camera = new THREE.PerspectiveCamera( 39 50, 40 innerWidth / innerHeight, 41 0.1, 42 1000 43 ); 44 camera.position.z = 30 45 camera.position.x = 0; 46 camera.position.y = -3; 47 48 let stacy_txt = new THREE.TextureLoader().load('https://fantasticfullstackdev.github.io/jinwangdev/assets/images/stacy.jpg'); 49 50 stacy_txt.flipY = false; // we flip the texture so that its the right way up 51 52 const stacy_mtl = new THREE.MeshPhongMaterial({ 53 map: stacy_txt, 54 color: 0xffffff, 55 skinning: true 56 }); 57 var loader = new THREE.GLTFLoader(); 58 loader.setCrossOrigin('Access-Control-Allow-Origin'); 59 loader.load( 60 MODEL_PATH, 61 function(gltf) { 62 // A lot is going to happen here 63 model = gltf.scene; 64 let fileAnimations = gltf.animations; 65 model.traverse(o => { 66 if (o.isMesh) { 67 o.castShadow = true; 68 o.receiveShadow = true; 69 o.material = stacy_mtl; // Add this line 70 } 71 72 73 // Reference the neck and waist bones 74 if (o.isBone && o.name === 'mixamorigNeck') { 75 neck = o; 76 } 77 if (o.isBone && o.name === 'mixamorigSpine') { 78 waist = o; 79 } 80 }); 81 82 83 // Set the models initial scale 84 model.scale.set(10, 10, 7); 85 86 model.position.y = -14 87 88 89 scene.add(model); 90 loaderAnim.remove(); 91 92 mixer = new THREE.AnimationMixer(model); 93 let clips = fileAnimations.filter(val => val.name !== 'idle'); 94 possibleAnims = clips.map(val => { 95 let clip = THREE.AnimationClip.findByName(clips, val.name); 96 clip.tracks.splice(3, 3); 97 clip.tracks.splice(9, 3); 98 clip = mixer.clipAction(clip); 99 return clip; 100 }); 101 102 let idleAnim = THREE.AnimationClip.findByName(fileAnimations, 'idle'); 103 idleAnim.tracks.splice(3, 3); 104 idleAnim.tracks.splice(9, 3); 105 idle = mixer.clipAction(idleAnim); 106 idle.play(); 107 108 }, 109 undefined, // We don't need this function 110 function(error) { 111 console.error(error); 112 } 113 ); 114 115 // Add lights 116 let hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.61); 117 hemiLight.position.set(0, 50, 0); 118 // Add hemisphere light to scene 119 scene.add(hemiLight); 120 121 let d = 8.25; 122 let dirLight = new THREE.DirectionalLight(0xffffff, 0.54); 123 dirLight.position.set(-8, 12, 8); 124 dirLight.castShadow = true; 125 dirLight.shadow.mapSize = new THREE.Vector2(1024, 1024); 126 dirLight.shadow.camera.near = 0.1; 127 dirLight.shadow.camera.far = 1500; 128 dirLight.shadow.camera.left = d * -1; 129 dirLight.shadow.camera.right = d; 130 dirLight.shadow.camera.top = d; 131 dirLight.shadow.camera.bottom = d * -1; 132 // Add directional Light to scene 133 scene.add(dirLight); 134 135 // Floor 136 // let floorGeometry = new THREE.PlaneGeometry(5000, 5000, 1, 1); 137 // let floorMaterial = new THREE.MeshPhongMaterial({ 138 // color: 0xeeeeee, 139 // shininess: 0, 140 // }); 141 142 // let floor = new THREE.Mesh(floorGeometry, floorMaterial); 143 // floor.rotation.x = -0.5 * Math.PI; // This is 90 degrees by the way 144 // floor.receiveShadow = true; 145 // floor.position.y = -11; 146 // scene.add(floor); 147 148 149 // let geometry = new THREE.SphereGeometry(8, 32, 32); 150 // let material = new THREE.MeshBasicMaterial({ color: 0x9bffaf }); // 0xf2ce2e 151 // let sphere = new THREE.Mesh(geometry, material); 152 // sphere.position.z = -15; 153 // sphere.position.y = -2.5; 154 // sphere.position.x = -0.25; 155 // scene.add(sphere); 156 } 157
158 function update() { 159 160 if (mixer) { 161 mixer.update(clock.getDelta()); 162 } 163 if (resizeRendererToDisplaySize(renderer)) { 164 const canvas = renderer.domElement; 165 camera.aspect = canvas.clientWidth / canvas.clientHeight; 166 camera.updateProjectionMatrix(); 167 } 168 renderer.render(scene, camera); 169 requestAnimationFrame(update); 170 } 171 update(); 172 173 function resizeRendererToDisplaySize(renderer) { 174 const canvas = renderer.domElement; 175 let width = innerWidth; 176 let height = innerHeight; 177 let canvasPixelWidth = canvas.width / devicePixelRatio; 178 let canvasPixelHeight = canvas.height / devicePixelRatio; 179 180 const needResize = 181 canvasPixelWidth !== width || canvasPixelHeight !== height; 182 if (needResize) { 183 renderer.setSize(width, height, false); 184 } 185 return needResize; 186 } 187 188 addEventListener('click', e => raycast(e)); 189 addEventListener('touchend', e => raycast(e, true)); 190 191 function raycast(e, touch = false) { 192 var mouse = {}; 193 if (touch) { 194 mouse.x = 2 * (e.changedTouches[0].clientX / innerWidth) - 1; 195 mouse.y = 1 - 2 * (e.changedTouches[0].clientY / innerHeight); 196 } else { 197 mouse.x = 2 * (e.clientX / innerWidth) - 1; 198 mouse.y = 1 - 2 * (e.clientY / innerHeight); 199 } 200 // update the picking ray with the camera and mouse position 201 raycaster.setFromCamera(mouse, camera); 202 203 // calculate objects intersecting the picking ray 204 var intersects = raycaster.intersectObjects(scene.children, true); 205 206 if (intersects[0]) { 207 var object = intersects[0].object; 208 209 if (object.name === 'stacy') { 210 211 if (!currentlyAnimating) { 212 currentlyAnimating = true; 213 playOnClick(); 214 } 215 } 216 } 217 } 218 219 // Get a random animation, and play it 220 function playOnClick() { 221 let anim = Math.floor(Math.random() * possibleAnims.length) + 0; 222 playModifierAnimation(idle, 0.25, possibleAnims[anim], 0.25); 223 } 224 225 function playOnScroll(name) { 226 const anims = ['pocket', 'rope', 'swingdance', 'jump', 'react', 'shrug', 'wave', 'golf', 'idle']; 227 let anim = anims.indexOf(name); 228 playModifierAnimation(idle, 0.25, possibleAnims[anim], 0.25); 229 } 230 231 function playModifierAnimation(from, fSpeed, to, tSpeed) { 232 to.setLoop(THREE.LoopOnce); 233 to.reset(); 234 to.play(); 235 from.crossFadeTo(to, fSpeed, true); 236 setTimeout(function() { 237 from.enabled = true; 238 to.crossFadeTo(from, tSpeed, true); 239 currentlyAnimating = false; 240 }, to._clip.duration * 1000 - ((tSpeed + fSpeed) * 1000)); 241 } 242 243 document.addEventListener('mousemove', function(e) { 244 var mousecoords = getMousePos(e); 245 if (neck && waist) { 246 moveJoint(mousecoords, neck, 50); 247 moveJoint(mousecoords, waist, 30); 248 } 249 }); 250 251 function getMousePos(e) { 252 return { x: e.clientX, y: e.clientY }; 253 } 254 255 document.addEventListener('mousemove', function(e) { 256 var mousecoords = getMousePos(e); 257 if (neck && waist) { 258 259 moveJoint(mousecoords, neck, 50); 260 moveJoint(mousecoords, waist, 30); 261 } 262 }); 263 264 function getMousePos(e) { 265 return { x: e.clientX, y: e.clientY }; 266 } 267 268 function moveJoint(mouse, joint, degreeLimit) { 269 let degrees = getMouseDegrees(mouse.x, mouse.y, degreeLimit); 270 joint.rotation.y = THREE.Math.degToRad(degrees.x); 271 joint.rotation.x = THREE.Math.degToRad(degrees.y); 272 // console.log(joint.rotation.x); 273 } 274 275 function getMouseDegrees(x, y, degreeLimit) { 276 let dx = 0, 277 dy = 0, 278 xdiff, 279 xPercentage, 280 ydiff, 281 yPercentage; 282
283 let w = { x: innerWidth, y: innerHeight }; 284 285 // Left (Rotates neck left between 0 and -degreeLimit) 286 // 1. If cursor is in the left half of screen 287 if (x <= w.x / 2) { 288 // 2. Get the difference between middle of screen and cursor position 289 xdiff = w.x / 2 - x; 290 // 3. Find the percentage of that difference (percentage toward edge of screen) 291 xPercentage = (xdiff / (w.x / 2)) * 100; 292 // 4. Convert that to a percentage of the maximum rotation we allow for the neck 293 dx = ((degreeLimit * xPercentage) / 100) * -1; 294 } 295 296 // Right (Rotates neck right between 0 and degreeLimit) 297 if (x >= w.x / 2) { 298 xdiff = x - w.x / 2; 299 xPercentage = (xdiff / (w.x / 2)) * 100; 300 dx = (degreeLimit * xPercentage) / 100; 301 } 302 // Up (Rotates neck up between 0 and -degreeLimit) 303 if (y <= w.y / 2) { 304 ydiff = w.y / 2 - y; 305 yPercentage = (ydiff / (w.y / 2)) * 100; 306 // Note that I cut degreeLimit in half when she looks up 307 dy = (((degreeLimit * 0.5) * yPercentage) / 100) * -1; 308 } 309 // Down (Rotates neck down between 0 and degreeLimit) 310 if (y >= w.y / 2) { 311 ydiff = y - w.y / 2; 312 yPercentage = (ydiff / (w.y / 2)) * 100; 313 dy = (degreeLimit * yPercentage) / 100; 314 } 315 return { x: dx, y: dy }; 316 } 317 318 function makeAnimation (num) { 319 console.log(num); 320 const anims = ['wave', 'shrug', 'rope', 'pocket', 'jump', 'golf', 'swingdance', 'react', 'wave']; 321 if (!currentlyAnimating) { 322 currentlyAnimating = true; 323 playOnScroll(anims[num]); 324 } 325 } 326 327 $(window).scroll(function(e){ 328 var value = $(window).scrollTop(); 329 if(value % 1100 < 50) { 330 makeAnimation(Math.floor(value / 1100)); 331 } 332 }); 333})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.