# AI 꾸러미 — PBR + 클리어코트 — Clearcoat (PBR coat layer)
> 나뭇결 · 색 재질 위에 반짝이는 투명 막을 한 겹 더 얹어, 니스 칠한 나무 · 반들한 플라스틱 말처럼 보이게 한다.  
> 견본: https://ai-techstudio.web.app/#t/u04

이 문서를 코드 도우미(Claude Code · Cursor · ChatGPT 등)에 그대로 주면 돼요. 「## 주문서」 가 할 일, 나머지는 참고 자료예요.

## 주문서

### 만들어 줘: PBR + 클리어코트 — Clearcoat (PBR coat layer)

#### 1. 목표
나무 판 위 체커 말 · 체스 폰에 클리어코트(바탕은 거칠고 위에 매끈한 투명 막)를 입혀 줘. 느낌은 니스 칠한 원목.

#### 2. 핵심 기술 용어
- **Clearcoat (PBR coat layer)** — 바탕 위 투명 막 한 겹 — 니스 · 코팅
- **MeshPhysicalMaterial.clearcoat · clearcoatRoughness** — three.js 막 세기 · 막 거칠기
- **Environment map reflection** — 환경 반사 — 막에 비칠 주변

#### 3. 환경
- 플랫폼: three.js r186 (ES 모듈 · TypeScript, `import * as THREE from "three"`), WebGL2, 외부 라이브러리 추가 없이
- 화면: 3D · 브라우저 — PC 와 폰(가로 844×390 · 세로 390×844) 모두, 60fps 목표

#### 4. 조건
- 바탕 재질과 막 재질을 같은 바탕값(map · roughness 0.85)으로 두고 clearcoat 만 달리해 비교
- scene.environment 에 반사할 환경을 넣기 (없으면 막이 안 보인다)
- 빛 하나를 천천히 돌려 막의 하이라이트가 움직이는 것을 보여 주기
- 「클리어코트」 0~1 · 「막 거칠기」 0~0.6 슬라이더

#### 5. 완성 기준 (이게 보이면 성공)
- 왼쪽 일반 재질 · 오른쪽 클리어코트를 나란히 두면, 오른쪽 나뭇결 위에만 또렷한 빛줄 · 창 반사가 보인다
- 빛이 돌면 오른쪽 하이라이트가 매끄럽게 미끄러진다
- 「막 거칠기」를 올리면 반사가 뿌옇게 번진다
- 폰에서도 60fps (말 수십 개 기준)

#### 6. 진행 방식
- 핵심 코드 위주로, 설명은 짧게. 내 프로젝트에 끼워 넣기 쉬운 함수 · 클래스로 나눠 줘.
- 처음 화면에 바로 결과가 보이게, 그리고 켬/끔(또는 전/후) 비교를 할 수 있게 만들어 줘.
- 그림 · 소리 · 모델 파일이 필요하면 코드로 만든 임시 대체물로 먼저 돌아가게 하고, 진짜 파일로 바꿀 자리를 표시해 줘.
- 마지막에 「확인 방법」(무엇을 보면 성공인지)과 「조절할 값」 목록을 짧게 정리해 줘.
- 답변과 코드 주석은 한국어로 해 줘.

## 원리
- 진짜 니스 칠은 거친 나무 위에 매끈한 투명 층이 있어, 빛이 두 번 반사된다.
- MeshPhysicalMaterial 은 바탕(roughness 0.85)과 별도로 막(clearcoat 1, clearcoatRoughness 0.05)을 계산한다.
- 바탕은 흐릿하게, 막은 또렷한 하이라이트 · 창 반사를 만든다.
- 막은 비칠 것이 있어야 보이므로 환경 지도(scene.environment)가 꼭 필요하다.

## 핵심 코드 — 같은 나뭇결에 막만 더하기
(발췌: demos/demosMaterial.ts u04 make() 를 정리)
```ts
// 막에 비칠 사진관 환경 (견본은 캔버스로 그린 equirect — RoomEnvironment 도 된다)
scene.environment = studioEnv;
scene.environmentIntensity = 1.8;

const wood = woodTex('#a85a2a');          // 캔버스로 그린 나뭇결 (u09)

// 왼쪽: 바탕만
const plain = new THREE.MeshStandardMaterial({ map: wood, roughness: 0.85 });
// 오른쪽: 같은 바탕 + 매끈한 막 한 겹
const coated = new THREE.MeshPhysicalMaterial({
  map: wood,
  roughness: 0.85,          // 바탕은 거칠게 — 나무결이 흐릿하게 빛을 받는다
  clearcoat: 1,             // 막 세기
  clearcoatRoughness: 0.05, // 막은 매끈 — 또렷한 창 반사
});

const disc = new THREE.Mesh(discGeo(0.6, 0.24), coated);
scene.add(disc);

// 빛을 천천히 돌려 막의 하이라이트를 보여 준다
const sun = new THREE.DirectionalLight(0xfff2dc, 2.6);
scene.add(sun);
function update(t: number) {
  sun.position.set(Math.sin(t * 0.7) * 5, 4, Math.cos(t * 0.7) * 3 + 2);
}
```

## 흔한 실수 · 확인 목록
- [ ] **환경 지도 없이 쓰면 막이 거의 안 보인다** — clearcoat 는 주로 반사로 드러난다. scene.environment 에 RoomEnvironment(PMREM) 나 그린 환경을 넣는다.
- [ ] **바탕 roughness 까지 낮추면 막과 구분이 안 된다** — 바탕은 0.8 안팎으로 거칠게, 막만 매끈하게 해야 「니스 칠」처럼 두 층이 보인다.
- [ ] **물리 재질을 수십 종 만들면 셰이더 컴파일이 길다** — 같은 설정은 재질 하나를 돌려 쓰고, 첫 등장 멈칫은 compileAsync 로 미리 데운다(i385).

## 완성 기준 체크리스트
- [ ] 왼쪽 일반 재질 · 오른쪽 클리어코트를 나란히 두면, 오른쪽 나뭇결 위에만 또렷한 빛줄 · 창 반사가 보인다
- [ ] 빛이 돌면 오른쪽 하이라이트가 매끄럽게 미끄러진다
- [ ] 「막 거칠기」를 올리면 반사가 뿌옇게 번진다
- [ ] 폰에서도 60fps (말 수십 개 기준)

## 이 기술 정보
- id: `u04` · 분류: 그래픽 · 셰이더 › 재질 · 그림체 · 3D · 난이도 쉬움 · 폰 부담 보통 (폰 주의) — MeshPhysicalMaterial 은 표준 재질보다 셰이더가 길고, 막 층 계산이 한 번 더 들어간다. 물체가 많은 폰 장면은 꼭 필요한 것만.
- 라이브 견본 (브라우저에서 직접 조작): https://ai-techstudio.web.app/#t/u04
- 쓰면 좋을 때: 보드게임 말 · 나무 판 · 장난감처럼 손으로 만지는 물건 / 움직이는 빛에 반짝임이 살아 있어야 할 때
- 쓰지 말 때: 흙 · 천 · 종이처럼 광이 없는 것 — 대신 일반 MeshStandardMaterial / 아주 많은 작은 물체를 폰에서 — 물리 재질이 무겁다. 대신 roughness 낮춘 표준 재질

## 견본 실제 코드 (라이브 견본이 돌리는 코드 — three.js · TypeScript)
### u04 견본 항목 — `src/demos/demosMaterial.ts:418`
```ts
  u04: {
    kind: '3d',
    caption: '왼쪽 일반 PBR · 오른쪽 클리어코트 — 나뭇결 위에 반짝이는 니스 막이 한 겹 더',
    make() {
      const B = base({ bg: gradBg('#1d2440', '#3b4a78', 'rgba(255,210,150,0.22)'), labels: ['일반 재질', '+ 클리어코트'], fit: [2.5, 0.95], target: [0, 0.15, 0], dir: [0, 0.55, 1], env: studioEnv(true, true) });
      const sun = lights(B.scene, 0xffffff, 0x302840, 0.3, 2.6);
      B.scene.environmentIntensity = 1.8;
      const wood = woodTex('#a85a2a');
      const woodB = woodTex('#3a2a20');
      const mats = {
        a: new THREE.MeshStandardMaterial({ map: wood, roughness: 0.85 }),
        b: new THREE.MeshPhysicalMaterial({ map: wood, roughness: 0.85, clearcoat: 1, clearcoatRoughness: 0.05 }),
        a2: new THREE.MeshStandardMaterial({ color: 0x2f8fe0, roughness: 0.8 }),
        b2: new THREE.MeshPhysicalMaterial({ color: 0x2f8fe0, roughness: 0.8, clearcoat: 1, clearcoatRoughness: 0.05 }),
        a3: new THREE.MeshStandardMaterial({ map: woodB, roughness: 0.85 }),
        b3: new THREE.MeshPhysicalMaterial({ map: woodB, roughness: 0.85, clearcoat: 1, clearcoatRoughness: 0.05 }),
      };
      const dg = discGeo(0.6, 0.24);
      const pg = pawnGeo();
      const set = (m1: THREE.Material, m2: THREE.Material, m3: THREE.Material): THREE.Group => {
        const g = new THREE.Group();
        const board = new THREE.Mesh(new RoundedBoxGeometry(2.1, 0.16, 1.5, 3, 0.05), m3);
        board.position.y = -0.55;
        const disc = new THREE.Mesh(dg, m1);
        disc.position.set(-0.4, -0.35, 0.15);
        const pawn = new THREE.Mesh(pg, m2);
        pawn.position.set(0.45, -0.47, -0.1);
        pawn.scale.setScalar(0.85);
        g.add(board, disc, pawn);
        return g;
      };
      const L = set(mats.a, mats.a2, mats.a3);
      const R = set(mats.b, mats.b2, mats.b3);
      L.position.x = -1.2;
      R.position.x = 1.2;
      B.scene.add(L, R);
      return B.done({
        update(t) {
          sun.position.set(Math.sin(t * 0.7) * 5, 4, Math.cos(t * 0.7) * 3 + 2);
          for (const g of [L, R]) g.rotation.y = Math.sin(t * 0.4) * 0.35;
        },
        controls: [
          { type: 'range', label: '클리어코트', min: 0, max: 1, step: 0.05, value: 1, on: (v) => { mats.b.clearcoat = mats.b2.clearcoat = mats.b3.clearcoat = v; } },
          { type: 'range', label: '막 거칠기', min: 0, max: 0.6, step: 0.01, value: 0.05, on: (v) => { mats.b.clearcoatRoughness = mats.b2.clearcoatRoughness = mats.b3.clearcoatRoughness = v; } },
        ],
      });
    },
  }
```

## 관련 기술
- 같은 방법으로 만든 효과 예시: [쉰(sheen)](https://ai-techstudio.web.app/ai/t/u05.md) `u05` · [진주빛 (iridescence)](https://ai-techstudio.web.app/ai/t/u06.md) `u06` · [비눗방울 박막 무지개](https://ai-techstudio.web.app/ai/t/i227.md) `i227`
- 먼저 알면 좋은 기술: [환경 반사 (RoomEnvironment + PMREM)](https://ai-techstudio.web.app/ai/t/u12.md) `u12`
- 다음에 해 볼 기술: [투과 · 굴절 (유리 · 얼음)](https://ai-techstudio.web.app/ai/t/u07.md) `u07` · [그린 요철 · 노멀 맵](https://ai-techstudio.web.app/ai/t/u10.md) `u10`
- 참고 문서: [three.js 예제 — webgl_materials_physical_clearcoat](https://threejs.org/examples/#webgl_materials_physical_clearcoat) · [three.js 문서 — MeshPhysicalMaterial](https://threejs.org/docs/#api/en/materials/MeshPhysicalMaterial)
