Skip to content

Instantly share code, notes, and snippets.

@KeanW
Created September 3, 2018 08:00
Show Gist options
  • Save KeanW/aaaa35bd6eedfae047176b90e8ef1d5a to your computer and use it in GitHub Desktop.
Save KeanW/aaaa35bd6eedfae047176b90e8ef1d5a to your computer and use it in GitHub Desktop.
/// <reference path='../../types/three.d.ts' />
import { Logger } from '../../core/Logger';
let logger = Logger.getInstance();
import { ShowableExtension } from '../../core/ShowableExtension';
import { DasherModel } from '../../core/DasherModel';
export class SkeletonExtension extends ShowableExtension {
private _skeletons: { [key: number]: [THREE.SkinnedMesh, THREE.Bone, THREE.SkeletonHelper] };
private _skeletonMaterial: any = null;
private _overlayScene = "DasherSkeletonOverlay";
constructor(viewer: Autodesk.Viewing.Private.GuiViewer3D, options: any) {
super(viewer, options);
this._skeletons = {};
}
public load(): boolean {
this.createUI(
'toolbar-sensor-skeleton',
'Skeletons',
'DasherControlSensors',
'grain'
);
this._dataModel.on(
DasherModel.eventTypes.CurrentHistoricTimeChanged,
this.onCurrentHistoricTimeChanged
);
logger.log('SkeletonExtension loaded');
return true;
}
public unload(): boolean {
this.destroyUI('DasherControlSensors');
this._dataModel.off(
DasherModel.eventTypes.CurrentHistoricTimeChanged,
this.onCurrentHistoricTimeChanged
);
logger.log('SkeletonExtension unloaded');
return true;
}
public show(): boolean {
this.viewer.addEventListener(
Autodesk.Viewing.SELECTION_CHANGED_EVENT,
this.onSelectionChanged);
this._skeletonMaterial = this.createSkeletonMaterial();
this.viewer.impl.createOverlayScene(this._overlayScene);
this.viewer.getSelection().forEach(fragId => {
this.drawSkeletonForFragment(fragId);
});
return true;
}
public hide(): boolean {
this.viewer.removeEventListener(
Autodesk.Viewing.SELECTION_CHANGED_EVENT,
this.onSelectionChanged);
this._skeletonMaterial = null;
for (let id in this._skeletons) {
let skel = this._skeletons[id];
if (skel) {
this.removeFromScene(skel[0]);
this.removeFromScene(skel[1]);
this.removeFromScene(skel[2]);
this._skeletons[id] = undefined;
this.viewer.impl.invalidate(false, true, true);
}
}
this.viewer.impl.removeOverlayScene(this._overlayScene);
return true;
}
private addToScene(obj: THREE.Object3D) {
// this.viewer.impl.scene.add(obj);
// this.viewer.impl.invalidate(true, true, false);
this.viewer.impl.addOverlay(this._overlayScene, obj);
this.viewer.impl.invalidate(false, false, true);
}
private removeFromScene(obj: THREE.Object3D) {
// this.viewer.impl.scene.remove(obj);
// this.viewer.impl.invalidate(true, true, false);
this.viewer.impl.removeOverlay(this._overlayScene, obj);
this.viewer.impl.invalidate(false, false, true);
}
private createSkeletonMaterial() {
let material = new THREE.MeshBasicMaterial( { color: 0x007700, skinning: true });
this.viewer.impl.matman().addMaterial(
'dasher-material-skeleton',
material,
true);
return material;
}
private onSelectionChanged = (event) => {
event.fragIdsArray.forEach(fragId => {
let skel = this._skeletons[fragId];
if (skel) {
this.removeFromScene(skel[0]);
this.removeFromScene(skel[1]);
this.removeFromScene(skel[2]);
this._skeletons[fragId] = undefined;
this.viewer.impl.invalidate(false, true, false);
} else {
this.drawSkeletonForFragment(fragId);
}
});
}
private onCurrentHistoricTimeChanged = (time: Date): void => {
this.update();
}
private drawSkeletonForFragment(fragId) {
let renderProxy = this.viewer.impl.getRenderProxy(
this.viewer.model,
fragId);
let matrix = renderProxy.matrixWorld;
this.addSkeleton(fragId, matrix);
}
private addSkeleton(id: number, mat: THREE.Matrix4): void {
// Define bone/joint parameters
const torsoLength = 6;
const headLength = 3;
const shoulderLength = 2;
const shoulderSlope = 1;
const upperArmLength = 3;
const upperArmSlope = 1;
const lowerArmLength = 3;
const lowerArmSlope = 0;
const hipLength = 2;
const hipSlope = 1;
const upperLegLength = 4;
const upperLegSlope = 0;
const lowerLegLength = 5;
const lowerLegSlope = 0;
// Define relative joint positions
const bodyRel = new THREE.Vector3(0, 0, 0);
const neckRel = new THREE.Vector3(0, torsoLength, 0);
const headRel = new THREE.Vector3(0, headLength, 0);
const leftShoulderRel = new THREE.Vector3(shoulderLength, -shoulderSlope, 0);
const rightShoulderRel = new THREE.Vector3(-shoulderLength, -shoulderSlope, 0);
const leftElbowRel = new THREE.Vector3(upperArmSlope, -upperArmLength, 0);
const rightElbowRel = new THREE.Vector3(-upperArmSlope, -upperArmLength, 0);
const leftHandRel = new THREE.Vector3(lowerArmSlope, -lowerArmLength, 0);
const rightHandRel = new THREE.Vector3(-lowerArmSlope, -lowerArmLength, 0);
const leftHipRel = new THREE.Vector3(hipLength, -hipSlope, 0);
const rightHipRel = new THREE.Vector3(-hipLength, -hipSlope, 0);
const leftKneeRel = new THREE.Vector3(upperLegSlope, -upperLegLength, 0);
const rightKneeRel = new THREE.Vector3(-upperLegSlope, -upperLegLength, 0);
const leftFootRel = new THREE.Vector3(lowerLegSlope, -lowerLegLength, 0);
const rightFootRel = new THREE.Vector3(-lowerLegSlope, -lowerLegLength, 0);
// Calculate absolute joint positions
const bodyAbs = bodyRel.clone();
const neckAbs = new THREE.Vector3().addVectors(bodyAbs, neckRel);
const headAbs = new THREE.Vector3().addVectors(neckAbs, headRel);
const leftShoulderAbs = new THREE.Vector3().addVectors(neckAbs, leftShoulderRel);
const leftElbowAbs = new THREE.Vector3().addVectors(leftShoulderAbs, leftElbowRel);
const leftHandAbs = new THREE.Vector3().addVectors(leftElbowAbs, leftHandRel);
const rightShoulderAbs = new THREE.Vector3().addVectors(neckAbs, rightShoulderRel);
const rightElbowAbs = new THREE.Vector3().addVectors(rightShoulderAbs, rightElbowRel);
const rightHandAbs = new THREE.Vector3().addVectors(rightElbowAbs, rightHandRel);
const leftHipAbs = new THREE.Vector3().addVectors(bodyAbs, leftHipRel);
const leftKneeAbs = new THREE.Vector3().addVectors(leftHipAbs, leftKneeRel);
const leftFootAbs = new THREE.Vector3().addVectors(leftKneeAbs, leftFootRel);
const rightHipAbs = new THREE.Vector3().addVectors(bodyAbs, rightHipRel);
const rightKneeAbs = new THREE.Vector3().addVectors(rightHipAbs, rightKneeRel);
const rightFootAbs = new THREE.Vector3().addVectors(rightKneeAbs, rightFootRel);
// Declare the mesh, create it later
let mesh = null;
// Create the bones connected to the mesh
let bodyBone = new THREE.Bone(mesh);
let headBone = new THREE.Bone(mesh);
let neckBone = new THREE.Bone(mesh);
let leftShoulderBone = new THREE.Bone(mesh);
let leftElbowBone = new THREE.Bone(mesh);
let leftHandBone = new THREE.Bone(mesh);
let rightShoulderBone = new THREE.Bone(mesh);
let rightElbowBone = new THREE.Bone(mesh);
let rightHandBone = new THREE.Bone(mesh);
let leftHipBone = new THREE.Bone(mesh);
let leftKneeBone = new THREE.Bone(mesh);
let leftFootBone = new THREE.Bone(mesh);
let rightHipBone = new THREE.Bone(mesh);
let rightKneeBone = new THREE.Bone(mesh);
let rightFootBone = new THREE.Bone(mesh);
// Set the relative positions of the joints
bodyBone.position.set(bodyRel.x, bodyRel.y, bodyRel.z);
headBone.position.set(headRel.x, headRel.y, headRel.z);
neckBone.position.set(neckRel.x, neckRel.y, neckRel.z);
leftShoulderBone.position.set(leftShoulderRel.x, leftShoulderRel.y, leftShoulderRel.z);
leftElbowBone.position.set(leftElbowRel.x, leftElbowRel.y, leftElbowRel.z);
leftHandBone.position.set(leftHandRel.x, leftHandRel.y, leftHandRel.z);
rightShoulderBone.position.set(rightShoulderRel.x, rightShoulderRel.y, rightShoulderRel.z);
rightElbowBone.position.set(rightElbowRel.x, rightElbowRel.y, rightElbowRel.z);
rightHandBone.position.set(rightHandRel.x, rightHandRel.y, rightHandRel.z);
leftHipBone.position.set(leftHipRel.x, leftHipRel.y, leftHipRel.z);
leftKneeBone.position.set(leftKneeRel.x, leftKneeRel.y, leftKneeRel.z);
leftFootBone.position.set(leftFootRel.x, leftFootRel.y, leftFootRel.z);
rightHipBone.position.set(rightHipRel.x, rightHipRel.y, rightHipRel.z);
rightKneeBone.position.set(rightKneeRel.x, rightKneeRel.y, rightKneeRel.z);
rightFootBone.position.set(rightFootRel.x, rightFootRel.y, rightFootRel.z);
// Define the bone topology by adding them to their parents
bodyBone.add(neckBone);
neckBone.add(headBone);
neckBone.add(leftShoulderBone);
leftShoulderBone.add(leftElbowBone);
leftElbowBone.add(leftHandBone);
neckBone.add(rightShoulderBone);
rightShoulderBone.add(rightElbowBone);
rightElbowBone.add(rightHandBone);
bodyBone.add(leftHipBone);
leftHipBone.add(leftKneeBone);
leftKneeBone.add(leftFootBone);
bodyBone.add(rightHipBone);
rightHipBone.add(rightKneeBone);
rightKneeBone.add(rightFootBone);
// Create a list of bones for this skeleton
let bones = [];
bones.push(bodyBone);
bones.push(neckBone);
bones.push(headBone);
bones.push(leftShoulderBone);
bones.push(leftElbowBone);
bones.push(leftHandBone);
bones.push(rightShoulderBone);
bones.push(rightElbowBone);
bones.push(rightHandBone);
bones.push(leftHipBone);
bones.push(leftKneeBone);
bones.push(leftFootBone);
bones.push(rightHipBone);
bones.push(rightKneeBone);
bones.push(rightFootBone);
let skeleton = new THREE.Skeleton(bones);
let humanGeometry = new THREE.Geometry();
mesh = new THREE.SkinnedMesh(humanGeometry, this._skeletonMaterial);
mesh.add(bodyBone);
mesh.bind(skeleton);
let helper = new THREE.SkeletonHelper(mesh);
this.addToScene(mesh);
this.addToScene(bodyBone);
this.addToScene(helper);
// Transform the skeleton and the mesh
let rotate = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), Math.PI / 2); // Make upright
let translate = new THREE.Matrix4().makeTranslation(0, 0, hipSlope + upperLegLength + lowerLegLength); // Move to surface
let scale = new THREE.Matrix4().makeScale(0.5, 0.5, 0.5); // Make it half the size
mat.multiply(scale).multiply(translate).multiply(rotate); // Combine with the transform passed in
mesh.applyMatrix(mat);
bodyBone.applyMatrix(mat);
this._skeletons[id] = [mesh, bodyBone, helper];
}
private update() {
let angle = Math.sin(Date.now() * 0.003);
let ang = (Math.PI * angle) / 8;
for (let id in this._skeletons) {
let skelInfo = this._skeletons[id];
if (skelInfo) {
let bones = skelInfo[0].skeleton.bones;
bones[3].rotation.x = ang; // Left shoulder
bones[4].rotation.x = ang; // Left elbow
bones[6].rotation.x = -ang; // Right shoulder
bones[7].rotation.x = -ang; // Right elbow
bones[9].rotation.x = -ang; // Left hip
bones[10].rotation.x = -ang; // Left knee
bones[12].rotation.x = ang; // Right hip
bones[13].rotation.x = ang; // Right knee
skelInfo[2].update();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment