Example #1
0
exports.get_rotation = function(obj, dest) {
    if (m_cons.get_type(obj) == m_cons.CONS_TYPE_CHILD_OF) {
        var offset = m_cons.get_child_of_offset(obj);
        m_quat.copy(m_tsr.get_quat_view(offset), dest);
    } else {
        m_quat.copy(obj._render.quat, dest);
    }
}
Example #2
0
      var rotate_cb = function(obj, id, pulse) {
        if (pulse > 0) {

          var curr_angles = m_ctl.get_sensor_payload(obj, id, 0);
          if (m_cam.is_eye_camera(obj)) {
            var alpha = curr_angles[2];
            var beta  = curr_angles[1];
            var gamma = curr_angles[0];

            var quaternion = _quat_tmp;
            var c1 = Math.cos(alpha / 2);
            var c2 = Math.cos(beta  / 2);
            var c3 = Math.cos(gamma / 2);
            var s1 = Math.sin(alpha / 2);
            var s2 = Math.sin(beta  / 2);
            var s3 = Math.sin(gamma / 2);
            quaternion[0] = c1 * s2 * c3 - s1 * c2 * s3;
            quaternion[1] = c1 * c2 * s3 + s1 * s2 * c3;
            quaternion[2] = s1 * c2 * c3 + c1 * s2 * s3;
            quaternion[3] = c1 * c2 * c3 - s1 * s2 * s3;

            var orientation = Math.PI * window.orientation / 180;
            var screen_quat = m_quat.setAxisAngle(m_util.AXIS_Z,
              -orientation, _quat_tmp2);

              quaternion = m_quat.multiply(quaternion, screen_quat, _quat_tmp);

              var quat = m_quat.setAxisAngle(m_util.AXIS_X, Math.PI / 2,
                _quat_tmp2);
                quaternion = m_quat.multiply(quaternion, quat, _quat_tmp);

                if (save_angles) {
                  m_quat.copy(quaternion, _last_gyro_quat);
                  save_angles = false;
                } else {
                  var last_gyro_inv_quat = m_quat.invert(_last_gyro_quat, _last_gyro_quat);
                  var cam_quat = m_trans.get_rotation(obj, _quat_tmp2);
                  var clear_cam_quat = m_quat.multiply(cam_quat, last_gyro_inv_quat, _quat_tmp2);
                  var new_cam_quat = m_quat.multiply(clear_cam_quat, quaternion, _quat_tmp2);

                  var up_axis = m_vec3.transformQuat(m_util.AXIS_MZ,
                    new_cam_quat, _vec3_tmp);

                    m_cam.set_vertical_axis(obj, up_axis);

                    m_trans.set_rotation_v(obj, new_cam_quat);
                    m_quat.copy(quaternion, _last_gyro_quat);
                  }
                }
              }
            }
Example #3
0
exports.append_semi_stiff_cam_obj = function(obj, obj_parent, offset, 
                                             rotation_offset, clamp_left, 
                                             clamp_right, clamp_up, clamp_down) {

    var cons = init_cons(CONS_TYPE_SEMI_STIFF_CAM_OBJ);
    var quat = obj._render.quat;
    var p_quat = obj_parent._render.quat;

    // link to parent object
    cons.obj_parent = obj_parent;
    cons.offset = new Float32Array(offset);

    cons.parent_prev_rotation = new Float32Array(p_quat);

    cons.clamp_left = clamp_left;
    cons.clamp_right = clamp_right;
    cons.clamp_up = clamp_up;
    cons.clamp_down = clamp_down;

    // override initial rotation for object
    if (rotation_offset) {
        m_quat.copy(rotation_offset, quat);
        m_quat.multiply(p_quat, quat, quat);
    }

    apply_cons(obj, cons);
    update_cons(obj, cons, 0);
}
Example #4
0
function hor_rot(ev_track, cur_dir, elapsed, new_rot_q, new_hor_dir) {

    var cur_rot_q   = _quat4_tmp_2;
    var cur_hor_dir = _vec3_tmp_4;

    m_trans.get_rotation_quat(ev_track.collider, cur_rot_q);
    m_vec3.transformQuat(m_util.AXIS_Z, cur_rot_q, cur_dir);

    cur_hor_dir[0]  = cur_dir[0];
    cur_hor_dir[1]  = 0;
    cur_hor_dir[2]  = cur_dir[2];
    m_vec3.normalize(cur_hor_dir, cur_hor_dir);

    var vec_dot = m_vec3.dot(cur_hor_dir, new_hor_dir);

    var angle_to_turn = Math.acos(vec_dot);
    var angle_ratio   = Math.abs(angle_to_turn) / Math.PI;
    var slerp         = elapsed / angle_ratio * ev_track.rot_speed * ev_track.rotation_mult;

    m_quat.rotationTo(cur_hor_dir, new_hor_dir, new_rot_q);
    m_quat.rotationTo(m_util.AXIS_Z, cur_hor_dir, cur_rot_q);

    if (Math.abs(vec_dot) >= 1) {
        m_quat.copy(cur_rot_q, new_rot_q);
        return;
    }

    m_quat.multiply(new_rot_q, cur_rot_q, new_rot_q);
    m_quat.slerp(cur_rot_q, new_rot_q, Math.min(slerp, 1), new_rot_q);
}
exports.append_semi_stiff_cam_obj = function(obj, obj_parent, offset,
                                             rotation_offset, clamp_left,
                                             clamp_right, clamp_up, clamp_down) {

    var cons = init_cons(CONS_TYPE_SEMI_STIFF_CAM_OBJ);
    var quat = obj._render.quat;
    var p_quat = obj_parent._render.quat;

    // link to parent object
    cons.obj_parent = obj_parent;
    cons.offset = new Float32Array(offset);

    cons.parent_prev_rotation = new Float32Array(p_quat);

    cons.clamp_left = m_util.angle_wrap_0_2pi(clamp_left);
    cons.clamp_right = m_util.angle_wrap_0_2pi(clamp_right);
    cons.clamp_up = m_util.angle_wrap_periodic(clamp_up, -Math.PI, Math.PI);
    cons.clamp_down = m_util.angle_wrap_periodic(clamp_down, -Math.PI, Math.PI);

    if (rotation_offset) {
        cons.rotation_offset = new Float32Array(rotation_offset);

        // override initial rotation for object
        m_quat.copy(rotation_offset, quat);
        m_quat.multiply(p_quat, quat, quat);
    } else
        cons.rotation_offset = m_quat.create();

    apply_cons(obj, cons);
    update_cons(obj, cons, 0);
}
Example #6
0
/**
 * @methodOf camera
 */
