文字を立体で表示する(HTML/CSS/JS)

前書き

文字を立体で表示する方法を掲載しています。

目次

  1. cssで立体に見せる
  2. three.jsで文字を表示する
  3. 参考

cssで立体に見せる

下記ページを参考にしています。
text-shadowを重ねて立体に見せています。

【CSS】text-shadowを使ったテキストの装飾パターンを色々作ってみた

いろはに
ほへと


<p class="text">いろはに<br>ほへと</p>

.text{
  color: #a675a5;
  text-shadow:
    1px 1px #845080,
    2px 2px #845080,
    3px 3px #845080,
    4px 4px #845080,
    5px 5px #845080,
    6px 6px 4px #777;
}

three.jsで文字を表示する

下記ページを参考にしています。
フォントを準備する必要があります。

threejs examples #webgl_geometry_shapes
threejs examples #webgl_geometry_text_shapes

概要

  • 日本語のフォント(TrueType形式)をjsonに変換
  • そのフォントを読み込んで形を作る
  • 立体にする

英語のフォント

three.js/examples/fonts/

今回利用したフォント、サイト

フォントな

Facetype.js

見本


<div class="wrap js-wrap-a">
  <canvas class="canvas js-canvas"></canvas>
</div>

.wrap{
  position: relative; padding: 50% 0 0; overflow: hidden;
}
.canvas{
  position: absolute; top: 0; left: 0; width: 100%; height: 100%;
}

import * as THREE from './three_r127/build/three.module.js';
import { OrbitControls } from './three_r127/examples/jsm/controls/OrbitControls.js';

// サイズ------------------
const wrap = document.querySelector(".js-wrap-a");
let wrapWidth = wrap.clientWidth;
let wrapHeight = wrap.clientHeight;

