【制作物共有】3D Earth
制作日
2021年10月27日
使用しているプラグインなど
・webpack
・Typescript
・gsap
・three.js
制作について
今回の制作の目的は「サイトをできるだけ再現すること」です。
参考とするサイトはこちら
このサイトは弊社で週一で行っているサイト鑑賞で悠太さんが紹介してくれました。
早速作成していきます。
まずはBlenderで地球を作成します。
glTF形式で読み込んで、地球を透過しようとしたら失敗しました。
どうやらマテリアルで画像を貼り付けてglTFにすると透過できないっぽい
以下がその時のコード
// glTF形式の3Dモデルを読み込む;
const loader = new GLTFLoader();
loader.load(this.srcObj, (obj) => {
const data = obj.scene;
data.traverse((n: any) => {
//モデルの構成要素をforEach的に走査
if (n.isMesh) {
//その構成要素がメッシュだったら
n.material.transparent = true;
n.material.alphaToCoverage = true; // 追加
n.material.opacity = 0.2;
}
});
諦めてThree.jsで地球を作りました。
透過もできて良い感じです。
コードです。
const loader = new THREE.TextureLoader();
loader.load(this.srcTexture, (texture) => {
// 球体を作る
const sphere = new THREE.Mesh(
new THREE.SphereGeometry(80, 20, 20), // 形状
new THREE.MeshLambertMaterial({
// 材質
map: texture,
opacity: 0.5,
transparent: true,
})
);
sphere.position.set(0, 0, 0);
this.three.scene.add(sphere);
});
次に海を表現してみます。
使ったのはSky.jsとWater.jsです。
実装はできたのですが、ちょっと地球と合わないので却下しました。
背景はCSSでグラデーションを設定し、Three.jsでパーティクルを実装します。
コード
setParticle() {
// 形状データを作成
const SIZE = 3000;
// 配置する個数
const LENGTH = 1000;
// 頂点情報を格納する配列
const vertices = [];
for (let i = 0; i < LENGTH; i++) {
const x = SIZE * (Math.random() - 0.5);
const y = SIZE * (Math.random() - 0.5);
const z = SIZE * (Math.random() - 0.5);
vertices.push(x, y, z);
}
// 形状データを作成
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
// マテリアルを作成
const material = new THREE.PointsMaterial({
//サイズ
size: 10,
// 色
color: 0xffffff,
});
// 物体を作成
this.three.mesh = new THREE.Points(geometry, material);
this.three.scene.add(this.three.mesh);
}
少し寂しいので色と動きを追加します。
webpack + typesctipt + glslの構成で、
fragmentshaderとvertexshaderは別ファイルとして読み込みたいので
glsl.d.tsの作成とraw-loaderの追加を行いました。
setParticle(): void {
let uniforms;
const radius = 200;
const positions = [];
const colors = [];
const sizes = [];
this.three.particles = 2000;
uniforms = {
pointTexture: { value: new THREE.TextureLoader().load(this.srcTexture.spark) },
};
const shaderMaterial = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true,
vertexColors: true,
});
this.three.geometry = new THREE.BufferGeometry();
const color = new THREE.Color();
for (let i = 0; i < this.three.particles; i++) {
positions.push((Math.random() * 2 - 1) * radius);
positions.push((Math.random() * 2 - 1) * radius);
positions.push((Math.random() * 2 - 1) * radius);
color.setHSL(i / this.three.particles, 1.0, 0.5);
colors.push(color.r, color.g, color.b);
sizes.push(20);
}
this.three.geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
this.three.geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
this.three.geometry.setAttribute('size', new THREE.Float32BufferAttribute(sizes, 1).setUsage(THREE.DynamicDrawUsage));
this.three.particleSystem = new THREE.Points(this.three.geometry, shaderMaterial);
this.three.scene.add(this.three.particleSystem);
}
地球と同じ要領で木星と土星を追加しました。
時間経過でライトを強弱したり、移動したりも実装しましたがあまり雰囲気に合わずやめてしまいました。
テキストを追加して完成です。
目標とする参考サイトのように水中を表現するのはできなかったですが、マウスによって動かす部分など、近付けることができてよかったです。
参考
高橋悠太さん
3Dモデルの透過
webpack + typesctipt + glslの構成でfragmentshaderとvertexshaderを別ファイルとして読み込む
この記事が気に入ったらサポートをしてみませんか?