mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 04:37:23 +02:00
Merge pull request #5849 from sethalves/hand-controller-adjustment
Hand controller adjustment
This commit is contained in:
commit
35e38a443c
3 changed files with 122 additions and 85 deletions
|
@ -18,7 +18,7 @@ Script.include("../libraries/utils.js");
|
||||||
// these tune time-averaging and "on" value for analog trigger
|
// these tune time-averaging and "on" value for analog trigger
|
||||||
//
|
//
|
||||||
|
|
||||||
var TRIGGER_SMOOTH_RATIO = 0.7;
|
var TRIGGER_SMOOTH_RATIO = 0.0; // 0.0 disables smoothing of trigger value
|
||||||
var TRIGGER_ON_VALUE = 0.2;
|
var TRIGGER_ON_VALUE = 0.2;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
|
@ -26,7 +26,7 @@ var TRIGGER_ON_VALUE = 0.2;
|
||||||
// distant manipulation
|
// distant manipulation
|
||||||
//
|
//
|
||||||
|
|
||||||
var DISTANCE_HOLDING_RADIUS_FACTOR = 4; // multiplied by distance between hand and object
|
var DISTANCE_HOLDING_RADIUS_FACTOR = 5; // multiplied by distance between hand and object
|
||||||
var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position
|
var DISTANCE_HOLDING_ACTION_TIMEFRAME = 0.1; // how quickly objects move to their new position
|
||||||
var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did
|
var DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR = 2.0; // object rotates this much more than hand did
|
||||||
var NO_INTERSECT_COLOR = {red: 10, green: 10, blue: 255}; // line color when pick misses
|
var NO_INTERSECT_COLOR = {red: 10, green: 10, blue: 255}; // line color when pick misses
|
||||||
|
@ -37,14 +37,14 @@ var LINE_LENGTH = 500;
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// close grabbing
|
// near grabbing
|
||||||
//
|
//
|
||||||
|
|
||||||
var GRAB_RADIUS = 0.3; // if the ray misses but an object is this close, it will still be selected
|
var GRAB_RADIUS = 0.3; // if the ray misses but an object is this close, it will still be selected
|
||||||
var CLOSE_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
|
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
|
||||||
var CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO = 0.9; // adjust time-averaging of held object's velocity
|
var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable.
|
||||||
var CLOSE_PICK_MAX_DISTANCE = 0.6; // max length of pick-ray for close grabbing to be selected
|
var NEAR_PICK_MAX_DISTANCE = 0.6; // max length of pick-ray for close grabbing to be selected
|
||||||
|
var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@ -65,9 +65,10 @@ var LIFETIME = 10;
|
||||||
// states for the state machine
|
// states for the state machine
|
||||||
var STATE_SEARCHING = 0;
|
var STATE_SEARCHING = 0;
|
||||||
var STATE_DISTANCE_HOLDING = 1;
|
var STATE_DISTANCE_HOLDING = 1;
|
||||||
var STATE_CLOSE_GRABBING = 2;
|
var STATE_CONTINUE_DISTANCE_HOLDING = 2;
|
||||||
var STATE_CONTINUE_CLOSE_GRABBING = 3;
|
var STATE_NEAR_GRABBING = 3;
|
||||||
var STATE_RELEASE = 4;
|
var STATE_CONTINUE_NEAR_GRABBING = 4;
|
||||||
|
var STATE_RELEASE = 5;
|
||||||
|
|
||||||
var GRAB_USER_DATA_KEY = "grabKey";
|
var GRAB_USER_DATA_KEY = "grabKey";
|
||||||
|
|
||||||
|
@ -87,10 +88,9 @@ function controller(hand, triggerAction) {
|
||||||
this.actionID = null; // action this script created...
|
this.actionID = null; // action this script created...
|
||||||
this.grabbedEntity = null; // on this entity.
|
this.grabbedEntity = null; // on this entity.
|
||||||
this.grabbedVelocity = ZERO_VEC; // rolling average of held object's velocity
|
this.grabbedVelocity = ZERO_VEC; // rolling average of held object's velocity
|
||||||
this.state = 0; // 0 = searching, 1 = distanceHolding, 2 = closeGrabbing
|
this.state = 0;
|
||||||
this.pointer = null; // entity-id of line object
|
this.pointer = null; // entity-id of line object
|
||||||
this.triggerValue = 0; // rolling average of trigger value
|
this.triggerValue = 0; // rolling average of trigger value
|
||||||
this.alreadyDistanceHolding = false; // FIXME - I'll leave it to Seth to potentially make this another state
|
|
||||||
|
|
||||||
this.update = function() {
|
this.update = function() {
|
||||||
switch(this.state) {
|
switch(this.state) {
|
||||||
|
@ -100,11 +100,14 @@ function controller(hand, triggerAction) {
|
||||||
case STATE_DISTANCE_HOLDING:
|
case STATE_DISTANCE_HOLDING:
|
||||||
this.distanceHolding();
|
this.distanceHolding();
|
||||||
break;
|
break;
|
||||||
case STATE_CLOSE_GRABBING:
|
case STATE_CONTINUE_DISTANCE_HOLDING:
|
||||||
this.closeGrabbing();
|
this.continueDistanceHolding();
|
||||||
break;
|
break;
|
||||||
case STATE_CONTINUE_CLOSE_GRABBING:
|
case STATE_NEAR_GRABBING:
|
||||||
this.continueCloseGrabbing();
|
this.nearGrabbing();
|
||||||
|
break;
|
||||||
|
case STATE_CONTINUE_NEAR_GRABBING:
|
||||||
|
this.continueNearGrabbing();
|
||||||
break;
|
break;
|
||||||
case STATE_RELEASE:
|
case STATE_RELEASE:
|
||||||
this.release();
|
this.release();
|
||||||
|
@ -177,9 +180,9 @@ function controller(hand, triggerAction) {
|
||||||
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
|
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
|
||||||
var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection);
|
var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection);
|
||||||
this.grabbedEntity = intersection.entityID;
|
this.grabbedEntity = intersection.entityID;
|
||||||
if (intersectionDistance < CLOSE_PICK_MAX_DISTANCE) {
|
if (intersectionDistance < NEAR_PICK_MAX_DISTANCE) {
|
||||||
// the hand is very close to the intersected object. go into close-grabbing mode.
|
// the hand is very close to the intersected object. go into close-grabbing mode.
|
||||||
this.state = STATE_CLOSE_GRABBING;
|
this.state = STATE_NEAR_GRABBING;
|
||||||
} else {
|
} else {
|
||||||
// the hand is far from the intersected object. go into distance-holding mode
|
// the hand is far from the intersected object. go into distance-holding mode
|
||||||
this.state = STATE_DISTANCE_HOLDING;
|
this.state = STATE_DISTANCE_HOLDING;
|
||||||
|
@ -203,34 +206,18 @@ function controller(hand, triggerAction) {
|
||||||
if (this.grabbedEntity === null) {
|
if (this.grabbedEntity === null) {
|
||||||
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||||
} else {
|
} else {
|
||||||
this.state = STATE_CLOSE_GRABBING;
|
this.state = STATE_NEAR_GRABBING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.distanceHolding = function() {
|
this.distanceHolding = function() {
|
||||||
if (!this.triggerSmoothedSqueezed()) {
|
|
||||||
this.state = STATE_RELEASE;
|
|
||||||
this.alreadyDistanceHolding = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.alreadyDistanceHolding) {
|
|
||||||
this.activateEntity(this.grabbedEntity);
|
|
||||||
this.alreadyDistanceHolding = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var handPosition = this.getHandPosition();
|
|
||||||
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
|
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
|
||||||
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
|
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
|
||||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position","rotation"]);
|
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position","rotation"]);
|
||||||
Entities.callEntityMethod(this.grabbedEntity, "distanceHolding");
|
|
||||||
|
|
||||||
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
|
// add the action and initialize some variables
|
||||||
|
|
||||||
if (this.actionID === null) {
|
|
||||||
// first time here since trigger pulled -- add the action and initialize some variables
|
|
||||||
this.currentObjectPosition = grabbedProperties.position;
|
this.currentObjectPosition = grabbedProperties.position;
|
||||||
this.currentObjectRotation = grabbedProperties.rotation;
|
this.currentObjectRotation = grabbedProperties.rotation;
|
||||||
this.handPreviousPosition = handControllerPosition;
|
this.handPreviousPosition = handControllerPosition;
|
||||||
|
@ -245,7 +232,34 @@ function controller(hand, triggerAction) {
|
||||||
if (this.actionID == NULL_ACTION_ID) {
|
if (this.actionID == NULL_ACTION_ID) {
|
||||||
this.actionID = null;
|
this.actionID = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.actionID != null) {
|
||||||
|
this.state = STATE_CONTINUE_DISTANCE_HOLDING;
|
||||||
|
this.activateEntity(this.grabbedEntity);
|
||||||
|
Entities.callEntityMethod(this.grabbedEntity, "startDistantGrab");
|
||||||
|
|
||||||
|
if (this.hand === RIGHT_HAND) {
|
||||||
|
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
|
||||||
} else {
|
} else {
|
||||||
|
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.continueDistanceHolding = function() {
|
||||||
|
if (!this.triggerSmoothedSqueezed()) {
|
||||||
|
this.state = STATE_RELEASE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var handPosition = this.getHandPosition();
|
||||||
|
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
|
||||||
|
var handRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(this.palm));
|
||||||
|
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position","rotation"]);
|
||||||
|
|
||||||
|
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
|
||||||
|
|
||||||
// the action was set up on a previous call. update the targets.
|
// the action was set up on a previous call. update the targets.
|
||||||
var radius = Math.max(Vec3.distance(this.currentObjectPosition,
|
var radius = Math.max(Vec3.distance(this.currentObjectPosition,
|
||||||
handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR,
|
handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR,
|
||||||
|
@ -263,15 +277,16 @@ function controller(hand, triggerAction) {
|
||||||
this.handPreviousRotation = handRotation;
|
this.handPreviousRotation = handRotation;
|
||||||
this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
|
this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
|
||||||
|
|
||||||
|
Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab");
|
||||||
|
|
||||||
Entities.updateAction(this.grabbedEntity, this.actionID, {
|
Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||||
targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
targetPosition: this.currentObjectPosition, linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||||
targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME
|
targetRotation: this.currentObjectRotation, angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
this.closeGrabbing = function() {
|
this.nearGrabbing = function() {
|
||||||
if (!this.triggerSmoothedSqueezed()) {
|
if (!this.triggerSmoothedSqueezed()) {
|
||||||
this.state = STATE_RELEASE;
|
this.state = STATE_RELEASE;
|
||||||
return;
|
return;
|
||||||
|
@ -289,54 +304,61 @@ function controller(hand, triggerAction) {
|
||||||
var objectRotation = grabbedProperties.rotation;
|
var objectRotation = grabbedProperties.rotation;
|
||||||
var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
var offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
||||||
|
|
||||||
this.currentObjectPosition = grabbedProperties.position;
|
currentObjectPosition = grabbedProperties.position;
|
||||||
this.currentObjectTime = Date.now();
|
var offset = Vec3.subtract(currentObjectPosition, handPosition);
|
||||||
var offset = Vec3.subtract(this.currentObjectPosition, handPosition);
|
|
||||||
var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset);
|
var offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, offsetRotation)), offset);
|
||||||
|
|
||||||
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
|
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
|
||||||
hand: this.hand == RIGHT_HAND ? "right" : "left",
|
hand: this.hand == RIGHT_HAND ? "right" : "left",
|
||||||
timeScale: CLOSE_GRABBING_ACTION_TIMEFRAME,
|
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||||
relativePosition: offsetPosition,
|
relativePosition: offsetPosition,
|
||||||
relativeRotation: offsetRotation
|
relativeRotation: offsetRotation
|
||||||
});
|
});
|
||||||
if (this.actionID == NULL_ACTION_ID) {
|
if (this.actionID == NULL_ACTION_ID) {
|
||||||
this.actionID = null;
|
this.actionID = null;
|
||||||
} else {
|
} else {
|
||||||
this.state = STATE_CONTINUE_CLOSE_GRABBING;
|
this.state = STATE_CONTINUE_NEAR_GRABBING;
|
||||||
|
Entities.callEntityMethod(this.grabbedEntity, "startNearGrab");
|
||||||
|
if (this.hand === RIGHT_HAND) {
|
||||||
|
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
|
||||||
|
} else {
|
||||||
|
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
|
||||||
}
|
}
|
||||||
Entities.callEntityMethod(this.grabbedEntity, "closeGrabbing");
|
}
|
||||||
|
|
||||||
|
this.currentHandControllerPosition = Controller.getSpatialControlPosition(this.palm);
|
||||||
|
this.currentObjectTime = Date.now();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.continueCloseGrabbing = function() {
|
this.continueNearGrabbing = function() {
|
||||||
if (!this.triggerSmoothedSqueezed()) {
|
if (!this.triggerSmoothedSqueezed()) {
|
||||||
this.state = STATE_RELEASE;
|
this.state = STATE_RELEASE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// keep track of the measured velocity of the held object
|
// keep track of the measured velocity of the held object
|
||||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity);
|
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
|
|
||||||
var deltaPosition = Vec3.subtract(grabbedProperties.position, this.currentObjectPosition); // meters
|
var deltaPosition = Vec3.subtract(handControllerPosition, this.currentHandControllerPosition); // meters
|
||||||
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
|
var deltaTime = (now - this.currentObjectTime) / MSEC_PER_SEC; // convert to seconds
|
||||||
|
|
||||||
if (deltaTime > 0.0) {
|
if (deltaTime > 0.0 && !vec3equal(this.currentHandControllerPosition, handControllerPosition)) {
|
||||||
var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime);
|
var grabbedVelocity = Vec3.multiply(deltaPosition, 1.0 / deltaTime);
|
||||||
// don't update grabbedVelocity if the trigger is off. the smoothing of the trigger
|
// don't update grabbedVelocity if the trigger is off. the smoothing of the trigger
|
||||||
// value would otherwise give the held object time to slow down.
|
// value would otherwise give the held object time to slow down.
|
||||||
if (this.triggerSqueezed()) {
|
if (this.triggerSqueezed()) {
|
||||||
this.grabbedVelocity =
|
this.grabbedVelocity =
|
||||||
Vec3.sum(Vec3.multiply(this.grabbedVelocity,
|
Vec3.sum(Vec3.multiply(this.grabbedVelocity,
|
||||||
(1.0 - CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO)),
|
(1.0 - NEAR_GRABBING_VELOCITY_SMOOTH_RATIO)),
|
||||||
Vec3.multiply(grabbedVelocity, CLOSE_GRABBING_VELOCITY_SMOOTH_RATIO));
|
Vec3.multiply(grabbedVelocity, NEAR_GRABBING_VELOCITY_SMOOTH_RATIO));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.currentObjectPosition = grabbedProperties.position;
|
this.currentHandControllerPosition = handControllerPosition;
|
||||||
this.currentObjectTime = now;
|
this.currentObjectTime = now;
|
||||||
Entities.callEntityMethod(this.grabbedEntity, "continueCloseGrabbing");
|
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -349,9 +371,10 @@ function controller(hand, triggerAction) {
|
||||||
|
|
||||||
// the action will tend to quickly bring an object's velocity to zero. now that
|
// the action will tend to quickly bring an object's velocity to zero. now that
|
||||||
// the action is gone, set the objects velocity to something the holder might expect.
|
// the action is gone, set the objects velocity to something the holder might expect.
|
||||||
Entities.editEntity(this.grabbedEntity, { velocity: this.grabbedVelocity });
|
Entities.editEntity(this.grabbedEntity,
|
||||||
|
{velocity: Vec3.multiply(this.grabbedVelocity, RELEASE_VELOCITY_MULTIPLIER)}
|
||||||
Entities.callEntityMethod(this.grabbedEntity, "release");
|
);
|
||||||
|
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
|
||||||
this.deactivateEntity(this.grabbedEntity);
|
this.deactivateEntity(this.grabbedEntity);
|
||||||
|
|
||||||
this.grabbedVelocity = ZERO_VEC;
|
this.grabbedVelocity = ZERO_VEC;
|
||||||
|
|
|
@ -23,16 +23,27 @@
|
||||||
|
|
||||||
DetectGrabbed.prototype = {
|
DetectGrabbed.prototype = {
|
||||||
|
|
||||||
distanceHolding: function () {
|
setRightHand: function () {
|
||||||
print("I am being distance held... entity:" + this.entityID);
|
print("I am being held in a right hand... entity:" + this.entityID);
|
||||||
|
},
|
||||||
|
setLeftHand: function () {
|
||||||
|
print("I am being held in a left hand... entity:" + this.entityID);
|
||||||
},
|
},
|
||||||
|
|
||||||
closeGrabbing: function () {
|
startDistantGrab: function () {
|
||||||
|
print("I am being distance held... entity:" + this.entityID);
|
||||||
|
},
|
||||||
|
continueDistantGrab: function () {
|
||||||
|
print("I continue to be distance held... entity:" + this.entityID);
|
||||||
|
},
|
||||||
|
|
||||||
|
startNearGrab: function () {
|
||||||
print("I was just grabbed... entity:" + this.entityID);
|
print("I was just grabbed... entity:" + this.entityID);
|
||||||
},
|
},
|
||||||
continueCloseGrabbing: function () {
|
continueNearGrab: function () {
|
||||||
print("I am still being grabbed... entity:" + this.entityID);
|
print("I am still being grabbed... entity:" + this.entityID);
|
||||||
},
|
},
|
||||||
|
|
||||||
release: function () {
|
release: function () {
|
||||||
print("I was released... entity:" + this.entityID);
|
print("I was released... entity:" + this.entityID);
|
||||||
},
|
},
|
||||||
|
|
|
@ -6,11 +6,14 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
vec3toStr = function (v, digits) {
|
vec3toStr = function(v, digits) {
|
||||||
if (!digits) { digits = 3; }
|
if (!digits) { digits = 3; }
|
||||||
return "{ " + v.x.toFixed(digits) + ", " + v.y.toFixed(digits) + ", " + v.z.toFixed(digits)+ " }";
|
return "{ " + v.x.toFixed(digits) + ", " + v.y.toFixed(digits) + ", " + v.z.toFixed(digits)+ " }";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vec3equal = function(v0, v1) {
|
||||||
|
return (v0.x == v1.x) && (v0.y == v1.y) && (v0.z == v1.z);
|
||||||
|
}
|
||||||
|
|
||||||
colorMix = function(colorA, colorB, mix) {
|
colorMix = function(colorA, colorB, mix) {
|
||||||
var result = {};
|
var result = {};
|
||||||
|
|
Loading…
Reference in a new issue