Andrew Meadowsarchive remaining JS scriptsc0b446c10 years agoHistory
239 lines · 8.9 KB · JavaScript
RawDownload
var JOINT_PARENT_MAP = {    Hips: "",    RightUpLeg: "Hips",    RightLeg: "RightUpLeg",    RightFoot: "RightLeg",    LeftUpLeg: "Hips",    LeftLeg: "LeftUpLeg",    LeftFoot: "LeftLeg",    Spine: "Hips",    Spine1: "Spine",    Spine2: "Spine1",    Spine3: "Spine2",    Neck: "Spine3",    Head: "Neck",    RightShoulder: "Spine3",    RightArm: "RightShoulder",    RightForeArm: "RightArm",    RightHand: "RightForeArm",    RightHandThumb1: "RightHand",    RightHandThumb2: "RightHandThumb1",    RightHandThumb3: "RightHandThumb2",    RightHandThumb4: "RightHandThumb3",    RightHandIndex1: "RightHand",    RightHandIndex2: "RightHandIndex1",    RightHandIndex3: "RightHandIndex2",    RightHandIndex4: "RightHandIndex3",    RightHandMiddle1: "RightHand",    RightHandMiddle2: "RightHandMiddle1",    RightHandMiddle3: "RightHandMiddle2",    RightHandMiddle4: "RightHandMiddle3",    RightHandRing1: "RightHand",    RightHandRing2: "RightHandRing1",    RightHandRing3: "RightHandRing2",    RightHandRing4: "RightHandRing3",    RightHandPinky1: "RightHand",    RightHandPinky2: "RightHandPinky1",    RightHandPinky3: "RightHandPinky2",    RightHandPinky4: "RightHandPinky3",    LeftShoulder: "Spine3",    LeftArm: "LeftShoulder",    LeftForeArm: "LeftArm",    LeftHand: "LeftForeArm",    LeftHandThumb1: "LeftHand",    LeftHandThumb2: "LeftHandThumb1",    LeftHandThumb3: "LeftHandThumb2",    LeftHandThumb4: "LeftHandThumb3",    LeftHandIndex1: "LeftHand",    LeftHandIndex2: "LeftHandIndex1",    LeftHandIndex3: "LeftHandIndex2",    LeftHandIndex4: "LeftHandIndex3",    LeftHandMiddle1: "LeftHand",    LeftHandMiddle2: "LeftHandMiddle1",    LeftHandMiddle3: "LeftHandMiddle2",    LeftHandMiddle4: "LeftHandMiddle3",    LeftHandRing1: "LeftHand",    LeftHandRing2: "LeftHandRing1",    LeftHandRing3: "LeftHandRing2",    LeftHandRing4: "LeftHandRing3",    LeftHandPinky1: "LeftHand",    LeftHandPinky2: "LeftHandPinky1",    LeftHandPinky3: "LeftHandPinky2",    LeftHandPinky: "LeftHandPinky3",}; var USE_TRANSLATIONS = false; // ctorfunction Xform(rot, pos) {    this.rot = rot;    this.pos = pos;};Xform.mul = function (lhs, rhs) {    var rot = Quat.multiply(lhs.rot, rhs.rot);    var pos = Vec3.sum(lhs.pos, Vec3.multiplyQbyV(lhs.rot, rhs.pos));    return new Xform(rot, pos);};Xform.prototype.inv = function () {    var invRot = Quat.inverse(this.rot);    var invPos = Vec3.multiply(-1, this.pos);    return new Xform(invRot, Vec3.multiplyQbyV(invRot, invPos));};Xform.prototype.toString = function () {    var rot = this.rot;    var pos = this.pos;    return "Xform rot = (" + rot.x + ", " + rot.y + ", " + rot.z + ", " + rot.w + "), pos = (" + pos.x + ", " + pos.y + ", " + pos.z + ")";}; function dumpHardwareMapping() {    Object.keys(Controller.Hardware).forEach(function (deviceName) {        Object.keys(Controller.Hardware[deviceName]).forEach(function (input) {            print("Controller.Hardware." + deviceName + "." + input + ":" + Controller.Hardware[deviceName][input]);        });    });} // ctorfunction NeuronAvatar() {    var self = this;    Script.scriptEnding.connect(function () {        self.shutdown();    });    Controller.hardwareChanged.connect(function () {        self.hardwareChanged();    });     if (Controller.Hardware.Neuron) {        this.activate();    } else {        this.deactivate();    }} NeuronAvatar.prototype.shutdown = function () {    this.deactivate();}; NeuronAvatar.prototype.hardwareChanged = function () {    if (Controller.Hardware.Neuron) {        this.activate();    } else {        this.deactivate();    }}; NeuronAvatar.prototype.activate = function () {    if (!this._active) {        Script.update.connect(updateCallback);    }    this._active = true;     // build absDefaultPoseMap    this._defaultAbsRotMap = {};    this._defaultAbsPosMap = {};    this._defaultAbsRotMap[""] = {x: 0, y: 0, z: 0, w: 1};    this._defaultAbsPosMap[""] = {x: 0, y: 0, z: 0};    var keys = Object.keys(JOINT_PARENT_MAP);    var i, l = keys.length;    for (i = 0; i < l; i++) {        var jointName = keys[i];        var j = MyAvatar.getJointIndex(jointName);        var parentJointName = JOINT_PARENT_MAP[jointName];        this._defaultAbsRotMap[jointName] = Quat.multiply(this._defaultAbsRotMap[parentJointName], MyAvatar.getDefaultJointRotation(j));        this._defaultAbsPosMap[jointName] = Vec3.sum(this._defaultAbsPosMap[parentJointName],                                                     Quat.multiply(this._defaultAbsRotMap[parentJointName], MyAvatar.getDefaultJointTranslation(j)));    }}; NeuronAvatar.prototype.deactivate = function () {    if (this._active) {        var self = this;        Script.update.disconnect(updateCallback);    }    this._active = false;    MyAvatar.clearJointsData();}; NeuronAvatar.prototype.update = function (deltaTime) {     var hmdActive = HMD.active;    var keys = Object.keys(JOINT_PARENT_MAP);    var i, l = keys.length;    var absDefaultRot = {};    var jointName, channel, pose, parentJointName, j, parentDefaultAbsRot;    var localRotations = {};    var localTranslations = {};    for (i = 0; i < l; i++) {        var jointName = keys[i];        var channel = Controller.Hardware.Neuron[jointName];        if (channel) {            pose = Controller.getPoseValue(channel);            parentJointName = JOINT_PARENT_MAP[jointName];            j = MyAvatar.getJointIndex(jointName);            defaultAbsRot = this._defaultAbsRotMap[jointName];            parentDefaultAbsRot = this._defaultAbsRotMap[parentJointName];             // Rotations from the neuron controller are in world orientation but are delta's from the default pose.            // So first we build the absolute rotation of the default pose (local into world).            // Then apply the rotation from the controller, in world space.            // Then we transform back into joint local by multiplying by the inverse of the parents absolute rotation.            var localRotation = Quat.multiply(Quat.inverse(parentDefaultAbsRot), Quat.multiply(pose.rotation, defaultAbsRot));            if (!hmdActive || jointName !== "Hips") {                MyAvatar.setJointRotation(j, localRotation);            }            localRotations[jointName] = localRotation;             // translation proportions might be different from the neuron avatar and the user avatar skeleton.            // so this is disabled by default            if (USE_TRANSLATIONS) {                var localTranslation = Vec3.multiplyQbyV(Quat.inverse(parentDefaultAbsRot), pose.translation);                MyAvatar.setJointTranslation(j, localTranslation);                localTranslations[jointName] = localTranslation;            } else {                localTranslations[jointName] = MyAvatar.getDefaultJointTranslation(j);            }        }    }     // it attempts to adjust the hips so that the avatar's head is at the same location & oreintation as the HMD.    // however it's fighting with the internal c++ code that also attempts to adjust the hips.    if (hmdActive) {        var UNIT_SCALE = 1 / 100;        var hmdXform = new Xform(HMD.orientation, Vec3.multiply(1 / UNIT_SCALE, HMD.position)); // convert to cm        var y180Xform = new Xform({x: 0, y: 1, z: 0, w: 0}, {x: 0, y: 0, z: 0});        var avatarXform = new Xform(MyAvatar.orientation, Vec3.multiply(1 / UNIT_SCALE, MyAvatar.position)); // convert to cm        var hipsJointIndex = MyAvatar.getJointIndex("Hips");        var modelOffsetInvXform = new Xform({x: 0, y: 0, z: 0, w: 1}, MyAvatar.getDefaultJointTranslation(hipsJointIndex));        var defaultHipsXform = new Xform(MyAvatar.getDefaultJointRotation(hipsJointIndex), MyAvatar.getDefaultJointTranslation(hipsJointIndex));         var headXform = new Xform(localRotations["Head"], localTranslations["Head"]);         // transform eyes down the heirarchy chain into avatar space.        var hierarchy = ["Neck", "Spine3", "Spine2", "Spine1", "Spine"];        var i, l = hierarchy.length;        for (i = 0; i < l; i++) {            var xform = new Xform(localRotations[hierarchy[i]], localTranslations[hierarchy[i]]);            headXform = Xform.mul(xform, headXform);        }        headXform = Xform.mul(defaultHipsXform, headXform);         var preXform = Xform.mul(headXform, y180Xform);        var postXform = Xform.mul(avatarXform, Xform.mul(y180Xform, modelOffsetInvXform.inv()));         // solve for the offset that will put the eyes at the hmd position & orientation.        var hipsOffsetXform = Xform.mul(postXform.inv(), Xform.mul(hmdXform, preXform.inv()));         // now combine it with the default hips transform        var hipsXform = Xform.mul(hipsOffsetXform, defaultHipsXform);         MyAvatar.setJointRotation("Hips", hipsXform.rot);        MyAvatar.setJointTranslation("Hips", hipsXform.pos);    }}; var neuronAvatar = new NeuronAvatar(); function updateCallback(deltaTime) {    neuronAvatar.update(deltaTime);}