以前、はじめてのthree.jsを書いてから、全然three.jsを触る機会がなかったのですが、このままでは昨今の3Dブームに置いて行かれてしまうと思い、再び触り始めました。
今回は、前回までの知識をフル活用して、自分のアイコンをつくってみましたので、その過程をメモしておこうと思います。
今回つくるもの
このアイコンを3Dにしようと思います。
まずはDOMでつくってみる
このアイコンは 9 × 9 の 81個のブロックでつくられています。
なのでまずはJavaScriptをつかってDOMでつくってみました。
((win, doc) => { "use strict"; const top = 100, left = 100, width = 20, height = 20, margin = width / 5; var colors = [ "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#000000", "#637952", "#637952", "#637952", "#000000", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#000000", "#637952", "#637952", "#637952", "#637952", "#637952", "#000000", "#637952", "#637952", "#637952", "#000000", "#000000", "#000000", "#000000", "#000000", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952", "#637952" ]; for (let i = 0, length = colors.length; i < length; ++i) { let p = doc.createElement("p"); p.style.cssText = [ "position: absolute", "top:" + (top + (i / 9 | 0) * (height + margin)) + "px", "left:" + (left + (i % 9) * (width + margin)) + "px", "width:" + width + "px", "height:" + height + "px", "background:" + colors[i] ].join(";"); doc.body.appendChild(p); } })(window, document);
左上から順番に色を配列に入れていって、それをfor文でまわして作成しました。
もっと効率よくかけますが、モックなので開発スピード重視で書いてます。
DEMO
three.js で書いてみる
81個のブロックをfor文で書くことに成功したので、そのままthree.jsに移植してみます。
座標系が逆なので、DOMバージョンとは配列が逆になっています。
((win, doc) => { "use strict"; const renderer = new THREE.WebGLRenderer(), scene = new THREE.Scene(), camera = new THREE.PerspectiveCamera( 60, win.innerWidth / win.innerHeight, 1, 10 ), light = new THREE.PointLight(0xffffff, 2.5), top = -1.5, left = -1.5, size = .2, margin = size * .8, colors = [ 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x000000, 0x000000, 0x000000, 0x000000, 0x000000, 0x637952, 0x637952, 0x637952, 0x000000, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x000000, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x000000, 0x637952, 0x637952, 0x637952, 0x000000, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952, 0x637952 ]; var boxes = []; scene.add(light); camera.position.set(1, 1, 5); camera.lookAt(new THREE.Vector3(0, 0, 0)); light.position.set(1, 1, 1); renderer.setSize(win.innerWidth, win.innerHeight); doc.body.appendChild(renderer.domElement); for (let i = 0, length = colors.length; i < length; ++i) { var geometry = new THREE.BoxGeometry(size, size, size), material = new THREE.MeshLambertMaterial({ color: colors[i] }); boxes[i] = new THREE.Mesh(geometry, material); boxes[i].position.set( left + (i % 9) * (size + margin), top + (i / 9 | 0) * (size + margin), 0 ); scene.add(boxes[i]); } (function render() { for (let i = 0, length = boxes.length; i < length; ++i) { boxes[i].rotation.x += 0.01; boxes[i].rotation.y += 0.01; boxes[i].rotation.z += 0.01; } renderer.render(scene, camera); requestAnimationFrame(render); })(); })(window, document);
DEMO
ポジションは適当にあわせました。
2Dのときより怖いですね。