Sandbox

学習記録や試作したものを掲載しています

All(23)

Blender

ガラス風の質感を表現する

ガラス風の質感を表現する

Blender でガラス風の質感を得る練習。

Memo

  • 「サーフェス」を「グラスBSDF」に設定し、「粗さ」の数値を下げることでガラス風の質感が得られる

    ライティングを施すことで、ガラスが透過して中身が見えるようになる(「Cycles」に設定する)

  • 「シェーダーミックス」で2つの質感を混ぜ合わせた表現が作れる
  • モディファイアーで「ソリッド化」を適用している場合、テクスチャを貼ると内側にも表示されてしまう

    理想 ↓

    現実 ↓

    これを解消するには、新たなマテリアルを追加した上で、[モディファイアープロパティ] > [Solidify] > [マテリアル] > [マテリアルインデックスオフセット] を 1 に設定する。この値は設定しているマテリアル群の先頭を 0 とし、適用するマテリアルが何番目に当たるかを指す。

  • 平均クリース:サブディビジョンサーフェスをどのくらいの強さでかけるか
    • 値が 0 の時に影響が最大、1 の時に影響がゼロ
    • サブディビジョンサーフェスで潰れてしまった角を部分的に調整できる
    • N キーでメニューパネルを開き、[アイテム] > [トランスフォーム] > [辺データ] > [平均クリース] から設定可能
    • ショートカット:Shift + E
  • HDRI はビューが「透視投影」の場合にのみ確認できる
  • [レンダープロパティ] > [カラーマネジメント] > [ルック] からコントラストを調整できる
  • Ctrl + I:選択の反転

参考

Blender

金属風の質感と環境テクスチャ

金属風の質感と環境テクスチャ

Blender で金属風の質感を得る練習。

Memo

  • 「メタリック」の数値を上げ、「粗さ」の数値を下げることで金属風の質感が得られる
  • [レンダープロパティ] > [アンビエントオクルージョン], [スクリーンスペース反射]
    • アンビエントオクルージョン: 陰影を表示して立体感や接地感を向上させる
    • スクリーンスペース反射: 光の屈折や反射を表現できる
    • これらは Blender v.4.2 以降では削除され、以下で代替できる
      • スクリーンスペース反射 ⇒ [レイトレーシング] > [方式: スクリーントレース]
      • アンビエントオクルージョン ⇒ [レイトレーシング] > [高速GI近似] > [方式: アンビエントオクルージョン]
  • 環境テクスチャで HDR 画像を設定する
    • [ワールドプロパティ] > [カラー]
    • HDR 画像を設定することで、光源で光をあてるよりもリアルな質感を表現できる。設定する画像によって反射の具合が変化する。

参考

Blender

ライトベイクしてブラウザで質感を再現する

ライトベイクしてブラウザで質感を再現する

Blender のライティング効果をそのままブラウザに移植することは難しい。
代わりに、Three.js のライティングで再現しようとすると以下の問題が生じる。

  • Blender の質感を再現できない
  • 陰影づけの計算負荷が増し、ブラウザでのパフォーマンスが低下する

質感の再現が難しい理由は、Blender と Three.js の光の計算方式やレンダリング方式の違いによるところが大きい。
一方で、シーン内の光源やオブジェクトが固定されている場合は、必ずしも Three.js 側でライティングや陰影を計算する必要はなく、Blender 側でライトベイクを行うことで軽量に再現できる。

以下の例では、Blender でライティング効果を含めてテクスチャにベイクし、それをオブジェクトに貼り付けて Three.js で表示している。
なお、Three.js 側ではアンビエントライト(白色光)のみ使用した。

(比較)Blender の表示

ベイクしたテクスチャ画像

若干の色味の違いはあるものの、概ね Blender の質感を再現できていることがわかる。

Demo

https://koji014-blender-light-baking.vercel.app

参考

Blender

3D モデルのデータを圧縮する

3D モデルのデータを圧縮する

glTF は、多くの頂点データやテクスチャ画像を含むため、得てしてファイル容量が大きくなりやすい。

