Loading...

Loading...

Scroll

Blog

Development and Information etc...

Categories

Tags

Monthly Archives

Keyword

Back

My website has been renewaled

2016.07.08

Category

Tags

かねてより企んでいた自身のサイトのリニューアルが完了しました。

自分の実績を載せるページが欲しかったのですが、コンテンツが寂しいと思ったので、今までサブドメインで運用していたブログとブックマークサイトを統合しました。RSSを登録頂いていた方はいかに登録し直していただけると幸いです。

・Blog
https://tkmh.me/blog/feed/

・Bookmarks
https://tkmh.me/bookmarks/feed/

ついでに新設のWorksのRSSも。

・Works
https://tkmh.me/works/feed/

技術的にも盛り込みたいものは盛り込めたし (WebGL、非同期遷移、レスポンシブ etc…) 、デザインも綺麗にまとまって、割と気に入ってます。

このサイトの一番の見せ場はメインビジュアルのトランスフォームです。エンジニアの方向けに少しだけ解説します。

メインビジュアルはWebGL (three.js) で組んでいます。ロゴの形の3Dオブジェクトはモデリングをしたのではなく、プログラムで構築しています。直方体を組み合わせた形なので、そんなに複雑ではないです。

ただし、ポリゴンをバラバラにしてトランスフォームさせたかったので、BoxGeometryを使用せず、BefferGeometryに自分で頂点を追加しています。かつバラバラのキューブ状でも動かしたかったので、ボクセルを構築しています。なので普通にBoxGeometryを使用して同じ形を作るよりも、頂点数は遥かに多いです。

あとはポリゴン単位で動かしたり、キューブ単位で動かしたり、頂点単位で動かしたりしています。
頂点の座標計算はすべてシェーダないで行っています。これはGPGPUという手法です。

GPGPUでトランスフォームをどのように制御しているかというと、頂点シェーダ内にすべてのアニメーションパターンを記述しておき、それを係数によってどのアニメーションを適用するかを決めています。以下に簡単な例を記述します。

// 頂点シェーダ例
uniform mat4 modelViewMatrix;
uniform mat4 modelMatrix;
uniform mat4 projectionMatrix;
uniform float animationParam1;
uniform float animationParam2;

void main() {
  vec3 pos = position;

  // パターン1
  pos.x += animationParam1 * 100;

  // パターン2
  pos.y += animationParam2 * 100;

  gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}

デフォルトの状態ではanimationParam1に1をセット、animationParam2に0をセットし、パターン1のみが適用されている状態で、パターン1からパターン2にトランスフォームする際は、animationParam1を0に、animationParam1を1に値を徐々に変化させる処理を同時行っています。そうすることによって、2つのアニメーションパターン間をシームレスに遷移させることができます。

実際はイージングの処理を入れたり、ノイズを入れたり、時間差処理を入れたりしてるので、これよりもずっと複雑ですが、面倒なので割愛。

各コンテンツのタイトルの形状に変形させていますが、それは予め各コンテンツのタイトルの文字の画像 (Works) などを読み込んで、ピクセル情報を取得し、黒い色が付いているところをランダムでピックアップし、GeometryのAttributeにvec3として渡しているので、その情報を元に座標を決めています。

↑こんな背景透過画像を使用しています。

以下はタイトルの画像のピクセル情報取得部分の抜粋です。 (CoffeeScript)

# 一部抜粋
$img = $('').one 'load', (e)=>
  # drawImageでタイトルの文字をcanvasに描画
  img = $img.get 0
  canvas = document.createElement 'canvas'
  context = canvas.getContext '2d'
  canvas.width = img.width
  canvas.height = img.height
  context.drawImage img, 0, 0, img.width, img.height

  # ピクセルの色情報を取得
  imgData = context.getImageData 0, 0, img.width, img.height

  points = []
  for i in [0...imgData.data.length - 1] by 4
    alpha = imgData.data[i + 3]
    index = i / 4
    if alpha > 0
      # アルファが0より大きい場合に、ピクセルの座標をpointsにpush
      points.push {
        x: index % img.width - img.width / 2
        y: img.height / 2 - Math.floor(index / img.width)
      }

  # ... 以下、pointsに入っている座標をランダムにピックアップし、シェーダに渡す

.attr 'src', imgPath  # imgPathはタイトルの文字の画像パス

色の制御は適当にsimplexNoise等を使用して決めてます。

すごい適当な説明になってしまいましたが、要は結構本気出して実装しました。

Related Posts

Top

My new portfolio site has been launched!

If you want to see the recent works please visit the new site.

visit the new site( https://unshift.jp/ )

stay here