# Text

## Text Geometry

> Text Geometry를 생성할 때 사용할 폰트 정보를 함께 전달해주어야 한다.
>
> 이 때 전달하는 폰트의 형식은 ttf, otf 같은 형식이 아닌 **`typeface`**&#xB77C;는 JSON 형식의 폰트를 전달 해야한다

```javascript
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry';

const geometry = new TextGeometry('Hello Words', {
    font: font, // 사용할 폰트
    size: 80, // 폰트 사이즈 (default: 100)
    height: 5, // 텍스트 돌출 두께 (default: 50)
    curveSegments: 12, // 곡선의 세그먼트 수 (default: 12)
    bevelEnabled: true, // bevel(경사)을 컨트롤 할지 여부 (default: false) 
    bevelThickness: 10, // 경사진 면의 두께 (default: 10)
    bevelSize: 8, // 텍스트 윤곽선에서 경사진 면이 얼마나 멀리 떨어져 있는지 (default: 8)
    bevelOffset: 0, // 텍스트 윤곽선에서 경사진 면이 시작되는 거리 (default: 0)
    bevelSegments: 5, // 경사진 면을 몇개의 레이러로 나눌것인지,많은수록 부드러워진다. (default: 3)
  });
```

### Bevel

> 그래픽 디자인과 3D 모델링에서 사용되는 용어로, 경사진 면을 뜻하며 객체 또는 텍스트의 가장자리를 부드럽게 꺾거나 둥글게 만들어 각진 모서리를 부드럽게 처리할 수 있다.

