3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ローポリな海を作ってGitHub ActionsでGitHub Pagesにデプロイ

Posted at

概要

three.jsで,スクリーンセーバーをイメージしてローポリな海を作りました.ソースコードはこちらで公開しています.

また,作ったページをGitHub ActionsGitHub Pagesにビルド & デプロイし,以下のページで公開しています.

ocean.png

海を作る

開発環境

  • Vite
    • React + TypeScript
  • Three.js r174

一部解説

格子状に点群を設置:

const rows = 50;
const cols = 100;
const spacing = 10;

for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
        const x = (j - cols / 2) * spacing;
        const y = (i - rows / 2) * spacing;
        const z = 0;
        points.push(x, y, z);
    }
}
geometry.setAttribute("position", new THREE.Float32BufferAttribute(points, 3));

const pointCloud = new THREE.Points(geometry, material);
// pointCloud.visible = false;
scene.add(pointCloud);

格子状の点群を描画し,それらの座標をsin関数とcos関数を組み合わせて変化させ,海面の揺らぎを表現:

requestAnimationFrame(animate);
const positions = geometry.attributes.position.array as Float32Array;
const time = performance.now() * 0.001;

for (let i = 0; i < rows; i++) {
    for (let j = 0; j < cols; j++) {
        const index = (i * cols + j) * 3 + 2;
        positions[index] = (Math.sin(time + i * 0.2) * Math.cos(time * 0.3 + j * 0.2) +
            Math.sin(time * 0.5 + i * 0.4) * Math.cos(time * 0.6 + j * 0.4)) * 3;
    }
}
geometry.attributes.position.needsUpdate = true;

各点から隣り合う縦・横・(ひとつの)斜め方向に線をつなぎ,海面を表現:

function updateLines() {
    linePositions.length = 0;
    const positions = geometry.attributes.position.array as Float32Array;
    
    for (let i = 0; i < rows; i++) {
        for (let j = 0; j < cols; j++) {
            const index = (i * cols + j) * 3;
            const x = positions[index];
            const y = positions[index + 1];
            const z = positions[index + 2];
    
            if (j < cols - 1) {
                linePositions.push(x, y, z, positions[index + 3], positions[index + 4], positions[index + 5]);
            }
            if (i < rows - 1) {
                const belowIndex = ((i + 1) * cols + j) * 3;
                linePositions.push(x, y, z, positions[belowIndex], positions[belowIndex + 1], positions[belowIndex + 2]);
            }
            if (i < rows - 1 && j < cols - 1) {
                const diagonalIndex = ((i + 1) * cols + (j + 1)) * 3;
                linePositions.push(x, y, z, positions[diagonalIndex], positions[diagonalIndex + 1], positions[diagonalIndex + 2]);
            }
        }
    }
    lineGeometry.setAttribute("position", new THREE.Float32BufferAttribute(linePositions, 3));
    lineGeometry.attributes.position.needsUpdate = true;
}

const animate = () => {
    updateLines();
};

点群は消すかどうか迷いましたが,光を反射しているみたいできれいなので残すようにしました.月とかを設置するようにしたい.

ビルド & デプロイ

色々試したせいで余計なコードが含まれているかもしれないです.

手元でビルドするのではなく,リポジトリにpushしたとき,GitHub Actions内の仮想環境(ubuntu-latest)上でビルドするようにしました.手動でビルドするのが面倒だからこうしてみたけど,時間かかるしエラーが出るかもしれないことを考えるとあんまりよくないのかもしれない.

  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'npm'

      - name: Install dependencies
        run: npm install

      - name: Build project
        run: npm run build
        env:
          VITE_BASE: '/Ocean/'
          GITHUB_PAGES: true

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: ./dist

おわりに

わざわざコンポーネント化したのは今後これを何かのページでインポートしたかったからです.ChatGPTに提案されたからuseEffectを使ったけど,useEffectを完全に理解できていないから今後勉強する.

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?