function set_view(cam, camobj) {

    var trans = camobj._render.trans;
    var quat  = camobj._render.quat;

    var wm = _mat4_tmp;

    m_mat4.rotateX(camobj._render.world_matrix, -Math.PI/2, wm);
    m_mat4.invert(wm, cam.view_matrix);

    if (cam.reflection_plane) {
        reflect_view_matrix(cam);
        reflect_proj_matrix(cam);
    } 

    var x = cam.view_matrix[12];
    var y = cam.view_matrix[13];
    var z = cam.view_matrix[14];

    if (cam.type == exports.TYPE_STEREO_LEFT)
        cam.view_matrix[12] += cam.stereo_eye_dist/2;
    else if (cam.type == exports.TYPE_STEREO_RIGHT)
        cam.view_matrix[12] -= cam.stereo_eye_dist/2;

    // update view projection matrix
    m_mat4.multiply(cam.proj_matrix, cam.view_matrix, cam.view_proj_matrix);

    calc_sky_vp_inverse(cam);
        
    m_vec3.copy(cam.eye, cam.eye_last);
    m_vec3.copy(trans, cam.eye);
    m_quat.copy(quat, cam.quat);
}
Example #7
0
    var move_cam_cb = function(obj, id, pulse) {
        var cam_obj = m_scenes.get_active_camera();

        if (!cam_obj)
            return;

        if (pulse > 0) {
            // NOTE: init part
            if (!updated_eye_data) {
                var hmd_left_fov = get_fov("left", _vec4_tmp);
                var hmd_right_fov = get_fov("right", _vec4_tmp2);
                if (hmd_left_fov && hmd_left_fov)
                    m_cam.set_hmd_fov(cam_obj, hmd_left_fov, hmd_right_fov);

                var eye_distance = get_eye_distance();
                if (eye_distance)
                    m_cam.set_eye_distance(cam_obj, eye_distance);

                var hmd_params = {};
                if (_hmd_device.deviceName.toLowerCase().indexOf("oculus") !== -1)
                    var hmd_name = "oculus";
                else
                    var hmd_name = "default";

                hmd_params.distortion_coefs = [
                        _devices_params[hmd_name]["distortion_coefs"][0],
                        _devices_params[hmd_name]["distortion_coefs"][1]
                ];

                hmd_params.chromatic_aberration_coefs = [
                        _devices_params[hmd_name]["chromatic_aberration_coefs"][0],
                        _devices_params[hmd_name]["chromatic_aberration_coefs"][1],
                        _devices_params[hmd_name]["chromatic_aberration_coefs"][2],
                        _devices_params[hmd_name]["chromatic_aberration_coefs"][3]
                ];

                hmd_params.distortion_scale  = _devices_params[hmd_name]["distortion_scale"];
                // TODO: set distortion_offset
                hmd_params.distortion_offset = 0.0;
                hmd_params.enable_hmd_stereo = true;

                m_scenes.set_hmd_params(hmd_params);

                var canvas_container_elem = m_cont.get_container();
                var ccw = canvas_container_elem.clientWidth;
                var cch = canvas_container_elem.clientHeight;
                m_cont.resize(ccw, cch, true);

                updated_eye_data = true;

                _last_cam_quat = m_trans.get_rotation(cam_obj, _last_cam_quat);
                reset_hmd();
            }

            // NOTE: It is executed every frame.
            // uses _vec3_tmp, _vec3_tmp2, _vec3_tmp3, _quat_tmp, _quat_tmp2
            if (m_cam.is_eye_camera(cam_obj)) {
                if (control_type == HMD_ALL_AXES_MOUSE_NONE) {
                    var hmd_quat = get_sensor_orientation(_quat_tmp);

                    if (hmd_quat) {
                        var quat = m_quat.setAxisAngle(m_util.AXIS_X, Math.PI / 2, _quat_tmp2);
                        m_quat.normalize(quat, quat);
                        hmd_quat = m_quat.multiply(hmd_quat, quat, _quat_tmp);
                        var up_axis = m_vec3.transformQuat(m_util.AXIS_Z, hmd_quat, _vec3_tmp);
                        m_cam.set_vertical_axis(cam_obj, up_axis);
                        m_trans.set_rotation_v(cam_obj, hmd_quat);
                    }
                } else if (control_type == HMD_ROLL_PITCH_MOUSE_YAW ||
                        control_type == HMD_ALL_AXES_MOUSE_YAW) {
                    var hmd_quat = get_sensor_orientation(_quat_tmp);

                    if (hmd_quat) {
                        // NOTE: hmd_quat to WEBGL axis orientation
                        var quat = m_quat.setAxisAngle(m_util.AXIS_X, Math.PI / 2,
                                _quat_tmp2);
                        m_quat.normalize(quat, quat);
                        hmd_quat = m_quat.multiply(hmd_quat, quat, _quat_tmp);

                        var cam_quat = m_trans.get_rotation(cam_obj,
                                _quat_tmp2);
                        var inv_cam_quat = m_quat.invert(cam_quat,
                                _quat_tmp2);
                        var diff_cam_quat = m_quat.multiply(_last_cam_quat,
                                inv_cam_quat, _quat_tmp2);

                        var cur_vertical_axis = m_cam.get_vertical_axis(cam_obj,
                                _vec3_tmp);
                        if (Math.abs(cur_vertical_axis[2]) < Math.PI / 4)
                            var first_horiz_vec = m_vec3.cross(cur_vertical_axis,
                                    m_util.AXIS_Z, _vec3_tmp2);
                        else if (Math.abs(cur_vertical_axis[1]) < Math.PI / 4)
                            var first_horiz_vec = m_vec3.cross(cur_vertical_axis,
                                    m_util.AXIS_Y, _vec3_tmp2);

                        m_vec3.normalize(first_horiz_vec, first_horiz_vec);

                        var rotated_first_horiz_vec = m_vec3.transformQuat(
                                first_horiz_vec, diff_cam_quat, _vec3_tmp3);

                        var vertical_coef = m_vec3.dot(cur_vertical_axis,
                                rotated_first_horiz_vec);
                        var second_horiz_vec = m_vec3.scaleAndAdd(rotated_first_horiz_vec,
                                cur_vertical_axis, -vertical_coef, _vec3_tmp3);
                        m_vec3.normalize(second_horiz_vec, second_horiz_vec);

                        var sign_horiz_vec = m_vec3.cross(cur_vertical_axis,
                                first_horiz_vec, _vec3_tmp);
                        var abs_yaw_angle = Math.acos(m_util.clamp(
                                m_vec3.dot(first_horiz_vec, second_horiz_vec),
                                0, 1));
                        var sign_yaw_angle = m_util.sign(m_vec3.dot(
                                second_horiz_vec, sign_horiz_vec));
                        var diff_yaw_cam_angle = abs_yaw_angle * sign_yaw_angle;

                        _yaw_cam_angle += diff_yaw_cam_angle;
                        var yaw_cam_quat = m_quat.setAxisAngle(m_util.AXIS_Y,
                                -_yaw_cam_angle, _quat_tmp2);

                        if (control_type == HMD_ALL_AXES_MOUSE_YAW) {
                            var new_cam_quat = m_quat.multiply(yaw_cam_quat,
                                    hmd_quat, _quat_tmp);
                        } else {
                            var yaw_hmd_quat = m_util.quat_project(hmd_quat, m_util.AXIS_MY,
                                    m_util.AXIS_Y, m_util.AXIS_MZ, _quat_tmp3);
                            var yaw_hmd_inv_quat = m_quat.invert(yaw_hmd_quat, _quat_tmp3);
                            var vertical_hmd_quat = m_quat.multiply(
                                    yaw_hmd_inv_quat, hmd_quat, _quat_tmp3);

                            var new_cam_quat = m_quat.multiply(yaw_cam_quat,
                                    vertical_hmd_quat, _quat_tmp);
                        }
                        var up_axis = m_vec3.transformQuat(m_util.AXIS_Z,
                                new_cam_quat, _vec3_tmp);
                        m_cam.set_vertical_axis(cam_obj, up_axis);

                        m_trans.set_rotation_v(cam_obj, new_cam_quat);
                        m_quat.copy(new_cam_quat, _last_cam_quat)
                    }
                }
            }
        }
    }
Example #8
0
function update_sensor(sensor, timeline, elapsed) {
    if (!elapsed)
        return;

    switch (sensor.type) {
    case ST_MOTION:

        var obj = sensor.source_object;

        var trans = obj._render.trans;
        var quat = obj._render.quat;

        var dist = m_vec3.dist(sensor.trans_last, trans);

        var quat_temp = sensor.quat_temp;

        m_quat.invert(sensor.quat_last, quat_temp);
        m_quat.multiply(quat, quat_temp, quat_temp);
        m_quat.normalize(quat_temp, quat_temp);
        var angle = Math.abs(2 * Math.acos(quat_temp[3]));

        var linear_vel = dist / elapsed;
        sensor.avg_linear_vel = m_util.smooth(linear_vel, sensor.avg_linear_vel,
                elapsed, SENSOR_SMOOTH_PERIOD);
        sensor.payload[0] = linear_vel;

        var angular_vel = angle / elapsed;
        sensor.avg_angular_vel = m_util.smooth(angular_vel,
                sensor.avg_angular_vel, elapsed, SENSOR_SMOOTH_PERIOD);
        sensor.payload[1] = angular_vel;

        if (sensor.avg_linear_vel >= sensor.threshold || sensor.avg_angular_vel
                >= sensor.rotation_threshold)
            sensor_set_value(sensor, 1);
        else
            sensor_set_value(sensor, 0);

        m_vec3.copy(trans, sensor.trans_last);
        m_quat.copy(quat, sensor.quat_last);

        sensor.time_last = timeline;
        break;

    case ST_V_VELOCITY:

        var obj = sensor.source_object;
        var trans = obj._render.trans;

        var vel = Math.abs(trans[1] - sensor.trans_last[1]) / elapsed;
        sensor.avg_vertical_vel = m_util.smooth(vel, sensor.avg_vertical_vel,
                elapsed, SENSOR_SMOOTH_PERIOD);
        sensor.payload = vel;

        if (sensor.avg_vertical_vel >= sensor.threshold)
            sensor_set_value(sensor, 1);
        else
            sensor_set_value(sensor, 0);

        m_vec3.copy(trans, sensor.trans_last);

        sensor.time_last = timeline;
        break;

    case ST_TIMER:
        if ((timeline - sensor.time_last) >= sensor.period) {
            sensor_set_value(sensor, 1);
            sensor.time_last = timeline;
        }
        break;

    case ST_ELAPSED:
        if (!sensor.time_last) {
            sensor.time_last = timeline;
        }

        sensor_set_value(sensor, timeline - sensor.time_last);
        sensor.time_last = timeline;
        break;

    case ST_TIMELINE:
        sensor_set_value(sensor, timeline);
        break;

    default:
        break;
    }
}
Example #9
0
/**
 * Only trans/quat affected by constraint here
 */
function update_cons(obj, cons, elapsed) {
    switch (cons.type) {
    case CONS_TYPE_STIFF_OBJ:

        var trans = obj._render.trans;
        var quat = obj._render.quat;

        var p_world_matrix = cons.obj_parent._render.world_matrix; 
        var p_trans = cons.obj_parent._render.trans; 
        var p_quat = cons.obj_parent._render.quat; 

        if (cons.rotation_offset) {
            m_quat.copy(cons.rotation_offset, quat);
            m_quat.multiply(p_quat, quat, quat);
        } else
            m_quat.copy(p_quat, quat);

        m_vec3.transformMat4(cons.offset, p_world_matrix, obj._render.trans);
        obj._render.scale = cons.scale_offset * cons.obj_parent._render.scale;

        break;
    case CONS_TYPE_SEMI_STIFF_OBJ:

        var trans = obj._render.trans;
        var quat = obj._render.quat;
        
        var p_world_matrix = cons.obj_parent._render.world_matrix; 
        var p_quat = cons.obj_parent._render.quat; 

        // Qp * Qp_prev_inv * Q
        m_quat.multiply(
                m_quat.invert(cons.parent_prev_rotation, cons.parent_prev_rotation),
                quat, quat);
        m_quat.multiply(p_quat, quat, quat);

        m_vec3.transformMat4(cons.offset, p_world_matrix, trans);
        m_quat.copy(p_quat, cons.parent_prev_rotation);

        break;
    case CONS_TYPE_SEMI_STIFF_CAM_OBJ:

        var trans = obj._render.trans;
        var quat = obj._render.quat;
        
        var p_world_matrix = cons.obj_parent._render.world_matrix; 
        var p_quat = cons.obj_parent._render.quat; 

        // Qp * Qp_prev_inv * Q
        m_quat.multiply(
                m_quat.invert(cons.parent_prev_rotation, cons.parent_prev_rotation),
                quat, quat);
        m_quat.multiply(p_quat, quat, quat);

        m_vec3.transformMat4(cons.offset, p_world_matrix, trans);
        m_quat.copy(p_quat, cons.parent_prev_rotation)

        clamp_angles(obj, cons);
        if (obj._render.type == "CAMERA") {
            var p_y_axis = m_vec3.transformQuat(m_util.AXIS_Y, p_quat, _vec3_tmp_2);
            correct_up(obj, p_y_axis);
        }

        break;
    case CONS_TYPE_SEMI_SOFT_CAM_OBJ:

        var trans          = obj._render.trans;
        var quat           = obj._render.quat;
        var p_world_matrix = cons.obj_parent._render.world_matrix;
        var p_trans        = cons.obj_parent._render.trans;
        var trans_pivot    = _vec3_tmp;
        var quat_pivot     = _quat4_tmp;

        m_vec3.transformMat4(cons.offset, p_world_matrix, trans_pivot);

        m_util.smooth_v(trans_pivot, trans, elapsed, 0.3, trans);

        var dir_to_obj = _vec3_tmp;
        m_vec3.sub(p_trans, trans, dir_to_obj);
        m_vec3.normalize(dir_to_obj, dir_to_obj);
        cam_rotate_to(quat, dir_to_obj, quat_pivot);
        m_util.smooth_q(quat_pivot, quat, elapsed, 0.1, quat);

        break;
    case CONS_TYPE_STIFF_BONE:
        var trans = obj._render.trans;
        var quat = obj._render.quat;

        var p_trans = _vec4_tmp;
        var p_quat = _quat4_tmp;

        get_bone_pose(cons.obj_parent, cons.bone_name, true, p_trans, p_quat);

        if (cons.rotation_offset) {
            m_quat.copy(cons.rotation_offset, quat);
            m_quat.multiply(p_quat, quat, quat);
        } else
            m_quat.copy(p_quat, quat);

        m_util.transform_vec3(cons.offset, 1, p_quat, p_trans, obj._render.trans);

        break;
    case CONS_TYPE_TRACK_OBJ:
        var trans = obj._render.trans;
        var quat = obj._render.quat;
        var t_trans = cons.obj_parent._render.trans; 

        rotate_to(trans, quat, t_trans);
        if (obj._render.type == "CAMERA")
            correct_up(obj, m_util.AXIS_Y);
        break;
    case CONS_TYPE_TRACK_POINT:
        var trans = obj._render.trans;
        var quat = obj._render.quat;
        var t_trans = cons.target; 

        rotate_to(trans, quat, t_trans);
        if (obj._render.type == "CAMERA")
            correct_up(obj, m_util.AXIS_Y);
        break;

    case CONS_TYPE_FOLLOW_OBJ:
        var trans = obj._render.trans;
        var quat = obj._render.quat;
        var t_trans = cons.obj_parent._render.trans; 

        var is_rotated = rotate_to_limits(trans, quat, t_trans, CONS_ROTATE_LIMIT);
        
        // shrink distance
        var dist = m_vec3.dist(trans, t_trans);

        // passing target location
        if (!is_rotated)
            delta = dist + cons.offset_min;
        else {
            if (dist > cons.offset_max)
                var delta = dist - cons.offset_max;
            else if (dist < cons.offset_min)
                var delta = dist - cons.offset_min;
            else
                var delta = 0.0;
        }

        if (delta) {
            // NOTE: from trans to t_trans
            m_vec3.sub(t_trans, trans, _vec3_tmp);
            m_vec3.normalize(_vec3_tmp, _vec3_tmp);
            m_vec3.scale(_vec3_tmp, delta, _vec3_tmp);
            m_vec3.add(trans, _vec3_tmp, trans);
        }
        
        if (obj._render.type == "CAMERA")
            correct_up(obj, m_util.AXIS_Y);

        break;
    case CONS_TYPE_FOLLOW_POINT:
        var trans = obj._render.trans;
        var quat = obj._render.quat;
        var t_trans = cons.target; 

        var is_rotated = rotate_to_limits(trans, quat, t_trans, CONS_ROTATE_LIMIT);

        // shrink distance
        var dist = m_vec3.dist(trans, t_trans);

        // passing target location
        if (!is_rotated)
            delta = dist + cons.offset_min;
        else {
            if (dist > cons.offset_max)
                var delta = dist - cons.offset_max;
            else if (dist < cons.offset_min)
                var delta = dist - cons.offset_min;
            else
                var delta = 0.0;
        }

        if (delta) {
            // NOTE: from trans to t_trans
            m_vec3.sub(t_trans, trans, _vec3_tmp);
            m_vec3.normalize(_vec3_tmp, _vec3_tmp);
            m_vec3.scale(_vec3_tmp, delta, _vec3_tmp);
            m_vec3.add(trans, _vec3_tmp, trans);
        }
        
        if (obj._render.type == "CAMERA")
            correct_up(obj, m_util.AXIS_Y);
        break;
    case CONS_TYPE_STIFF_TRANS_OBJ:
        var p_world_matrix = cons.obj_parent._render.world_matrix; 
        m_vec3.transformMat4(cons.offset, p_world_matrix, obj._render.trans);
        break;
    case CONS_TYPE_COPY_TRANS_OBJ:
        var p_trans = cons.obj_parent._render.trans; 
        var trans = obj._render.trans;
        m_vec3.add(p_trans, cons.offset, trans);
        break;
    case CONS_TYPE_STIFF_TRANS_ROT_OBJ:

        var trans = obj._render.trans;
        var quat = obj._render.quat;

        var p_world_matrix = cons.obj_parent._render.world_matrix;
        var p_trans = cons.obj_parent._render.trans;
        var p_quat = cons.obj_parent._render.quat;

        if (cons.rotation_offset) {
            m_quat.copy(cons.rotation_offset, quat);
            m_quat.multiply(p_quat, quat, quat);
        } else
            m_quat.copy(p_quat, quat);

        m_vec3.transformMat4(cons.offset, p_world_matrix, obj._render.trans);
        break;
    case CONS_TYPE_CHILD_OF:
        var prender = cons.obj_parent._render; 
        var ptsr = m_tsr.create_sep(prender.trans, prender.scale, prender.quat,
                _tsr8_tmp);
        var tsr_offset = cons.tsr_offset;

        m_tsr.multiply(ptsr, tsr_offset, ptsr);
        
        var trans = obj._render.trans;
        trans[0] = ptsr[0];
        trans[1] = ptsr[1];
        trans[2] = ptsr[2];

        obj._render.scale = ptsr[3];

        var quat = obj._render.quat;
        quat[0] = ptsr[4];
        quat[1] = ptsr[5];
        quat[2] = ptsr[6];
        quat[3] = ptsr[7];

        break;
    default:
        break;
    }
}
/**
 * Only trans/quat affected by constraint here
 */
