前回の第9回
マウスポインタの水平の位置に応じてカメラを回り込ませる
まず、
var centerX = stageWidth / 2;
var centerY = stageHeight / 2;
var lastX = centerX;
function initialize() {
document.onmousemove = recordMouse;
}
function recordMouse(eventObject) {
lastX = eventObject.clientX;
}
function rotate(timeStamp) {
// angle += timeStamp / 2000;
angle += (lastX - centerX) / 5000;
}
画面の中心座標は変数
これで、
![図1 3次元領域の外にポインタを遠ざけるほどカメラが速く回る 図1 3次元領域の外にポインタを遠ざけるほどカメラが速く回る](/assets/images/design/serial/01/away3d-typescript/0010/thumb/TH800_001.png)
Viewオブジェクトの領域を超えても、
function recordMouse(eventObject) {
// lastX = eventObject.clientX;
var mouseX = eventObject.clientX;
if (mouseX < stageWidth) {
lastX = mouseX;
} else {
lastX = stageWidth;
}
}
これで、
var LoaderEvent = require("awayjs-core/lib/events/LoaderEvent");
var Vector3D = require("awayjs-core/lib/geom/Vector3D");
var Matrix3D = require("awayjs-core/lib/geom/Matrix3D");
var AssetLibrary = require("awayjs-core/lib/library/AssetLibrary");
var URLRequest = require("awayjs-core/lib/net/URLRequest");
var RequestAnimationFrame = require("awayjs-core/lib/utils/RequestAnimationFrame");
var View = require("awayjs-display/lib/containers/View");
var DirectionalLight = require("awayjs-display/lib/entities/DirectionalLight");
var MouseEvent = require("awayjs-display/lib/events/MouseEvent"); //
var StaticLightPicker = require("awayjs-display/lib/materials/lightpickers/StaticLightPicker");
var PrimitiveCubePrefab = require("awayjs-display/lib/prefabs/PrimitiveCubePrefab");
var DefaultRenderer = require("awayjs-renderergl/lib/DefaultRenderer");
var TriangleMethodMaterial = require("awayjs-methodmaterials/lib/TriangleMethodMaterial");
var view;
var cube;
var imageDiffuse = "assets/trinket_diffuse.jpg";
var timer;
var ORIGIN = new Vector3D();
var angle = -Math.PI / 2;
var distance = 1500;
var stageWidth = 240;
var stageHeight = 180;
var centerX = stageWidth / 2;
var centerY = stageHeight / 2;
var lastX = centerX;
var lastY = centerY;
var urls = [
"http://gihyo.jp/design/serial/01/away3d-typescript",
"http://gihyo.jp/design/serial/01/createjs",
"http://typescript.away3d.com",
"https://developer.mozilla.org/ja/docs/Web/JavaScript",
"http://createjs.com/#!/Home"
];
function initialize() {
var directionalLight = createDirectionalLight(0.5, 0xFFFFFF);
view = createView(stageWidth, stageHeight, 0x0);
cube = createCube(400, 400, 400, directionalLight);
setCamera(view.camera, distance, angle);
cube.url = "http://fumiononaka.com";
view.scene.addChild(cube);
cloneMesh(cube, urls);
AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
AssetLibrary.load(new URLRequest(imageDiffuse));
timer = new RequestAnimationFrame(rotate);
timer.start();
document.onmousemove = recordMouse;
view.render();
}
function createView(width, height, backgroundColor) {
var defaultRenderer = new DefaultRenderer();
var view = new View(defaultRenderer);
view.width = width;
view.height = height;
view.backgroundColor = backgroundColor;
view.forceMouseMove = true;
return view;
}
function createCube(width, height, depth, light) {
var material = new TriangleMethodMaterial();
var cube = new PrimitiveCubePrefab(width, height, depth, 1, 1, 1, false)
.getNewObject();
cube.material = material;
setScale(cube, 1);
setMouseListener(cube, onMouseOver, onMouseOut, onClick);
material.lightPicker = new StaticLightPicker([light]);
return cube;
}
function cloneMesh(mesh, urls) {
var scene = view.scene;
var count = urls.length;
for (var i = 0; i < count; i++) {
var clone = mesh.clone();
var distance = getRandom(500, 1200);
var scale = getRandom(0.3, 0.5);
var rotationX = getRandom(-60, 60);
var rotationY = getRandom(-180, 180);
var position = getPolarPosition(distance, rotationX, rotationY);
clone.x = position.x;
clone.y = position.y;
clone.z = position.z;
clone.url = urls[i];
setScale(clone, scale);
clone.rotationY = rotationY;
setMouseListener(clone, onMouseOver, onMouseOut, onClick);
scene.addChild(clone);
}
}
function setMouseListener(mesh, over, out, click) {
mesh.addEventListener(MouseEvent.MOUSE_OVER, over);
mesh.addEventListener(MouseEvent.MOUSE_OUT, out);
mesh.addEventListener(MouseEvent.CLICK, click);
}
function recordMouse(eventObject) {
var mouseX = eventObject.clientX;
if (mouseX < stageWidth) {
lastX = mouseX;
} else {
lastX = stageWidth;
}
}
function onMouseOver(eventObject) {
var mesh = eventObject.object;
changeScale(mesh, 1.5);
}
function onMouseOut(eventObject) {
var mesh = eventObject.object;
changeScale(mesh, 1);
}
function onClick(eventObject) {
var mesh = eventObject.object;
window.open(mesh.url);
}
function setScale(mesh, scale) {
mesh.scale = scale;
changeScale(mesh, 1);
}
function changeScale(mesh, scale) {
var _scale = mesh.scale * scale;
mesh.transform.scale = new Vector3D(_scale, _scale, _scale);
}
function createDirectionalLight(ambient, color) {
var light = new DirectionalLight();
light.ambient = ambient;
light.color = color;
return light;
}
function onResourceComplete(eventObject) {
var assets = eventObject.assets;
var material = cube.material;
material.texture = assets[0];
view.render();
}
function rotate(timeStamp) {
var camera = view.camera;
angle += (lastX - centerX) / 5000;
setCamera(camera, distance, angle);
view.render();
}
function setCamera(camera, distance, angle) {
camera.x = Math.cos(angle) * distance;
camera.z = Math.sin(angle) * distance;
camera.lookAt(ORIGIN);
}
function getRandom(min, max) {
var random = Math.random() * (max - min) + min;
return random;
}
function getPolarPosition(distance, rotationX, rotationY) {
var vector = new Vector3D(distance, 0, 0);
var matrix = new Matrix3D();
matrix.appendRotation(rotationY, Vector3D.Y_AXIS);
matrix.appendRotation(rotationX, Vector3D.X_AXIS);
return matrix.transformVector(vector);
}
マウスポインタの垂直の位置に応じてカメラを上下する
つぎに、
var lastY = centerY;
function recordMouse(eventObject) {
var mouseY = eventObject.clientY;
if (mouseY < stageHeight) {
lastY = mouseY;
} else {
lastY = stageHeight;
}
}
function setCamera(camera, distance, angle) {
var targetY = (lastY - centerY) * -10;
camera.y += (targetY - camera.y) * 0.05;
}
カメラの垂直の動きは、
![図2 マウスポインタの垂直位置に応じてカメラが上下する 図2 マウスポインタの垂直位置に応じてカメラが上下する](/assets/images/design/serial/01/away3d-typescript/0010/thumb/TH195_00201.png)
![図2 マウスポインタの垂直位置に応じてカメラが上下する 図2 マウスポインタの垂直位置に応じてカメラが上下する](/assets/images/design/serial/01/away3d-typescript/0010/thumb/TH195_00202.png)
var LoaderEvent = require("awayjs-core/lib/events/LoaderEvent");
var Vector3D = require("awayjs-core/lib/geom/Vector3D");
var Matrix3D = require("awayjs-core/lib/geom/Matrix3D");
var AssetLibrary = require("awayjs-core/lib/library/AssetLibrary");
var URLRequest = require("awayjs-core/lib/net/URLRequest");
var RequestAnimationFrame = require("awayjs-core/lib/utils/RequestAnimationFrame");
var View = require("awayjs-display/lib/containers/View");
var DirectionalLight = require("awayjs-display/lib/entities/DirectionalLight");
var MouseEvent = require("awayjs-display/lib/events/MouseEvent"); //
var StaticLightPicker = require("awayjs-display/lib/materials/lightpickers/StaticLightPicker");
var PrimitiveCubePrefab = require("awayjs-display/lib/prefabs/PrimitiveCubePrefab");
var DefaultRenderer = require("awayjs-renderergl/lib/DefaultRenderer");
var TriangleMethodMaterial = require("awayjs-methodmaterials/lib/TriangleMethodMaterial");
var view;
var cube;
var imageDiffuse = "assets/trinket_diffuse.jpg";
var timer;
var ORIGIN = new Vector3D();
var angle = -Math.PI / 2;
var distance = 1500;
var stageWidth = 240;
var stageHeight = 180;
var centerX = stageWidth / 2;
var centerY = stageHeight / 2;
var lastX = centerX;
var lastY = centerY;
var urls = [
"http://gihyo.jp/design/serial/01/away3d-typescript",
"http://gihyo.jp/design/serial/01/createjs",
"http://typescript.away3d.com",
"https://developer.mozilla.org/ja/docs/Web/JavaScript",
"http://createjs.com/#!/Home"
];
function initialize() {
var directionalLight = createDirectionalLight(0.5, 0xFFFFFF);
view = createView(stageWidth, stageHeight, 0x0);
cube = createCube(400, 400, 400, directionalLight);
setCamera(view.camera, distance, angle);
cube.url = "http://fumiononaka.com";
view.scene.addChild(cube);
cloneMesh(cube, urls);
AssetLibrary.addEventListener(LoaderEvent.RESOURCE_COMPLETE, onResourceComplete);
AssetLibrary.load(new URLRequest(imageDiffuse));
timer = new RequestAnimationFrame(rotate);
timer.start();
document.onmousemove = recordMouse;
view.render();
}
function createView(width, height, backgroundColor) {
var defaultRenderer = new DefaultRenderer();
var view = new View(defaultRenderer);
view.width = width;
view.height = height;
view.backgroundColor = backgroundColor;
view.forceMouseMove = true;
return view;
}
function createCube(width, height, depth, light) {
var material = new TriangleMethodMaterial();
var cube = new PrimitiveCubePrefab(width, height, depth, 1, 1, 1, false)
.getNewObject();
cube.material = material;
setScale(cube, 1);
setMouseListener(cube, onMouseOver, onMouseOut, onClick);
material.lightPicker = new StaticLightPicker([light]);
return cube;
}
function cloneMesh(mesh, urls) {
var scene = view.scene;
var count = urls.length;
for (var i = 0; i < count; i++) {
var clone = mesh.clone();
var distance = getRandom(500, 1200);
var scale = getRandom(0.3, 0.5);
var rotationX = getRandom(-60, 60);
var rotationY = getRandom(-180, 180);
var position = getPolarPosition(distance, rotationX, rotationY);
clone.x = position.x;
clone.y = position.y;
clone.z = position.z;
clone.url = urls[i];
setScale(clone, scale);
clone.rotationY = rotationY;
setMouseListener(clone, onMouseOver, onMouseOut, onClick);
scene.addChild(clone);
}
}
function setMouseListener(mesh, over, out, click) {
mesh.addEventListener(MouseEvent.MOUSE_OVER, over);
mesh.addEventListener(MouseEvent.MOUSE_OUT, out);
mesh.addEventListener(MouseEvent.CLICK, click);
}
function recordMouse(eventObject) {
var mouseX = eventObject.clientX;
var mouseY = eventObject.clientY;
if (mouseX < stageWidth) {
lastX = mouseX;
} else {
lastX = stageWidth;
}
if (mouseY < stageHeight) {
lastY = mouseY;
} else {
lastY = stageHeight;
}
}
function onMouseOver(eventObject) {
var mesh = eventObject.object;
changeScale(mesh, 1.5);
}
function onMouseOut(eventObject) {
var mesh = eventObject.object;
changeScale(mesh, 1);
}
function onClick(eventObject) {
var mesh = eventObject.object;
window.open(mesh.url);
}
function setScale(mesh, scale) {
mesh.scale = scale;
changeScale(mesh, 1);
}
function changeScale(mesh, scale) {
var _scale = mesh.scale * scale;
mesh.transform.scale = new Vector3D(_scale, _scale, _scale);
}
function createDirectionalLight(ambient, color) {
var light = new DirectionalLight();
light.ambient = ambient;
light.color = color;
return light;
}
function onResourceComplete(eventObject) {
var assets = eventObject.assets;
var material = cube.material;
material.texture = assets[0];
view.render();
}
function rotate(timeStamp) {
var camera = view.camera;
angle += (lastX - centerX) / 5000;
setCamera(camera, distance, angle);
view.render();
}
function setCamera(camera, distance, angle) {
var targetY = (lastY - centerY) * -10;
camera.x = Math.cos(angle) * distance;
camera.z = Math.sin(angle) * distance;
camera.y += (targetY - camera.y) * 0.05;
camera.lookAt(ORIGIN);
}
function getRandom(min, max) {
var random = Math.random() * (max - min) + min;
return random;
}
function getPolarPosition(distance, rotationX, rotationY) {
var vector = new Vector3D(distance, 0, 0);
var matrix = new Matrix3D();
matrix.appendRotation(rotationY, Vector3D.Y_AXIS);
matrix.appendRotation(rotationX, Vector3D.X_AXIS);
return matrix.transformVector(vector);
}
減速を表す式 ー イーズアウト
結びとして、
function rotate(timeStamp) {
angle += (lastX - centerX) / 5000;
}
function setCamera(camera, distance, angle) {
var targetY = (lastY - centerY) * -10;
camera.y += (targetY - camera.y) * 0.05;
}
この式は、
速度 = (目標値 - 現在値) * 減速率 (0
![図3 動きが遅くなりながら目標に近づく 図3 動きが遅くなりながら目標に近づく](/assets/images/design/serial/01/away3d-typescript/0010/thumb/TH800_003.png)
位置を速度に足し込んでつぎの位置を求めるというのは、
この
微分計算そのものはしなくても、