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
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>