function update_cons(obj, cons, elapsed) {
    switch (cons.type) {
    case CONS_TYPE_STIFF_OBJ:

        var quat = obj._render.quat;

        var p_world_matrix = cons.obj_parent._render.world_matrix;
        var p_quat = cons.obj_parent._render.quat;

        if (cons.rotation_offset) {
            m_quat.copy(cons.rotation_offset, quat);
            m_quat.multiply(p_quat, quat, quat);
        } else
            m_quat.copy(p_quat, quat);

        m_vec3.transformMat4(cons.offset, p_world_matrix, obj._render.trans);
        obj._render.scale = cons.scale_offset * cons.obj_parent._render.scale;

        break;
    case CONS_TYPE_SEMI_STIFF_OBJ:

        var trans = obj._render.trans;
        var quat = obj._render.quat;

        var p_world_matrix = cons.obj_parent._render.world_matrix;
        var p_quat = cons.obj_parent._render.quat;

        // Qp * Qp_prev_inv * Q
        m_quat.multiply(
                m_quat.invert(cons.parent_prev_rotation, cons.parent_prev_rotation),
                quat, quat);
        m_quat.multiply(p_quat, quat, quat);

        m_vec3.transformMat4(cons.offset, p_world_matrix, trans);
        m_quat.copy(p_quat, cons.parent_prev_rotation);

        break;
    case CONS_TYPE_SEMI_STIFF_CAM_OBJ:

        var trans = obj._render.trans;
        var quat = obj._render.quat;

        var p_world_matrix = cons.obj_parent._render.world_matrix;
        var p_quat = cons.obj_parent._render.quat;

        // Qp * Qp_prev_inv * Q
        m_quat.multiply(
                m_quat.invert(cons.parent_prev_rotation, cons.parent_prev_rotation),
                quat, quat);
        m_quat.multiply(p_quat, quat, quat);

        m_vec3.transformMat4(cons.offset, p_world_matrix, trans);
        m_quat.copy(p_quat, cons.parent_prev_rotation)

        clamp_orientation(obj, cons);

        break;
    case CONS_TYPE_SEMI_SOFT_CAM_OBJ:

        var trans          = obj._render.trans;
        var quat           = obj._render.quat;
        var p_world_matrix = cons.obj_parent._render.world_matrix;
        var p_trans        = cons.obj_parent._render.trans;
        var softness       = cons.softness;
        var trans_pivot    = _vec3_tmp;
        var quat_pivot     = _quat4_tmp;
        var softness_ratio = 0.16;

        m_vec3.transformMat4(cons.offset, p_world_matrix, trans_pivot);

        m_util.smooth_v(trans_pivot, trans, elapsed, softness, trans);

        var dir_to_obj = _vec3_tmp;
        m_vec3.sub(p_trans, trans, dir_to_obj);
        m_vec3.normalize(dir_to_obj, dir_to_obj);
        cam_rotate_to(quat, dir_to_obj, quat_pivot);
        m_util.smooth_q(quat_pivot, quat, elapsed, softness * softness_ratio, quat);

        break;
    case CONS_TYPE_STIFF_BONE:
        var quat = obj._render.quat;

        var p_transscale = _vec4_tmp;
        var p_quat = _quat4_tmp;

        get_bone_pose(cons.obj_parent, cons.bone_name, true, p_transscale, 
                p_quat);

        if (cons.rotation_offset) {
            m_quat.copy(cons.rotation_offset, quat);
            m_quat.multiply(p_quat, quat, quat);
        } else
            m_quat.copy(p_quat, quat);

        obj._render.scale = cons.scale_offset * p_transscale[3];

        m_util.transform_vec3(cons.offset, p_transscale[3], p_quat, p_transscale, 
                obj._render.trans);

        break;
    case CONS_TYPE_TRACK_OBJ:
        var trans = obj._render.trans;
        var quat = obj._render.quat;
        var t_trans = cons.obj_parent._render.trans;

        rotate_to(trans, quat, t_trans);
        break;
    case CONS_TYPE_TRACK_POINT:
        var trans = obj._render.trans;
        var quat = obj._render.quat;
        var t_trans = cons.target;

        rotate_to(trans, quat, t_trans);
        break;

    case CONS_TYPE_FOLLOW_OBJ:
        var trans = obj._render.trans;
        var quat = obj._render.quat;
        var t_trans = cons.obj_parent._render.trans;

        rotate_to(trans, quat, t_trans);

        // shrink distance
        var dist = m_vec3.dist(trans, t_trans);

        // passing target location
        if (dist > cons.offset_max)
            var delta = dist - cons.offset_max;
        else if (dist < cons.offset_min)
            var delta = dist - cons.offset_min;
        else
            var delta = 0.0;

        if (delta) {
            // NOTE: from trans to t_trans
            m_vec3.sub(t_trans, trans, _vec3_tmp);
            m_vec3.normalize(_vec3_tmp, _vec3_tmp);
            m_vec3.scale(_vec3_tmp, delta, _vec3_tmp);
            m_vec3.add(trans, _vec3_tmp, trans);
        }

        break;
    case CONS_TYPE_FOLLOW_POINT:
        var trans = obj._render.trans;
        var quat = obj._render.quat;
        var t_trans = cons.target;

        rotate_to(trans, quat, t_trans);

        // shrink distance
        var dist = m_vec3.dist(trans, t_trans);

        // passing target location
        if (dist > cons.offset_max)
            var delta = dist - cons.offset_max;
        else if (dist < cons.offset_min)
            var delta = dist - cons.offset_min;
        else
            var delta = 0.0;

        if (delta) {
            // NOTE: from trans to t_trans
            m_vec3.sub(t_trans, trans, _vec3_tmp);
            m_vec3.normalize(_vec3_tmp, _vec3_tmp);
            m_vec3.scale(_vec3_tmp, delta, _vec3_tmp);
            m_vec3.add(trans, _vec3_tmp, trans);
        }

        break;
    case CONS_TYPE_STIFF_TRANS_OBJ:
        var p_world_matrix = cons.obj_parent._render.world_matrix;
        m_vec3.transformMat4(cons.offset, p_world_matrix, obj._render.trans);
        break;
    case CONS_TYPE_COPY_TRANS_OBJ:
        var p_trans = cons.obj_parent._render.trans;
        var trans = obj._render.trans;
        m_vec3.add(p_trans, cons.offset, trans);
        break;
    case CONS_TYPE_STIFF_TRANS_ROT_OBJ:

        var quat = obj._render.quat;

        var p_world_matrix = cons.obj_parent._render.world_matrix;
        var p_quat = cons.obj_parent._render.quat;

        if (cons.rotation_offset) {
            m_quat.copy(cons.rotation_offset, quat);
            m_quat.multiply(p_quat, quat, quat);
        } else
            m_quat.copy(p_quat, quat);

        m_vec3.transformMat4(cons.offset, p_world_matrix, obj._render.trans);
        break;
    case CONS_TYPE_CHILD_OF:
        var prender = cons.obj_parent._render;
        var ptsr = m_tsr.create_sep(prender.trans, prender.scale, prender.quat,
                _tsr8_tmp);
        var tsr_offset = cons.tsr_offset;

        m_tsr.multiply(ptsr, tsr_offset, ptsr);

        var trans = obj._render.trans;
        trans[0] = ptsr[0];
        trans[1] = ptsr[1];
        trans[2] = ptsr[2];

        obj._render.scale = ptsr[3];

        var quat = obj._render.quat;
        quat[0] = ptsr[4];
        quat[1] = ptsr[5];
        quat[2] = ptsr[6];
        quat[3] = ptsr[7];

        break;
    case CONS_TYPE_STIFF_VIEWPORT:
        var camobj = cons.obj_parent;
        var cam = m_cam.get_first_cam(camobj);

        var trans = obj._render.trans;

        var top = m_cam.get_edge(cam, "TOP");
        var bottom = m_cam.get_edge(cam, "BOTTOM");
        var height = top - bottom;

        if (cons.left_edge) {
            var left = m_cam.get_edge(cam, "LEFT");
            trans[0] = left + height * cons.left_right_dist;
        } else {
            var right = m_cam.get_edge(cam, "RIGHT");
            trans[0] = right - height * cons.left_right_dist;
        }

        // in the camera's local space (not view space)
        if (cons.top_edge)
            trans[2] = -(top - height * cons.top_bottom_dist);
        else
            trans[2] = -(bottom + height * cons.top_bottom_dist);

        // NOTE: ortho cameras have scaling problems
        if (m_cam.is_ortho(cam)) {
            trans[1] = -cons.distance;
        } else {
            trans[1] = -1;
            m_vec3.normalize(trans, trans);
            var scale = cons.distance/Math.abs(trans[1]);
            m_vec3.scale(trans, scale, trans);
        }

        m_tsr.transform_dir_vec3(trans, camobj._render.tsr, trans);
        m_vec3.add(camobj._render.trans, trans, trans);

        var quat = obj._render.quat;

        if (cons.rotation_offset) {
            m_quat.copy(cons.rotation_offset, quat);
            m_quat.multiply(camobj._render.quat, quat, quat);
        } else
            m_quat.copy(camobj._render.quat, quat);

        break;
    default:
        break;
    }

    if (obj._render.type == "CAMERA") {
        var corr_axis = m_util.AXIS_Y;
        if (cons.type == CONS_TYPE_SEMI_STIFF_CAM_OBJ) {
            var p_quat = cons.obj_parent._render.quat;
            corr_axis = m_vec3.transformQuat(corr_axis, p_quat, _parent_y_axis);
        }

        m_cam.update_camera_upside_down(obj);
        correct_up(obj, corr_axis);
    }
}