2020年09月30日

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

Three.jsでいろいろと制作できるようになりたいと思い、「Learning 3D Graphics With Three.js | Dynamic Geometry」を参考に、球体の頂点アニメーションを試してみました。※Three.jsはr120を使用しています。

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

● 球体を生成

まずは、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);

● 球体の頂点を取得

球体の頂点を取得します。Geometryで取得できる頂点はVector3形式で、sphere.geometry.verticesで取得します。

for(let i = 0; i < sphere.geometry.vertices.length; i++){

	//Vector3形式で頂点を取得
	const p = sphere.geometry.vertices[i];
}

● 球体の頂点を操作

取得した頂点を単位ベクトルにし、ランダムな値を積算して球体を凸凹にします。

ベクトルは方向と長さの情報を持ち、長さが1のベクトルのことを単位ベクトルといいます。取得した頂点をnormalizeで正規化し、単位ベクトルにします。

perlin.js」はパーリンノイズを生成するライブラリで、noise.perlin3(x,y,z)でノイズを生成します。単位ベクトルに対し、multiplyScalarでランダムな値(パーリンノイズ)を積算して球体を凸凹にします。

for(let i = 0; i < sphere.geometry.vertices.length; i++){
	const p = sphere.geometry.vertices[i];
	p.normalize().multiplyScalar(3 + 2 * noise.perlin3(p.x,p.y,p.z));
}

頂点座標の更新を通知して、レンダリングします。

sphere.geometry.verticesNeedUpdate = true;

法線は面に対して垂直に伸びる線のことで、光の反射などに影響します。法線を設定すると、影ができて立体的になります。

法線を設定するため、更新を通知します。

sphere.geometry.computeVertexNormals();

● 頂点アニメーション

球体の頂点をアニメーションさせます。performance.nowでタイムスタンプを取得し、パーリンノイズの値に加算してアニメーションさせます。

let sphere;

const geometry = new THREE.SphereGeometry(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 r = 3;

	//ノイズのサイズ調整
	const k = 2;

	for(let i = 0; i < sphere.geometry.vertices.length; i++){
		const p = sphere.geometry.vertices[i];
		p.normalize().multiplyScalar(r + 0.3 * noise.perlin3(p.x * k + time, p.y * k, p.z * k));
	}

	sphere.geometry.verticesNeedUpdate = true;
	sphere.geometry.computeVertexNormals();

	renderer.render(scene,camera);
}

● BufferGeometryに変更

GeometryをBufferGeometryに変更します。GeometryとBufferGeometryでは、頂点の取得方法や取得できる頂点のデータの形式が違うため、BufferGeometryに合わせて修正します。

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を使用してライティングを調整しました。

  • このエントリーをはてなブックマークに追加

関連記事

前の記事へ

Three.jsで星空を制作

次の記事へ

Three.jsでラインアニメーション