[HandTris] #3. TypeError: Cannot read properties of undefined - (์ ๋์์ผ๋ก ํ๋ ์จ๋ผ์ธ ์น ํ ํธ๋ฆฌ์ค ๊ฒ์ ๋ง
socket์ url์ ๊ฐ์ ธ์ฌ ์ ์๋ค.soccket ๋ณ์์ ๋ด๊ฒจ ์๋ url ์์ฑ์ ๊ฐ์ ธ์ sessionId๋ฅผ parsing ํ๊ณ ์ ํ๋ ์ค ๋ง๋ฌ๋ ์๋ฌ ์ค ์์ธ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์ง ์์ ๋ฐ์ํ ์๋ฌ์ ๋ํด ์ ๋ฆฌํ๊ณ ์ ํ๋ค. ์ ๋ชฉ์ 'Typ
seungineer.tistory.com
๊ฐ๋ฐ ์ค์ธ ํธ๋ํธ๋ฆฌ์ค๊ฐ toy project ์์ค์ด๋ผ๋ ๋๋์ ๋ฒ๋ฆด ์ ์์๋ค. ์ด๋ค ์์๊ฐ ์ด๋ ๊ฒ ์๊ฐํ๊ฒ ๋ง๋๋์ง ๊ณฐ๊ณฐ์ด ์๊ฐํด ๋ณด๋ ์น์บ ํ๋ฉด์ด๋ผ๋ ์๊ฐ์ด ๋ค์๋ค. ํ์ฌ ํธ๋ํธ๋ฆฌ์ค๋ ์น์บ ์ ๋น์น๋ ํ๋ ์ด์ด์ ํ๋ฉด์ด ์ผ์ชฝ ์๋จ์ ๋ณด์ด๋ ํํ์ด๋ค. ์ ๋์์ด ์น์บ ์ ์ ๋น์น๊ณ ์๋์ง ํ๋ ์ด์ด๊ฐ ํ์ธํด์ผ ํ๊ธฐ์ ๋น์น๋ ํ๋ฉด์ด ๋ณด์ด๋ ๊ฒ ํ์๋ผ๊ณ ์๊ฐํ๋ค. ๊ทธ๋ฐ๋ฐ, ์๊ฐํด๋ณด๋ ์ด๋ค ์บ ์ ์ด์ฉํ ๊ฒ์๋ ์น์บ ์ ํ๋ฉด์ด ๊ทธ๋๋ก ๋์ค์ง๋ ์๋๋ค๋ ์ ์ ๊นจ๋ซ๊ฒ ๋์๋ค. ์น์บ ํ๋ฉด์ ๊ฐ๋ ค์ผ ํ๋ ์ด์ ๊ฐ ์๊ฒผ๋ค.
ํผํธ๋์ค ๋ณต์ฑ2(์ข), ํผํธ๋์ค ๋ฌ๋(์ฐ) ๋ฑ ์บ ์ ์ด์ฉํ ๊ฒ์์ ํ๋ ์ด์ด๊ฐ ์ง์ ์ ์ผ๋ก ๋ณด์ด์ง ์์
Three.js
์น์บ ํ๋ฉด์ ๊ฐ๋ฆฌ๊ธฐ ์ํด์ ๊ฐ์ฅ ๋จผ์ ๋ ์๊ฐ์ ์๊ฐ๋ฝ์ ์ ์ฒด ์ฅ๊ฐ์ ์์ฐ๋ ๊ฒ์ด๋ค. ์ฅ๊ฐ๋ง ๋ณด์ด๊ณ , ํ๋ ์ด์ด ๋ชจ์ต์ ๊ฐ๋ฆด ์ ์๊ธฐ์ ํ๋ ์ด์ด๋ ์์ ์ ์์ด ์ ์ธ์๋๊ณ ์๋์ง ์ ์ ์๋ค. Mini Milestone์ Three.js๋ก ์์ ๋์ฐ๋ ๊ฒ์ ๋ชฉํ๋ก ์ก์๋ค. Three.js๋ x, y, z ์ธ ๊ฐ์ ์ถ๊ณผ camera view, ๊ทธ๋ฆฌ๊ณ obj, stl ๋ฑ๊ณผ ๊ฐ์ 3D ๋ชจ๋ธ๋ง ํ์ผ์ด ํ์ํ๋ค. ์ฐ์ ์ ์ผ๋ก๋ง ์ด๋ฃจ์ด์ง .obj ํ์ผ๋ก ํ ์คํธ๋ฅผ ํด๋ณด์๋ค.
์คํฌ๋ฆฐ์ท ์ฐ์ธก์ ์ ์ผ๋ก๋ง ์ด๋ฃจ์ด์ง obj ํ์ผ์ ๋ณผ ์ ์๋ค. Three.js๋ก ์ด๋ฅผ ๋ ๋ํ ๊ฒฐ๊ณผ ์น์ ์ฐฝ ์ three.js canvas์ ๊ฐ์ด ์ ๋ค์ด ์ฐํ๋ค(์ฐ์ธก ์๋จ์ ์์ฃผ ์์ ํฐ ์ ). ์ด ์ ๋ค์ ์์ ๋ง๋์ ์ฐ๊ฒฐํ์ฌ ์์ง์ด๊ฒ ํด์ค์ผ ํ๋ค. Mediapipe component์ landmark(์์ ๋ง๋ ์์น) ์ํ๋ฅผ Three.js ์ปดํฌ๋ํธ๋ก props๋ฅผ ํตํด ์ ๋ฌํ์ฌ, Three.js์์ landmark ์ ๋ณด๋ฅผ ํ์ฉํ๋๋ก ํ์๋ค. ์ด๋ฅผ ํตํด ์์ด ์์ง์ผ ๋๋ง๋ค ๋๋๋งํฌ ์ํ๊ฐ ๋ณํ์ฌ Three.js ์ปดํฌ๋ํธ์์ ๋ฐ์ ์ ์๋๋ก ๊ตฌ์ฑํ ์ ์์๋ค.
21๊ฐ์ ์ ์ด ์์ ์์น์ ๋ฐ๋ผ ์์ง์ด๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์ ๋ง ์๋ obj ํ์ผ์ ์ ์ ์ถ๊ฐํ์ฌ three.js ์์ ์์ ์ ์ ์ถ๊ฐํ์๋ค.
๐ .obj ํ์ผ ๋ณด๊ธฐ
# ๋ฌผ์ฒด ์ด๋ฆ
o Hand
# ๋ง๋
v 0.0 0.0 0.0
v 0.0 1.0 0.0
v 0.0 2.0 0.0
v 0.0 3.0 0.0
v 0.0 4.0 0.0
v 1.0 1.0 0.0
v 1.0 2.0 0.0
v 1.0 3.0 0.0
v 1.0 4.0 0.0
v 2.0 0.0 0.0
v 2.0 1.0 0.0
v 2.0 2.0 0.0
v 2.0 3.0 0.0
v 3.0 0.0 0.0
v 3.0 1.0 0.0
v 3.0 2.0 0.0
v 3.0 3.0 0.0
v 4.0 0.0 0.0
v 4.0 1.0 0.0
v 4.0 2.0 0.0
v 4.0 3.0 0.0
v 5.0 0.0 0.0
v 5.0 1.0 0.0
v 5.0 2.0 0.0
v 5.0 3.0 0.0
# ์
l 1 2
l 2 3
l 3 4
l 4 5
l 2 6
l 6 7
l 2 10
l 10 11
l 11 12
l 12 13
์ด๋ ๊ฒ Mini Milestone์ ๋ฌ์ฑํ ์ ์์๋ค. ์ฌ๊ธฐ์ .obj ํ์ผ์ ์๊ฐ๋ฝ ํํ๋ฅผ ์ ํ์ค์ผ ํ์ผ๋ ์ด๋ 3D ๋ชจ๋ธ๋ง์ ์์ญ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ๋ชจ๋ธ์ ์ด๋ค ์ง์ ๊ณผ ์์ ์ด๋ค ์ง์ ์ ์ฐ๊ฒฐํ๋ ๊ฒ์ด ๋งค์ฐ ๋ฒ๊ฑฐ๋ก์ด ์ผ์ด๋ผ๋ ๊ฒ์ ์๊ฒ ๋์๋ค.
๐น๏ธ ํธ๋์กฐ์ด์คํฑ
๊ธฐ์กด ์๊ฐ๋ฝ ํํ๋ฅผ ์ธ์ํด ํ ํธ๋ฆฌ์ค ๋ธ๋ญ์ ์กฐ์ํ๋ ๊ฒ์ ์ค๊ฐ๋ฐํ ์ดํ ํธ๋ ์กฐ์ด์คํฑ ํํ๋ก ์ ํํ๊ณ ์ ํ์๋ค. ์ด์ ์กฐ์ด์คํฑ ํํ์ 3D Object๋ฅผ ์์ ์์ง์์ ๋ฐ๋ผ ์ด๋ํ๊ฒ ํ๋ฉด, ์์ ์ธ์ ๋ ์น์บ ์ ๊ฐ๋ฆฌ์๋ ๋ชฉํ๋ฅผ ๋ฌ์ฑํ ์ ์์ ๊ฒ์ด๋ผ ์๊ฐํ๋ค. ๊ทธ๋ฆฌ๊ณ ์์ landmark ์ ๋ณด๋ฅผ three.js์์ ํ์ฉํ ์ ์๋ค๋ ๊ฒ์ ํ์ธํ๊ธฐ์ ์คํ ๊ฐ๋ฅํ ๊ฒ์ผ๋ก ํ๋จํ๋ค.
๐ ๋ชจ๋ธ๋ง ํ์ผ ๋ก๋ ์ camera view ๋ฌธ์
์กฐ์ด์คํฑ ํํ์ .obj ํ์ผ์ three.js์ load ํ์๋ค. ์ฌ๋ฐ๋ฅด๊ฒ load ํ ๊ฒ์ผ๋ก ์๊ฐํ์ผ๋ three.js canvas์๋ ์ด๋ค ๊ฒ๋ ํ์๋์ง ์์๋ค.
Three.js์ ์ต์ํ์ง ์์ load์ ์ค๋ฅ์ธ์ง, object ํ์ผ์ด ์๋ชป๋ ๊ฒ์ธ์ง, ํ์๋๊ณ ์๋๋ฐ ์์ฃผ ์๊ฒ ๋์ค๊ณ ์๋์ง ์ ์๊ฐ ์์๋ค. load๋ ์์ Mini Milestone์ผ๋ก ์ ํ ๊ณผ์ ๋ฅผ ํ๋ฉฐ ํ ์คํธํ์๊ณ , object ํ์ผ๋ obj ๋ทฐ์ด๋ก ์ด์ด๋ณด๋ ์ ์ด๋ ธ๋ค. load๋ ๋๋๋ฐ, ๋ด๊ฐ ๋ณด๋ ์์ ์ ์๋ ๊ฒ์ด๋ผ๋ ์๊ฐ์ด ๋ค์๋ค.
์ด๋ค object ํ์ผ์ด๋๋ผ๋ ์ต์ด load ์ ๋ฌผ์ฒด๊ฐ ๋ณด์ผ ์ ์๊ฒ camera view๋ฅผ ์กฐ์ ํด ์ฃผ์๋ค.
if (!cameraAdjusted) {
const box = new THREE.Box3().setFromObject(joystick);
const boxSize = box.getSize(new THREE.Vector3()).length();
const boxCenter = box.getCenter(new THREE.Vector3());
const halfSizeToFitOnScreen = boxSize * 0.5;
const halfFovY = THREE.MathUtils.degToRad(cameraRef.current.fov * 0.5);
const distance = halfSizeToFitOnScreen / Math.tan(halfFovY);
cameraRef.current.position.copy(boxCenter);
cameraRef.current.position.z += distance * 1.5; // Add some distance for better view
cameraRef.current.lookAt(boxCenter);
cameraRef.current.updateProjectionMatrix();
setCameraAdjusted(true); // ์นด๋ฉ๋ผ ์กฐ์ ๋์์ ํ์
}
์กฐ์ด์คํฑ ํ๊ณผ ์กฐ์ด์คํฑ ์์ก์ด์ ๋ถ๋ฆฌ ํ์
์ ์ด๋ฏธ์ง์ ๊ฐ์ด ์์ ์์ง์์ ๋ฐ๋ผ ๋ชจ๋ธ์ด ํจ๊ป ์์ง์ธ๋ค. ๋ด๊ฐ ์๋ํ ๊ฒ์ ์กฐ์ด์คํฑ ํ์ ๊ณ ์ ๋์ด ์๊ณ , ์กฐ์ด์คํฑ ์์ก์ด๋ง ์์ง์ด๋ ๊ฒ์ด์๋ค.. ์กฐ์ด์คํฑ์์ ํ(Plate)์ ๋ถ๋ฆฌํ์ฌ ๊ณ ์ ์ํค๊ณ , ์์ก์ด ๋ถ๋ถ์ ์์ด ํ์ ํ๋ ๋งํผ ํ์ ํ๋๋ก ๊ฐ๋ฐ ์ ๋ต์ ๋ฐ๊พธ์๋ค.
Three.js scene์ plate๋ฅผ ๋จผ์ add ํ๋ค. Plate์ x, y, z ์ขํ๋ landmark๊ฐ ๋ณํ๋๋ผ๋ ๊ณ ์ ์ํจ๋ค.
// ํ
loader.load(
objUrlPlate,
(obj) => {
obj.traverse((node) => {
if (node.isMesh) {
node.material = new THREE.MeshPhongMaterial({
color: 0xff0000,
emissive: 0x333333,
});
}
});
obj.scale.set(0.15, 0.15, 0.15);
obj.position.set(0, 1, 1);
scene.add(obj);
console.log('Joystick model loaded:', obj);
}
์ดํ scene์ stick์ addํ๋ค. Stick ๋ํ x, y, z ์ขํ๋ ๋ชจ๋ธ ์์ ์ x, y, z ์ขํ๋ฅผ ๊ฐ๋๋ก ํ๋ค. plate์ ๋ค๋ฅธ ์ ์ landmarks๋ก๋ถํฐ ๊ณ์ฐํ ์๋ชฉ๊ณผ ์์ง์ ๊ฐ๋๋งํผ stick์ ํ์ ์ํจ๋ค๋ ๊ฒ์ด๋ค.
const deltaZ = landmark3.z - landmark0.z; // ์ฌ๋์ ์กฐ์๊ณผ ์น์บ ์ ๋ณด์ฌ์ง๋ ํ๋ฉด์ ์ฐจ์ด๋ก์ธํด 3๊ณผ 0์ ์์๊ฐ ๋ค๋ฆ
const deltaX = landmark0.x - landmark3.x;
const angle = -Math.atan2(deltaZ, deltaX); // theta, ๋จ์: rad
if (angle > 0.3 && angle < 3.0){ // 17๋ ์ด์ 171๋ ์ดํ ์์ง์ ์ ํ
joystick.rotation.z = angle;

Three.js ๋ฐฐ๊ฒฝ๋ ์ง์ฐ๊ณ , ์นด๋ฉ๋ผ ๋ทฐ๋ ์ด๋ ์ ๋ ์ ๋ณด๊ณ , ์๋ ์ ํ๋ฉด ์์ ๋ฐ๋ผ๊ฐ๋ ๊ทธ๋ด์ธํ ์กฐ์ด์คํฑ์ด ๋ง๋ค์ด์ง ๊ฒ ๊ฐ๋ค๐ค. ์ด์ ์ค๋ฅธ์์ผ๋ก ๋๋ฅด๋ ๋ฒํผ๋ ๋ง๋ค์ด์ผ๊ฒ ๋ค.
์ต์ข ๋ฐํ D-13