mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 05:48:26 +02:00
Example script solarsystem.js with orbiting satellite game
This commit is contained in:
parent
6e41a79551
commit
ccb3d433af
3 changed files with 1030 additions and 0 deletions
279
examples/example/games/satellite.js
Normal file
279
examples/example/games/satellite.js
Normal file
|
@ -0,0 +1,279 @@
|
||||||
|
//
|
||||||
|
// satellite.js
|
||||||
|
// games
|
||||||
|
//
|
||||||
|
// Created by Bridget Went 7/1/2015.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// A game to bring a satellite model into orbit around an animated earth model .
|
||||||
|
// - Double click to create a new satellite
|
||||||
|
// - Click on the satellite, drag a vector arrow to specify initial velocity
|
||||||
|
// - Release mouse to launch the active satellite
|
||||||
|
// - Orbital movement is calculated using equations of gravitational physics
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
Script.include('../../utilities/tools/vector.js');
|
||||||
|
|
||||||
|
var URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/";
|
||||||
|
|
||||||
|
SatelliteGame = function() {
|
||||||
|
var MAX_RANGE = 50.0;
|
||||||
|
var Y_AXIS = {
|
||||||
|
x: 0,
|
||||||
|
y: 1,
|
||||||
|
z: 0
|
||||||
|
}
|
||||||
|
var LIFETIME = 6000;
|
||||||
|
|
||||||
|
var v0;
|
||||||
|
var T = 4.0;
|
||||||
|
var M = 16000.0;
|
||||||
|
var m = M * 0.000000333;
|
||||||
|
var ERROR_THRESH = 20.0;
|
||||||
|
|
||||||
|
// Create the spinning earth model
|
||||||
|
var EARTH_SIZE = 20.0;
|
||||||
|
var CLOUDS_OFFSET = 0.5;
|
||||||
|
var SPIN = 0.1;
|
||||||
|
var ZONE_DIM = 10.0;
|
||||||
|
var LIGHT_INTENSITY = 1.2;
|
||||||
|
|
||||||
|
Earth = function(position, size) {
|
||||||
|
this.earth = Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
shapeType: 'sphere',
|
||||||
|
modelURL: URL + "earth.fbx",
|
||||||
|
position: position,
|
||||||
|
dimensions: {
|
||||||
|
x: size,
|
||||||
|
y: size,
|
||||||
|
z: size
|
||||||
|
},
|
||||||
|
rotation: Quat.angleAxis(180, {x: 1, y: 0, z: 0}),
|
||||||
|
angularVelocity: { x: 0.00, y: 0.5 * SPIN, z: 0.00 },
|
||||||
|
angularDamping: 0.0,
|
||||||
|
damping: 0.0,
|
||||||
|
ignoreCollisions: false,
|
||||||
|
lifetime: 6000,
|
||||||
|
collisionsWillMove: false,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
|
||||||
|
this.clouds = Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
shapeType: 'sphere',
|
||||||
|
modelURL: URL + "clouds.fbx?",
|
||||||
|
position: position,
|
||||||
|
dimensions: {
|
||||||
|
x: size + CLOUDS_OFFSET,
|
||||||
|
y: size + CLOUDS_OFFSET,
|
||||||
|
z: size + CLOUDS_OFFSET
|
||||||
|
},
|
||||||
|
angularVelocity: { x: 0.00, y: SPIN, z: 0.00 },
|
||||||
|
angularDamping: 0.0,
|
||||||
|
damping: 0.0,
|
||||||
|
ignoreCollisions: false,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
collisionsWillMove: false,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
|
||||||
|
this.zone = Entities.addEntity({
|
||||||
|
type: "Zone",
|
||||||
|
position: position,
|
||||||
|
dimensions: {
|
||||||
|
x: ZONE_DIM,
|
||||||
|
y: ZONE_DIM,
|
||||||
|
z: ZONE_DIM
|
||||||
|
},
|
||||||
|
keyLightDirection: Vec3.normalize(Vec3.subtract(position, Camera.getPosition())),
|
||||||
|
keyLightIntensity: LIGHT_INTENSITY
|
||||||
|
});
|
||||||
|
|
||||||
|
this.cleanup = function() {
|
||||||
|
Entities.deleteEntity(this.clouds);
|
||||||
|
Entities.deleteEntity(this.earth);
|
||||||
|
Entities.deleteEntity(this.zone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create earth model
|
||||||
|
var center = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation())));
|
||||||
|
var distance = Vec3.length(Vec3.subtract(center, Camera.getPosition()));
|
||||||
|
var earth = new Earth(center, EARTH_SIZE);
|
||||||
|
|
||||||
|
var satellites = [];
|
||||||
|
var SATELLITE_SIZE = 2.0;
|
||||||
|
var launched = false;
|
||||||
|
var activeSatellite;
|
||||||
|
|
||||||
|
Satellite = function(position, planetCenter) {
|
||||||
|
// The Satellite class
|
||||||
|
|
||||||
|
this.launched = false;
|
||||||
|
this.startPosition = position;
|
||||||
|
this.readyToLaunch = false;
|
||||||
|
this.radius = Vec3.length(Vec3.subtract(position, planetCenter));
|
||||||
|
|
||||||
|
this.satellite = Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
modelURL: "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/satellite/satellite.fbx",
|
||||||
|
position: this.startPosition,
|
||||||
|
dimensions: {
|
||||||
|
x: SATELLITE_SIZE,
|
||||||
|
y: SATELLITE_SIZE,
|
||||||
|
z: SATELLITE_SIZE
|
||||||
|
},
|
||||||
|
angularDamping: 0.0,
|
||||||
|
damping: 0.0,
|
||||||
|
ignoreCollisions: false,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
collisionsWillMove: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.getProperties = function() {
|
||||||
|
return Entities.getEntityProperties(this.satellite);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.launch = function() {
|
||||||
|
var prop = Entities.getEntityProperties(this.satellite);
|
||||||
|
var between = Vec3.subtract(planetCenter, prop.position);
|
||||||
|
var radius = Vec3.length(between);
|
||||||
|
this.G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T);
|
||||||
|
|
||||||
|
var v0 = Vec3.normalize(Vec3.cross(between, Y_AXIS));
|
||||||
|
v0 = Vec3.multiply(Math.sqrt((this.G * M) / radius), v0);
|
||||||
|
v0 = Vec3.multiply(this.arrow.magnitude, v0);
|
||||||
|
v0 = Vec3.multiply(Vec3.length(v0), this.arrow.direction);
|
||||||
|
|
||||||
|
Entities.editEntity(this.satellite, { velocity: v0 });
|
||||||
|
this.launched = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.update = function(deltaTime) {
|
||||||
|
var prop = Entities.getEntityProperties(this.satellite);
|
||||||
|
var between = Vec3.subtract(prop.position, planetCenter);
|
||||||
|
var radius = Vec3.length(between);
|
||||||
|
var a = -(this.G * M) * Math.pow(radius, (-2.0));
|
||||||
|
var speed = a * deltaTime;
|
||||||
|
var vel = Vec3.multiply(speed, Vec3.normalize(between));
|
||||||
|
|
||||||
|
var newVelocity = Vec3.sum(prop.velocity, vel);
|
||||||
|
var newPos = Vec3.sum(prop.position, Vec3.multiply(newVelocity, deltaTime));
|
||||||
|
|
||||||
|
Entities.editEntity(this.satellite, {
|
||||||
|
velocity: newVelocity,
|
||||||
|
position: newPos
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseDoublePressEvent(event) {
|
||||||
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
var addVector = Vec3.multiply(pickRay.direction, distance);
|
||||||
|
var point = Vec3.sum(Camera.getPosition(), addVector);
|
||||||
|
|
||||||
|
// Create a new satellite
|
||||||
|
activeSatellite = new Satellite(point, center);
|
||||||
|
satellites.push(activeSatellite);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
if (!activeSatellite) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Reset label
|
||||||
|
if (activeSatellite.arrow) {
|
||||||
|
activeSatellite.arrow.deleteLabel();
|
||||||
|
}
|
||||||
|
var statsPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(MAX_RANGE * 0.5, Quat.getFront(Camera.getOrientation())));
|
||||||
|
var pickRay = Camera.computePickRay(event.x, event.y)
|
||||||
|
var rayPickResult = Entities.findRayIntersection(pickRay, true);
|
||||||
|
if (rayPickResult.entityID === activeSatellite.satellite) {
|
||||||
|
// Create a draggable vector arrow at satellite position
|
||||||
|
activeSatellite.arrow = new VectorArrow(distance, true, "INITIAL VELOCITY", statsPosition);
|
||||||
|
activeSatellite.arrow.onMousePressEvent(event);
|
||||||
|
activeSatellite.arrow.isDragging = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseMoveEvent(event) {
|
||||||
|
if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
activeSatellite.arrow.onMouseMoveEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseReleaseEvent(event) {
|
||||||
|
if(!activeSatellite || !activeSatellite.arrow || !activeSatellite.arrow.isDragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
activeSatellite.arrow.onMouseReleaseEvent(event);
|
||||||
|
activeSatellite.launch();
|
||||||
|
activeSatellite.arrow.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
var counter = 0.0;
|
||||||
|
var TIME = 500;
|
||||||
|
|
||||||
|
function update(deltaTime) {
|
||||||
|
if(!activeSatellite) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Update all satellites
|
||||||
|
for (var i = 0; i < satellites.length; i++) {
|
||||||
|
if (!satellites[i].launched) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
satellites[i].update(deltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
counter++;
|
||||||
|
if (counter % TIME == 0) {
|
||||||
|
var prop = activeSatellite.getProperties();
|
||||||
|
var error = calcEnergyError(prop.position, Vec3.length(prop.velocity));
|
||||||
|
if (Math.abs(error) <= ERROR_THRESH) {
|
||||||
|
activeSatellite.arrow.editLabel("Nice job! The satellite has reached a stable orbit.");
|
||||||
|
} else {
|
||||||
|
activeSatellite.arrow.editLabel("Try again! The satellite is in an unstable orbit.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.endGame = function() {
|
||||||
|
print("ending game");
|
||||||
|
for(var i = 0; i < satellites.length; i++) {
|
||||||
|
Entities.deleteEntitiy(satellites[i].satellite);
|
||||||
|
satellites[i].arrow.cleanup();
|
||||||
|
}
|
||||||
|
earth.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function calcEnergyError(pos, vel) {
|
||||||
|
//Calculate total energy error for active satellite's orbital motion
|
||||||
|
var radius = activeSatellite.radius;
|
||||||
|
var G = (4.0 * Math.PI * Math.PI * Math.pow(radius, 3.0)) / (M * T * T);
|
||||||
|
var v0 = Math.sqrt((G * M) / radius);
|
||||||
|
|
||||||
|
var totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius);
|
||||||
|
var measuredEnergy = 0.5 * M * Math.pow(vel, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(pos, center)));
|
||||||
|
var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
|
Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent);
|
||||||
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||||
|
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||||
|
Script.update.connect(update);
|
||||||
|
Script.scriptEnding.connect(this.endGame);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
554
examples/example/games/solarsystem.js
Normal file
554
examples/example/games/solarsystem.js
Normal file
|
@ -0,0 +1,554 @@
|
||||||
|
//
|
||||||
|
// solarsystem.js
|
||||||
|
// games
|
||||||
|
//
|
||||||
|
// Created by Bridget Went, 5/28/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// The start to a project to build a virtual physics classroom to simulate the solar system, gravity, and orbital physics.
|
||||||
|
// A sun with oribiting planets is created in front of the user. UI elements allow for adjusting the period, gravity, trails, and energy recalculations.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
Script.include('../../utilities/tools/cookies.js');
|
||||||
|
Script.include('satellite.js');
|
||||||
|
|
||||||
|
var BASE_URL = "https://s3.amazonaws.com/hifi-public/marketplace/hificontent/Scripts/planets/planets/";
|
||||||
|
|
||||||
|
var NUM_PLANETS = 8;
|
||||||
|
|
||||||
|
var trailsEnabled = true;
|
||||||
|
var energyConserved = true;
|
||||||
|
var planetView = false;
|
||||||
|
var earthView = false;
|
||||||
|
var satelliteGame;
|
||||||
|
|
||||||
|
var PANEL_X = 850;
|
||||||
|
var PANEL_Y = 600;
|
||||||
|
var BUTTON_SIZE = 20;
|
||||||
|
var PADDING = 20;
|
||||||
|
|
||||||
|
var DAMPING = 0.0;
|
||||||
|
var LIFETIME = 6000;
|
||||||
|
var ERROR_THRESH = 2.0;
|
||||||
|
var TIME_STEP = 70.0;
|
||||||
|
|
||||||
|
var MAX_POINTS_PER_LINE = 5;
|
||||||
|
var LINE_DIM = 10;
|
||||||
|
var LINE_WIDTH = 3.0;
|
||||||
|
var line;
|
||||||
|
var planetLines = [];
|
||||||
|
var trails = [];
|
||||||
|
|
||||||
|
var BOUNDS = 200;
|
||||||
|
|
||||||
|
|
||||||
|
// Alert user to move if they are too close to domain bounds
|
||||||
|
if (MyAvatar.position.x < BOUNDS || MyAvatar.position.x > TREE_SCALE - BOUNDS
|
||||||
|
|| MyAvatar.position.y < BOUNDS || MyAvatar.position.y > TREE_SCALE - BOUNDS
|
||||||
|
|| MyAvatar.position.z < BOUNDS || MyAvatar.position.z > TREE_SCALE - BOUNDS) {
|
||||||
|
Window.alert("Please move at least 200m away from domain bounds.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save intiial avatar and camera position
|
||||||
|
var startingPosition = MyAvatar.position;
|
||||||
|
var startFrame = Window.location.href;
|
||||||
|
|
||||||
|
// Place the sun
|
||||||
|
var MAX_RANGE = 80.0;
|
||||||
|
var SUN_SIZE = 8.0;
|
||||||
|
var center = Vec3.sum(startingPosition, Vec3.multiply(MAX_RANGE, Quat.getFront(Camera.getOrientation())));
|
||||||
|
|
||||||
|
var theSun = Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
modelURL: BASE_URL + "sun.fbx",
|
||||||
|
position: center,
|
||||||
|
dimensions: {
|
||||||
|
x: SUN_SIZE,
|
||||||
|
y: SUN_SIZE,
|
||||||
|
z: SUN_SIZE
|
||||||
|
},
|
||||||
|
angularDamping: DAMPING,
|
||||||
|
damping: DAMPING,
|
||||||
|
ignoreCollisions: false,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
collisionsWillMove: false
|
||||||
|
});
|
||||||
|
|
||||||
|
var planets = [];
|
||||||
|
var planet_properties = [];
|
||||||
|
|
||||||
|
// Reference values
|
||||||
|
var radius = 7.0;
|
||||||
|
var T_ref = 1.0;
|
||||||
|
var size = 1.0;
|
||||||
|
var M = 250.0;
|
||||||
|
var m = M * 0.000000333;
|
||||||
|
var G = (Math.pow(radius, 3.0) / Math.pow((T_ref / (2.0 * Math.PI)), 2.0)) / M;
|
||||||
|
var G_ref = G;
|
||||||
|
|
||||||
|
// Adjust size and distance as number of planets increases
|
||||||
|
var DELTA_RADIUS = 1.8;
|
||||||
|
var DELTA_SIZE = 0.2;
|
||||||
|
|
||||||
|
function initPlanets() {
|
||||||
|
for (var i = 0; i < NUM_PLANETS; ++i) {
|
||||||
|
var v0 = Math.sqrt((G * M) / radius);
|
||||||
|
var T = (2.0 * Math.PI) * Math.sqrt(Math.pow(radius, 3.0) / (G * M));
|
||||||
|
|
||||||
|
if (i == 0) {
|
||||||
|
var color = {red: 255, green: 255, blue: 255};
|
||||||
|
} else if (i == 1) {
|
||||||
|
var color = {red: 255, green: 160, blue: 110};
|
||||||
|
} else if (i == 2) {
|
||||||
|
var color = {red: 10, green: 150, blue: 160};
|
||||||
|
} else if (i == 3) {
|
||||||
|
var color = {red: 180, green: 70, blue: 10};
|
||||||
|
} else if (i == 4) {
|
||||||
|
var color = {red: 250, green: 140, blue: 0};
|
||||||
|
} else if (i == 5) {
|
||||||
|
var color = {red: 235, green: 215, blue: 0};
|
||||||
|
} else if (i == 6) {
|
||||||
|
var color = {red:135, green: 205, blue: 240};
|
||||||
|
} else if (i == 7) {
|
||||||
|
var color = {red:30, green: 140, blue: 255};
|
||||||
|
}
|
||||||
|
|
||||||
|
var prop = {
|
||||||
|
radius: radius,
|
||||||
|
position: Vec3.sum(center, {x: radius, y: 0.0, z: 0.0}),
|
||||||
|
lineColor: color,
|
||||||
|
period: T,
|
||||||
|
dimensions: size,
|
||||||
|
velocity: Vec3.multiply(v0, Vec3.normalize({x: 0, y: -0.2, z: 0.9}))
|
||||||
|
};
|
||||||
|
planet_properties.push(prop);
|
||||||
|
|
||||||
|
planets.push(Entities.addEntity({
|
||||||
|
type: "Model",
|
||||||
|
modelURL: BASE_URL + (i + 1) + ".fbx",
|
||||||
|
position: prop.position,
|
||||||
|
dimensions: {
|
||||||
|
x: prop.dimensions,
|
||||||
|
y: prop.dimensions,
|
||||||
|
z: prop.dimensions
|
||||||
|
},
|
||||||
|
velocity: prop.velocity,
|
||||||
|
angularDamping: DAMPING,
|
||||||
|
damping: DAMPING,
|
||||||
|
ignoreCollisions: false,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
collisionsWillMove: true,
|
||||||
|
}));
|
||||||
|
|
||||||
|
radius *= DELTA_RADIUS;
|
||||||
|
size += DELTA_SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize planets
|
||||||
|
initPlanets();
|
||||||
|
|
||||||
|
|
||||||
|
var labels = [];
|
||||||
|
var labelLines = [];
|
||||||
|
var labelsShowing = false;
|
||||||
|
var LABEL_X = 8.0;
|
||||||
|
var LABEL_Y = 3.0;
|
||||||
|
var LABEL_Z = 1.0;
|
||||||
|
var LABEL_DIST = 8.0;
|
||||||
|
var TEXT_HEIGHT = 1.0;
|
||||||
|
var sunLabel;
|
||||||
|
|
||||||
|
function showLabels() {
|
||||||
|
labelsShowing = true;
|
||||||
|
for (var i = 0; i < NUM_PLANETS; i++) {
|
||||||
|
var properties = planet_properties[i];
|
||||||
|
var text;
|
||||||
|
if (i == 0) {
|
||||||
|
text = "Mercury";
|
||||||
|
} else if (i == 1) {
|
||||||
|
text = "Venus";
|
||||||
|
} else if (i == 2) {
|
||||||
|
text = "Earth";
|
||||||
|
} else if (i == 3) {
|
||||||
|
text = "Mars";
|
||||||
|
} else if (i == 4) {
|
||||||
|
text = "Jupiter";
|
||||||
|
} else if (i == 5) {
|
||||||
|
text = "Saturn";
|
||||||
|
} else if (i == 6) {
|
||||||
|
text = "Uranus";
|
||||||
|
} else if (i == 7) {
|
||||||
|
text = "Neptune";
|
||||||
|
}
|
||||||
|
|
||||||
|
text = text + " Speed: " + Vec3.length(properties.velocity).toFixed(2);
|
||||||
|
|
||||||
|
var labelPos = Vec3.sum(planet_properties[i].position, {x: 0.0, y: LABEL_DIST, z: LABEL_DIST});
|
||||||
|
var linePos = planet_properties[i].position;
|
||||||
|
labelLines.push(Entities.addEntity( {
|
||||||
|
type: "Line",
|
||||||
|
position: linePos,
|
||||||
|
dimensions: {x: 20, y: 20, z: 20},
|
||||||
|
lineWidth: 3.0,
|
||||||
|
color: {red: 255, green: 255, blue: 255},
|
||||||
|
linePoints: [{x: 0, y: 0, z: 0}, computeLocalPoint(linePos, labelPos)]
|
||||||
|
}));
|
||||||
|
|
||||||
|
labels.push(Entities.addEntity( {
|
||||||
|
type: "Text",
|
||||||
|
text: text,
|
||||||
|
lineHeight: TEXT_HEIGHT,
|
||||||
|
dimensions: {x: LABEL_X, y: LABEL_Y, z: LABEL_Z},
|
||||||
|
position: labelPos,
|
||||||
|
backgroundColor: {red: 10, green: 10, blue: 10},
|
||||||
|
textColor: {red: 255, green: 255, blue: 255},
|
||||||
|
faceCamera: true
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideLabels() {
|
||||||
|
labelsShowing = false;
|
||||||
|
Entities.deleteEntity(sunLabel);
|
||||||
|
|
||||||
|
for (var i = 0; i < NUM_PLANETS; ++i) {
|
||||||
|
Entities.deleteEntity(labelLines[i]);
|
||||||
|
Entities.deleteEntity(labels[i]);
|
||||||
|
}
|
||||||
|
labels = [];
|
||||||
|
labelLines = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var time = 0.0;
|
||||||
|
var elapsed;
|
||||||
|
var counter = 0;
|
||||||
|
var dt = 1.0 / TIME_STEP;
|
||||||
|
|
||||||
|
function update(deltaTime) {
|
||||||
|
if (paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
deltaTime = dt;
|
||||||
|
time++;
|
||||||
|
|
||||||
|
for (var i = 0; i < NUM_PLANETS; ++i) {
|
||||||
|
var properties = planet_properties[i];
|
||||||
|
var between = Vec3.subtract(properties.position, center);
|
||||||
|
var speed = getAcceleration(properties.radius) * deltaTime;
|
||||||
|
var vel = Vec3.multiply(speed, Vec3.normalize(between));
|
||||||
|
|
||||||
|
// Update velocity and position
|
||||||
|
properties.velocity = Vec3.sum(properties.velocity, vel);
|
||||||
|
properties.position = Vec3.sum(properties.position, Vec3.multiply(properties.velocity, deltaTime));
|
||||||
|
Entities.editEntity(planets[i], {
|
||||||
|
velocity: properties.velocity,
|
||||||
|
position: properties.position
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Create new or update current trail
|
||||||
|
if (trailsEnabled) {
|
||||||
|
var lineStack = planetLines[i];
|
||||||
|
var point = properties.position;
|
||||||
|
var prop = Entities.getEntityProperties(lineStack[lineStack.length - 1]);
|
||||||
|
var linePos = prop.position;
|
||||||
|
|
||||||
|
trails[i].push(computeLocalPoint(linePos, point));
|
||||||
|
|
||||||
|
Entities.editEntity(lineStack[lineStack.length - 1], {
|
||||||
|
linePoints: trails[i]
|
||||||
|
});
|
||||||
|
if (trails[i].length === MAX_POINTS_PER_LINE) {
|
||||||
|
trails[i] = newLine(lineStack, point, properties.period, properties.lineColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure total energy every 10 updates, recalibrate velocity if necessary
|
||||||
|
if (energyConserved) {
|
||||||
|
if (counter % 10 === 0) {
|
||||||
|
var error = calcEnergyError(planets[i], properties.radius, properties.v0, properties.velocity, properties.position);
|
||||||
|
if (Math.abs(error) >= ERROR_THRESH) {
|
||||||
|
var speed = adjustVelocity(planets[i], properties.position);
|
||||||
|
properties.velocity = Vec3.multiply(speed, Vec3.normalize(properties.velocity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
counter++;
|
||||||
|
if (time % TIME_STEP == 0) {
|
||||||
|
elapsed++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeLocalPoint(linePos, worldPoint) {
|
||||||
|
var localPoint = Vec3.subtract(worldPoint, linePos);
|
||||||
|
return localPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAcceleration(radius) {
|
||||||
|
var acc = -(G * M) * Math.pow(radius, (-2.0));
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new trail
|
||||||
|
function resetTrails(planetIndex) {
|
||||||
|
elapsed = 0.0;
|
||||||
|
var properties = planet_properties[planetIndex];
|
||||||
|
|
||||||
|
var trail = [];
|
||||||
|
var lineStack = [];
|
||||||
|
|
||||||
|
//add the first line to both the line entity stack and the trail
|
||||||
|
trails.push(newLine(lineStack, properties.position, properties.period, properties.lineColor));
|
||||||
|
planetLines.push(lineStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new line
|
||||||
|
function newLine(lineStack, point, period, color) {
|
||||||
|
if (elapsed < period) {
|
||||||
|
var line = Entities.addEntity({
|
||||||
|
position: point,
|
||||||
|
type: "Line",
|
||||||
|
color: color,
|
||||||
|
dimensions: {
|
||||||
|
x: LINE_DIM,
|
||||||
|
y: LINE_DIM,
|
||||||
|
z: LINE_DIM
|
||||||
|
},
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
lineWidth: LINE_WIDTH
|
||||||
|
});
|
||||||
|
lineStack.push(line);
|
||||||
|
} else {
|
||||||
|
// Begin overwriting first lines after one full revolution (one period)
|
||||||
|
var firstLine = lineStack.shift();
|
||||||
|
Entities.editEntity(firstLine, {
|
||||||
|
position: point,
|
||||||
|
linePoints: [{x: 0.0, y: 0.0, z: 0.0}]
|
||||||
|
});
|
||||||
|
lineStack.push(firstLine);
|
||||||
|
|
||||||
|
}
|
||||||
|
var points = [];
|
||||||
|
points.push(computeLocalPoint(point, point));
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Measure energy error, recalculate velocity to return to initial net energy
|
||||||
|
var totalEnergy;
|
||||||
|
var measuredEnergy;
|
||||||
|
var measuredPE;
|
||||||
|
|
||||||
|
function calcEnergyError(planet, radius, v0, v, pos) {
|
||||||
|
totalEnergy = 0.5 * M * Math.pow(v0, 2.0) - ((G * M * m) / radius);
|
||||||
|
measuredEnergy = 0.5 * M * Math.pow(v, 2.0) - ((G * M * m) / Vec3.length(Vec3.subtract(center, pos)));
|
||||||
|
var error = ((measuredEnergy - totalEnergy) / totalEnergy) * 100;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
function adjustVelocity(planet, pos) {
|
||||||
|
var measuredPE = -(G * M * m) / Vec3.length(Vec3.subtract(center, pos));
|
||||||
|
return Math.sqrt(2 * (totalEnergy - measuredPE) / M);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Allow user to toggle pausing the model, switch to planet view
|
||||||
|
var pauseButton = Overlays.addOverlay("text", {
|
||||||
|
backgroundColor: { red: 200, green: 200, blue: 255 },
|
||||||
|
text: "Pause",
|
||||||
|
x: PANEL_X,
|
||||||
|
y: PANEL_Y - 30,
|
||||||
|
width: 70,
|
||||||
|
height: 20,
|
||||||
|
alpha: 1.0,
|
||||||
|
backgroundAlpha: 0.5,
|
||||||
|
visible: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var paused = false;
|
||||||
|
|
||||||
|
function mousePressEvent(event) {
|
||||||
|
var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y });
|
||||||
|
if(clickedOverlay == pauseButton) {
|
||||||
|
paused = !paused;
|
||||||
|
for (var i = 0; i < NUM_PLANETS; ++i) {
|
||||||
|
Entities.editEntity(planets[i], { velocity: {x: 0.0, y: 0.0, z: 0.0} });
|
||||||
|
}
|
||||||
|
if (paused && !labelsShowing) {
|
||||||
|
Overlays.editOverlay(pauseButton, { text: "Paused", backgroundColor: {red: 255, green: 50, blue: 50} } );
|
||||||
|
showLabels();
|
||||||
|
}
|
||||||
|
if (paused == false && labelsShowing) {
|
||||||
|
Overlays.editOverlay(pauseButton, { text: "Pause", backgroundColor: {red: 200, green: 200, blue: 255}});
|
||||||
|
hideLabels();
|
||||||
|
}
|
||||||
|
planetView = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyPressEvent(event) {
|
||||||
|
// Jump back to solar system view
|
||||||
|
if (event.text == "TAB" && planetView) {
|
||||||
|
if (earthView) {
|
||||||
|
satelliteGame.endGame();
|
||||||
|
earthView = false;
|
||||||
|
}
|
||||||
|
MyAvatar.position = startingPosition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseDoublePressEvent(event) {
|
||||||
|
if(earthView) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var pickRay = Camera.computePickRay(event.x, event.y)
|
||||||
|
var rayPickResult = Entities.findRayIntersection(pickRay, true);
|
||||||
|
|
||||||
|
for (var i = 0; i < NUM_PLANETS; ++i) {
|
||||||
|
if (rayPickResult.entityID === labels[i]) {
|
||||||
|
planetView = true;
|
||||||
|
if (i == 2) {
|
||||||
|
MyAvatar.position = Vec3.sum(center, {x: 200, y: 200, z: 200});
|
||||||
|
Camera.setPosition(Vec3.sum(center, {x: 200, y: 200, z: 200}));
|
||||||
|
earthView = true;
|
||||||
|
satelliteGame = new SatelliteGame();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
MyAvatar.position = Vec3.sum({x: 0.0, y: 0.0, z: 3.0}, planet_properties[i].position);
|
||||||
|
Camera.lookAt(planet_properties[i].position);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Create UI panel
|
||||||
|
var panel = new Panel(PANEL_X, PANEL_Y);
|
||||||
|
var panelItems = [];
|
||||||
|
|
||||||
|
var g_multiplier = 1.0;
|
||||||
|
panelItems.push(panel.newSlider("Adjust Gravitational Force: ", 0.1, 5.0,
|
||||||
|
function (value) {
|
||||||
|
g_multiplier = value;
|
||||||
|
G = G_ref * g_multiplier;
|
||||||
|
},
|
||||||
|
|
||||||
|
function () {
|
||||||
|
return g_multiplier;
|
||||||
|
},
|
||||||
|
function (value) {
|
||||||
|
return value.toFixed(1) + "x";
|
||||||
|
}));
|
||||||
|
|
||||||
|
var period_multiplier = 1.0;
|
||||||
|
var last_alpha = period_multiplier;
|
||||||
|
panelItems.push(panel.newSlider("Adjust Orbital Period: ", 0.1, 3.0,
|
||||||
|
function (value) {
|
||||||
|
period_multiplier = value;
|
||||||
|
changePeriod(period_multiplier);
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
return period_multiplier;
|
||||||
|
},
|
||||||
|
function (value) {
|
||||||
|
return (value).toFixed(2) + "x";
|
||||||
|
}));
|
||||||
|
|
||||||
|
panelItems.push(panel.newCheckbox("Leave Trails: ",
|
||||||
|
function (value) {
|
||||||
|
trailsEnabled = value;
|
||||||
|
if (trailsEnabled) {
|
||||||
|
for (var i = 0; i < NUM_PLANETS; ++i) {
|
||||||
|
resetTrails(i);
|
||||||
|
}
|
||||||
|
//if trails are off and we've already created trails, remove existing trails
|
||||||
|
} else if (planetLines.length != 0) {
|
||||||
|
for (var i = 0; i < NUM_PLANETS; ++i) {
|
||||||
|
for (var j = 0; j < planetLines[i].length; ++j) {
|
||||||
|
Entities.deleteEntity(planetLines[i][j]);
|
||||||
|
}
|
||||||
|
planetLines[i] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
return trailsEnabled;
|
||||||
|
},
|
||||||
|
function (value) {
|
||||||
|
return value;
|
||||||
|
}));
|
||||||
|
|
||||||
|
panelItems.push(panel.newCheckbox("Energy Error Calculations: ",
|
||||||
|
function (value) {
|
||||||
|
energyConserved = value;
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
return energyConserved;
|
||||||
|
},
|
||||||
|
function (value) {
|
||||||
|
return value;
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Update global G constant, period, poke velocity to new value
|
||||||
|
function changePeriod(alpha) {
|
||||||
|
var ratio = last_alpha / alpha;
|
||||||
|
G = Math.pow(ratio, 2.0) * G;
|
||||||
|
for (var i = 0; i < NUM_PLANETS; ++i) {
|
||||||
|
var properties = planet_properties[i];
|
||||||
|
properties.period = ratio * properties.period;
|
||||||
|
properties.velocity = Vec3.multiply(ratio, properties.velocity);
|
||||||
|
|
||||||
|
}
|
||||||
|
last_alpha = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Clean up models, UI panels, lines, and button overlays
|
||||||
|
function scriptEnding() {
|
||||||
|
|
||||||
|
satelliteGame.endGame();
|
||||||
|
|
||||||
|
Entities.deleteEntity(theSun);
|
||||||
|
for (var i = 0; i < NUM_PLANETS; ++i) {
|
||||||
|
Entities.deleteEntity(planets[i]);
|
||||||
|
}
|
||||||
|
Menu.removeMenu("Developer > Scene");
|
||||||
|
panel.destroy();
|
||||||
|
Overlays.deleteOverlay(pauseButton);
|
||||||
|
|
||||||
|
var e = Entities.findEntities(MyAvatar.position, 16000);
|
||||||
|
for (i = 0; i < e.length; i++) {
|
||||||
|
var props = Entities.getEntityProperties(e[i]);
|
||||||
|
if (props.type === "Line" || props.type === "Text") {
|
||||||
|
Entities.deleteEntity(e[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) {
|
||||||
|
return panel.mouseMoveEvent(event);
|
||||||
|
});
|
||||||
|
Controller.mousePressEvent.connect(function panelMousePressEvent(event) {
|
||||||
|
return panel.mousePressEvent(event);
|
||||||
|
});
|
||||||
|
Controller.mouseDoublePressEvent.connect(function panelMouseDoublePressEvent(event) {
|
||||||
|
return panel.mouseDoublePressEvent(event);
|
||||||
|
});
|
||||||
|
Controller.mouseReleaseEvent.connect(function (event) {
|
||||||
|
return panel.mouseReleaseEvent(event);
|
||||||
|
});
|
||||||
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
|
Controller.mouseDoublePressEvent.connect(mouseDoublePressEvent);
|
||||||
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(scriptEnding);
|
||||||
|
Script.update.connect(update);
|
197
examples/utilities/tools/vector.js
Normal file
197
examples/utilities/tools/vector.js
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
//
|
||||||
|
// vector.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Bridget Went on 7/1/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// A template for creating vector arrows using line entities. A VectorArrow object creates a
|
||||||
|
// draggable vector arrow where the user clicked at a specified distance from the viewer.
|
||||||
|
// The relative magnitude and direction of the vector may be displayed.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
var LINE_DIMENSIONS = 100;
|
||||||
|
var LIFETIME = 6000;
|
||||||
|
var RAD_TO_DEG = 180.0 / Math.PI;
|
||||||
|
|
||||||
|
var LINE_WIDTH = 4;
|
||||||
|
var ARROW_WIDTH = 6;
|
||||||
|
var line, linePosition;
|
||||||
|
var arrow1, arrow2;
|
||||||
|
|
||||||
|
var SCALE = 0.15;
|
||||||
|
var ANGLE = 150.0;
|
||||||
|
|
||||||
|
|
||||||
|
VectorArrow = function(distance, showStats, statsTitle, statsPosition) {
|
||||||
|
this.magnitude = 0;
|
||||||
|
this.direction = {x: 0, y: 0, z: 0};
|
||||||
|
|
||||||
|
this.showStats = showStats;
|
||||||
|
this.isDragging = false;
|
||||||
|
|
||||||
|
this.newLine = function(position) {
|
||||||
|
linePosition = position;
|
||||||
|
var points = [];
|
||||||
|
|
||||||
|
line = Entities.addEntity({
|
||||||
|
position: linePosition,
|
||||||
|
type: "Line",
|
||||||
|
color: {red: 255, green: 255, blue: 255},
|
||||||
|
dimensions: {
|
||||||
|
x: LINE_DIMENSIONS,
|
||||||
|
y: LINE_DIMENSIONS,
|
||||||
|
z: LINE_DIMENSIONS
|
||||||
|
},
|
||||||
|
lineWidth: LINE_WIDTH,
|
||||||
|
lifetime: LIFETIME,
|
||||||
|
linePoints: []
|
||||||
|
});
|
||||||
|
|
||||||
|
arrow1 = Entities.addEntity({
|
||||||
|
position: {x: 0, y: 0, z: 0},
|
||||||
|
type: "Line",
|
||||||
|
dimensions: {
|
||||||
|
x: LINE_DIMENSIONS,
|
||||||
|
y: LINE_DIMENSIONS,
|
||||||
|
z: LINE_DIMENSIONS
|
||||||
|
},
|
||||||
|
color: {red: 255, green: 255, blue: 255},
|
||||||
|
lineWidth: ARROW_WIDTH,
|
||||||
|
linePoints: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
arrow2 = Entities.addEntity({
|
||||||
|
position: {x: 0, y: 0, z: 0},
|
||||||
|
type: "Line",
|
||||||
|
dimensions: {
|
||||||
|
x: LINE_DIMENSIONS,
|
||||||
|
y: LINE_DIMENSIONS,
|
||||||
|
z: LINE_DIMENSIONS
|
||||||
|
},
|
||||||
|
color: {red: 255, green: 255, blue: 255},
|
||||||
|
lineWidth: ARROW_WIDTH,
|
||||||
|
linePoints: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.onMousePressEvent = function(event) {
|
||||||
|
|
||||||
|
this.newLine(computeWorldPoint(event));
|
||||||
|
|
||||||
|
if (this.showStats) {
|
||||||
|
this.label = Entities.addEntity({
|
||||||
|
type: "Text",
|
||||||
|
position: statsPosition,
|
||||||
|
dimensions: {
|
||||||
|
x: 4.0,
|
||||||
|
y: 1.5,
|
||||||
|
z: 0.1
|
||||||
|
},
|
||||||
|
lineHeight: 0.3,
|
||||||
|
faceCamera: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isDragging = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.onMouseMoveEvent = function(event) {
|
||||||
|
|
||||||
|
if (!this.isDragging) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var worldPoint = computeWorldPoint(event);
|
||||||
|
var localPoint = computeLocalPoint(event, linePosition);
|
||||||
|
points = [{x: 0, y: 0, z: 0}, localPoint];
|
||||||
|
Entities.editEntity(line, { linePoints: points });
|
||||||
|
|
||||||
|
var nextOffset = Vec3.multiply(SCALE, localPoint);
|
||||||
|
var normOffset = Vec3.normalize(localPoint);
|
||||||
|
var axis = Vec3.cross(normOffset, Quat.getFront(Camera.getOrientation()) );
|
||||||
|
axis = Vec3.cross(axis, normOffset);
|
||||||
|
var rotate1 = Quat.angleAxis(ANGLE, axis);
|
||||||
|
var rotate2 = Quat.angleAxis(-ANGLE, axis);
|
||||||
|
|
||||||
|
// Rotate arrow head to follow direction of the line
|
||||||
|
Entities.editEntity(arrow1, {
|
||||||
|
visible: true,
|
||||||
|
position: worldPoint,
|
||||||
|
linePoints: [{x: 0, y: 0, z: 0}, nextOffset],
|
||||||
|
rotation: rotate1
|
||||||
|
});
|
||||||
|
Entities.editEntity(arrow2, {
|
||||||
|
visible: true,
|
||||||
|
position: worldPoint,
|
||||||
|
linePoints: [{x: 0, y: 0, z: 0}, nextOffset],
|
||||||
|
rotation: rotate2
|
||||||
|
});
|
||||||
|
|
||||||
|
this.magnitude = Vec3.length(localPoint) / 10.0;
|
||||||
|
this.direction = Vec3.normalize(Vec3.subtract(worldPoint, linePosition));
|
||||||
|
|
||||||
|
if (this.showStats) {
|
||||||
|
this.editLabel(statsTitle + " Magnitude " + this.magnitude.toFixed(2) + ", Direction: " +
|
||||||
|
this.direction.x.toFixed(2) + ", " + this.direction.y.toFixed(2) + ", " + this.direction.z.toFixed(2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onMouseReleaseEvent = function() {
|
||||||
|
this.isDragging = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.cleanup = function() {
|
||||||
|
Entities.deleteEntity(line);
|
||||||
|
Entities.deleteEntity(arrow1);
|
||||||
|
Entities.deleteEntity(arrow2);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.deleteLabel = function() {
|
||||||
|
Entities.deleteEntity(this.label);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editLabel = function(str) {
|
||||||
|
if(!this.showStats) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Entities.editEntity(this.label, {
|
||||||
|
text: str
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeWorldPoint(event) {
|
||||||
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
var addVector = Vec3.multiply(pickRay.direction, distance);
|
||||||
|
return Vec3.sum(Camera.getPosition(), addVector);
|
||||||
|
}
|
||||||
|
|
||||||
|
function computeLocalPoint(event, linePosition) {
|
||||||
|
var localPoint = Vec3.subtract(computeWorldPoint(event), linePosition);
|
||||||
|
return localPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue