Microsoft Kinect controller for a threejs character: bones not moving correctly

Hi all,

I am working on a project to control a character in threejs using a microsoft kinect.
The data for the connect is coming in correctly, The mapping for the bones is working I guess.
But when you look at the movement in the top left - that is the kinect data mapped to points displaying a skeleton - the character is not moving the same way :slight_smile:

Would someone be willing to help out/collab on this or does anyone see where I have gone wrong?

All input is much appreciated!

<!DOCTYPE html>
<html>

<head>
    <title>Kinect ThreeJS Controller</title>
    <style>
        body {
            margin: 0;
        }

        canvas {
            display: block;
            position: absolute;
            top: 0;
            left: 0;
        }

        #bodyCanvas {
            z-index: 1;
            pointer-events: none;
        }
    </style>
</head>

<body>
    <canvas id="artifactCanvas"></canvas>

    <canvas id="bodyCanvas" width="512" height="424"></canvas>

    <script src="https://cdn.jsdelivr.net/npm/fflate@0.8.2/umd/index.min.js"></script>
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/loaders/FBXLoader.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>

    <script>
        const socket = io.connect('http://localhost:8000/');
        // Set up scene, camera, and renderer
        const windowWidth = window.innerWidth;
        const windowHeight = window.innerHeight;

        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, windowWidth / windowHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer({ canvas: artifactCanvas });
        renderer.setSize(windowWidth, windowHeight);
        //document.body.appendChild(renderer.domElement);

        // Add lights
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
        scene.add(ambientLight);
        const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
        directionalLight.position.set(0, 1, 1);
        scene.add(directionalLight);

        // Set up camera position and controls
        camera.position.set(0, 100, 300);  // Adjust these values
        camera.lookAt(0, 0, 0);
        const controls = new THREE.OrbitControls(camera, renderer.domElement);

        let skeleton;

        // Load FBX model
        const fbxLoader = new THREE.FBXLoader();
        fbxLoader.load('santa.fbx', (fbx) => {
            // Try a larger scale
            //fbx.scale.setScalar(1.0);  // Adjust this value to match skeleton size
            scene.add(fbx);

            skeleton = fbx.skeleton;

            // Add skeleton helper to visualize the skeleton
            const skeletonHelper = new THREE.SkeletonHelper(fbx);
            skeletonHelper.material.linewidth = 2; // Make bones more visible
            skeletonHelper.visible = true;
            scene.add(skeletonHelper);

            // Store bone references for easier access
            const bones = {};
            const initialPositions = {};
            fbx.traverse((bone) => {
                if (bone.isBone) {
                    const name = bone.name.toLowerCase();
                    bones[name] = bone;
                    initialPositions[name] = bone.position.clone();
                }
            });
            // Connect to socket


            socket.on('bodyFrame', (data) => {
                const joints = JSON.parse(data);
                // Map Kinect joints to model bones
                for (const jointName in joints) {
                    const joint = joints[jointName];
                    const boneName = mapJointToBone(jointName);
                    if (bones[boneName]) {
                        // Apply position relative to initial pose
                        bones[boneName].position.set(
                            initialPositions[boneName].x + joint.cameraX * 10,
                            initialPositions[boneName].y + joint.cameraY * 10,
                            initialPositions[boneName].z - joint.cameraZ
                        );
                    }
                }
            });
        });

        // Helper function to map Kinect joint names to model bone names
        function mapJointToBone(jointName) {
            /*
            "mixamorigHead"
            "mixamorigHeadTop_End"
            "mixamorigHips"
            "mixamorigLeftArm"
            "mixamorigLeftFoot"
            "mixamorigLeftForeArm"
            "mixamorigLeftHand"
            "mixamorigLeftLeg"
            "mixamorigLeftShoulder"
            "mixamorigLeftToe_End"
            "mixamorigLeftToeBase"
            "mixamorigLeftUpLeg"
            "mixamorigNeck"
            "mixamorigRightArm"
            "mixamorigRightFoot"
            "mixamorigRightForeArm"
            "mixamorigRightHand"
            "mixamorigRightLeg"
            "mixamorigRightShoulder"
            "mixamorigRightToe_End"
            "mixamorigRightToeBase"
            "mixamorigRightUpLeg"
            "mixamorigSpine"
            "mixamorigSpine1"
            "mixamorigSpine2"
  
            */
            const mapping = {
                0: 'mixamorigspine',
                2: 'mixamorigneck',
                3: 'mixamorighead',
                4: 'mixamorigleftshoulder',
                5: 'mixamorigleftarm',
                6: 'mixamorigleftforearm',
                7: 'mixamoriglefthand',
                8: 'mixamorigrightshoulder',
                9: 'mixamorigrightarm',
                10: 'mixamorigrightforearm',
                11: 'mixamorigrighthand',
                12: 'mixamorigleftupleg',
                13: 'mixamorigleftleg',
                14: 'mixamoriglefttoe_end',
                16: 'mixamorigrightupleg',
                17: 'mixamorigrightleg',
                18: 'mixamorigrighttoe_end'
            };
            return mapping[jointName] || jointName;
        }

        // Animation loop
        const clock = new THREE.Clock();

        function animate() {
            requestAnimationFrame(animate);
            controls.update();
            renderer.render(scene, camera);
        }

        // Handle window resize
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        });

        animate();



        var canvas = document.getElementById('bodyCanvas');
        var ctx = canvas.getContext('2d');
        var colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#00ffff', '#ff00ff'];

        // handstate circle size
        var HANDSIZE = 2;

        // closed hand state color
        var HANDCLOSEDCOLOR = "red";

        // open hand state color
        var HANDOPENCOLOR = "green";

        // lasso hand state color
        var HANDLASSOCOLOR = "blue";

        function updateHandState(handState, jointPoint) {
            switch (handState) {
                case 3:
                    drawHand(jointPoint, HANDCLOSEDCOLOR);
                    break;

                case 2:
                    drawHand(jointPoint, HANDOPENCOLOR);
                    break;

                case 4:
                    drawHand(jointPoint, HANDLASSOCOLOR);
                    break;
            }
        }

        function drawHand(jointPoint, handColor) {
            // draw semi transparent hand cicles
            ctx.globalAlpha = 0.75;
            ctx.beginPath();
            ctx.fillStyle = handColor;
            ctx.arc(jointPoint.depthX * 512, jointPoint.depthY * 424, HANDSIZE, 0, Math.PI * 2, true);
            ctx.fill();
            ctx.closePath();
            ctx.globalAlpha = 1;
        }



        socket.on('bodyFrame', function (bodyFrame) {
            bodyFrame = JSON.parse(bodyFrame);

            ctx.clearRect(0, 0, canvas.width, canvas.height);
            var index = 0;
            bodyFrame.forEach(function (aJoint) {

                for (var jointType in aJoint) {
                    ctx.fillStyle = colors[index];
                    ctx.fillRect(aJoint.depthX * 512, aJoint.depthY * 424, HANDSIZE, HANDSIZE);
                }
                //updateElbowState(body.joints[5], body.joints[9]);
                index++;
            });
        });

        // Add grid helper for reference
        const gridHelper = new THREE.GridHelper(1000, 100);
        scene.add(gridHelper);

    </script>

</body>

</html>