// レンダラー------------------
const renderer = new THREE.WebGLRenderer({
  canvas: document.querySelector(".js-canvas"),
  antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(wrapWidth, wrapHeight);

// シーン------------------
const scene = new THREE.Scene();
scene.background = new THREE.Color( 0xf5edf3 ); //背景色

// カメラ------------------
const camera = new THREE.PerspectiveCamera( 45, wrapWidth / wrapHeight );
camera.position.set( 0, 0, 600 );

// カメラコントローラーを作成
const controls = new OrbitControls( camera, renderer.domElement );

// 光源------------------
const hLight = new THREE.HemisphereLight(0xffffff, 1); // 半球光源
scene.add(hLight);

// フォント ------------------
const fontInit = e => {

  // 共通
  const message = "いろはに\n ほへと";

  //塗りつぶす文字の形状
  const shapesA = e.generateShapes( message, 100 );

  //縁取りをする文字の形状( 穴の開いている部分のパスを追加する )
  const shapesB = e.generateShapes( message, 100 );
  const holeShapes = [];
  for ( let i = 0; i < shapesB.length; i ++ ) {
    const shape = shapesB[ i ];
    if ( shape.holes && shape.holes.length > 0 ) {
      for ( let j = 0; j < shape.holes.length; j ++ ) {
        const hole = shape.holes[ j ];
        holeShapes.push( hole );
      }
    }
  }
  shapesB.push.apply( shapesB, holeShapes );

  //位置調整
  const group = new THREE.Group();
  const geometry00 = new THREE.ShapeGeometry( shapesA );
  geometry00.computeBoundingBox();
  const x = - 0.5 * ( geometry00.boundingBox.max.x + geometry00.boundingBox.min.x );
  const y = - 0.5 * ( geometry00.boundingBox.max.y + geometry00.boundingBox.min.y );
  group.position.x = x;
  group.position.y = y;
  scene.add( group );

  // 01 塗りつぶしの文字(平面) ------------------
  const material01 = new THREE.MeshBasicMaterial( {
    color: 0x845080,
    side: THREE.DoubleSide
  });
  const geometry01 = new THREE.ShapeGeometry( shapesA );
  const text01 = new THREE.Mesh( geometry01, material01 );
  text01.position.z = - 50;
  group.add( text01 );

  // 02 塗りつぶしの文字(立体) ------------------
  const material02 = new THREE.MeshPhongMaterial( {
    color: 0x845080,
    side: THREE.DoubleSide
  });
  const extrudeSettings02 = {
    depth: 25,
    bevelThickness: 1,
  };
  const geometry02 = new THREE.ExtrudeGeometry( shapesA, extrudeSettings02 );
  const text02 = new THREE.Mesh( geometry02, material02 ) ;
  text02.position.z = -150;
  group.add( text02 );

  // 03 縁取りをする文字(実線) ------------------
  const material03 = new THREE.LineBasicMaterial( {
    color: 0x845080,
    side: THREE.DoubleSide
  });

  const text03 = new THREE.Object3D();
  for ( let i = 0; i < shapesB.length; i ++ ) {
    const shape = shapesB[ i ];
    const points = shape.getPoints();
    const geometry03 = new THREE.BufferGeometry().setFromPoints( points );
    const mesh = new THREE.Line( geometry03, material03 );
    text03.add( mesh );
  }
  text03.position.z = 50;
  group.add( text03 );

  // 04 縁取りをする文字(点線) ------------------
  const material04 = new THREE.PointsMaterial( {
    color: 0x845080,
    size: 5,
    side: THREE.DoubleSide
  });

  const text04 = new THREE.Object3D();
  for ( let i = 0; i < shapesB.length; i ++ ) {
    const shape = shapesB[ i ];
    const length = shape.getLength(); //曲線の長さ
    const spacedPoints = shape.getSpacedPoints( length * 0.2 ); //点の間隔
    const geometry04 = new THREE.BufferGeometry().setFromPoints( spacedPoints );
    const mesh = new THREE.Points( geometry04, material04 );
    text04.add( mesh );
  }
  text04.position.z = 150;
  group.add( text04 );
}

// フォントの読み込み
const loader = new THREE.FontLoader();
loader.load( './three_r127/examples/fonts/font.typeface.json', fontInit);

//リサイズ------------------
const wrapResize = () =>{
  wrapWidth = wrap.clientWidth;
  wrapHeight = wrap.clientHeight;
  renderer.setSize(wrapWidth, wrapHeight);
  // camera.aspect = wrapWidth / wrapHeight;
  // camera.updateProjectionMatrix();
}

//一定時間毎に処理------------------
let tick;
const switching = (e) => {
  if( e[0].isIntersecting ){ //見えてる時
    tick = () => {
      wrapResize(); //リサイズ
      renderer.render(scene, camera); //レンダリング
      requestAnimationFrame( tick ); //繰り返し
    }
    requestAnimationFrame( tick );
  }else{ //見えてない時
    tick = () => {
      cancelAnimationFrame( tick )
    }
  }
}

//見えているかどうか(Intersection Observer API)------------------
const createObserver = () => {
  let observer;
  const options = { root: null, rootMargin: "0%", threshold: 0 };
  observer = new IntersectionObserver(switching, options); //コールバック関数とオプションを渡す
  observer.observe(wrap); //要素の監視を開始
}
createObserver();

参考

【CSS】text-shadowを使ったテキストの装飾パターンを色々作ってみた

threejs examples #webgl_geometry_shapes

threejs examples #webgl_geometry_text_shapes

フォントな

Facetype.js

関連記事

簡単な地図を自作する(HTML/CSS/JS)

パーティクルを作成する(HTML/JS)

360度画像を表示する(HTML/JS)

うにょうにょ動かす(HTML/CSS/JS)

円を描くように要素を動かす(HTML/CSS/JS)

マウスの位置に合わせて要素を動かす(HTML/CSS/JS)

先頭に戻る
ページの先頭に戻る