241 lines
7.9 KiB (Stored with Git LFS)
Plaintext

웹 리모컨 리타게팅 시스템 - 전체 작업 요약
이 세션에서는 Unity KindRetargeting 시스템의 웹 리모컨 기능을 개선했습니다.
1. 메뉴 순서 정렬
문제: 웹 리모컨과 Unity Editor 창(RetargetingControlWindow)의 메뉴 순서가 달랐음
해결: JavaScript에서 섹션 순서를 Unity Editor와 동일하게 재정렬
1. 가중치 설정 (IK weights)
2. 힙 위치 보정
3. 무릎 위치 조정
4. 발 위치 조정
5. 손가락 제어 설정
6. 손가락 복제 설정
7. 모션 설정 (Struggle)
8. 바닥 높이 설정
9. 아바타 크기 설정
10. 머리 크기 설정
11. 캘리브레이션
2. 손가락 제어 스크립트 활성화 문제 해결
문제: 손가락 제어 기능이 동작하지 않음 - HandPoseController 컴포넌트가 기본적으로 비활성화 상태
해결:
C# 수정 (RetargetingRemoteController.cs):
// handPoseEnabled 속성 추가
case "handPoseEnabled":
if (handPose != null)
handPose.enabled = message.value > 0.5f;
break;
// 손 활성화 시 자동으로 스크립트도 활성화
case "leftHandEnabled":
if (handPose != null)
{
handPose.leftHandEnabled = message.value > 0.5f;
if (handPose.leftHandEnabled)
handPose.enabled = true; // 자동 활성화
}
break;
JavaScript 수정: 프리셋 적용 시에도 자동으로 스크립트 및 해당 손 활성화
function applyPreset(charId, name, hand) {
send({ action: 'setHandPosePreset', characterId: charId, property: hand, stringValue: name });
// 스크립트 자동 활성화
var scriptCheckbox = document.getElementById('handPoseEnabled_' + charId);
if (scriptCheckbox) scriptCheckbox.checked = true;
// 해당 손 체크박스도 활성화
var handCheckbox = document.getElementById((hand === 'leftHandPreset' ? 'leftHandEnabled' : 'rightHandEnabled') + '_' + charId);
if (handCheckbox) handCheckbox.checked = true;
}
UI 추가: "스크립트 활성화" 체크박스 추가
3. 수치 직접 입력 필드 추가
사용자 요청: "수치값을 직접 입력을 할수 있는 인풋필드가 있으면 좋겠어"
HTML 구조:
<div class="slider-header">
<label>라벨명</label>
<input type="number" class="value-input" step="0.01" />
</div>
<div class="slider-row">
<button class="btn-fine">-</button>
<input type="range" />
<button class="btn-fine">+</button>
</div>
JavaScript 함수 추가:
function inputValueChange(charId, prop, inputEl, sliderId, min, max) {
var val = parseFloat(inputEl.value) || 0;
val = Math.max(min, Math.min(max, val));
inputEl.value = val.toFixed(2);
document.getElementById(sliderId).value = val;
send({ action: 'updateValueRealtime', characterId: charId, property: prop, value: val });
}
function inputKeyDown(e, charId, prop, inputEl, sliderId, min, max) {
if (e.key === 'Enter') {
inputValueChange(charId, prop, inputEl, sliderId, min, max);
inputEl.blur();
}
}
CSS 스타일:
.value-input {
font-family: monospace;
background: var(--bg);
border: 1px solid var(--surface-light);
border-radius: 4px;
padding: 4px 6px;
font-size: 0.8em;
color: var(--text);
width: 80px;
text-align: right;
}
4. 로컬 접속 지원
문제: 같은 PC에서 localhost 접속이 안 됨
해결 (RetargetingHTTPServer.cs):
listener.Prefixes.Add($"http://localhost:{httpPort}/");
listener.Prefixes.Add($"http://127.0.0.1:{httpPort}/");
// 외부 접속도 시도
try {
listener.Prefixes.Add($"http://+:{httpPort}/");
} catch (Exception) {
Debug.LogWarning("[RetargetingHTTP] 외부 접속 바인딩 실패. localhost만 사용 가능합니다.");
}
로그 출력:
[RetargetingHTTP] 로컬 접속: http://localhost:8080
[RetargetingHTTP] 로컬 접속: http://127.0.0.1:8080
[RetargetingHTTP] 외부 접속: http://192.168.x.x:8080
5. UI 상태 업데이트 동기화
문제: 손 활성화/프리셋 적용 시 체크박스 상태가 업데이트 안 됨
해결:
function updateToggle(charId, prop, checked) {
send({ action: 'updateValueRealtime', characterId: charId, property: prop, value: checked ? 1 : 0 });
// 손 활성화 시 스크립트 체크박스도 자동 체크
if ((prop === 'leftHandEnabled' || prop === 'rightHandEnabled') && checked) {
var scriptCheckbox = document.getElementById('handPoseEnabled_' + charId);
if (scriptCheckbox) scriptCheckbox.checked = true;
}
}
6. WebSocket 로그 제거
사용자 요청: "이거 로그 이제 안나와도 될꺼 같음"
수정 (RetargetingWebSocketServer.cs):
protected override void OnMessage(MessageEventArgs e)
{
// Debug.Log 제거
TriggerMessageReceived(e.Data);
}
7. 캘리브레이션 상태 저장 문제 해결
문제: I포즈 캘리브레이션 후에도 "캘리브레이션 데이터 없음" 표시
해결 (RetargetingRemoteController.cs):
case "iPoseCalibration":
script.I_PoseCalibration();
script.SaveSettings(); // 캘리브레이션 후 설정 저장 추가
SendCharacterData(characterId);
break;
8. 가로 스크롤 기능 구현
CSS 수정:
.characters-container {
display: flex;
flex-wrap: nowrap;
overflow-x: auto;
padding-bottom: 20px;
gap: 12px;
min-height: calc(100vh - 60px);
align-items: flex-start;
}
.characters-container::-webkit-scrollbar { height: 12px; }
.characters-container::-webkit-scrollbar-track { background: var(--surface); border-radius: 6px; }
.characters-container::-webkit-scrollbar-thumb { background: var(--primary); border-radius: 6px; }
결과:
PC: 캐릭터 패널 가로 나열 + 가로 스크롤바 (12px, 보라색)
세로 스크롤: 글로벌 브라우저 스크롤
9. 모바일 세로 스크롤만 유지
@media (max-width: 768px) {
.characters-container {
flex-direction: column;
overflow-x: visible;
}
.character-panel {
width: 100%;
min-width: 100%;
}
}
10. 웹 리소스를 Resources 폴더로 이동
이전 구조 (삭제됨):
Assets/Scripts/.../Remote/WebResources/
새 구조:
Assets/Resources/KindRetargeting/
├── retargeting_style.txt (CSS)
├── retargeting_template.txt (HTML 템플릿)
└── retargeting_script.txt (JavaScript)
11. HTTP 서버 코드 단순화
변경된 리소스 로드 방식:
private void LoadResources()
{
TextAsset cssAsset = Resources.Load<TextAsset>("KindRetargeting/retargeting_style");
TextAsset templateAsset = Resources.Load<TextAsset>("KindRetargeting/retargeting_template");
TextAsset jsAsset = Resources.Load<TextAsset>("KindRetargeting/retargeting_script");
cachedCSS = cssAsset != null ? cssAsset.text : GetFallbackCSS();
cachedTemplate = templateAsset != null ? templateAsset.text : GetFallbackTemplate();
cachedJS = jsAsset != null ? jsAsset.text : GetFallbackJS();
}
제거된 항목:
System.IO 의존성
외부 파일 경로 로직
에디터 전용 코드 (#if UNITY_EDITOR)
WebResources 폴더
최종 파일 구조
Assets/
├── Resources/KindRetargeting/
│ ├── retargeting_style.txt ← CSS (가로 스크롤, 입력 필드 스타일)
│ ├── retargeting_template.txt ← HTML 템플릿
│ └── retargeting_script.txt ← JavaScript (메뉴 순서, 손가락 제어, 입력 필드)
└── Scripts/UtilityScript/KindRetargeting/Remote/
├── RetargetingHTTPServer.cs ← Resources 로드 방식으로 변경
├── RetargetingWebSocketServer.cs ← 로그 제거
└── RetargetingRemoteController.cs ← 손가락 스크립트 활성화, 캘리브레이션 저장
빌드 후 동작 보장
Resources.Load<TextAsset>() 사용으로 빌드에 자동 포함
에디터와 빌드 환경에서 동일한 코드로 동작
Windows Standalone 빌드에서 HTTP/WebSocket 서버 정상 동작