球体の頂点アニメーション

Three.jsでいろいろと制作できるようになりたいと思い、「Learning 3D Graphics With Three.js | Dynamic Geometry」を参考に、球体の頂点アニメーションを試しました。
※Three.jsの仕様が変更になったため内容を修正しました。Three.jsはr126を使用しています。(2021年3月27日)
球体の頂点アニメーション
● 球体を生成
まずは、SphereGeometryを使用して球体を生成します。動作確認のため、マテリアルはライティングを必要としないMeshNormalMaterialを使用します。
const geometry = new THREE.SphereGeometry(3,128,128); const material = new THREE.MeshNormalMaterial(); const sphere = new THREE.Mesh(geometry,material); scene.add(sphere);
● 球体の頂点を取得
球体の頂点を取得します。Three.jsのr125からGeometryが廃止され、SphereGeometryはBufferGeometryを継承するようになったため、BufferGeometryと同じ要領で球体の頂点を取得します。
const positions = sphere.geometry.attributes.position.array;
for(let i = 0; i < positions.length; i++){
}
● 球体の頂点を操作
取得した頂点を単位ベクトルにし、ランダムな値を積算して球体を凸凹にします。
ベクトルは方向と長さの情報を持ち、長さが1のベクトルのことを単位ベクトルといいます。取得した頂点をnormalizeで正規化し、単位ベクトルにします。
「perlin.js」はパーリンノイズを生成するライブラリで、noise.perlin3(x,y,z)でノイズを生成します。単位ベクトルに対し、multiplyScalarでランダムな値(パーリンノイズ)を積算して球体を凸凹にします。
const positions = sphere.geometry.attributes.position.array;
for(let i = 0; i < positions.length; i++){
const p = new THREE.Vector3(
positions[i*3],
positions[i*3+1],
positions[i*3+2]
);
p.normalize().multiplyScalar(r + 0.3 * noise.perlin3(p.x * k + time, p.y * k, p.z * k));
positions[i*3] = p.x
positions[i*3+1] = p.y
positions[i*3+2] = p.z;
}
頂点座標の更新を通知して、レンダリングします。
sphere.geometry.attributes.position.needsUpdate = true;
法線は面に対して垂直に伸びる線のことで、光の反射などに影響します。法線を設定すると、影ができて立体的になります。
法線を設定するため、更新を通知します。
sphere.geometry.computeVertexNormals();
● 頂点アニメーション
球体の頂点をアニメーションさせます。performance.nowでタイムスタンプを取得し、パーリンノイズの値に加算してアニメーションさせます。
let sphere;
const geometry = new THREE.SphereBufferGeometry(3,128,128);
const material = new THREE.MeshNormalMaterial();
sphere = new THREE.Mesh(geometry,material);
scene.add(sphere);
function rendering(){
requestAnimationFrame(rendering);
//タイムスタンプの取得
const time = performance.now() * 0.001;
const positions = sphere.geometry.attributes.position.array;
//球体の半径
const r = 3;
//ノイズのサイズ調整
const k = 2;
for(let i = 0; i < positions.length; i++){
const p = new THREE.Vector3(
positions[i*3],
positions[i*3+1],
positions[i*3+2]
);
p.normalize().multiplyScalar(r + 0.3 * noise.perlin3(p.x * k + time, p.y * k, p.z * k));
positions[i*3] = p.x
positions[i*3+1] = p.y
positions[i*3+2] = p.z;
}
sphere.geometry.attributes.position.needsUpdate = true;
sphere.geometry.computeVertexNormals();
renderer.render(scene,camera);
}
完成したデモになります。マテリアルはMeshNormalMaterialからMeshPhysicalMaterialに変更し、PointLightを使用してライティングを調整しました。

