Last active
December 14, 2016 02:53
-
-
Save shshaw/15ecb75c79b4cee0d6f74b7aadeb86a8 to your computer and use it in GitHub Desktop.
Space Joyride π+β+πΉ (#3December - Day 13)
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 class="controls">Thrust with <key>W</key>, click or touch. Steer with <key>left</key>/<key>right</key>, <key>A</key>/<key>D</key>, mouse or touch.</div> | |
<script id="vertexShader" type="x-shader/x-vertex"> | |
varying vec3 vNormal; | |
void main() | |
{ | |
vNormal = normalize( normalMatrix * normal ); | |
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); | |
} | |
</script> | |
<script id="fragmentShader" type="x-shader/x-vertex"> | |
varying vec3 vNormal; | |
void main() | |
{ | |
float intensity = pow( 0.6 - dot( vNormal, vec3( 0.0, 0.0, 1.0 ) ), 4.0 ); | |
gl_FragColor = vec4( 1.0, 1.0, 0.5, 0.9 ) * intensity; | |
} | |
</script> |
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
console.clear(); | |
var renderCalls = []; | |
function render () { | |
requestAnimationFrame( render ); | |
renderCalls.forEach((callback)=>{ callback(); }); | |
} | |
render(); | |
/*////////////////////////////////////////*/ | |
var keys = []; | |
document.body.addEventListener("keydown", function(e) { | |
keys[e.keyCode] = true; | |
e.preventDefault(); | |
}); | |
document.body.addEventListener("keyup", function(e) { | |
keys[e.keyCode] = false; | |
e.preventDefault(); | |
}); | |
/*////////////////////////////////////////*/ | |
var pointer = { | |
down: false, | |
x: 0, | |
y: 0, | |
onDown: function(e){ | |
pointer.down = true; | |
pointerMove(e); | |
}, | |
onUp: function(e){ | |
pointer.down = false; | |
pointerMove(e); | |
} | |
}; | |
document.addEventListener('mousedown', pointer.onDown); | |
document.addEventListener('touchstart', pointer.onDown); | |
document.addEventListener('mouseup', pointer.onUp); | |
document.addEventListener('touchend', pointer.onUp); | |
document.addEventListener('mousemove', pointerMove); | |
document.addEventListener('touchmove', pointerMove); | |
function pointerMove(e){ | |
let pos = e.touches ? e.touches[0] : e; | |
pointer.x = pos.clientX / window.innerWidth; | |
pointer.y = pos.clientY / window.innerWidth; | |
}; | |
/*////////////////////////////////////////*/ | |
var scene, renderer, orbit, light; | |
/*////////////////////////////////////////*/ | |
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 10, 3000 ); | |
camera.position.z = 600; | |
/*////////////////////////////////////////*/ | |
scene = new THREE.Scene(); | |
//scene.fog = new THREE.FogExp2( 0x000000, 0.0005);//new THREE.Fog(0xEEEEEE, 20, 600); | |
renderer = new THREE.WebGLRenderer( { antialias: true } ); | |
renderer.setPixelRatio( window.devicePixelRatio ); | |
renderer.setSize( window.innerWidth, window.innerHeight ); | |
renderer.setClearColor( 0x060712 ); | |
renderer.toneMapping = THREE.LinearToneMapping; | |
renderer.toneMappingExposure = Math.pow( 0.91, 5.0 ); | |
if ( window.innerWidth > 500 ) { | |
renderer.shadowMap.enabled = true; | |
renderer.shadowMap.type = THREE.PCFSoftShadowMap; | |
} | |
window.addEventListener( 'resize', function () { | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize( window.innerWidth, window.innerHeight ); | |
}, false ); | |
document.body.appendChild( renderer.domElement); | |
renderCalls.push(function(){ renderer.render( scene, camera ); }); | |
/*////////////////////////////////////////*/ | |
var ambientLight = new THREE.AmbientLight(0x222222); | |
scene.add(ambientLight); | |
var hemiLight = new THREE.HemisphereLight( 0xEBF7FD, 0xFFF7EB, 0.3 ); | |
//hemiLight.color.setRGB(0.75,0.8,0.95); | |
hemiLight.position.set( 0, 100, 0 ); | |
scene.add( hemiLight ); | |
/*////////////////////////////////////////*/ | |
function makeSun(){ | |
var geometry = new THREE.SphereGeometry( 80, 24, 8 ); | |
var customMaterial = new THREE.ShaderMaterial({ | |
uniforms: { }, | |
vertexShader: document.getElementById( 'vertexShader' ).textContent, | |
fragmentShader: document.getElementById( 'fragmentShader' ).textContent, | |
side: THREE.BackSide, | |
blending: THREE.AdditiveBlending, | |
transparent: true | |
}); | |
let sun = new THREE.Mesh( geometry, customMaterial ); | |
let light = new THREE.PointLight( 0xffffaa, 1 ); | |
light.power = 20; | |
//light.position.y = 400; | |
sun.add( light ); | |
let light2 = new THREE.PointLight( 0xffffaa, 1 ); | |
light2.power = 20; | |
sun.add( light2 ); | |
return sun; | |
} | |
var sun = makeSun(); | |
scene.add( sun ); | |
/*////////////////////////////////////////*/ | |
function makePlanet(size, distance, color, speed){ | |
size = size || 30, | |
distance = distance || 300; | |
speed = speed || 0.001; | |
color = color || 0x6DECB9; | |
let pivot = new THREE.Group(); | |
var geometry = new THREE.SphereGeometry( size, 16, 16 ); | |
var material = new THREE.MeshLambertMaterial( { | |
color: color, | |
emissive: 0x11999E, | |
emissiveIntensity: 0.3, | |
//shininess: 0, | |
reflectivity: 3, | |
}); | |
let planet = new THREE.Mesh( geometry, material ); | |
pivot.add(planet); | |
planet.position.z = distance; | |
pivot.rotation.y = Math.PI * (Math.random() - Math.random()); | |
renderCalls.push(function(){ | |
pivot.rotation.y -= 0.001; | |
planet.rotation.y += 0.005; | |
//pivot.rotation.x += 0.1006; | |
}); | |
return pivot; | |
} | |
var planet = makePlanet(25, 200, 0xB74242); | |
planet.rotation.x = Math.PI/7; | |
scene.add(planet); | |
var planet2 = makePlanet(15, 400, 0x6DECB9, 0.002); | |
planet2.rotation.x = Math.PI/7; | |
scene.add( planet2 ); | |
var planet3 = makePlanet(40, 700, 0xE3CE8B, 0.002); | |
planet3.rotation.x = Math.PI/7; | |
scene.add( planet3 ); | |
/*////////////////////////////////////////*/ | |
const TWOPI = Math.PI * 2; | |
const rad2deg = Math.PI * 180; | |
function ease(current,target,ease){ | |
return current + (target - current) * ( ease || 0.2 ); | |
} | |
function getDistance(x1, y1, x2, y2){ | |
return Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) ); | |
} | |
/*////////////////////////////////////////*/ | |
// fire = new Fire(); | |
// fire.position.y = 10; | |
let colors = [ 0xdb2902, 0xfb4402 ]; | |
function Flame(color){ | |
THREE.Group.apply(this,arguments); | |
var light = new THREE.PointLight( colors[1] || 0xFFFFFF , 1, 0 ); | |
light.castShadow = true; | |
light.shadow.mapSize.width = 512; | |
light.shadow.mapSize.height = 512; | |
light.shadow.camera.near = 0.1; | |
light.shadow.camera.far = 120; | |
light.shadow.bias = 0.9; | |
light.shadow.radius = 5; | |
light.power = 6; | |
this.light = light; | |
this.light.position.z -= 6; | |
this.light.position.y += 2; | |
this.add( this.light ); | |
let geometry = new THREE.CylinderGeometry( 2.5, 4, 1, 4 ); //new THREE.BoxGeometry(10,10,10); | |
let material = new THREE.MeshPhongMaterial({ | |
color: color, | |
//specular: 0x009900, | |
shininess: 50, | |
emissive: color, | |
transparent: true, | |
opacity: 0.6, | |
shading: THREE.FlatShading | |
}); | |
let flame = new THREE.Mesh( geometry, material ); | |
this.flame = flame; | |
this.add( flame ); | |
} | |
Flame.prototype = Object.assign(THREE.Group.prototype, { | |
constructor: Flame, | |
}); | |
function Ship(){ | |
THREE.Object3D.call(this); | |
let material = new THREE.MeshPhongMaterial({ | |
color: 0xEEEEEE, | |
shininess: 200, | |
shading: THREE.SmoothShading | |
}); | |
let geometry = new THREE.CylinderGeometry(12, 8, 20, 3, 1, false, Math.PI/2, Math.PI); | |
let body = new THREE.Mesh( geometry, material ); | |
body.rotation.x = Math.PI / 2; | |
body.receiveShadow = true; | |
body.castShadow = true; | |
this.add(body); | |
let domeGeometry = new THREE.SphereGeometry(3, 4, 4, 0, Math.PI); | |
let domeMaterial = new THREE.MeshPhongMaterial({ | |
color: 0xAAAAFF, | |
emissive: 0xAAAAFF, | |
emissiveIntensity: 0.8, | |
shininess: 500, | |
transparent: true, | |
opacity: 0.8, | |
shading: THREE.SmoothShading | |
}); | |
let dome = new THREE.Mesh(domeGeometry, domeMaterial); | |
dome.position.y = 8; | |
dome.rotation.x = Math.PI / -2; | |
this.add(dome); | |
let flame = new Flame(colors[0]); | |
flame.position.z = 15; | |
flame.position.y = 7; | |
flame.rotation.x = Math.PI / 2; | |
flame.rotation.y = Math.PI; | |
this.add(flame); | |
let count = 0; | |
renderCalls.push(()=>{ | |
count +=0.01; | |
flame.light.power = 4 + 6 * Math.sin( Math.abs(this.speed) + (Math.random() * 0.1)); | |
//flame.rotation.y = Math.abs(this.speed)/4 * count * Math.PI/4; | |
flame.scale.y = 1 + ( 0.5 * this.speed * (Math.random()+0.8) + (Math.sin(count)+1/2)) | |
}); | |
} | |
Ship.prototype = Object.assign(THREE.Object3D.prototype,{ | |
constructor: Ship, | |
maxspeed: 3, | |
speed: 0, | |
angle: 0, | |
steering: 0, | |
angleV: 0, | |
steeringV: 0, | |
acceleration: 0.015, | |
decceleration: 0.999, | |
steerPower: 0.0002, | |
controls: true, | |
control: function(){ | |
if ( !this.controls ) { return; } | |
// steering | |
if ( pointer.down ) { | |
this.steering += this.steerPower * (pointer.x - 0.5) * 0.25; | |
this.steeringV += this.steerPower * (pointer.y - 0.5); | |
} else if ( keys[39] || keys[68] ) { | |
this.steering += ( this.steering > -.01) ? this.steerPower : 0; | |
// left | |
} else if ( keys[37] || keys[65] ) { | |
this.steering -= ( this.steering < .01) ? this.steerPower : 0; | |
} else { | |
this.steering *= 0.98; | |
} | |
// gas | |
if ( keys[38] || keys[87] || pointer.down ) { | |
this.speed += (this.speed < this.maxspeed) ? this.acceleration : 0; | |
} else if ( keys[40] || keys[83] ) { // reverse | |
this.speed -= (this.speed > -this.maxspeed/2 )? this.acceleration : 0; | |
} else { | |
this.speed *= 0.995; | |
} | |
this.speed *= 1 - Math.abs(this.steering/2); | |
this.angle += this.steering * this.speed; | |
this.angleV += this.steeringV * this.speed; | |
}, | |
keepInBounds(){ | |
if ( this.tl ) { return; } | |
let near = getDistance(this.position.x, this.position.z, 0, 0) < 35; | |
let far = getDistance(this.position.x, this.position.z, 0, 0) > 950; | |
if ( near || far ) { | |
this.controls = false; | |
console.log('out of bounds!'); | |
var tl = new TimelineLite({ | |
onComplete: function(){ this.controls = true; this.tl = null; }, | |
onCompleteScope: this | |
}); | |
tl.to(this.position, 0.8, { | |
x: this.position.x * ( near ? 4 : 0.90 ), | |
z: this.position.z * ( near ? 4 : 0.90 ), | |
ease: Cubic.easeInOut | |
}) | |
tl.to(this, 0.7, { | |
angle: this.angle + ( this.speed > 0 ? ( this.angle > Math.PI ? -Math.PI : Math.PI ) : 0 ), | |
speed: this.speed * 0.2, | |
ease: Cubic.easeInOut | |
},0); | |
this.tl = tl; | |
} | |
}, | |
// Driving controls adapted from http://codepen.io/Beclamide/pen/bNyxVz?editors=0010 | |
update(){ | |
var prev = { | |
x: this.position.x, | |
y: this.position.y, | |
z: this.position.z, | |
rot: this.rotation.y | |
} | |
this.control(); | |
var xdir = this.speed * Math.cos(this.angle); | |
var ydir = this.speed * Math.sin(this.angle);// * Math.cos(this.angleV); | |
var zdir = this.speed * Math.sin(this.angleV)+1/2; | |
this.position.z += -xdir; | |
this.position.x += ydir; | |
//this.position.y += zdir; | |
this.rotation.y = -this.angle; | |
//this.rotation.z = this.angleV; | |
this.keepInBounds(); | |
camera.position.x = ease(camera.position.x, 50 * (this.steering * this.speed * 20),0.05); //ease(camera.position.y, 50 + ( 10 * this.speed ),0.05); | |
camera.position.z = ease(camera.position.z, 100 + 20 * (this.speed),0.05); | |
camera.position.y = ease(camera.position.y, 50 + ( 10 * this.speed ),0.05);//( this.position.y - camera.position.y + (60 - ( this.speed / 2 ) * 10 ) ); | |
}, | |
// update: function () { | |
// // Get the direction we are facing | |
// var radians = this.angle/(ra2deg); | |
// if(this.isThrusting){ | |
// this.velX += Math.cos(radians) * this.thrust; | |
// this.velY += Math.sin(radians) * this.thrust; | |
// } | |
// // calc the point out in front of the ship | |
// this.px = this.x - this.pointLength * Math.cos(radians); | |
// this.py = this.y - this.pointLength * Math.sin(radians); | |
// // apply friction | |
// this.velX *= 0.985; | |
// this.velY *= 0.985; | |
// // apply velocities | |
// this.x -= this.velX; | |
// this.y -= this.velY; | |
// } | |
}); | |
let ship = new Ship(); | |
ship.add(camera); | |
ship.position.z = 350; | |
camera.position.y = 50; | |
camera.position.z = 100; | |
renderCalls.push(ship.update.bind(ship)); | |
scene.add(ship); | |
/*////////////////////////////////////////*/ | |
function makeSprite(spriteSize){ | |
let canvas = document.createElement('canvas'), | |
ctx = canvas.getContext('2d'); | |
spriteSize = spriteSize || 32; | |
canvas.width = canvas.height = spriteSize * 2; | |
ctx.fillStyle = '#FFF'; | |
ctx.beginPath(); | |
ctx.arc( spriteSize, spriteSize, spriteSize, 0, TWOPI, true ); | |
ctx.fill(); | |
let sprite = new THREE.Texture(canvas); | |
sprite.needsUpdate = true; | |
return sprite; | |
} | |
function makeStars() { | |
let starMaterial = new THREE.PointsMaterial({ | |
size: 4, | |
map: makeSprite(), | |
blending: THREE.AdditiveBlending | |
}); | |
let geometry = new THREE.SphereGeometry(1200, 100, 100); | |
for (let i = 0, len = geometry.vertices.length; i < len; i++){ | |
let vertex = geometry.vertices[i]; | |
vertex.x += Math.random() * -500; | |
vertex.y += Math.random() * -500; | |
vertex.z += Math.random() * -500; | |
} | |
geometry.verticesNeedUpdate = true; | |
geometry.normalsNeedUpdate = true; | |
geometry.computeFaceNormals(); | |
// let starQty = 3000; | |
// let geometry = new THREE.Geometry();//; | |
// for (var i = 0; i < starQty; i++) { | |
// var starVertex = new THREE.Vector3(); | |
// starVertex.x = Math.random() * 1000 - 500; //500 - 250; | |
// starVertex.y = Math.random() * 1000 - 500; //500 - 250; | |
// starVertex.z = Math.random() * 1000 - 500; //500 - 250; | |
// geometry.vertices.push(starVertex); | |
// } | |
return new THREE.Points(geometry, starMaterial); | |
} | |
let stars = makeStars() | |
scene.add(stars); |
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
<script src="http://codepen.io/shshaw/pen/epmrgO"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script> | |
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script> |
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
canvas { display: block; } | |
.controls { position: absolute; bottom: 0; left: 0; right: 0; padding: 2em; z-index: 10; font-size: 10px; color: #FFF; opacity: 0.6; } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment