# AI 꾸러미 — 투과 · 굴절 (유리 · 얼음) — Transmission (physically based refraction)
> 빛이 물체 속을 지나며 꺾이고 색이 갈라지게 해, 뒤가 휘어 비치는 유리 · 얼음 · 보석을 만든다.  
> 견본: https://ai-techstudio.web.app/#t/u07

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

## 주문서

### 만들어 줘: 투과 · 굴절 (유리 · 얼음) — Transmission (physically based refraction)

#### 1. 목표
얼음 크리스탈 · 유리 상자를 투과 · 굴절 재질로 만들어 줘 — 뒤 무늬가 휘어 보이고 가장자리에 무지개 분산. 느낌은 맑고 차가운 얼음.

#### 2. 핵심 기술 용어
- **Transmission (physically based refraction)** — 투과 — 뒤 장면이 비쳐 보임
- **IOR · thickness** — 굴절률 · 두께 — 얼마나 꺾이나
- **Dispersion** — 분산 — 색마다 다르게 꺾여 가장자리에 무지개
- **attenuationColor · attenuationDistance** — 속을 지날수록 물드는 색

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

#### 4. 조건
- MeshPhysicalMaterial 의 transmission · ior · thickness · dispersion 으로 (opacity 로 흉내 내지 않기)
- roughness 는 0.03 처럼 아주 낮게 — 높으면 뒤가 뿌옇게 번진다
- 뒤에 또렷한 줄무늬 판을 두어 굴절이 보이게
- 「굴절률」 1~2.4 · 「분산」 0~8 · 「두께」 0~3 슬라이더

#### 5. 완성 기준 (이게 보이면 성공)
- 왼쪽 그냥 반투명 · 오른쪽 투과 재질을 나란히 두면, 오른쪽만 뒤 줄무늬가 휘고 가장자리에 무지개가 생긴다
- 굴절률을 올리면 뒤 무늬가 더 크게 꺾인다
- 분산 0 이면 무지개가 사라진다

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

## 원리
- 그냥 반투명(opacity)은 뒤를 흐릿하게 섞을 뿐, 휘지 않는다.
- transmission: 1 은 뒤 장면을 따로 그린 그림을 가져와, 굴절률(ior 1.5)과 두께(thickness 1.2)만큼 어긋나게 읽는다.
- dispersion(3)은 빨강 · 초록 · 파랑을 조금씩 다르게 꺾어 가장자리에 무지개를 만든다.
- attenuationColor 로 두꺼운 곳일수록 옅은 하늘색으로 물들인다.
- 뒤에 줄무늬처럼 또렷한 것이 있어야 굴절이 눈에 띈다.

## 핵심 코드 — 반투명과 투과 · 굴절 비교
(발췌: demos/demosMaterial.ts u07 make() 를 정리)
```ts
// 뒤 줄무늬 판 — 굴절이 눈에 띄게
const [c, g] = cv(256, 128);
const cols = ['#ff6b6b', '#ffd93d', '#6bcB77', '#4d96ff', '#c77dff'];
for (let i = 0; i < 16; i++) { g.fillStyle = cols[i % 5]; g.fillRect(i * 16, 0, 16, 128); }
const back = new THREE.Mesh(new THREE.PlaneGeometry(6.4, 2.2), new THREE.MeshBasicMaterial({ map: new THREE.CanvasTexture(c) }));
back.position.set(0, 0.1, -1.4);
scene.add(back);

// 왼쪽: 그냥 반투명 — 뒤가 휘지 않는다
const glassA = new THREE.MeshStandardMaterial({ color: 0xcfefff, roughness: 0.1, transparent: true, opacity: 0.45 });
// 오른쪽: 투과 + 굴절 + 분산
const glassB = new THREE.MeshPhysicalMaterial({
  color: 0xffffff,
  roughness: 0.03,
  transmission: 1,
  ior: 1.5,
  thickness: 1.2,
  dispersion: 3,
  attenuationColor: new THREE.Color(0xc8f0ff),
  attenuationDistance: 3,
});
const crystal = new THREE.Mesh(new THREE.OctahedronGeometry(0.62, 0), glassB);
crystal.scale.set(0.8, 1.35, 0.8);
scene.add(crystal);
scene.environment = studioEnv; // 겉면 반사도 함께
```

## 흔한 실수 · 확인 목록
- [ ] **opacity 만 낮추면 「유리」가 아니라 흐린 비닐처럼 보인다** — transmission 을 쓰고 transparent 는 켜지 않는다 (투과는 불투명 패스에서 따로 계산).
- [ ] **투과 물체끼리는 서로 비치지 않는다** — 투과용 그림에는 불투명 물체만 들어간다. 겹치는 보석 여러 개는 앞의 것만 투과로.
- [ ] **뒤가 단색이면 굴절이 안 보인다** — 줄무늬 · 격자처럼 또렷한 배경을 둔다. 얼음 별 게임은 속에 금 · 기포를 넣어 굴절을 드러냈다.

## 완성 기준 체크리스트
- [ ] 왼쪽 그냥 반투명 · 오른쪽 투과 재질을 나란히 두면, 오른쪽만 뒤 줄무늬가 휘고 가장자리에 무지개가 생긴다
- [ ] 굴절률을 올리면 뒤 무늬가 더 크게 꺾인다
- [ ] 분산 0 이면 무지개가 사라진다

