Skip to content

Instantly share code, notes, and snippets.

@sfpgmr
Last active August 29, 2015 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sfpgmr/9788400c632f51830e53 to your computer and use it in GitHub Desktop.
Save sfpgmr/9788400c632f51830e53 to your computer and use it in GitHub Desktop.
Three.jsでエドワード・マイブリッジの馬の連続写真をアニメーションする

##Three.jsでエドワード・マイブリッジの馬をアニメーションする

Wikipediaに載っているエドワード・マイブリッジの連続捨身?をThree.jsでアニメーションしてみた。

##使用したもの

  • d3.js
  • Three.js
<!DOCTYPE html>
<html vocab="http://schema.org" lang="ja">
<head>
<title>YouTube Uploader</title>
<meta charset="utf-8" />
<meta name="description" content="指定した音声ファイルと静止画をffmpegで動画化しYoutubeにアップロードします。" />
<meta name="keywords" content="Youtube,d3.js,Q.js,jquery" />
<meta name="author" content="sfpgmr" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/d3/3.5.2/d3.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/q.js/1.1.2/q.min.js" ></script>
<!--<script type="text/javascript" src="./graphics.js"></script> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.2/normalize.min.css" />
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="content"></div>
<script type="text/javascript" src="index.js"></script>
<script>
</script>
</body>
</html>
/// <reference path="http://cdnjs.cloudflare.com/ajax/libs/d3/3.5.2/d3.js" />
/// <reference path="http://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.js" />
/// <reference path="./q.intellisense.js" />
/// <reference path="./graphics.js" />
"use strict"
var WIDTH = window.innerWidth, HEIGHT = window.innerHeight;
var renderer = new THREE.WebGLRenderer({ antialias: false, sortObjects: true });
renderer.setSize(WIDTH, HEIGHT);
renderer.setClearColor(0x000000, 1);
renderer.domElement.id = 'console';
renderer.domElement.className = 'console';
renderer.domElement.style.zIndex = 0;
d3.select('#content').node().appendChild(renderer.domElement);
renderer.clear();
// シーンの作成
var scene = new THREE.Scene();
// カメラの作成
var camera = new THREE.PerspectiveCamera(90.0, WIDTH / HEIGHT);
camera.position.x = 0.0;
camera.position.y = 0.0;
camera.position.z = (WIDTH / 2.0) * HEIGHT / WIDTH;
camera.lookAt(new THREE.Vector3(0.0, 0.0, 0.0));
// テクスチャー定義
var textureFiles = {
totalTextureCount: 0,
promises: [],
textures: {}
};
function createSpriteGeometry(width,height) {
var geometry = new THREE.Geometry();
var sizeHalfX = width / 2;
var sizeHalfY = height / 2;
// geometry.
geometry.vertices.push(new THREE.Vector3(-sizeHalfX, sizeHalfY, 0));
geometry.vertices.push(new THREE.Vector3(sizeHalfX, sizeHalfY, 0));
geometry.vertices.push(new THREE.Vector3(sizeHalfX, -sizeHalfY, 0));
geometry.vertices.push(new THREE.Vector3(-sizeHalfX, -sizeHalfY, 0));
geometry.faces.push(new THREE.Face3(0, 2, 1));
geometry.faces.push(new THREE.Face3(0, 3, 2));
return geometry;
}
/// テクスチャー上の指定スプライトのUV座標を求める
function createSpriteUV(geometry, texture, cellWidth, cellHeight, cellNo) {
var width = texture.image.width;
var height = texture.image.height;
var uCellCount = (width / cellWidth) | 0;
var vCellCount = (height / cellHeight) | 0;
var vPos = vCellCount - ((cellNo / uCellCount) | 0);
var uPos = cellNo % uCellCount;
var uUnit = cellWidth / width;
var vUnit = cellHeight / height;
geometry.faceVertexUvs[0].push([
new THREE.Vector2((uPos) * cellWidth / width, (vPos) * cellHeight / height),
new THREE.Vector2((uPos + 1) * cellWidth / width, (vPos - 1) * cellHeight / height),
new THREE.Vector2((uPos + 1) * cellWidth / width, (vPos) * cellHeight / height)
]);
geometry.faceVertexUvs[0].push([
new THREE.Vector2((uPos) * cellWidth / width, (vPos) * cellHeight / height),
new THREE.Vector2((uPos) * cellWidth / width, (vPos - 1) * cellHeight / height),
new THREE.Vector2((uPos + 1) * cellWidth / width, (vPos - 1) * cellHeight / height)
]);
}
function updateSpriteUV(geometry, texture, cellWidth, cellHeight, cellNo) {
var width = texture.image.width;
var height = texture.image.height;
var uCellCount = (width / cellWidth) | 0;
var vCellCount = (height / cellHeight) | 0;
var vPos = vCellCount - ((cellNo / uCellCount) | 0);
var uPos = cellNo % uCellCount;
var uUnit = cellWidth / width;
var vUnit = cellHeight / height;
var uvs = geometry.faceVertexUvs[0][0];
uvs[0].x = (uPos) * uUnit;
uvs[0].y = (vPos) * vUnit;
uvs[1].x = (uPos + 1) * uUnit;
uvs[1].y = (vPos - 1) * vUnit;
uvs[2].x = (uPos + 1) * uUnit;
uvs[2].y = (vPos) * vUnit;
uvs = geometry.faceVertexUvs[0][1];
uvs[0].x = (uPos) * uUnit;
uvs[0].y = (vPos) * vUnit;
uvs[1].x = (uPos) * uUnit;
uvs[1].y = (vPos - 1) * vUnit;
uvs[2].x = (uPos + 1) * uUnit;
uvs[2].y = (vPos - 1) * vUnit;
geometry.uvsNeedUpdate = true;
}
function createSpriteMaterial(texture) {
// メッシュの作成・表示 ///
var material = new THREE.MeshBasicMaterial({ map: texture /*,depthTest:true*/, transparent: true });
material.shading = THREE.FlatShading;
material.side = THREE.FrontSide;
material.alphaTest = 0.5;
material.needsUpdate = true;
// material.
return material;
}
function loadTexture(info) {
var defer = Q.defer();
THREE.ImageUtils.loadTexture(info.path, {},
function (texture) {
info.texture = texture;
if (info.path.match(/\.png/i)) {
texture.premultiplyAlpha = true;
}
texture.magFilter = THREE.NearestFilter;
texture.minFilter = THREE.LinearMipMapLinearFilter;
defer.resolve(info);
},// Error
function (e) {
defer.reject(e);
});
return defer.promise;
}
var textureInfos = [
{ name:'horse' ,path: './The_Horse_in_Motion.jpg'},
{ name:'horse01',path:'./The_Horse_in_Motion01.jpg'}
];
window.addEventListener('load',function(){
Q.all(
textureInfos.map(function (info){
return loadTexture(info);
}))
.then(
function (array){
var textures = {};
array.forEach(function(info){
textures[info.name] = info.texture;
});
// 馬の絵
var horseMaterial = new THREE.MeshBasicMaterial({ map: textures.horse });
horseMaterial.shading = THREE.FlatShading;
//material.antialias = false;
horseMaterial.transparent = true;
horseMaterial.alphaTest = 0.5;
horseMaterial.depthTest = true;
var horseMesh = new THREE.Mesh(
new THREE.PlaneGeometry(textures.horse.image.width, textures.horse.image.height),
horseMaterial
);
horseMesh.scale.x = 1.0;
horseMesh.scale.y = 1.0;
horseMesh.position.y = 0.0;
// 馬スプライト
var spriteWidth = textures.horse01.image.width / 4;
var spriteHeight = textures.horse01.image.height / 3;
var horseSpriteMaterial = createSpriteMaterial(textures.horse01);
var horseGeometry = createSpriteGeometry(spriteWidth,spriteHeight);
createSpriteUV(horseGeometry,textures.horse01,spriteWidth,spriteHeight,0);
var horseSpriteMesh = new THREE.Mesh(horseGeometry,horseSpriteMaterial);
scene.add(horseSpriteMesh);
var index = 0.0;
var speed = (1.0 / 60.0)/(60.0 / (143.0 * 11.0)) ;
function render(){
requestAnimationFrame(render);
index += speed;
if(index > 10) index = 10.0 - index;
updateSpriteUV(horseGeometry,textures.horse01,spriteWidth,spriteHeight,parseInt(index));
renderer.render(scene,camera);
}
render();
}
).catch(
function (e){
alert(e.stack);
}
);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment