mirror of
https://github.com/overte-org/overte.git
synced 2025-04-07 19:12:28 +02:00
test app for bullet dynamics
This commit is contained in:
parent
dabec586ec
commit
41663c58b8
4 changed files with 919 additions and 0 deletions
64
scripts/developer/tests/dynamics/dynamics-tests-interface.js
Normal file
64
scripts/developer/tests/dynamics/dynamics-tests-interface.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
"use strict";
|
||||
/* globals $, EventBridge */
|
||||
|
||||
var parameters = {
|
||||
"lifetime":"integer"
|
||||
};
|
||||
|
||||
|
||||
function getQueryArgByName(name, url) {
|
||||
if (!url) {
|
||||
url = window.location.href;
|
||||
}
|
||||
name = name.replace(/[\[\]]/g, "\\$&");
|
||||
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
|
||||
results = regex.exec(url);
|
||||
if (!results) return null;
|
||||
if (!results[2]) return '';
|
||||
return decodeURIComponent(results[2].replace(/\+/g, " "));
|
||||
}
|
||||
|
||||
|
||||
function addCommandParameters(params) {
|
||||
// copy from html elements into an associative-array which will get passed (as JSON) through the EventBridge
|
||||
for (var parameterName in parameters) {
|
||||
if (parameters.hasOwnProperty(parameterName)) {
|
||||
var parameterType = parameters[parameterName];
|
||||
var strVal = $("#" + parameterName).val();
|
||||
if (parameterType == "integer") {
|
||||
params[parameterName] = parseInt(strVal);
|
||||
} else if (parameterType == "float") {
|
||||
params[parameterName] = parseFloat(strVal);
|
||||
} else {
|
||||
params[parameterName] = strVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
$(document).ready(function() {
|
||||
// hook all buttons to EventBridge
|
||||
$(":button").each(function(index) {
|
||||
$(this).click(function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify(addCommandParameters({ "dynamics-tests-command": this.id })));
|
||||
});
|
||||
});
|
||||
|
||||
// copy parameters from query-args into elements
|
||||
for (var parameterName in parameters) {
|
||||
if (parameters.hasOwnProperty(parameterName)) {
|
||||
var val = getQueryArgByName(parameterName);
|
||||
if (val) {
|
||||
var parameterType = parameters[parameterName];
|
||||
if (parameterType == "integer") {
|
||||
val = parseInt(val);
|
||||
} else if (parameterType == "float") {
|
||||
val = parseFloat(val);
|
||||
}
|
||||
$("#" + parameterName).val(val.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
37
scripts/developer/tests/dynamics/dynamics-tests.html
Normal file
37
scripts/developer/tests/dynamics/dynamics-tests.html
Normal file
|
@ -0,0 +1,37 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Dynamics Tests</title>
|
||||
<meta charset="utf-8">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
|
||||
<script src="dynamics-tests-interface.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
lifetime: <input id="lifetime" type="text" size=6>
|
||||
<hr>
|
||||
<input type="button" id="cone-twist-and-spring-lever-test" value="Cone-Twist and Spring-Action Lever"><br>
|
||||
A platform with a lever. The lever can be moved in a cone and rotated. A spring brings it back to its neutral position.
|
||||
<hr>
|
||||
<input type="button" id="door-vs-world-test" value="Hinge Between Swinging Door and World"><br>
|
||||
A grabbable door with a hinge between it and world-space.
|
||||
<hr>
|
||||
<input type="button" id="hinge-chain-test" value="Hinge Chain"><br>
|
||||
A chain of blocks connected by hinges.
|
||||
<hr>
|
||||
<input type="button" id="slider-vs-world-test" value="Slider vs World"><br>
|
||||
The block can only move up and down over a range of 1/2 meter.
|
||||
<hr>
|
||||
<input type="button" id="slider-chain-test" value="Slider Chain"><br>
|
||||
A chain of blocks connected by slider constraints.
|
||||
<hr>
|
||||
<input type="button" id="ball-socket-between-test" value="Ball-Socket Between Spheres Chain"><br>
|
||||
A chain of spheres connected by ball-and-socket joints between the spheres.
|
||||
<hr>
|
||||
<input type="button" id="ball-socket-coincident-test" value="Ball-Socket Coincident Spheres Chain"><br>
|
||||
A chain of spheres connected by ball-and-socket joints coincident-with the spheres.
|
||||
<hr>
|
||||
<input type="button" id="ragdoll-test" value="Ragdoll"><br>
|
||||
A self-righting ragdoll. The head is on a weak spring vs the body.
|
||||
|
||||
</body>
|
||||
</html>
|
749
scripts/developer/tests/dynamics/dynamicsTests.js
Normal file
749
scripts/developer/tests/dynamics/dynamicsTests.js
Normal file
|
@ -0,0 +1,749 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/* global Entities, Script, Tablet, MyAvatar, Vec3 */
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
var DYNAMICS_TESTS_URL = Script.resolvePath("dynamics-tests.html");
|
||||
var DEFAULT_LIFETIME = 120; // seconds
|
||||
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
|
||||
var button = tablet.addButton({
|
||||
icon: Script.resolvePath("dynamicsTests.svg"),
|
||||
text: "Dynamics",
|
||||
sortOrder: 15
|
||||
});
|
||||
|
||||
|
||||
|
||||
function coneTwistAndSpringLeverTest(params) {
|
||||
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: -0.5, z: -2}));
|
||||
var lifetime = params.lifetime;
|
||||
|
||||
var baseID = Entities.addEntity({
|
||||
name: "cone-twist test -- base",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 20 },
|
||||
dimensions: { x: 0.5, y: 0.2, z: 0.5 },
|
||||
position: Vec3.sum(pos, { x: 0, y: 0, z:0 }),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
var leverID = Entities.addEntity({
|
||||
name: "cone-twist test -- lever",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 200 },
|
||||
dimensions: { x: 0.05, y: 1, z: 0.05 },
|
||||
position: Vec3.sum(pos, { x: 0, y: 0.7, z:0 }),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addEntity({
|
||||
name: "cone-twist test -- handle",
|
||||
type: "Box",
|
||||
color: { blue: 30, green: 100, red: 200 },
|
||||
dimensions: { x: 0.1, y: 0.08, z: 0.08 },
|
||||
position: Vec3.sum(pos, { x: 0, y: 0.7 + 0.5, z:0 }),
|
||||
dynamic: false,
|
||||
collisionless: true,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: lifetime,
|
||||
parentID: leverID,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("cone-twist", baseID, {
|
||||
pivot: { x: 0, y: 0.2, z: 0 },
|
||||
axis: { x: 0, y: 1, z: 0 },
|
||||
otherEntityID: leverID,
|
||||
otherPivot: { x: 0, y: -0.55, z: 0 },
|
||||
otherAxis: { x: 0, y: 1, z: 0 },
|
||||
swingSpan1: Math.PI / 4,
|
||||
swingSpan2: Math.PI / 4,
|
||||
twistSpan: Math.PI / 2,
|
||||
tag: "cone-twist test"
|
||||
});
|
||||
|
||||
Entities.addAction("spring", leverID, {
|
||||
targetRotation: { x: 0, y: 0, z: 0, w: 1 },
|
||||
angularTimeScale: 0.2,
|
||||
tag: "cone-twist test spring"
|
||||
});
|
||||
|
||||
|
||||
Entities.editEntity(baseID, { gravity: { x: 0, y: -5, z: 0 } });
|
||||
}
|
||||
|
||||
function doorVSWorldTest(params) {
|
||||
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
|
||||
var lifetime = params.lifetime;
|
||||
|
||||
var doorID = Entities.addEntity({
|
||||
name: "door test",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 20, red: 20 },
|
||||
dimensions: { x: 1.0, y: 2, z: 0.1 },
|
||||
position: pos,
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
lifetime: lifetime,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("hinge", doorID, {
|
||||
pivot: { x: -0.5, y: 0, z: 0 },
|
||||
axis: { x: 0, y: 1, z: 0 },
|
||||
low: 0,
|
||||
high: Math.PI,
|
||||
tag: "door hinge test"
|
||||
});
|
||||
}
|
||||
|
||||
function hingeChainTest(params) {
|
||||
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
|
||||
var lifetime = params.lifetime;
|
||||
|
||||
var offset = 0.28;
|
||||
var prevEntityID = null;
|
||||
for (var i = 0; i < 5; i++) {
|
||||
var newID = Entities.addEntity({
|
||||
name: "hinge test " + i,
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 40 * i, red: 20 },
|
||||
dimensions: { x: 0.2, y: 0.2, z: 0.1 },
|
||||
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
lifetime: lifetime,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
if (prevEntityID) {
|
||||
Entities.addAction("hinge", prevEntityID, {
|
||||
pivot: { x: 0, y: offset / 2, z: 0 },
|
||||
axis: { x: 1, y: 0, z: 0 },
|
||||
otherEntityID: newID,
|
||||
otherPivot: { x: 0, y: -offset / 2, z: 0 },
|
||||
otherAxis: { x: 1, y: 0, z: 0 },
|
||||
tag: "A/B hinge test " + i
|
||||
});
|
||||
}
|
||||
prevEntityID = newID;
|
||||
}
|
||||
}
|
||||
|
||||
function sliderVSWorldTest(params) {
|
||||
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
|
||||
var lifetime = params.lifetime;
|
||||
|
||||
var sliderEntityID = Entities.addEntity({
|
||||
name: "slider test",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 20, red: 20 },
|
||||
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
|
||||
position: pos,
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("slider", sliderEntityID, {
|
||||
point: { x: -0.5, y: 0, z: 0 },
|
||||
axis: { x: 0, y: 1, z: 0 },
|
||||
linearLow: 0,
|
||||
linearHigh: 0.6,
|
||||
tag: "slider test"
|
||||
});
|
||||
}
|
||||
|
||||
function sliderChainTest(params) {
|
||||
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
|
||||
var lifetime = params.lifetime;
|
||||
|
||||
var offset = 0.28;
|
||||
var prevEntityID = null;
|
||||
for (var i = 0; i < 7; i++) {
|
||||
var newID = Entities.addEntity({
|
||||
name: "hinge test " + i,
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 40 * i, red: 20 },
|
||||
dimensions: { x: 0.2, y: 0.1, z: 0.2 },
|
||||
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
if (prevEntityID) {
|
||||
Entities.addAction("slider", prevEntityID, {
|
||||
point: { x: 0, y: 0, z: 0 },
|
||||
axis: { x: 0, y: 1, z: 0 },
|
||||
otherEntityID: newID,
|
||||
otherPoint: { x: 0, y: -offset / 2, z: 0 },
|
||||
otherAxis: { x: 0, y: 1, z: 0 },
|
||||
linearLow: 0,
|
||||
linearHigh: 0.6,
|
||||
tag: "A/B slider test " + i
|
||||
});
|
||||
}
|
||||
prevEntityID = newID;
|
||||
}
|
||||
}
|
||||
|
||||
function ballSocketBetweenTest(params) {
|
||||
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
|
||||
var lifetime = params.lifetime;
|
||||
|
||||
var offset = 0.2;
|
||||
var diameter = offset - 0.01;
|
||||
var prevEntityID = null;
|
||||
for (var i = 0; i < 7; i++) {
|
||||
var newID = Entities.addEntity({
|
||||
name: "ball and socket test " + i,
|
||||
type: "Sphere",
|
||||
color: { blue: 128, green: 40 * i, red: 20 },
|
||||
dimensions: { x: diameter, y: diameter, z: diameter },
|
||||
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
lifetime: lifetime,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
if (prevEntityID) {
|
||||
Entities.addAction("ball-socket", prevEntityID, {
|
||||
pivot: { x: 0, y: offset / 2, z: 0 },
|
||||
otherEntityID: newID,
|
||||
otherPivot: { x: 0, y: -offset / 2, z: 0 },
|
||||
tag: "A/B ball-and-socket test " + i
|
||||
});
|
||||
}
|
||||
prevEntityID = newID;
|
||||
}
|
||||
}
|
||||
|
||||
function ballSocketCoincidentTest(params) {
|
||||
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.1, z: -2}));
|
||||
var lifetime = params.lifetime;
|
||||
|
||||
var offset = 0.2;
|
||||
var diameter = offset - 0.01;
|
||||
var prevEntityID = null;
|
||||
for (var i = 0; i < 7; i++) {
|
||||
var newID = Entities.addEntity({
|
||||
name: "ball and socket test " + i,
|
||||
type: "Sphere",
|
||||
color: { blue: 128, green: 40 * i, red: 20 },
|
||||
dimensions: { x: diameter, y: diameter, z: diameter },
|
||||
position: Vec3.sum(pos, {x: 0, y: offset * i, z:0}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
lifetime: lifetime,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
if (prevEntityID) {
|
||||
Entities.addAction("ball-socket", prevEntityID, {
|
||||
pivot: { x: 0, y: 0, z: 0 },
|
||||
otherEntityID: newID,
|
||||
otherPivot: { x: 0, y: offset, z: 0 },
|
||||
tag: "A/B ball-and-socket test " + i
|
||||
});
|
||||
}
|
||||
prevEntityID = newID;
|
||||
}
|
||||
}
|
||||
|
||||
function ragdollTest(params) {
|
||||
var scale = 1.6;
|
||||
var lifetime = 120;
|
||||
var pos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 1.0, z: -2}));
|
||||
|
||||
var neckLength = scale * 0.05;
|
||||
var shoulderGap = scale * 0.1;
|
||||
var elbowGap = scale * 0.06;
|
||||
var hipGap = scale * 0.07;
|
||||
var kneeGap = scale * 0.08;
|
||||
var ankleGap = scale * 0.06;
|
||||
var ankleMin = 0;
|
||||
var ankleMax = Math.PI / 4;
|
||||
|
||||
var headSize = scale * 0.2;
|
||||
|
||||
var bodyHeight = scale * 0.4;
|
||||
var bodyWidth = scale * 0.3;
|
||||
var bodyDepth = scale * 0.2;
|
||||
|
||||
var upperArmThickness = scale * 0.05;
|
||||
var upperArmLength = scale * 0.2;
|
||||
|
||||
var lowerArmThickness = scale * 0.05;
|
||||
var lowerArmLength = scale * 0.2;
|
||||
|
||||
var legLength = scale * 0.3;
|
||||
var legThickness = scale * 0.08;
|
||||
|
||||
var shinLength = scale * 0.2;
|
||||
var shinThickness = scale * 0.06;
|
||||
|
||||
var footLength = scale * 0.2;
|
||||
var footThickness = scale * 0.03;
|
||||
var footWidth = scale * 0.08;
|
||||
|
||||
|
||||
//
|
||||
// body
|
||||
//
|
||||
|
||||
var bodyID = Entities.addEntity({
|
||||
name: "ragdoll body",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 20 },
|
||||
dimensions: { x: bodyDepth, y: bodyHeight, z: bodyWidth },
|
||||
position: Vec3.sum(pos, { x: 0, y: scale * 0.0, z:0 }),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
//
|
||||
// head
|
||||
//
|
||||
|
||||
var headID = Entities.addEntity({
|
||||
name: "ragdoll head",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 20 },
|
||||
dimensions: { x: headSize, y: headSize, z: headSize },
|
||||
position: Vec3.sum(pos, { x: 0, y: bodyHeight / 2 + headSize / 2 + neckLength, z:0 }),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: 0.5, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("spring", headID, {
|
||||
targetRotation: { x: 0, y: 0, z: 0, w: 1 },
|
||||
angularTimeScale: 2.0,
|
||||
otherID: bodyID,
|
||||
tag: "cone-twist test spring"
|
||||
});
|
||||
|
||||
|
||||
var noseID = Entities.addEntity({
|
||||
name: "ragdoll nose",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 100 },
|
||||
dimensions: { x: headSize / 5, y: headSize / 5, z: headSize / 5 },
|
||||
localPosition: { x: headSize / 2 + headSize / 10, y: 0, z: 0 },
|
||||
dynamic: false,
|
||||
collisionless: true,
|
||||
lifetime: lifetime,
|
||||
parentID: headID,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("cone-twist", headID, {
|
||||
pivot: { x: 0, y: -headSize / 2 - neckLength / 2, z: 0 },
|
||||
axis: { x: 0, y: 1, z: 0 },
|
||||
otherEntityID: bodyID,
|
||||
otherPivot: { x: 0, y: bodyHeight / 2 + neckLength / 2, z: 0 },
|
||||
otherAxis: { x: 0, y: 1, z: 0 },
|
||||
swingSpan1: Math.PI / 4,
|
||||
swingSpan2: Math.PI / 4,
|
||||
twistSpan: Math.PI / 2,
|
||||
tag: "ragdoll neck joint"
|
||||
});
|
||||
|
||||
//
|
||||
// right upper arm
|
||||
//
|
||||
|
||||
var rightUpperArmID = Entities.addEntity({
|
||||
name: "ragdoll right arm",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 20 },
|
||||
dimensions: { x: upperArmThickness, y: upperArmThickness, z: upperArmLength },
|
||||
position: Vec3.sum(pos, { x: 0,
|
||||
y: bodyHeight / 2 + upperArmThickness / 2,
|
||||
z: bodyWidth / 2 + shoulderGap + upperArmLength / 2
|
||||
}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("cone-twist", bodyID, {
|
||||
pivot: { x: 0, y: bodyHeight / 2 + upperArmThickness / 2, z: bodyWidth / 2 + shoulderGap / 2 },
|
||||
axis: { x: 0, y: 0, z: 1 },
|
||||
otherEntityID: rightUpperArmID,
|
||||
otherPivot: { x: 0, y: 0, z: -upperArmLength / 2 - shoulderGap / 2 },
|
||||
otherAxis: { x: 0, y: 0, z: 1 },
|
||||
swingSpan1: Math.PI / 2,
|
||||
swingSpan2: Math.PI / 2,
|
||||
twistSpan: 0,
|
||||
tag: "ragdoll right shoulder joint"
|
||||
});
|
||||
|
||||
//
|
||||
// left upper arm
|
||||
//
|
||||
|
||||
var leftUpperArmID = Entities.addEntity({
|
||||
name: "ragdoll left arm",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 20 },
|
||||
dimensions: { x: upperArmThickness, y: upperArmThickness, z: upperArmLength },
|
||||
position: Vec3.sum(pos, { x: 0,
|
||||
y: bodyHeight / 2 + upperArmThickness / 2,
|
||||
z: -bodyWidth / 2 - shoulderGap - upperArmLength / 2
|
||||
}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("cone-twist", bodyID, {
|
||||
pivot: { x: 0, y: bodyHeight / 2 + upperArmThickness / 2, z: -bodyWidth / 2 - shoulderGap / 2 },
|
||||
axis: { x: 0, y: 0, z: -1 },
|
||||
otherEntityID: leftUpperArmID,
|
||||
otherPivot: { x: 0, y: 0, z: upperArmLength / 2 + shoulderGap / 2 },
|
||||
otherAxis: { x: 0, y: 0, z: -1 },
|
||||
swingSpan1: Math.PI / 2,
|
||||
swingSpan2: Math.PI / 2,
|
||||
twistSpan: 0,
|
||||
tag: "ragdoll left shoulder joint"
|
||||
});
|
||||
|
||||
//
|
||||
// right lower arm
|
||||
//
|
||||
|
||||
var rightLowerArmID = Entities.addEntity({
|
||||
name: "ragdoll right lower arm",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 20 },
|
||||
dimensions: { x: lowerArmThickness, y: lowerArmThickness, z: lowerArmLength },
|
||||
position: Vec3.sum(pos, { x: 0,
|
||||
y: bodyHeight / 2 - upperArmThickness / 2,
|
||||
z: bodyWidth / 2 + shoulderGap + upperArmLength + elbowGap + lowerArmLength / 2
|
||||
}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: -1, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("hinge", rightLowerArmID, {
|
||||
pivot: { x: 0, y: 0, z: -lowerArmLength / 2 - elbowGap / 2 },
|
||||
axis: { x: 0, y: 1, z: 0 },
|
||||
otherEntityID: rightUpperArmID,
|
||||
otherPivot: { x: 0, y: 0, z: upperArmLength / 2 + elbowGap / 2 },
|
||||
otherAxis: { x: 0, y: 1, z: 0 },
|
||||
low: Math.PI / -2,
|
||||
high: 0,
|
||||
tag: "ragdoll right elbow joint"
|
||||
});
|
||||
|
||||
//
|
||||
// left lower arm
|
||||
//
|
||||
|
||||
var leftLowerArmID = Entities.addEntity({
|
||||
name: "ragdoll left lower arm",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 20 },
|
||||
dimensions: { x: lowerArmThickness, y: lowerArmThickness, z: lowerArmLength },
|
||||
position: Vec3.sum(pos, { x: 0,
|
||||
y: bodyHeight / 2 - upperArmThickness / 2,
|
||||
z: -bodyWidth / 2 - shoulderGap - upperArmLength - elbowGap - lowerArmLength / 2
|
||||
}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: -1, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("hinge", leftLowerArmID, {
|
||||
pivot: { x: 0, y: 0, z: lowerArmLength / 2 + elbowGap / 2 },
|
||||
axis: { x: 0, y: 1, z: 0 },
|
||||
otherEntityID: leftUpperArmID,
|
||||
otherPivot: { x: 0, y: 0, z: -upperArmLength / 2 - elbowGap / 2 },
|
||||
otherAxis: { x: 0, y: 1, z: 0 },
|
||||
low: 0,
|
||||
high: Math.PI / 2,
|
||||
tag: "ragdoll left elbow joint"
|
||||
});
|
||||
|
||||
//
|
||||
// right leg
|
||||
//
|
||||
|
||||
var rightLegID = Entities.addEntity({
|
||||
name: "ragdoll right arm",
|
||||
type: "Box",
|
||||
color: { blue: 20, green: 200, red: 20 },
|
||||
dimensions: { x: legThickness, y: legLength, z: legThickness },
|
||||
position: Vec3.sum(pos, { x: 0, y: -bodyHeight / 2 - hipGap - legLength / 2, z: bodyWidth / 2 - legThickness / 2 }),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("cone-twist", rightLegID, {
|
||||
pivot: { x: 0, y: legLength / 2 + hipGap / 2, z: 0 },
|
||||
axis: { x: 0, y: 1, z: 0 },
|
||||
otherEntityID: bodyID,
|
||||
otherPivot: { x: 0, y: -bodyHeight / 2 - hipGap / 2, z: bodyWidth / 2 - legThickness / 2 },
|
||||
otherAxis: Vec3.normalize({ x: -1, y: 1, z: 0 }),
|
||||
swingSpan1: Math.PI / 4,
|
||||
swingSpan2: Math.PI / 4,
|
||||
twistSpan: 0,
|
||||
tag: "ragdoll right hip joint"
|
||||
});
|
||||
|
||||
//
|
||||
// left leg
|
||||
//
|
||||
|
||||
var leftLegID = Entities.addEntity({
|
||||
name: "ragdoll left arm",
|
||||
type: "Box",
|
||||
color: { blue: 20, green: 200, red: 20 },
|
||||
dimensions: { x: legThickness, y: legLength, z: legThickness },
|
||||
position: Vec3.sum(pos, { x: 0, y: -bodyHeight / 2 - hipGap - legLength / 2, z: -bodyWidth / 2 + legThickness / 2 }),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("cone-twist", leftLegID, {
|
||||
pivot: { x: 0, y: legLength / 2 + hipGap / 2, z: 0 },
|
||||
axis: { x: 0, y: 1, z: 0 },
|
||||
otherEntityID: bodyID,
|
||||
otherPivot: { x: 0, y: -bodyHeight / 2 - hipGap / 2, z: -bodyWidth / 2 + legThickness / 2 },
|
||||
otherAxis: Vec3.normalize({ x: -1, y: 1, z: 0 }),
|
||||
swingSpan1: Math.PI / 4,
|
||||
swingSpan2: Math.PI / 4,
|
||||
twistSpan: 0,
|
||||
tag: "ragdoll left hip joint"
|
||||
});
|
||||
|
||||
//
|
||||
// right shin
|
||||
//
|
||||
|
||||
var rightShinID = Entities.addEntity({
|
||||
name: "ragdoll right shin",
|
||||
type: "Box",
|
||||
color: { blue: 20, green: 200, red: 20 },
|
||||
dimensions: { x: shinThickness, y: shinLength, z: shinThickness },
|
||||
position: Vec3.sum(pos, { x: 0,
|
||||
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength / 2,
|
||||
z: bodyWidth / 2 - legThickness / 2
|
||||
}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: -2, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("hinge", rightShinID, {
|
||||
pivot: { x: 0, y: shinLength / 2 + kneeGap / 2, z: 0 },
|
||||
axis: { x: 0, y: 0, z: 1 },
|
||||
otherEntityID: rightLegID,
|
||||
otherPivot: { x: 0, y: -legLength / 2 - kneeGap / 2, z: 0 },
|
||||
otherAxis: { x: 0, y: 0, z: 1 },
|
||||
low: 0,
|
||||
high: Math.PI / 2,
|
||||
tag: "ragdoll right knee joint"
|
||||
});
|
||||
|
||||
|
||||
//
|
||||
// left shin
|
||||
//
|
||||
|
||||
var leftShinID = Entities.addEntity({
|
||||
name: "ragdoll left shin",
|
||||
type: "Box",
|
||||
color: { blue: 20, green: 200, red: 20 },
|
||||
dimensions: { x: shinThickness, y: shinLength, z: shinThickness },
|
||||
position: Vec3.sum(pos, { x: 0,
|
||||
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength / 2,
|
||||
z: -bodyWidth / 2 + legThickness / 2
|
||||
}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: -2, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("hinge", leftShinID, {
|
||||
pivot: { x: 0, y: shinLength / 2 + kneeGap / 2, z: 0 },
|
||||
axis: { x: 0, y: 0, z: 1 },
|
||||
otherEntityID: leftLegID,
|
||||
otherPivot: { x: 0, y: -legLength / 2 - kneeGap / 2, z: 0 },
|
||||
otherAxis: { x: 0, y: 0, z: 1 },
|
||||
low: 0,
|
||||
high: Math.PI / 2,
|
||||
tag: "ragdoll left knee joint"
|
||||
});
|
||||
|
||||
//
|
||||
// right foot
|
||||
//
|
||||
|
||||
var rightFootID = Entities.addEntity({
|
||||
name: "ragdoll right foot",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 20 },
|
||||
dimensions: { x: footLength, y: footThickness, z: footWidth },
|
||||
position: Vec3.sum(pos, { x: -shinThickness / 2 + footLength / 2,
|
||||
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength - ankleGap - footThickness / 2,
|
||||
z: bodyWidth / 2 - legThickness / 2
|
||||
}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: -5, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("hinge", rightFootID, {
|
||||
pivot: { x: -footLength / 2 + shinThickness / 2, y: ankleGap / 2, z: 0 },
|
||||
axis: { x: 0, y: 0, z: 1 },
|
||||
otherEntityID: rightShinID,
|
||||
otherPivot: { x: 0, y: -shinLength / 2 - ankleGap / 2, z: 0 },
|
||||
otherAxis: { x: 0, y: 0, z: 1 },
|
||||
low: ankleMin,
|
||||
high: ankleMax,
|
||||
tag: "ragdoll right ankle joint"
|
||||
});
|
||||
|
||||
//
|
||||
// left foot
|
||||
//
|
||||
|
||||
var leftFootID = Entities.addEntity({
|
||||
name: "ragdoll left foot",
|
||||
type: "Box",
|
||||
color: { blue: 128, green: 100, red: 20 },
|
||||
dimensions: { x: footLength, y: footThickness, z: footWidth },
|
||||
position: Vec3.sum(pos, { x: -shinThickness / 2 + footLength / 2,
|
||||
y: -bodyHeight / 2 - hipGap - legLength - kneeGap - shinLength - ankleGap - footThickness / 2,
|
||||
z: bodyWidth / 2 - legThickness / 2
|
||||
}),
|
||||
dynamic: true,
|
||||
collisionless: false,
|
||||
gravity: { x: 0, y: -5, z: 0 },
|
||||
lifetime: lifetime,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": true, \"kinematic\": false } }"
|
||||
});
|
||||
|
||||
Entities.addAction("hinge", leftFootID, {
|
||||
pivot: { x: -footLength / 2 + shinThickness / 2, y: ankleGap / 2, z: 0 },
|
||||
axis: { x: 0, y: 0, z: 1 },
|
||||
otherEntityID: leftShinID,
|
||||
otherPivot: { x: 0, y: -shinLength / 2 - ankleGap / 2, z: 0 },
|
||||
otherAxis: { x: 0, y: 0, z: 1 },
|
||||
low: ankleMin,
|
||||
high: ankleMax,
|
||||
tag: "ragdoll left ankle joint"
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function onWebEventReceived(eventString) {
|
||||
print("received web event: " + JSON.stringify(eventString));
|
||||
if (typeof eventString === "string") {
|
||||
var event;
|
||||
try {
|
||||
event = JSON.parse(eventString);
|
||||
} catch(e) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event["dynamics-tests-command"]) {
|
||||
var commandToFunctionMap = {
|
||||
"cone-twist-and-spring-lever-test": coneTwistAndSpringLeverTest,
|
||||
"door-vs-world-test": doorVSWorldTest,
|
||||
"hinge-chain-test": hingeChainTest,
|
||||
"slider-vs-world-test": sliderVSWorldTest,
|
||||
"slider-chain-test": sliderChainTest,
|
||||
"ball-socket-between-test": ballSocketBetweenTest,
|
||||
"ball-socket-coincident-test": ballSocketCoincidentTest,
|
||||
"ragdoll-test": ragdollTest
|
||||
};
|
||||
|
||||
var cmd = event["dynamics-tests-command"];
|
||||
if (commandToFunctionMap.hasOwnProperty(cmd)) {
|
||||
var func = commandToFunctionMap[cmd];
|
||||
func(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var onDynamicsTestsScreen = false;
|
||||
var shouldActivateButton = false;
|
||||
|
||||
function onClicked() {
|
||||
if (onDynamicsTestsScreen) {
|
||||
tablet.gotoHomeScreen();
|
||||
} else {
|
||||
shouldActivateButton = true;
|
||||
tablet.gotoWebScreen(DYNAMICS_TESTS_URL +
|
||||
"?lifetime=" + DEFAULT_LIFETIME.toString()
|
||||
);
|
||||
onDynamicsTestsScreen = true;
|
||||
}
|
||||
}
|
||||
|
||||
function onScreenChanged() {
|
||||
// for toolbar mode: change button to active when window is first openend, false otherwise.
|
||||
button.editProperties({isActive: shouldActivateButton});
|
||||
shouldActivateButton = false;
|
||||
onDynamicsTestsScreen = shouldActivateButton;
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
button.clicked.disconnect(onClicked);
|
||||
tablet.removeButton(button);
|
||||
}
|
||||
|
||||
button.clicked.connect(onClicked);
|
||||
tablet.webEventReceived.connect(onWebEventReceived);
|
||||
tablet.screenChanged.connect(onScreenChanged);
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
}()); // END LOCAL_SCOPE
|
69
scripts/developer/tests/dynamics/dynamicsTests.svg
Normal file
69
scripts/developer/tests/dynamics/dynamicsTests.svg
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="210mm"
|
||||
height="297mm"
|
||||
viewBox="0 0 744.09448819 1052.3622047"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="dynamicsTests.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35"
|
||||
inkscape:cx="-482.14286"
|
||||
inkscape:cy="520"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="2815"
|
||||
inkscape:window-height="1776"
|
||||
inkscape:window-x="65"
|
||||
inkscape:window-y="24"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<path
|
||||
sodipodi:type="spiral"
|
||||
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:20;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path4136"
|
||||
sodipodi:cx="351.42856"
|
||||
sodipodi:cy="532.36218"
|
||||
sodipodi:expansion="1"
|
||||
sodipodi:revolution="3"
|
||||
sodipodi:radius="189.2628"
|
||||
sodipodi:argument="-18.34539"
|
||||
sodipodi:t0="0"
|
||||
d="m 351.42856,532.36218 c 8.30865,4.58408 -2.08005,13.46152 -7.61904,13.80953 -15.01033,0.94307 -22.49738,-16.46931 -20.00001,-29.04761 4.46719,-22.49963 30.09017,-32.38647 50.47618,-26.1905 29.91728,9.09285 42.49805,43.8703 32.38097,71.90475 -13.48446,37.36552 -57.7036,52.70019 -93.33331,38.57147 -44.83636,-17.77957 -62.94832,-71.56146 -44.76195,-114.76189 22.02613,-52.32152 85.43296,-73.22291 136.19046,-50.95243 59.81595,26.24498 83.51408,99.31294 57.14291,157.61902 -30.44656,67.31668 -113.1986,93.81634 -179.0476,63.3334 C 208.03536,622.01126 178.73083,529.55968 213.33329,456.17176 252.15203,373.8416 354.3141,341.72978 435.23803,380.45739 c 89.8409,42.99499 124.76183,154.87556 81.90485,243.3333"
|
||||
transform="matrix(1.6331701,0,0,2.2153757,-219.59811,-629.37371)" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
Loading…
Reference in a new issue