## 이 기술 정보
- id: `u07` · 분류: 그래픽 · 셰이더 › 재질 · 그림체 · 3D · 난이도 보통 · 폰 부담 무거움 — 투과 물체가 하나라도 있으면 장면을 한 번 더(투과용 그림) 그린다. 투과 물체끼리는 서로 안 비친다.
- 라이브 견본 (브라우저에서 직접 조작): https://ai-techstudio.web.app/#t/u07
- 쓰면 좋을 때: 얼음 · 유리 · 보석처럼 속이 비치는 물체가 주인공일 때 / 물체 수가 적고 크게 보일 때
- 쓰지 말 때: 투명한 물체가 수십 개 — 투과 패스 비용이 크다. 대신 opacity + 환경 반사 / 폰 저사양 모드 — 대신 매트캡(i09) 얼음 그림

## 견본 실제 코드 (라이브 견본이 돌리는 코드 — three.js · TypeScript)
### u07 견본 항목 — `src/demos/demosMaterial.ts:570`
```ts
  u07: {
    kind: '3d',
    caption: '왼쪽 그냥 반투명 · 오른쪽 투과+굴절+분산 — 뒤 줄무늬가 휘고 가장자리에 무지개',
    make() {
      const B = base({ bg: gradBg('#a8dcf8', '#eaf7ff'), labels: ['반투명 (opacity)', '투과 · 굴절'], fit: [2.5, 0.95], target: [0, 0.05, 0], env: studioEnv() });
      lights(B.scene, 0xffffff, 0x8090b0, 0.9, 1.8);
      // 뒤 줄무늬 판 — 굴절이 보이게
      const [c, g] = cv(256, 128);
      const cols = ['#ff6b6b', '#ffd93d', '#6bcB77', '#4d96ff', '#c77dff'];
      for (let i = 0; i < 16; i++) {
        g.fillStyle = cols[i % 5]!;
        g.fillRect(i * 16, 0, 16, 128);
      }
      const back = new THREE.Mesh(new THREE.PlaneGeometry(6.4, 2.2), new THREE.MeshBasicMaterial({ map: tex(c) }));
      back.position.set(0, 0.1, -1.4);
      B.scene.add(back);
      const glassA = new THREE.MeshStandardMaterial({ color: 0xcfefff, roughness: 0.1, transparent: true, opacity: 0.45 });
      const glassB = new THREE.MeshPhysicalMaterial({ color: 0xffffff, roughness: 0.03, transmission: 1, ior: 1.5, thickness: 1.2, dispersion: 3, attenuationColor: new THREE.Color(0xc8f0ff), attenuationDistance: 3 });
      const crys = new THREE.OctahedronGeometry(0.62, 0);
      const cube = new RoundedBoxGeometry(0.7, 0.7, 0.7, 4, 0.1);
      const set = (m: THREE.Material): { g: THREE.Group; a: THREE.Mesh; b: THREE.Mesh } => {
        const gg = new THREE.Group();
        const a = new THREE.Mesh(crys, m);
        a.scale.set(0.8, 1.35, 0.8);
        a.position.set(-0.32, 0.12, 0);
        const b = new THREE.Mesh(cube, m);
        b.position.set(0.48, -0.42, 0.25);
        gg.add(a, b);
        return { g: gg, a, b };
      };
      const L = set(glassA);
      const R = set(glassB);
      L.g.position.x = -1.2;
      R.g.position.x = 1.2;
      B.scene.add(L.g, R.g);
      return B.done({
        update(t) {
          for (const S of [L, R]) {
            S.a.rotation.y = t * 0.5;
            S.b.rotation.set(t * 0.3, t * 0.4, 0);
          }
        },
        controls: [
          { type: 'range', label: '굴절률 (ior)', min: 1, max: 2.4, step: 0.05, value: 1.5, on: (v) => { glassB.ior = v; } },
          { type: 'range', label: '분산 (무지개)', min: 0, max: 8, step: 0.5, value: 3, on: (v) => { glassB.dispersion = v; } },
          { type: 'range', label: '두께', min: 0, max: 3, step: 0.1, value: 1.2, on: (v) => { glassB.thickness = v; } },
        ],
      });
    },
  }
```

## 관련 기술
- 같은 방법으로 만든 효과 예시: [렌즈 · 유리 (굴절 · 반사 코팅)](https://ai-techstudio.web.app/ai/t/i473.md) `i473`
- 먼저 알면 좋은 기술: [PBR + 클리어코트](https://ai-techstudio.web.app/ai/t/u04.md) `u04` · [환경 반사 (RoomEnvironment + PMREM)](https://ai-techstudio.web.app/ai/t/u12.md) `u12`
- 다음에 해 볼 기술: [매트캡 (MatCap)](https://ai-techstudio.web.app/ai/t/i09.md) `i09`
- 참고 문서: [three.js 예제 — webgl_materials_physical_transmission](https://threejs.org/examples/#webgl_materials_physical_transmission) · [three.js 문서 — MeshPhysicalMaterial](https://threejs.org/docs/#api/en/materials/MeshPhysicalMaterial)