ここでは、以下の2つの圧縮を行い、その圧縮効果を評価する。

  • メッシュや点群データを圧縮する「Draco 圧縮」
  • テクスチャ画像の圧縮 or 軽量化(WebP 変換)

評価内容

上記圧縮について、以下の4パターンで比較する。

  1. Blender から glb 形式でエクスポートしたファイル
  2. Blender から glb 形式でエクスポートし、Draco 圧縮を行ったファイル
  3. Blender から gltf 形式でエクスポートし、テクスチャの軽量化を行ったのち、glb 形式に変換したファイル
  4. Blender から gltf 形式でエクスポートし、テクスチャの軽量化を行ったのち、glb 形式に変換、Draco 圧縮を行ったファイル

テクスチャ画像軽量化

Draco 圧縮

1

×

×

2

×

3

×

4

3D モデルは、書籍『10日で Blender 練習帳』で作成したものを使用する。

評価結果

ファイル容量 / MB

読み込み時間 / ms

1

50.6

153

2

10.2

50

3

44.3

127

4

3.9

23

※ 但し、上記結果は次の条件に基づく。

  • Draco 圧縮におけるデコード処理時間は測定対象外
  • ローカル開発サーバー上での測定結果

-- -- --

  1. Blender から glb 形式でエクスポートしたファイル
  1. Blender から glb 形式でエクスポートし、Draco 圧縮を行ったファイル
  1. Blender から gltf 形式でエクスポートし、テクスチャの軽量化を行ったのち、glb 形式に変換したファイル
  1. Blender から gltf 形式でエクスポートし、テクスチャの軽量化を行ったのち、glb 形式に変換、Draco 圧縮を行ったファイル

結論

テクスチャの軽量化を行ったのち、Draco 圧縮を行うことで、ファイル容量を 46.7 MB 削減(50.6 MB -> 3.9 MB)することができた。
両圧縮を行うことで、ファイル容量の大幅な削減が期待できる。

但し、下記を留意する。

  • Draco 圧縮では、頂点の定義が最も効率よく圧縮されるため、頂点の数自体が少ない場合には圧縮効率は低い(WebGL School より)。
  • Draco 圧縮をした場合、圧縮したファイルをブラウザ上でデコードする必要がある。そのデコーダのファイル容量が 1 MB ~ 2 MB 程度あるため、(圧縮後の 3D モデルのデータ容量)+(デコーダの容量)>(圧縮前の 3D モデルのデータ容量)とならないよう注意する。
  • テクスチャ画像の圧縮・軽量化は、3D モデルの品質を損なわない程度に行う。

Demo

「4. Blender から gltf 形式でエクスポートし、テクスチャの軽量化を行ったのち、glb 形式に変換、Draco 圧縮を行ったファイル」を使用。

https://koji014-blender10days.vercel.app

参考

Blender

『10日で Blender 練習帳』

『10日で Blender 練習帳』

2025.11.17 ~ 2025.11.27 の学習記録。
書籍『10日で Blender 練習帳』で Blender の学習を行った。

制作物

1日目:スイーツセット

2日目:テーブル

3日目:ベッド

4日目:望遠鏡

5日目:キャンドルとランプ

6日目:自転車のオブジェ

7日目:デスクセット

8日目:観葉植物と本

9日目:猫のキャラクター

10日目:部屋(完成)

Demo

https://koji014-blender10days.vercel.app

参考

関連

Three.js

Blender で作成した 3D モデルをブラウザ上で動かす

Blender で作成した 3D モデルをブラウザ上で動かす

Blender で作成した 3D モデルを Three.js を用いてブラウザ上で読み込み、インタラクションを加えて動かす練習を行った。

Demo: https://koji014-laptop.vercel.app

  • 天板部(液晶ディスプレイを除く)をクリックすると、PC が開閉する
  • 電源ボタンをクリックすると、PC の電源が ON になる

参考

Blender

Blender に入門する

Blender に入門する

Web Designing 2025年6月号 p.36 ~ p.49 の内容を参考に Blender の学習を行った。
基本的な操作方法や、モデリングからレンダリングまでの一連の流れを把握することができた。

以下、モデリングしたラップトップのデモ動画。

参考

JavaScript

非同期遷移を行うためのクラスを自作する

非同期遷移を行うためのクラスを自作する

非同期遷移を行うための Pjax クラスを自作した。
ブラウザバック・フォワードへの対応や、ページ遷移前のアンマウント処理、遷移後のマウント処理をカスタマイズできるように実装しており、メモリリークの防止にも配慮した。

以下、上から順に(1)フェードによる遷移、(2)CSS mask による遷移、(3)SVG animate による遷移。

WebGL

WebGL オブジェクトと DOM 要素の位置同期ずれを防ぐ

WebGL オブジェクトと DOM 要素の位置同期ずれを防ぐ

WebGL オブジェクトと DOM 要素の位置を同期した際、モバイルデバイスのネイティブスクロールで両者の位置がずれることがある。2025年4月4日に Lusion が公表した投稿によると、Canvas を ページコンテンツに追従させ、Canvas の位置を translateY で補正することで、このずれを解消できるという。この効果を確認すべく、デモを作成した。なお、この方法を理解する上で、長谷川巧さん(@_unshift)の図解を大いに参考にした。

Demo: https://koji014-webgl-scroll-sync.vercel.app

以下、上から順に(1)固定していない状態、(2)固定して Padding をつけていない状態、(3)固定して Padding をつけた状態。(2)の Padding をつけない場合、上へ戻ろうとする際に Canvas が見切れている(画像の表示が欠けている)ことがわかる。(3)では Padding をつけることで、これが改善されている。

参考

WebGL

非同期遷移を介した DOM と板ポリゴンの再同期

非同期遷移を介した DOM と板ポリゴンの再同期

同期していた DOM と板ポリゴンの関係を非同期遷移前に破棄し、遷移後に再び同期する。

WebGL

DOM と板ポリゴンを同期する

DOM と板ポリゴンを同期する

WebGL School プラスワン講義回で Taro Yoshimura さん(@ysmrt6)が解説した内容を参考に、Three.js を使わずに実装した。

Demo: https://koji014-dom-gl-sync.vercel.app

参考

  • WebGL School 2024 プラスワン講義回 Taro Yoshimura さんの Three.js を用いた実装

JavaScript

スクロール量に応じた操作をするためのクラスを自作する

スクロール量に応じた操作をするためのクラスを自作する

GSAP の ScrollTrigger の仕組みを理解するため、同じような挙動をする ScrollTrigger クラスを作成した。

Demo: https://koji014-scroll-trigger.vercel.app

使用例

const box = document.querySelector('.box');

const trigger = new ScrollTrigger({
    trigger: '#trigger',
    start: '10% 10%',
    end: '70% 70%',
    markers: true,
    onEnter: () => console.log('🍎onEnter'),
    onLeave: () => console.log('🍐onLeave'),
    onEnterBack: () => console.log('🍎onEnterBack'),
    onLeaveBack: () => console.log('🍐onLeaveBack'),
    onToggle: () => console.log('🍇onToggle'),
    onUpdate: (self) => {
        const breakPoints = [0, 0.4, 0.8, 1];
        const lastIndex = breakPoints.length - 1;

        const normalizedProgress = breakPoints.map((bp, i, arr) => {
            if (i === 0) return 1.0;
            const prev = arr[i - 1];
            return Math.min(Math.max(0, (self.progress - prev) / (bp - prev)), 1);
        });

        const transform = {
            translateX: 200,
            translateY: 800,
            rotate: 360,
        };

        if (self.progress < breakPoints[1]) {
            box.style.transform = `
                translateY(${transform.translateY * normalizedProgress[1]}px)
                rotate(${transform.rotate * normalizedProgress[1]}deg)
            `;
        } else if (self.progress < breakPoints[2]) {
            box.style.transform = `
                translateX(${transform.translateX * normalizedProgress[2]}px)
                translateY(${transform.translateY}px)
                rotate(${transform.rotate}deg)
            `;
        } else {
            box.style.transform = `
                translateX(${transform.translateX}px)
                translateY(${transform.translateY}px)
                rotate(${transform.rotate}deg)
            `;
            box.style.backgroundColor = `rgb(
                ${Math.round(255 * (1 - normalizedProgress[lastIndex]))} 0 255 / 0.5
            )`;
        }
    },
});