![](https://1912740209-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F3GVYdZvmqQyBVq29ebqk%2Fuploads%2FY40api5H2pk02KdtB84Y%2Fbevel.jpeg?alt=media\&token=7334d1fa-9c0b-48b5-94bb-ac835ef1e1ac)

* &#x20;Bevel과 관련된 속성들은 TextGeometry의 상위 클래스 **`extrudeGemtery`**&#xC5D0;서 지원되는 속성들이다.

### Three.js Built In Font

```javascript
// Three.js에서 기본적으로 제공되는 폰트들은 아래 경로에 서 찾아볼 수 있다.
import typeface from 'three/examples/fonts/'
```

{% hint style="danger" %}
기본적으로 내장된 폰트들은 한글이 지원되지 않는다.
{% endhint %}

### 한글을 지원하는 폰트를 사용하거나, 제공하지 않는 폰트를 사용하고 싶은 경우&#x20;

* 일반적으로 사용되는 폰트 파일(ttf, otf 등)을 `typeface` 형식으로 변환 해주어야 한다.&#x20;
* [Facetype.js](https://gero3.github.io/facetype.js/) 로 일반 폰트를 typeface로 변환해보자.
* 폰트를 불러 올 때 Three.js에서 내장된 `FontLoader` 클래스를 이용&#x20;
  * 폰트를 불러오는 방법으로는 2가지 방법이 있다.

```javascript
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader';

const fontLoader = new FontLoader(); 
```

{% hint style="info" %}
[눈누](https://noonnu.cc/) 사이트를 통해 무료로 폰트를 다운 받을 수 있다. (라이선스 확인 필수)
{% endhint %}

#### #1 load('file path', onLoadedCb, onProgressCb, onErrorCb)

> 폰트 경로를 기입하여 불러오는 메서드

* &#x20;첫 번째 인자로 불러올 폰트 파일 경로를 입력&#x20;
* 두 번쨰 인자로 폰트 로드가 완료되는 시점에 호출될 콜백을 입력
  * 불러온 폰트를 통해 `textGeometry`를 생성하고 `scene`에 추가해주는 작업을 작성&#x20;
* 세 번째 인자로 폰트가 로드되는 동안 실행될 콜백을 입력
* 네 번째 인자로 폰트 로드되는 동안 에러가 발생하면 실행될 콜백을 입력&#x20;

```javascript
fontLoader.load('./assets/The Jamsil OTF 3 Regular_Regular.json', (font) => {
    const textGeometry = new TextGeometry('헬로 월드', {
      font,
      size: 0.5,
      height: 0.1,
    });
    const textMaterial = new THREE.MeshPhongMaterial({ color: '#0066ff' });
    const text = new THREE.Mesh(textGeometry, textMaterial);

    scene.add(text); 
  });
```

#### loadAsync()

> load() 메서드는 콜백 함수로 비동기 코드를 작성하게되는데 코드가 자칫 더러워질 수 있다. (에러처리, 콜백지옥)
>
> 좀 더 깔끔한 코드와 스코프를 맞추기 위해  `loadAsync()` 메서드를 사용해보자.

* load() 메서드와 기본적으로 사용방법이 동일하지만, 로드된 폰트를 받아서 사용하는 부분만 다르다.&#x20;
* 해당 함수 자체가 Promise를 반환하기에 `await` 키워드를 필요로 한다. (동기식으로 작성할 경우)
* 모두 같은 스코프로 되어 있어 값에 접근하기 쉬워진다.

```javascript
  const font = await fontLoader.loadAsync(
    './assets/Yeongdeok Snow Crab_Regular.json'
  );
  const textGeometry = new TextGeometry('왜이러니', {
    font,
    size: 0.5,
    height: 0.1,
  });
  const textMaterial = new THREE.MeshPhongMaterial({ color: 0x00c896 });
  const text = new THREE.Mesh(textGeometry, textMaterial); 
  scene.add(text);
```

#### #2 parse(typeface)&#x20;

> typeface json 객체를 임포트하여 THREE.js에서 이해할 수 있는 형식으로 파싱해주는 메서드&#x20;

* 첫 번째 인자로 typeface 객체를 넣어 THREE.js에서 이해할 수 있는 폰트로 반환
* 반환된 폰트를 `textGeometry` 를 생성할때 사용

```javascript
import typeface from '...' 

const font = fontLoader.parse(typeface);
```

### Text Align Center

> 렌더링된 텍스트를 보면 전체적으로  오른쪽으로 치우쳐저 보인다.&#x20;
>
> 텍스트가 차지하는 너비만큼  X축으로 빼주면 가운데 정렬이 된다.&#x20;

#### BoundingBox&#x20;

BoundingBox란 TextGeometry 경계 영역을 감싸고 있는 박스

* 기본적으로 계산 되어지지 않기 때문에 `.computeBoundingBox()` 호출하여 명시적으로 설정 해주어야 한다.

```javascript
const textGeometry = new TextGeometry('왜이러니', {
    font,
    size: 0.5,
    height: 0.1,
  }); 
textGeometry.computeBoundingBox();
console.log(textGeometry.boundingBox);
// 로그에 찍힌 boundingBox 데이터는 하기와 같다.
// Box3 {isBox3: true, min: _Vector3, max: _Vector3}
// isBox3: true
// max: _Vector3 {x: 2.7249999046325684, y: 0.5299999713897705, z: 0.10000000149011612}
// min: _Vector3 {x: 0.02850000001490116, y: -0.11299999803304672, z: 0}
```

* boundingBox의 `max.x`(끝점)에서 `min.x`(시작점)을 빼주면 textGeometry 영역의 너비를 계산할 수 있다.
* 즉, 계산된 너비값의 절반을 X축에서 빼주면 가운데 정렬이 된다.&#x20;
* textGeometry의 축 이동은 `translate()`를 이용

```javascript
const { min, max } = textGeometry.boundingBox;
textGeometry.translate(
  -(max.x - min.x) * 0.5,
  -(max.y - min.y) * 0.5,
  -(max.z - min.z) * 0.5
);  // x, y, z
```

#### center()&#x20;

> 단순히 가운데 정렬이 목적이라면 center() 메서드로 간단히 동일한 결과를 얻을 수 있다.

```javascript
 textGeometry.center();
```

### Texture 추가하기

> gemoetry의 표면을 어떤 이미지로 덮는다는 의미

* **`TextureLoader()`**&#xB97C; 이용하여 텍스쳐를 추가하는데 폰트를 불러오는 방법과 비슷하다.
* 한 가지 다른점은 `loadAsync` 를 사용하지 않아도 텍스쳐를 반환해준다.
* 반환된 텍스쳐를 textMaterial의 map 속성에 넣어주면 적용된다.

```javascript
const textureLoader = new THREE.TextureLoader().setPath('./assets/textures/);
const textTexture = textureLoader.load('holographic.jpeg');
textMaterial.map = textTexture;
```

{% hint style="info" %}
**`TextureLoader.setPath()`**&#xB97C; 설정하면 텍스쳐 파일들의 베이스 경로를 지정하여 사용할 때 파일이름만 입력해도 동일하게 사용할 수 있다.
{% endhint %}
