Skip to content

Instantly share code, notes, and snippets.

@Sphinxxxx
Last active November 7, 2017 00:51
Show Gist options
  • Save Sphinxxxx/2907af1636e869a3c027bdf0e111457a to your computer and use it in GitHub Desktop.
Save Sphinxxxx/2907af1636e869a3c027bdf0e111457a to your computer and use it in GitHub Desktop.
three.js praxinoscope
"use strict";
console.clear();
// camera
var VIEW_ANGLE = 45;
var NEAR = 1;
var FAR = 500;
//var FRAMES_URL = 'http://crossorigin.me/https://docs.coronalabs.com/images/simulator/sprites-cat-running.png',
// FRAMES_X = 4, FRAMES_Y = 2;
var FRAMES_URL =
'//programming.enthuses.me/assets/codepen/Muybridge%20-%20three.js.jpg',
//'https://i.imgur.com/EUWJA2s.jpg',
//'https://upload.wikimedia.org/wikipedia/commons/4/4a/Muybridge_race_horse_gallop.jpg',
FRAMES_X = 4, FRAMES_Y = 4;
var camera, scene, renderer;
var cameraControls, stats;
var praxinoGroup,
magniSphere, magniCamera;
function init() {
// renderer
renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio( window.devicePixelRatio );
// scene
scene = new THREE.Scene();
// camera
camera = new THREE.PerspectiveCamera(VIEW_ANGLE, 1, NEAR, FAR);
camera.position.set( 0, 45, 150 );
function resize() {
var aspect = window.innerWidth / window.innerHeight;
camera.aspect = aspect;
camera.fov = VIEW_ANGLE/((aspect+1)/2);
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', resize, false);
resize();
cameraControls = new THREE.OrbitControls(camera, renderer.domElement);
cameraControls.target.set(0, 0, 0);
cameraControls.maxDistance = 500;
//cameraControls.minDistance = 30;
cameraControls.update();
var container = document.getElementById( 'container' );
container.appendChild( renderer.domElement );
//https://github.com/mrdoob/stats.js/
stats = new Stats();
stats.setMode(0); // 0: fps, 1: ms, 2: mb
stats.domElement.style.position = 'absolute';
stats.domElement.style.left = '0px';
stats.domElement.style.top = '0px';
container.appendChild( stats.domElement );
}
function fillScene() {
var boxMaterial = new THREE.MeshPhongMaterial( { color: 0xffffff/*, side: THREE.DoubleSide*/ } ),
imgCount = FRAMES_X * FRAMES_Y,
mirrorRad = 20,
imgRad = mirrorRad * 2;
var imgAngle = Math.PI*2 / imgCount,
//https://www.mathsisfun.com/sine-cosine-tangent.html
//tan(a) = opposite/adjacent
//tan(mirrorAngle/2) = mirrorWidth/2 / mirrorsRad
mirrorWidth = Math.tan(imgAngle/2) * 2 * mirrorRad,
mirrorHeight = mirrorRad,
mirrorY = mirrorHeight/4;
praxinoGroup = new THREE.Object3D();
scene.add(praxinoGroup);
var planeBottom = new THREE.Mesh( new THREE.PlaneBufferGeometry( imgRad*2.2, imgRad*2.2), boxMaterial );
//planeBack.position.z = -50;
planeBottom.position.y = -mirrorHeight/2;
planeBottom.rotateX( -Math.PI/2 );
praxinoGroup.add( planeBottom );
//http://stackoverflow.com/questions/13223168/open-ended-cylinder-not-showing-inside-material
var frameMaterial = boxMaterial.clone();
frameMaterial.side = THREE.DoubleSide;
var outerFrame = new THREE.Mesh(
new THREE.CylinderGeometry(imgRad*1.1, imgRad*1.1,
mirrorHeight, 20, 1, true),
frameMaterial
);
praxinoGroup.add(outerFrame);
var mirrorsLid = new THREE.Mesh(
new THREE.CylinderGeometry(mirrorRad, mirrorRad,
.1, 20),
boxMaterial
);
mirrorsLid.position.y = mirrorHeight/2 + mirrorY;
praxinoGroup.add(mirrorsLid);
//Mirrors and images
function addMirrorAndImage(i) {
var theta = imgAngle * i,
x = mirrorRad * Math.sin(theta),
z = mirrorRad * Math.cos(theta);
//console.log(i, imgAngle, theta);
//Mirror
var mirror = new THREE.Reflector(
mirrorWidth,
mirrorHeight,
{ clipBias: 0.0001, textureWidth: 1024, textureHeight: 1024, color: 0x777777 }
);
mirror.position.y = mirrorY;
mirror.position.x = x;
mirror.position.z = z;
mirror.rotateY(theta);
praxinoGroup.add(mirror);
//Image
//https://threejs.org/docs/#Reference/Loaders/TextureLoader
// instantiate a loader
var loader = new THREE.TextureLoader();
loader.crossOrigin = '';
// load a resource
loader.load(
// resource URL
FRAMES_URL,
// Function when resource is loaded
function ( imgTexture ) {
//https://github.com/mrdoob/three.js/issues/1847
imgTexture.repeat.x = 1/FRAMES_X;
imgTexture.repeat.y = 1/FRAMES_Y;
//.75 -> 0
imgTexture.offset.y = 1 - (1 + Math.floor(i / FRAMES_X))/FRAMES_Y;
imgTexture.offset.x = (1/FRAMES_X) * (i % FRAMES_X);
//console.log(i, imgTexture.offset.y, imgTexture.offset.x)
/*
//http://stackoverflow.com/questions/24087757/three-js-and-loading-a-cross-domain-image
//http://jsfiddle.net/greggman/MZpx8/
var imgMaterial = new THREE.MeshPhongMaterial({
map: imgTexture,
//specular: 0xFFFFFF,
//shininess: 5,
shading: THREE.FlatShading,
});
*/
var imgMaterial = new THREE.MeshBasicMaterial({
map: imgTexture
});
var img = new THREE.Mesh( new THREE.PlaneBufferGeometry( mirrorWidth*1.5, mirrorWidth ), imgMaterial /*new THREE.MeshPhongMaterial( { color: 0x00ff00 } )*/ );
//img.position.y = mirrorY;
img.position.x = x*2;
img.position.z = -z*2;
img.rotateY(-theta);
praxinoGroup.add( img );
}
);
}
for(var i=0; i<imgCount; i++) {
addMirrorAndImage(i);
}
//Magnifying glass
var magnifierGroup = new THREE.Object3D();
//https://www.script-tutorials.com/webgl-with-three-js-lesson-5/
magniCamera = new THREE.CubeCamera(NEAR, FAR, 500);
magniCamera.renderTarget.mapping = THREE.CubeRefractionMapping;
// create refracting material and spherical mesh
var magniMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
envMap: magniCamera.renderTarget,
refractionRatio: 1,
reflectivity: 0.9
});
//magniSphere = new THREE.Mesh( new THREE.SphereGeometry(10, 32, 32), magniMaterial);
magniSphere = new THREE.Mesh( new THREE.CylinderGeometry( 14, 14, 2, 30 ), magniMaterial);
var magniFrame = new THREE.Mesh( new THREE.CylinderGeometry( 15, 15, 1.9, 30 ), boxMaterial);
var magniHandle = new THREE.Mesh( new THREE.CylinderGeometry( 1, 1.5, 18, 8 ), boxMaterial);
magniHandle.rotateZ(Math.PI/2);
magniHandle.position.set(24,0,0);
magnifierGroup.add(magniSphere);
magnifierGroup.add(magniFrame);
magnifierGroup.add(magniHandle);
magnifierGroup.position.set(0, 21, 70);
magnifierGroup.rotateX(1);
magnifierGroup.rotateY(-1);
//magniSphere.position/2 - The closer, the more magnification:
magniCamera.position.set(0, 10, 35);
scene.add(magniCamera);
scene.add(magnifierGroup);
// lights
var mainLight = new THREE.PointLight( 0xffff00, .5, 250 );
mainLight.position.y = 60;
//scene.add( mainLight );
var spotLight = new THREE.PointLight( 0xffaa00, 2, 250 );
spotLight.position.y = 60;
spotLight.position.z = 100;
scene.add( spotLight );
}
function render() {
// update refracting object
magniSphere.visible = false;
magniCamera.update(renderer, scene);
magniSphere.visible = true;
renderer.render(scene, camera);
}
function update() {
requestAnimationFrame( update );
var timer = Date.now() * 0.001;
//camera.position.x = Math.cos( timer/2 ) * 200;
//camera.position.z = Math.sin( timer/2 ) * 200;
//camera.lookAt( scene.position );
praxinoGroup.rotation.y = (timer*2);
cameraControls.update();
stats.update();
render();
}
init();
fillScene();
update();
<script src="https://threejs.org/examples/js/libs/stats.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script>
<script src="//cdn.rawgit.com/mrdoob/three.js/r88/examples/js/objects/Reflector.js"></script>
<script src="//cdn.rawgit.com/mrdoob/three.js/r88/examples/js/controls/OrbitControls.js"></script>
body {
background-color: #000;
margin: 0px;
overflow: hidden;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment