【Three.js】背景色を徐々に変化させる
できた時すごく嬉しかった
はじめに
クリックしたら背景色が変わるヤツを作ります。最初は白だけど、じわじわと黄色になるようにしたいと思います。
背景色の設定方法
webGLRenderer = new THREE.WebGLRenderer();
webGLRenderer.setClearColor(new THREE.Color(0xfff8d4));
WebGLRendererクラスのsetClearColorメソッドで背景色の設定ができます。↑この例だと16進数で色の指定をしていますが、書き方は他にも色々あります。ちなみにRGBで指定する時はこうです↓。
webGLRenderer.setClearColor("rgb(255, 248, 212)");
setClearColorメソッドの引数を少しずつ変化させていけば、背景色もじわじわと変わってくれるという事です。
Tween.jsでアニメーションさせる
出ました。みんな大好きTween。これを使ってsetClearColorメソッドに渡す値を変化させていこうと思います。
function clickWindow() {
let color = {c: 0xfff8d4};
new TWEEN.Tween(color)
.to({c: 0xf9ff52}, 2000)
.easing(TWEEN.Easing.Linear.None)
.onUpdate(function() {
webGLRenderer.setClearColor(new THREE.Color(color.c));
})
.start();
}
↑こう書いたらこうなりました↓。(チカチカします!)
setClearColorメソッドに渡す値を、2秒かけて0xfff8d4から0xf9ff52へ減らしているんですけど、16進数のままだとダメみたいですね。単純に数を減らしているだけなので、いろいろな色を通ってしまうようです。そのせいでチカチカします。
RGBで指定するように変更
function clickWindow() {
let color = {r: 255, g: 248, b: 212};
new TWEEN.Tween(color)
.to({r: 249, g: 255, b: 82}, 2000)
.easing(TWEEN.Easing.Linear.None)
.onUpdate(function() {
webGLRenderer.setClearColor(new THREE.Color("rgb(" + Math.floor(color.r) + "," +
Math.floor(color.g) + "," +
Math.floor(color.b) + ")"));
})
.start();
}
16進数を2桁ずつ分けて10進数にします。それをrとgとbに割り当てました。そうしたらこうなりました↓。
とってもイイ感じ。自分でもうまくできたなぁと感心しました。
ムニュムニュ動いてるヤツについては何も触れませんでしたが、これはパーリンノイズを使って動かしてます。全コードを載せておくので良かったら参考にしてください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>ムニュムニュ</title>
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<script type="text/javascript" src="../libs/utils/perlin.js"></script>
<style>
* {
margin: 0;
padding: 0;
}
html,body {
overflow: hidden;
height: 100%;
}
</style>
</head>
<body>
<div id="screen"></div>
<script type="module">
import * as THREE from "https://unpkg.com/three@0.127.0/build/three.module.js";
import { TrackballControls } from "https://unpkg.com/three@0.127.0/examples/jsm/controls/TrackballControls.js";
import { TWEEN } from "https://unpkg.com/three@0.127.0/examples/jsm/libs/tween.module.min.js";
window.onload = function() {
let scene, camera, webGLRenderer;
let plane, trackballControls;
let circleMesh, circleMesh2;
let aspRatio, fov;
init();
main();
renderScene();
window.addEventListener("resize", resizeWindow);
window.addEventListener("click", clickWindow);
// 初期化
function init() {
scene = new THREE.Scene();
aspRatio = window.innerWidth / window.innerHeight;
fov = getFov(aspRatio);
camera = new THREE.PerspectiveCamera(fov, aspRatio, 1, 10000);
camera.position.set(0, 10, 50);
scene.add(camera);
webGLRenderer = new THREE.WebGLRenderer();
webGLRenderer.setSize(window.innerWidth, window.innerHeight);
webGLRenderer.setClearColor(new THREE.Color(0xfff8d4));
document.getElementById("screen").appendChild(webGLRenderer.domElement);
const plane = new THREE.GridHelper(200, 16);
scene.add(plane);
trackballControls = new TrackballControls(camera, webGLRenderer.domElement);
trackballControls.target = new THREE.Vector3(0, 0, 0);
trackballControls.rotateSpeed = 3;
}
// メイン
function main() {
const geo = new THREE.CircleGeometry(10, 64);
const mat = new THREE.MeshBasicMaterial({color: 0xffff00});
mat.side = THREE.DoubleSide;
circleMesh = new THREE.Mesh(geo, mat);
scene.add(circleMesh);
}
// 円の頂点を動かす
function moveCircleVertex() {
const positions = circleMesh.geometry.attributes.position.array;
const time = Date.now() / 1000;
const r = 10;
const k = 1;
for (let i = 0; i < positions.length; i+=3) {
const p = new THREE.Vector2(
positions[i],
positions[i + 1]
);
p.normalize().multiplyScalar(r + 1.0 * noise.perlin2(p.x * k + time, p.y * k));
positions[i] = p.x
positions[i + 1] = p.y
}
// 頂点情報の更新
circleMesh.geometry.attributes.position.needsUpdate = true;
// 法線情報の更新
circleMesh.geometry.computeVertexNormals();
}
// 度→ラジアン
function degToRad(deg) {
return deg * Math.PI / 180;
}
// ラジアン→度
function radToDeg(rad) {
return rad * 180 / Math.PI;
}
// ウィンドウリサイズ
function resizeWindow() {
aspRatio = window.innerWidth / window.innerHeight;
camera.aspect = aspRatio
camera.fov = getFov(aspRatio);
camera.updateProjectionMatrix();
webGLRenderer.setSize(window.innerWidth, window.innerHeight);
renderScene();
}
// ウィンドウクリック
function clickWindow() {
let color = {r: 255, g: 248, b: 212};
new TWEEN.Tween(color)
.to({r: 249, g: 255, b: 82}, 2000)
.easing(TWEEN.Easing.Linear.None)
.onUpdate(function() {
webGLRenderer.setClearColor(new THREE.Color("rgb(" + Math.floor(color.r) + "," +
Math.floor(color.g) + "," +
Math.floor(color.b) + ")"));
})
.start();
}
// 視野角取得
function getFov(aspRatio) {
let fov;
if (aspRatio > 1) {
fov = 25;
} else if (aspRatio > 0.8) {
fov = 30;
} else if (aspRatio > 0.6) {
fov = 40;
} else if (aspRatio > 0.5) {
fov = 50;
} else {
fov = 60;
}
return fov;
}
// 描画
function renderScene() {
const clock = new THREE.Clock();
const delta = clock.getDelta();
trackballControls.update(delta);
moveCircleVertex();
TWEEN.update();
requestAnimationFrame(renderScene);
webGLRenderer.render(scene, camera);
}
}
</script>
</body>
</html>
あとがき
できましたねぇ。どうやったらできるのか相当頭ひねったので、意図した通りに動いたときの感動たるや。プログラミングの醍醐味ですわねぇ。
今回できたものをもう少し作りこんで、おしゃれなモノを完成させようと思っています。ありがとうございました。
おしゃれ度
★★☆☆☆
ディスカッション
コメント一覧
まだ、コメントがありません