JavaScript

カルーセルを自作する

カルーセルを自作する

Demo

https://koji014-carousel.vercel.app

const targetSelector = '.my-carousel';

new Carousel(targetSelector, {
    isLoop: true,
    autoInterval: 4000,
    autoPlay: true,
    showIndicators: true,
    label: '秋冬の景色',
    enableLiveRegion: true,
 });
// 共通設定(初期設定)
.carousel {
     --_slidesPerView: 1; // 1ビューあたりのスライド数
     --_slidesPerGroup: 1;  // 1度のスワイプで何枚分移動させるか
     --_spaceBetween: 0rem;  // スライド間の距離(単位:rem)
     --_speed: 0.4s; // スライドの遷移時間(単位: s)
     --_inner: 3.6rem; // スライド両脇の余白
}

// 個別設定 
.my-carousel {
     --_slidesPerView: 1;
     --_slidesPerGroup: 1;
     --_spaceBetween: 1rem;      

     @include gl.mq('md') {    
          --_slidesPerView: 2.5;
          --_slidesPerGroup: 2;
          --_spaceBetween: 2rem;
     } 
}

実装機能

  • ナビゲーションボタン(前へ・次へ)
    • 活性・非活性制御
  • インジケータ
  • ループ機能
  • 自動再生機能
    • 停止ボタン
    • スライドをマウスオーバーすると自動再生を停止
  • タブレット操作時のドラッグ対応
  • アクセシビリティ
    • aria-属性の自動付与
    • ライブリージョン

参考

関連

Next.js

Next.js で基本的な UI 機能の実装練習をする

Next.js で基本的な UI 機能の実装練習をする

Next.js と TypeScript のアウトプットを目的として、基本的な UI 機能をスクラッチした。
同時に、Jest を使用した単体テストを書く練習を実施した。Webサイトという文脈でどれほどテストが重要視されているか認識できていないが、aria-属性の変化などを目視で確認せず済むことに利点を感じた。

参考

関連

CI/CD

microCMS の Webhook と GitHub Actions を連携してビルドとデプロイを自動化する

microCMS の Webhook と GitHub Actions を連携してビルドとデプロイを自動化する

microCMS の Webhook と GitHub Actions を連携し、ビルドと XServer へのデプロイを自動化した。
記事の更新や main ブランチへのプッシュをトリガーとしてワークフローが実行される。

参考

Laravel

Laravel で CMS を自作する

Laravel で CMS を自作する

小山健人さん(@koya_zo)の Udemy 講座を通じて、Laravel の学習を行った。

ログイン認証機能やブログ管理機能、メールフォームを Laravel で実装する方法を学んだ。
CSRF 等の脆弱性対策がフレームワーク側で自動的に行われるため、アプリ本体の機能開発に集中できることに Laravel の大きな利点を感じた。

なお、Laravel の環境構築をするに先んじて、Docker の学習を行った。環境構築には Laravel Sail を使用した。

参考

PHP

ToDo アプリをつくる(CRUD とトランザクションの練習)

ToDo アプリをつくる(CRUD とトランザクションの練習)

CRUD とトランザクションの練習として、ToDo アプリを作成した。

追加・編集・削除といった機能に加え、完了ステータスを JavaScript で監視することで、完了したタスクを別テーブルに移動(アーカイブ化)し、リアルタイムで表示が更新されるようにした。この操作にはトランザクションを使用し、途中で処理が失敗してもデータの整合性が保たれるようにした。

また、CRUD 操作において XSS, CSRF, SQLインジェクションの脆弱性対策を実施した。アーカイブ化における fetch を使用した非同期リクエストでは、HTML の meta タグから取得した CSRF トークンを X-CSRF-TOKEN ヘッダに付与し、サーバ側でそのトークンを検証している。

  • 1
  • 2