2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

インタラクティブ3Dアート!Three.jsで画像ピクセルをパーティクルに変換する方法

Last updated at Posted at 2023-12-28

画像ピクセルをパーティクル化!Three.jsとシェーダーで作るインタラクティブな3Dグラフィック

概要

この記事では、Three.jsとシェーダーを使用して、画像のピクセルデータをパーティクルとして3D空間に配置し、インタラクティブで表現力豊かなグラフィックを実現する方法を解説します。
GSAPによるアニメーションやSplitTextによるテキストエフェクトも組み合わせ、視覚的に美しい名言集を作成します。

スクリーンショット 2023-12-28 18.55.26.png

https://codepen.io/Prodouga/pen/LYqbwmx

目次

  1. プロジェクトの概要

    • 使用技術
    • 制作意図
    • こだわりポイント
  2. HTMLの解説

    • Three.jsのキャンバス配置
    • 名言テキストとボタンの配置
  3. CSSの解説

    • レイアウトとスタイリング
    • レスポンシブデザイン
  4. JavaScriptの解説

    • Three.jsの初期化とシーンの構築
    • パーティクルの生成とシェーダーの設定
    • GSAPによるアニメーション制御
    • マウスインタラクションの実装
  5. シェーダーの解説

    • 頂点シェーダー
    • フラグメントシェーダー
  6. まとめ

    • プロジェクトの学びと今後の展望

プロジェクトの概要

使用技術

  • Three.js: 3Dグラフィックの描画
  • GSAP: アニメーションの制御
  • SplitText: テキストの分割表示
  • GLSL: シェーダーによるパーティクルの表現

制作意図

  • Three.jsの可能性を探る
  • アニメーションとインタラクションの組み合わせ方を学ぶ
  • 視覚的に美しいデザインを実現する

こだわりポイント

  • シェーダーを使ったパーティクルの表現
  • マウスインタラクションによるパーティクルの動き
  • 名言とアニメーションの調和

HTMLの解説

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>名言集 - prodouga.com</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="preconnect" href="https://fonts.gstatic.com">
  <link href="https://fonts.googleapis.com/css2?family=Comfortaa:wght@400;700&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <div id="wrapper">
    <div id="canvas_container"></div>
    <div class="text">
      <p class="quoteText">物語は<span style="font-style: italic; font-size: 1.4rem; color:#ED760D">ここ</span>から始まるのだ<br><small>手塚治虫</small></p>
    </div>
    <p class="clickInfo">クリックすると物語が始まります</p>
    <img id="first" src="https://i.imgur.com/TwYg3BB.jpg" style="display:none;">
    <a href="https://prodouga.com/contact" target="_blank" class="btn btn_works">お問い合わせ</a>
    <button class="btn" id="fullscr">フルスクリーン</button>
  </div>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/r125/three.min.js'></script>
  <script src='https://unpkg.co/gsap@3/dist/gsap.min.js'></script>
  <script src='https://assets.codepen.io/16327/SplitText3.min.js'></script>
  <script src="./script.js"></script>
</body>
</html>

ポイント

  • #canvas_containerにThree.jsのキャンバスを配置
  • .textに名言テキストを表示
  • GSAPとSplitTextのライブラリを読み込み
  • フルスクリーンボタンやお問い合わせリンクを配置

CSSの解説

* {
  margin: 0;
  padding: 0;
}

body {
  overflow: hidden;
}

#wrapper {
  position: relative;
  height: 100vh;
  background: #000;
  font-family: 'Comfortaa', serif;
}

#canvas_container {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100vh;
  z-index: 0;
}

.text {
  width: 100%;
  height: 100px;
  text-align: center;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 10;
  cursor: pointer;
  color: rgb(255, 255, 255);
  background-color: rgba(0, 0, 0, 0.81);
  font-size: 1.6rem;
  line-height: 1.5;
  user-select: none;
  overflow: hidden;
  display: flex;
  align-items:center;
}

ポイント

  • Three.jsのキャンバスを全画面表示
  • 名言テキストを中央に配置
  • レスポンシブ対応のためのメディアクエリ

JavaScriptの解説

Three.jsの初期化

webgl.scene = new THREE.Scene();
webgl.camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 10000);
webgl.camera.position.z = 180;
webgl.renderer = new THREE.WebGLRenderer({ alpha: true });
webgl.renderer.setSize(webgl.container.clientWidth, webgl.container.clientHeight);
webgl.container.appendChild(webgl.renderer.domElement);

パーティクルの生成

webgl.geometryParticles = new THREE.InstancedBufferGeometry();
const positions = new THREE.BufferAttribute(new Float32Array(4 * 3), 3);
positions.setXYZ(0, -0.5, 0.5, 0.0);
positions.setXYZ(1, 0.5, 0.5, 0.0);
positions.setXYZ(2, -0.5, -0.5, 0.0);
positions.setXYZ(3, 0.5, -0.5, 0.0);
webgl.geometryParticles.setAttribute('position', positions);

GSAPによるアニメーション

webgl.firstAnimation1 = gsap.to(webgl.particlesMesh.rotation, 30, { z: 2, repeat: -1, yoyo: true });
webgl.firstAnimation2 = gsap.fromTo(webgl.particlesMesh.material.uniforms.uDepth, 2, { value: 30 }, { value: 45.0, ease: "elastic.in(1, 0.3)", delay: 2 });

マウスインタラクション

window.addEventListener("mousemove", onMouseMove, false);
function onMouseMove(event) {
  webgl.mouse.x = (event.clientX / webgl.renderer.domElement.clientWidth) * 2 - 1;
  webgl.mouse.y = - (event.clientY / webgl.renderer.domElement.clientHeight) * 2 + 1;
  webgl.raycaster.setFromCamera(webgl.mouse, webgl.camera);
}

シェーダーの解説

頂点シェーダー

void main() {
  vec2 puv = offset.xy / uTextureSize;
  vec4 colA = texture2D(uTexture, puv);
  float grey = colA.r * 0.21 + colA.g * 0.71 + colA.b * 0.07;
  vec3 displaced = offset;
  displaced.z += rndz * (random(pindex) * 2.0 * uDepth);
  gl_Position = projectionMatrix * mvPosition;
}

フラグメントシェーダー

void main() {
  vec4 color = vec4(0.0);
  vec2 uv = vUv;
  vec2 puv = vPUv;
  vec4 colA = texture2D(uTexture, puv);
  float dist = radius - distance(uv, vec2(0.5));
  float t = smoothstep(uCircleORsquare, border, dist);
  color = colA;
  color.a = t;
  gl_FragColor = vec4(color.r, color.g, color.b, t - uAlphaCircle);
}

まとめ

このプロジェクトでは、Three.jsとシェーダーを使用して、画像のピクセルデータをパーティクルとして3D空間に配置し、インタラクティブで表現力豊かなグラフィックを実現しました。GSAPによるアニメーションやSplitTextによるテキストエフェクトも組み合わせ、視覚的に美しい名言集を作成しました。

今後の展望として、より複雑なシェーダーエフェクトや、ユーザーが自由に画像をアップロードできる機能を追加することを検討しています。Three.jsの可能性は無限大です!ぜひ、このプロジェクトを参考に、独自の3Dグラフィックを作成してみてください。


この記事が、Three.jsを使った3Dグラフィック制作の一助となれば幸いです。質問やフィードバックがあれば、ぜひコメントをお寄せください!🚀

2
2
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
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?