241 lines
7.9 KiB (Stored with Git LFS)
Plaintext
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 서버 정상 동작 |