javascript callback animations - javascript

I have written a small animate function using three.js for 3D rendering(full test application below):
each time I click on the screen the cube rotates based on the animation descibed in the function call. But I was expecting that if the cube was already animating under one animation adding another would cause it to flicker about as the same properties are being animated by multiple animation calls. but this is not what happens the last animation is halted and the new one takes over, even though my callback function at the end shows that the old animation function was still running! So why does the cube not flicker about when multiple clicks are sent?
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
<script src="three-mini.js"></script>
<style>
* {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script>
var animate = function(obj, prop, targetValue, length, callback) {
var startTime = Date.now(), inverseLength = 1 / length, startValue = obj[prop];
if( typeof targetValue === "string") {
if(targetValue.substring(0, 2) === "+=") {
targetValue = obj[prop] + Number(targetValue.substring(2));
} else {
targetValue = obj[prop] - Number(targetValue.substring(2));
}
}
var animateProp = function() {
var elapsed = (Date.now() - startTime) * inverseLength;
if(elapsed >= 1) {
obj[prop] = targetValue;
if( callback instanceof Function) {
requestAnimationFrame(callback);
}
return;
} else {
obj[prop] = (startValue - targetValue) * (Math.cos(elapsed * Math.PI) + 1) * 0.5 + targetValue;
requestAnimationFrame(animateProp);
}
};
requestAnimationFrame(animateProp);
};
var camera, scene, renderer;
var geometry, material, mesh;
init();
function init() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 1000;
scene = new THREE.Scene();
geometry = new THREE.CubeGeometry(200, 200, 200);
material = new THREE.MeshBasicMaterial({
color : 0xff0000,
wireframe : true
});
mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.domElement.addEventListener('click', function() {
animate(mesh.rotation, "x", "-=" + Math.PI * 2 * 10, 5000, function() {
alert("CALLED BACK!")
});
animate(mesh.rotation, "y", "-=" + Math.PI * 2 * 10, 15000, function() {
});
});
window.addEventListener('load', render);
window.addEventListener('resize', function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
}
function render() {
// note: three.js includes requestAnimationFrame shim
requestAnimationFrame(render);
renderer.render(scene, camera);
}
</script>
</body>
</html>
UPDATE 1:
In an attempt to find out what's going on I add more meshes and animated them all differently, the code is below, it animates each mesh for each subsequent click and it animates them first by rotation then it moves them forwards then backwards, then back to rotation. You can animate position without halting the animation on rotation and you can animate one mesh at the same time as another mesh without halting previous animations, so why doesn't the animation flicker when multiple animations are running on the same mesh and on the same properties?
<!DOCTYPE html>
<html>
<head>
<title>Test Page</title>
<script src="three-mini.js"></script>
<style>
* {
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<script>
var animate = function(obj, prop, targetValue, length, callback) {
var startTime = Date.now(), inverseLength = 1 / length, startValue = obj[prop];
if( typeof targetValue === "string") {
if(targetValue.substring(0, 2) === "+=") {
targetValue = obj[prop] + Number(targetValue.substring(2));
} else {
targetValue = obj[prop] - Number(targetValue.substring(2));
}
}
var animateProp = function() {
var elapsed = (Date.now() - startTime) * inverseLength;
if(elapsed >= 1) {
obj[prop] = targetValue;
if( callback instanceof Function) {
requestAnimationFrame(callback);
}
return;
} else {
obj[prop] = (startValue - targetValue) * (Math.cos(elapsed * Math.PI) + 1) * 0.5 + targetValue;
requestAnimationFrame(animateProp);
}
};
requestAnimationFrame(animateProp);
};
var camera, scene, renderer, geometry, material, mesh1, mesh2, mesh3, mesh4, mesh5, i = 0, j = 0;
init();
function init() {
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000);
camera.position.z = 1000;
scene = new THREE.Scene();
geometry = new THREE.CubeGeometry(200, 200, 200);
material = new THREE.MeshBasicMaterial({
color : 0xff0000,
wireframe : true
});
mesh1 = new THREE.Mesh(geometry, material);
scene.add(mesh1);
mesh2 = new THREE.Mesh(geometry, material);
mesh2.position.x = mesh2.position.y = mesh2.position.z = 200;
scene.add(mesh2);
mesh3 = new THREE.Mesh(geometry, material);
mesh3.position.x = mesh3.position.z = 200;
mesh3.position.y = -200;
scene.add(mesh3);
mesh4 = new THREE.Mesh(geometry, material);
mesh4.position.y = mesh4.position.z = 200;
mesh4.position.x = -200;
scene.add(mesh4);
mesh5 = new THREE.Mesh(geometry, material);
mesh5.position.y = mesh5.position.x = -200;
mesh5.position.z = 200;
scene.add(mesh5);
renderer = new THREE.CanvasRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
renderer.domElement.addEventListener('click', function() {
var mesh;
if(i === 5) {
i = 0;
j++;
if(j === 3) {
j = 0;
}
}
i++;
var mesh = window['mesh' + i];
if(j === 1) {
animate(mesh.position, "z", "+=" + 500, 2000, function() {
//alert("CALLED BACK!")
});
return;
}
if(j === 2) {
animate(mesh.position, "z", "-=" + 500, 3000, function() {
//alert("CALLED BACK!")
}); retunr;
}
animate(mesh.rotation, "x", "-=" + Math.PI * 2 * 5, 5000, function() {
//alert("CALLED BACK!")
});
animate(mesh.rotation, "y", "-=" + Math.PI * 2 * 6, 10000, function() {
});
});
window.addEventListener('load', render);
window.addEventListener('resize', function() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
});
}
function render() {
// note: three.js includes requestAnimationFrame shim
requestAnimationFrame(render);
renderer.render(scene, camera);
}
</script>
</body>
</html>
comment for WestLangley:
let me try and explain a bit more, I apologise for not being clear. lets say I click once and it starts an animation from position.x = 0 to targetValue: '+=200'. and then halfway through that animation I click again which this time animates in the negative x direction which will start with position.x = 100 (as it's starting halfway through the first animation) and has targetValue: '-=200'. Now I expect that the first animation is still running so it is continuing to animate from x=100 to x=200, and the second animation is now also running from x=100 to x=-100, so as each animation function is called I would expect to see the cube jump left and right until the first animation comes to an end and then the second animation can continue unhindered. This is what I was expecting to happen, thus I was expecting it to flicker. But apparently multiple animation functions are running at the same time but only the latest one is having any effect updating the mesh properties. :S at least as far as I can tell.
My main worry about this is that I can tell from the experimenting that the "hidden" animation calls are still being processed and so throwing away precious processor cycles, it also leads to problems with adding animation calls in the callback function. To this end my main concern is how can I stop these "hidden" animation calls?

I'm still not entirely certain on what is happening, but what I do know is that multiple animations are running at the same time even though the earlier ones are not being shown. My main concern about this is that it's using up processing power that is not necessary. So I have added in a suffix notation and I now add the animating functions to the animated property owning object itself, so if I am animating position.x i create my animation function and assign it to position.x_animate and position.x_animate_alt alternatively. this is so I can cancel the previous, still running animation so I'm not wasting processor cycles. full snippet just for animate function below:
var animate = function(obj, prop, targetValue, length, callback) {
var suffix = '_animate', altSuffix = '_animate_alt', thisSuffix = suffix, startTime = Date.now(), inverseLength = 1 / length, startValue = obj[prop];
if( typeof targetValue === "string") {
if(targetValue.substring(0, 2) === "+=") {
targetValue = obj[prop] + Number(targetValue.substring(2));
} else {
targetValue = obj[prop] - Number(targetValue.substring(2));
}
}
if(obj[prop+suffix] instanceof Function){
obj[prop+suffix].cancelled = true;
thisSuffix = altSuffix;
}
if(obj[prop+altSuffix] instanceof Function){
obj[prop+altSuffix].cancelled = true;
thisSuffix = suffix;
}
obj[prop+thisSuffix] = function() {
var elapsed;
if(obj[prop+thisSuffix].cancelled){
delete obj[prop+thisSuffix];
return;
}
elapsed = (Date.now() - startTime) * inverseLength;
if(elapsed >= 1) {
obj[prop] = targetValue;
delete obj[prop+thisSuffix];
if( callback instanceof Function) {
requestAnimationFrame(callback);
}
return;
} else {
obj[prop] = (startValue - targetValue) * (Math.cos(elapsed * Math.PI) + 1) * 0.5 + targetValue;
requestAnimationFrame(obj[prop+thisSuffix]);
}
};
requestAnimationFrame(obj[prop+thisSuffix]);
};

Related

ThreeJS: How to move background only in one direction?

I have a fully working model of a car mesh moving right, left, up and down using Three.JS
The input data are acceleration on the X and Z direction, we apply double integration on the acceleration to compute the displacement. So I have been able to animate the car in all directions and making the background move to keep the car in the center of the canvas. However, I only need to background to move in the right and left direction, and not for the up and down
That's my code:
<html>
<head>
<style>
canvas {
position: fixed;
top: 0;
left: 0;
}
</style>
</head>
<body>
<script src="./libs/three.min.js"></script>
<script src="./libs/OrbitControls.js"></script>
<script src="./libs/KeyboardState.js"></script>
<script src="./libs/MTLLoader.js"></script>
<script src="./libs/OBJMTLLoader.js"></script>
<script src="./data/accXaccZCOMBINEDMOTIONS.json"></script>
</body>
<script>
var data = JSON.parse(JSON.stringify(data));
var toycar;
var valid = 1;
const dispArrayX = Array.from({ length: 1 }).fill(0);
const dispArrayZ = Array.from({ length: 1 }).fill(0);
let sensorValue = 0;
var initialVelocity = 0;
var angle = 0;
var currentIndex = 0;
var initialDisplacement = 0;
var scene, renderer, camera;
var width = window.innerWidth;
var height = window.innerHeight;
var time = data[currentIndex].time
var pos = new THREE.Vector3(0, 0, 0);
init();
animate();
function init() {
var width = window.innerWidth;
var height = window.innerHeight;
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setClearColor(0x626d73, 1);
renderer.setSize(width, height);
document.body.appendChild(renderer.domElement);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(10, width / height, 1, 10000);
// camera.position.y = -150;
// camera.position.y = 200;
// camera.position.x = 100;
camera.lookAt(new THREE.Vector3(0, 0, 0));
var loader = new THREE.OBJMTLLoader();
loader.load('https://jyunming-chen.github.io/tutsplus/models/toycar.obj', 'https://jyunming-chen.github.io/tutsplus/models/toycar.mtl',
function (object) {
toycar = object;
toycar.rotateZ(10.8); //toycar.rotateZ(-10.99);
scene.add(toycar);
});
var gridXZ = new THREE.GridHelper(100000, 10);
gridXZ.setColors(new THREE.Color(0xff0000), new THREE.Color(0xffffff));
scene.add(gridXZ);
var pointLight = new THREE.PointLight(0xffffff);
pointLight.position.set(350, 10, 5);
scene.add(pointLight);
var ambientLight = new THREE.AmbientLight(0x111111);
scene.add(ambientLight);
}
function animate(dt) {
let time = data[currentIndex].time
dt *= 10 ** -9
time += dt
while (data[currentIndex].time < time) {
currentIndex++
if (currentIndex >= data.length) return
}
const { accX,accZ } = data[currentIndex]
var dir = new THREE.Vector3(0, 0, -1);
dir.applyAxisAngle(new THREE.Vector3(0, 0, 0), 10);
pos.add(dir);
if (toycar != undefined) {
toycar.scale.set(0.1, 0.1, 0.1);
if (currentIndex > 0) {
// compute the displacement by double integrating the acceleration for accZ (e.i. Right and left movement)
const deltaTime = ((data[currentIndex].time) / (24 * 60 * 60)) - 1; // convert time from second per day to second
const velocityInitialZ = ((data[currentIndex-3].accZ + data[currentIndex-2].accZ)/2)*deltaTime; // compute initialVelocity two step backward
const velocityCurrentZ = velocityInitialZ + ((data[currentIndex-1].accZ + data[currentIndex].accZ)/2)*deltaTime; // compute currentVelocity one step backward
const previousDispZ = dispArrayZ[0] + (deltaTime * ((velocityCurrentZ + velocityInitialZ)/2));
dispArrayZ[0] = previousDispZ;
const dispCurrentZ = previousDispZ + dispArrayZ[0];
// compute the displacement by double integrating the acceleration for accX (e.i. Up and down movement)
const velocityInitialX = ((data[currentIndex-3].accX + data[currentIndex-2].accX)/2)*deltaTime; // compute initialVelocity two step backward
const velocityCurrentX = velocityInitialX + ((data[currentIndex-1].accX + data[currentIndex].accX)/2)*deltaTime; // compute currentVelocity one step backward
const previousDispX = dispArrayX[0] + (deltaTime * ((velocityCurrentX + velocityInitialX)/2));
dispArrayX[0] = previousDispX;
const dispCurrentX = previousDispX + dispArrayX[0];
const dispCurrentXscaled = dispCurrentX/3500;
// Move the car up and down
if (dispCurrentXscaled*0.0001 < 0){
toycar.position.x = dispCurrentXscaled*0.00001;
}
else if (dispCurrentXscaled*0.0001 > 8){
toycar.position.x = dispCurrentXscaled*0.0000001;
}
else{
toycar.position.x = dispCurrentXscaled*0.0001;
}
toycar.position.y = 0;
// Move the car right and left
toycar.position.z = -(dispCurrentZ/4000)*0.0005;
// print out displacementX and displacementZ
console.log("DispX: " + (dispCurrentX*0.0000001).toFixed(5) + " DispZ: " + ((dispCurrentZ/4000)*0.0005).toFixed(5));
}
toycar.rotation.x = (angle + Math.PI);;
var relativeCameraOffset = new THREE.Vector3(-1600, 400, 0);
var cameraOffset = relativeCameraOffset.applyMatrix4(toycar.matrixWorld);
camera.position.x = cameraOffset.x*0.5;
camera.position.y = cameraOffset.y;
camera.position.z = cameraOffset.z;
camera.lookAt(toycar.position);
}
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
</script>
</html>
I am using from a JSON file as input.
That's how the movement of the car looks like:
You can see that the background is following the car motion. For Up and Down I only need the car to move (not the background) and the right and left are fine because is moving so it stays within the canvas. Can you please help with that?

Three.js change the pivot point of each particle

I'm trying to rotate each particle along its own axis of rotation rather than rotate them all along one point. I've looked at many similar questions on setting the pivot points, but I'm lost and confused to be honest.
My goal is to animate the particles as if they're falling from top to bottom, similar to this animation.
var camera,
scene,
renderer,
materials = [],
parameters;
var windowHalfX = window.innerWidth / 2,
windowHalfY = window.innerHeight / 2;
var particles = [];
var confetti = {
maxCount: 2000, //set max confetti count
speed: 1, //set the particle animation speed
frameInterval: 30, //the confetti animation frame interval in milliseconds
waveThreshold: 3, //
start: null, //call to start confetti animation (with optional timeout in milliseconds, and optional min and max random confetti count)
stop: null, //call to stop adding confetti
toggle: null, //call to start or stop the confetti animation depending on whether it's already running
pause: null, //call to freeze confetti animation
resume: null, //call to unfreeze confetti animation
togglePause: null, //call to toggle whether the confetti animation is paused
remove: null, //call to stop the confetti animation and remove all confetti immediately
isPaused: null, //call and returns true or false depending on whether the confetti animation is paused
isRunning: null //call and returns true or false depending on whether the animation is running
};
init();
animate();
window.addEventListener('resize', onWindowResize);
function init() {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 20, 900);
camera.position.z = 100;
var geometry = new THREE.BufferGeometry();
var vertices = [];
var textureLoader = new THREE.TextureLoader();
var sprite1 = textureLoader.load('https://i.postimg.cc/Rhx8t6CM/confetti1.png');
var sprite2 = textureLoader.load('https://i.postimg.cc/Rhx8t6CM/confetti1.png');
var sprite3 = textureLoader.load('https://i.postimg.cc/Rhx8t6CM/confetti1.png');
var sprite4 = textureLoader.load('https://i.postimg.cc/Rhx8t6CM/confetti1.png');
var sprite5 = textureLoader.load('https://i.postimg.cc/Rhx8t6CM/confetti1.png');
for (var i = 0; i < confetti.maxCount; i++) {
var x = Math.random() * 2000 - 1000;
var y = Math.random() * 2000 - 1000;
var z = Math.random() * 1000 - 900;
vertices.push(x, y, z);
//particles[i].tilt = Math.random() * 10 - 10;
//particle.tiltAngleIncrement = Math.random() * 0.07 + 0.05;
//particles[i].tiltAngle = Math.random() * Math.PI;
particles.push({
'tilt': Math.random() * 1 - 1,
'tiltAngle': Math.random() * Math.PI
})
}
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
parameters = [
[sprite2, 10],
[sprite3, 9],
[sprite1, 10],
[sprite5, 8],
[sprite4, 10]
];
for (var i = 0; i < parameters.length; i++) {
var sprite = parameters[i][0];
var size = parameters[i][1];
materials[i] = new THREE.PointsMaterial({
size: size,
map: sprite,
blending: THREE.AdditiveBlending,
depthTest: false,
transparent: true
});
var particle = new THREE.Points(geometry, materials[i]);
particle.rotation.x = Math.random() * 5;
particle.rotation.y = Math.random() * 5;
particle.rotation.z = Math.random() * 5;
scene.add(particle);
}
renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setClearColor('#121212')
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
}
function onWindowResize() {
renderer.setSize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
}
function animate() {
requestAnimationFrame(animate);
render();
}
function render() {
var time = Date.now() * 0.00005;
for (var i = 0; i < scene.children.length; i++) {
var object = scene.children[i];
if (object instanceof THREE.Points) {
//object.rotation.x = time * ( i < 4 ? i + 1 : ( i + 1 ) );
//object.position.x -= time * ( i < 4 ? i + 1 : -( i + 1 ) );
object.position.y -= 1;
object.position.x += particles[i]['tilt'] / 3;
object.rotation.y += .001;
//object.rotation.x += time * particles[i]['tiltAngle'];
}
}
renderer.render(scene, camera);
}
body {
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/109/three.js" type="text/javascript"></script>

how to check dynamically changing boolean value using three js

I'm making a 3D 4x4x4 tic tac toe with three js, and to check win combo condition, I created a boolean array. Since there are 16*4=64 blocks, I made a boolean array of size 64 and set it to false by default. And then whenever the user clicks one of the blocks it changes the clicked object to true dynamically.
To check the horizontal win condition, i used this,
var camera, scene, renderer, mesh, material, controls;
var targetList = [];
var targetListBool = new Array(64).fill(false);
console.log(targetListBool);
// var projector, mouse = { x: 0, y: 0 };
var projecter;
var mouse = new THREE.Vector2(),
INTERSECTED;
init();
animate();
addCubes();
render();
function addCubes() {
var xDistance = 30;
var zDistance = 15;
var geometry = new THREE.BoxBufferGeometry(10, 10, 10);
var material = new THREE.MeshBasicMaterial({
color: 0x6C70A8
});
//initial offset so does not start in middle.
var xOffset = -80;
//1
for (let i = 0; i < 4; i++) {
for (let j = 0; j < 4; j++) {
var mesh = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: 0xadc9f4
}));
mesh.position.x = (xDistance * (i)) + xOffset;
mesh.position.z = (zDistance * (j));
scene.add(mesh);
targetList.push(mesh);
}
//2
for (let j = 0; j < 4; j++) {
var mesh2 = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: 0xadc9f4
}));
mesh2.position.x = (xDistance * (i)) + xOffset;
mesh2.position.z = (zDistance * (j));
mesh2.position.y = 15;
scene.add(mesh2);
targetList.push(mesh2);
}
//3
for (let j = 0; j < 4; j++) {
var mesh3 = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: 0xadc9f4
}));
mesh3.position.x = (xDistance * (i)) + xOffset;
mesh3.position.z = (zDistance * (j));
mesh3.position.y = 30;
scene.add(mesh3);
targetList.push(mesh3);
}
//4
for (let j = 0; j < 4; j++) {
var mesh4 = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({
color: 0xadc9f4
}));
mesh4.position.x = (xDistance * (i)) + xOffset;
mesh4.position.z = (zDistance * (j));
mesh4.position.y = 45;
scene.add(mesh4);
targetList.push(mesh4);
}
}
for (var i = 0; i < targetList.length; i++) {
targetList[i].name = i;
}
}
function init() {
// Renderer.
renderer = new THREE.WebGLRenderer({
antialias: true
});
// renderer = new THREE.WebGLRenderer();
//renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
// Add renderer to page
document.body.appendChild(renderer.domElement);
// Create camera.
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 150;
// Add controls
controls = new THREE.TrackballControls(camera);
controls.addEventListener('change', render);
controls.target.set(0, 0, -50);
// Create scene.
scene = new THREE.Scene();
scene.background = new THREE.Color(0xffffff);
// Create directional light and add to scene.
var pointLight = new THREE.PointLight(0xFFFFFF, 1, 100000);
pointLight.position.set(1, 1, 1).normalize();
scene.add(pointLight);
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
// Add listener for window resize.
window.addEventListener('resize', onWindowResize, false);
}
// initialize object to perform world/screen calculations
projector = new THREE.Projector();
// when the mouse moves, call the given function
document.addEventListener('mousedown', onDocumentMouseDown, false);
function onDocumentMouseDown(event) {
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
event.preventDefault();
console.log("Click.");
// update the mouse variable
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// find intersections
// create a Ray with origin at the mouse position
// and direction into the scene (camera direction)
var vector = new THREE.Vector3(mouse.x, mouse.y, 1);
projector.unprojectVector(vector, camera);
var ray = new THREE.Raycaster();
ray.setFromCamera(mouse, camera);
// create an array containing all objects in the scene with which the ray intersects
var intersects = ray.intersectObjects(targetList);
// if there is one (or more) intersections
if (intersects.length > 0 && INTERSECTED != intersects[0].object) {
INTERSECTED = intersects[0].object;
INTERSECTED.material.emissive.setHex(0xff0000);
console.log(INTERSECTED.name);
// console.log("Hit # " + toString( intersects[0].point ) );
// change the color of the closest face.
// intersects[ 0 ].face.color.setHex(0xffa500);
// intersects[ 0 ].object.geometry.colorsNeedUpdate = true;
for (var i = 0; i < targetList.length; i++) {
if (INTERSECTED.name == i) {
targetListBool[i] = true;
}
}
console.log(targetListBool);
}
}
// $(intersec).click(function(){
// alert('you clicked number 1 block');
// });
function toString(v) {
return "[ " + v.x + ", " + v.y + ", " + v.z + " ]";
}
function animate() {
requestAnimationFrame(animate);
render();
controls.update();
}
function render() {
renderer.render(scene, camera);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
controls.handleResize();
}
for (let i = 0; i <targetListBool.length ; i+=4) {
if(targetListBool[i]
&&targetListBool[i+1]
&&targetListBool[i+2]
&&targetListBool[i+3]){
alert('win');
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Tic tac toe</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
.info {
position: absolute;
background-color: black;
opacity: 0.8;
color: white;
text-align: center;
top: 0px;
width: 100%;
}
.info a {
color: #00ffff;
}
button {
display: hidden;
}
</style>
</head>
<body>
<div id="container">
<div>
<!-- <button id="restart">Restart</button> -->
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/threejs/r84/three.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/controls/TrackballControls.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/utils/BufferGeometryUtils.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/libs/dat.gui.min.js"></script>
<script src="https://rawgit.com/mrdoob/three.js/master/examples/js/renderers/Projector.js"></script>
</body>
</html>
I'm trying to check just horizontal win combination for a starter now.
for (let i = 0; i <targetListBool.length ; i+=4) {
if(targetListBool[i]
&&targetListBool[i+1]
&&targetListBool[i+2]
&&targetListBool[i+3]){
alert('win');
}
}
But it doesn't know that some values have changed by click event earier.
Just to clarify, it's supposed to alert 'win' if 4 consecutive horizontal blocks are clicked in each plane. but I guess something's wrong with the if statement in the for loop at the end of the snippet.
It's my first time using three js and i'm not really familiar with javaScript either. I would appreciate any help. Thanks.
Your system wins if it has 4 in a row on either the x,y or z axis. Your function only check the booleans in one direction. So best is to track the data in a 3 dimensional way. Here is an example of it. I manually set 4 on a row on the z axis and then do the check.
The check could and should be improved though. It's pretty inefficient, but kept it easy for the example and because I don't know your exact intentions. Should diagonals be checked too for example?
//Fill a variable with x,y,z coordinates with a boolean value that is false.
var locations = {};
for (var x = 1; x <= 4; x++) {
locations[x] = {};
for (var y = 1; y <= 4; y++) {
locations[x][y] = {};
for (var z = 1; z <= 4; z++) {
locations[x][y][z] = false;
}
}
}
//Set 4 values on the X axis to true for testing
locations[1][2][3] = true;
locations[2][2][3] = true;
locations[3][2][3] = true;
locations[4][2][3] = true;
//Set 4 values on the Z axis to true for testing
locations[1][2][1] = true;
locations[1][2][2] = true;
locations[1][2][3] = true;
locations[1][2][4] = true;
//Test if there are 4 on a row - note this can be done more efficient with a bit more thought and does not work for diagonals
var winX = false;
var winY = false;
var winZ = false;
for (var x = 1; x <= 4; x++) {
for (var y = 1; y <= 4; y++) {
for (var z = 1; z <= 4; z++) {
if(locations[x][y][z]) {
//check X for current position
if(locations[1][y][z] && locations[2][y][z] && locations[3][y][z] && locations[4][y][z]) {
winX = true;
}
//check Y for current position
if(locations[x][1][z] && locations[x][2][z] && locations[x][3][z] && locations[x][4][z]) {
winY = true;
}
//check Z for current position
if(locations[x][y][1] && locations[x][y][2] && locations[x][y][3] && locations[x][y][4]) {
winZ = true;
}
}
}
}
}
//Log the results, should return true for X and Z and false for Y
console.log("Win X: " + winX);
console.log("Win Y: " + winY);
console.log("Win Z: " + winZ);

Bullet collision detection in three.js

For my first years of studies, i have a Three.js project. I have to create a little fps. I have followed a tutorial, everything is fine except the bullet collision detection. I try some stuff i have found on internet, follow some tutorial trying to understand as much as i can, because i don't want to just copy and paste stuff.
But i have to confess i am a bit lost. Here is the code i have develop. What i want to do is to detect when a bullet touch another object. Like for example make disappear a box when a bullet touch it.
The bullet are defined like this :
var bullet = new THREE.Mesh(
new THREE.SphereGeometry(0.05,8,8),
new THREE.MeshBasicMaterial({color:0xffffff})
Here is also my code
var scene, camera, renderer, mesh, clock;
var meshFloor, ambientLight, light;
var crate, crateTexture, crateNormalMap, crateBumpMap;
var keyboard = {};
var player = { height:1.8, speed:0.2, turnSpeed:Math.PI*0.02, canShoot:0 };
var USE_WIREFRAME = false;
var loadingScreen = {
scene: new THREE.Scene(),
camera: new THREE.PerspectiveCamera(90, 1280/720, 0.1, 100),
box: new THREE.Mesh(
new THREE.BoxGeometry(0.5,0.5,0.5),
new THREE.MeshBasicMaterial({ color:0x4444ff })
)
};
var loadingManager = null;
var RESOURCES_LOADED = false;
// Models index
var models = {
tent: {
obj:"models/Tent_Poles_01.obj",
mtl:"models/Tent_Poles_01.mtl",
mesh: null
},
campfire: {
obj:"models/Campfire_01.obj",
mtl:"models/Campfire_01.mtl",
mesh: null
},
pirateship: {
obj:"models/Pirateship.obj",
mtl:"models/Pirateship.mtl",
mesh: null
},
uzi: {
obj:"models/uziGold.obj",
mtl:"models/uziGold.mtl",
mesh: null,
castShadow:false
}
};
// Meshes index
var meshes = {};
// Bullets array
var bullets = [];
function init(){
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(90, 1280/720, 0.1, 1000);
clock = new THREE.Clock();
loadingScreen.box.position.set(0,0,5);
loadingScreen.camera.lookAt(loadingScreen.box.position);
loadingScreen.scene.add(loadingScreen.box);
loadingManager = new THREE.LoadingManager();
loadingManager.onProgress = function(item, loaded, total){
console.log(item, loaded, total);
};
loadingManager.onLoad = function(){
console.log("loaded all resources");
RESOURCES_LOADED = true;
onResourcesLoaded();
};
mesh = new THREE.Mesh(
new THREE.BoxGeometry(1,1,1),
new THREE.MeshPhongMaterial({color:0xff4444, wireframe:USE_WIREFRAME})
);
mesh.position.y += 1;
mesh.receiveShadow = true;
mesh.castShadow = true;
//scene.add(mesh);
meshFloor = new THREE.Mesh(
new THREE.PlaneGeometry(20,20, 10,10),
new THREE.MeshPhongMaterial({color:0xffffff, wireframe:USE_WIREFRAME})
);
meshFloor.rotation.x -= Math.PI / 2;
meshFloor.receiveShadow = true;
scene.add(meshFloor);
ambientLight = new THREE.AmbientLight(0xffffff, 0.2);
scene.add(ambientLight);
light = new THREE.PointLight(0xffffff, 0.8, 18);
light.position.set(-3,6,-3);
light.castShadow = true;
light.shadow.camera.near = 0.1;
light.shadow.camera.far = 25;
scene.add(light);
var textureLoader = new THREE.TextureLoader(loadingManager);
crateTexture = textureLoader.load("crate0/crate0_diffuse.jpg");
crateBumpMap = textureLoader.load("crate0/crate0_bump.jpg");
crateNormalMap = textureLoader.load("crate0/crate0_normal.jpg");
crate = new THREE.Mesh(
new THREE.BoxGeometry(3,3,3),
new THREE.MeshPhongMaterial({
color:0xffffff,
map:crateTexture,
bumpMap:crateBumpMap,
normalMap:crateNormalMap
})
);
crate.position.set(2.5, 3/2, 2.5);
crate.receiveShadow = true;
crate.castShadow = true;
// Load models
// REMEMBER: Loading in Javascript is asynchronous, so you need
// to wrap the code in a function and pass it the index. If you
// don't, then the index '_key' can change while the model is being
// downloaded, and so the wrong model will be matched with the wrong
// index key.
for( var _key in models ){
(function(key){
var mtlLoader = new THREE.MTLLoader(loadingManager);
mtlLoader.load(models[key].mtl, function(materials){
materials.preload();
var objLoader = new THREE.OBJLoader(loadingManager);
objLoader.setMaterials(materials);
objLoader.load(models[key].obj, function(mesh){
mesh.traverse(function(node){
if( node instanceof THREE.Mesh ){
if('castShadow' in models[key])
node.castShadow = models[key].castShadow;
else
node.castShadow = true;
if('receiveShadow' in models[key])
node.receiveShadow = models[key].receiveShadow;
else
node.receiveShadow = true;
}
});
models[key].mesh = mesh;
});
});
})(_key);
}
camera.position.set(0, player.height, -5);
camera.lookAt(new THREE.Vector3(0,player.height,0));
renderer = new THREE.WebGLRenderer();
renderer.setSize(1280, 720);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.BasicShadowMap;
document.body.appendChild(renderer.domElement);
animate();
}
// Runs when all resources are loaded
function onResourcesLoaded(){
// Clone models into meshes.
meshes["tent1"] = models.tent.mesh.clone();
meshes["tent2"] = models.tent.mesh.clone();
meshes["campfire1"] = models.campfire.mesh.clone();
meshes["campfire2"] = models.campfire.mesh.clone();
// Reposition individual meshes, then add meshes to scene
meshes["tent1"].position.set(-5, 0, 4);
scene.add(meshes["tent1"]);
meshes["tent2"].position.set(-8, 0, 4);
scene.add(meshes["tent2"]);
meshes["campfire1"].position.set(-5, 0, 1);
meshes["campfire2"].position.set(-8, 0, 1);
scene.add(meshes["campfire1"]);
scene.add(meshes["campfire2"]);
// player weapon
meshes["playerweapon"] = models.uzi.mesh.clone();
meshes["playerweapon"].position.set(0,2,0);
meshes["playerweapon"].scale.set(10,10,10);
scene.add(meshes["playerweapon"]);
}
function animate(){
// Play the loading screen until resources are loaded.
if( RESOURCES_LOADED == false ){
requestAnimationFrame(animate);
loadingScreen.box.position.x -= 0.05;
if( loadingScreen.box.position.x < -10 ) loadingScreen.box.position.x = 10;
loadingScreen.box.position.y = Math.sin(loadingScreen.box.position.x);
renderer.render(loadingScreen.scene, loadingScreen.camera);
return;
}
requestAnimationFrame(animate);
var time = Date.now() * 0.0005;
var delta = clock.getDelta();
mesh.rotation.x += 0.01;
mesh.rotation.y += 0.02;
crate.rotation.y += 0.01;
// Uncomment for absurdity!
// meshes["pirateship"].rotation.z += 0.01;
// go through bullets array and update position
// remove bullets when appropriate
for(var index=0; index<bullets.length; index+=1){
if( bullets[index] === undefined ) continue;
if( bullets[index].alive == false ){
bullets.splice(index,1);
continue;
}
bullets[index].position.add(bullets[index].velocity);
}
if(keyboard[38]){ // UP button
camera.position.x -= Math.sin(camera.rotation.y) * player.speed;
camera.position.z -= -Math.cos(camera.rotation.y) * player.speed;
}
if(keyboard[40]){ // DOWN button
camera.position.x += Math.sin(camera.rotation.y) * player.speed;
camera.position.z += -Math.cos(camera.rotation.y) * player.speed;
}
if(keyboard[65]){ // A key
camera.position.x += Math.sin(camera.rotation.y + Math.PI/2) * player.speed;
camera.position.z += -Math.cos(camera.rotation.y + Math.PI/2) * player.speed;
}
if(keyboard[68]){ // D key
camera.position.x += Math.sin(camera.rotation.y - Math.PI/2) * player.speed;
camera.position.z += -Math.cos(camera.rotation.y - Math.PI/2) * player.speed;
}
if(keyboard[37]){ // left arrow key
camera.rotation.y -= player.turnSpeed;
}
if(keyboard[39]){ // right arrow key
camera.rotation.y += player.turnSpeed;
}
// shoot a bullet
if(keyboard[32] && player.canShoot <= 0){ // spacebar key
// creates a bullet as a Mesh object
var bullet = new THREE.Mesh(
new THREE.SphereGeometry(0.05,8,8),
new THREE.MeshBasicMaterial({color:0xffffff})
);
// this is silly.
// var bullet = models.pirateship.mesh.clone();
// position the bullet to come from the player's weapon
bullet.position.set(
meshes["playerweapon"].position.x + 0.0 ,
meshes["playerweapon"].position.y + 0.10,
meshes["playerweapon"].position.z + 0.1
);
// set the velocity of the bullet
bullet.velocity = new THREE.Vector3(
-Math.sin(camera.rotation.y),
0,
Math.cos(camera.rotation.y)
);
// after 1000ms, set alive to false and remove from scene
// setting alive to false flags our update code to remove
// the bullet from the bullets array
bullet.alive = true;
setTimeout(function(){
bullet.alive = false;
scene.remove(bullet);
}, 1000);
// add to scene, array, and set the delay to 10 frames
bullets.push(bullet);
scene.add(bullet);
player.canShoot = 10;
}
if(player.canShoot > 0) player.canShoot -= 1;
// position the gun in front of the camera
meshes["playerweapon"].position.set(
camera.position.x - Math.sin(camera.rotation.y + Math.PI/6) * 0.75,
camera.position.y - 0.5 + Math.sin(time*4 + camera.position.x + camera.position.z)*0.01,
camera.position.z + Math.cos(camera.rotation.y + Math.PI/6) * 0.75
);
meshes["playerweapon"].rotation.set(
camera.rotation.x,
camera.rotation.y - Math.PI,
camera.rotation.z
);
renderer.render(scene, camera);
}
function keyDown(event){
keyboard[event.keyCode] = true;
}
function keyUp(event){
keyboard[event.keyCode] = false;
}
window.addEventListener('keydown', keyDown);
window.addEventListener('keyup', keyUp);
window.onload = init;
Here is a fiddle with the code i have already developed:
https://jsfiddle.net/Mxfrd/bany0afg/
If someone have an idea how can i do that, it will be super ! i am very lost on that point.
Thanks

Draw dimension lines along with 3D cube using Three.js

Can we draw "lines" with Cube to show "Dimensions" at run time?
Here is how I have created the cube and getting dimensions from user and changing the cube at run time: http://jsfiddle.net/9Lvk61j3/
But now I want to show the Dimension, so the user knows what the length, width, and height is, which they will be changing.
This is what I am trying to make as end result:
Here is my code:
HTML:
<script src="http://www.html5canvastutorials.com/libraries/three.min.js"></script>
<div id="container"></div>
<div class="inputRow clear" id="dimensionsNotRound" data-role="tooltip">
<label class="grid-8">Dimensions (pixels):</label>
<br/>
<br/>
<div> <span>Length</span>
<input class="numeric-textbox" id="inp-length" type="text" value="100">
<br/>
<br/>
</div>
<div> <span>Width</span>
<input class="numeric-textbox" id="inp-width" type="text" value="50">
<br/>
<br/>
</div>
<div> <span>Height</span>
<input class="numeric-textbox" id="inp-height" type="text" value="40">
<br/>
<br/>
</div>
<button id="btn">Click me to change the Dimensions</button>
JS
var shape = null;
//Script for 3D Box
// revolutions per second
var angularSpeed = 0.2;
var lastTime = 0;
var cube = 0;
// this function is executed on each animation frame
function animate() {
// update
var time = (new Date()).getTime();
var timeDiff = time - lastTime;
var angleChange = angularSpeed * timeDiff * 2 * Math.PI / 1000;
//cube.rotation.y += angleChange; //Starts Rotating Object
lastTime = time;
// render
renderer.render(scene, camera);
// request new frame
requestAnimationFrame(function () {
animate();
});
}
// renderer
var container = document.getElementById("container");
var renderer = new THREE.WebGLRenderer();
renderer.setSize(container.offsetWidth, container.offsetHeight - 4);
container.appendChild(renderer.domElement);
// camera
var camera = new THREE.PerspectiveCamera(60, container.offsetWidth / container.offsetHeight, 1, 1000);
camera.position.z = 800;
// scene
var scene = new THREE.Scene();
scene.remove();
// cube
cube = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), new THREE.MeshLambertMaterial({
color: '#cccccc'
}));
cube.overdraw = true;
cube.rotation.x = Math.PI * 0.1;
cube.rotation.y = Math.PI * 0.3;
scene.add(cube);
// add subtle ambient lighting
var ambientLight = new THREE.AmbientLight(0x319ec5);
scene.add(ambientLight);
// directional lighting
var directionalLight = new THREE.DirectionalLight(0x666666);
directionalLight.position.set(1, 1, 1).normalize();
scene.add(directionalLight);
shape = cube;
// start animation
animate();
var $ = function(id) { return document.getElementById(id); };
$('btn').onclick = function() {
console.log("Button Clicked");
var width = parseInt(document.getElementById('inp-width').value * 3.779528),
height = parseInt(document.getElementById('inp-height').value * 3.779528),
length = parseInt(document.getElementById('inp-length').value * 3.779528);
console.log("length " + length + " height " + height + " width " + width);
shape.scale.x = length;
shape.scale.y = height;
shape.scale.z = width;
};
Here is the Fiddle for the same! http://jsfiddle.net/9Lvk61j3/
Let me know if you need any other information.
Please suggest.
There's a bit of a problem with drawing dimensions:
You may have many of them, and not all of them may be perfectly visible:
some may be hidden,
some may appear too small, if the camera is far away from the object,
some may overlay other dimensions (or even object elements),
some may be seen from inconvenient angle.
The text should retain perfectly same size, no matter how you navigate camera,
Most of these points are addressed in my solution: https://jsfiddle.net/mmalex/j35p1fw8/
var geometry = new THREE.BoxGeometry(8.15, 0.5, 12.25);
var material = new THREE.MeshPhongMaterial({
color: 0x09f9f9,
transparent: true,
opacity: 0.75
});
var cube = new THREE.Mesh(geometry, material);
cube.geometry.computeBoundingBox ();
root.add(cube);
var bbox = cube.geometry.boundingBox;
var dim = new LinearDimension(document.body, renderer, camera);
// define start and end point of dimension
var from = new THREE.Vector3(bbox.min.x, bbox.min.y, bbox.min.z);
var to = new THREE.Vector3(bbox.max.x, bbox.min.y, bbox.max.z);
// in which direction to "extrude" dimension away from object
var direction = new THREE.Vector3(0, 0, 1);
// request LinearDimension to create threejs node
var newDimension = dim.create(from, to, direction);
// make it cube child
cube.add(newDimension);
var animate = function() {
requestAnimationFrame(animate);
// we need to reposition dimension label on each camera change
dim.update(camera);
renderer.render(scene, camera);
};
Let's see into helper classes now.
✔ Dimension line is only visible when camera angle is not too sharp (more than 45°),
class FacingCamera will let you know world plane, that is best facing to the camera. Useful to hide dimensions, which are facing camera with too sharp (acute) angle.
Separate fiddle to play with class FacingCamera can be found here: https://jsfiddle.net/mmalex/56gzn8pL/
class FacingCamera {
constructor() {
// camera looking direction will be saved here
this.dirVector = new THREE.Vector3();
// all world directions
this.dirs = [
new THREE.Vector3(+1, 0, 0),
new THREE.Vector3(-1, 0, 0),
new THREE.Vector3(0, +1, 0),
new THREE.Vector3(0, -1, 0),
new THREE.Vector3(0, 0, +1),
new THREE.Vector3(0, 0, -1)
];
// index of best facing direction will be saved here
this.facingDirs = [];
this.bestFacingDir = undefined;
// TODO: add other facing directions too
// event listeners are collected here
this.cb = {
facingDirChange: []
};
}
check(camera) {
camera.getWorldDirection(this.dirVector);
this.dirVector.negate();
var maxk = 0;
var maxdot = -1e19;
var oldFacingDirs = this.facingDirs;
var facingDirsChanged = false;
this.facingDirs = [];
for (var k = 0; k < this.dirs.length; k++) {
var dot = this.dirs[k].dot(this.dirVector);
var angle = Math.acos(dot);
if (angle > -Math.PI / 2 && angle < Math.PI / 2) {
this.facingDirs.push(k);
if (oldFacingDirs.indexOf(k) === -1) {
facingDirsChanged = true;
}
if (Math.abs(dot) > maxdot) {
maxdot = dot;
maxk = k;
}
}
}
// and if facing direction changed, notify subscribers
if (maxk !== this.bestFacingDir || facingDirsChanged) {
var prevDir = this.bestFacingDir;
this.bestFacingDir = maxk;
for (var i = 0; i < this.cb.facingDirChange.length; i++) {
this.cb.facingDirChange[i]({
before: {
facing: oldFacingDirs,
best: prevDir
},
current: {
facing: this.facingDirs,
best: this.bestFacingDir
}
}, this);
}
}
}
}
✔ Dimension text is HTML element, styled with CSS and positioned with three.js raycasting logic.
class LinearDimension creates an instance of linear dimension with arrows and text label, and controls it.
LinearDimension complete implementation:
class LinearDimension {
constructor(domRoot, renderer, camera) {
this.domRoot = domRoot;
this.renderer = renderer;
this.camera = camera;
this.cb = {
onChange: []
};
this.config = {
headLength: 0.5,
headWidth: 0.35,
units: "mm",
unitsConverter: function(v) {
return v;
}
};
}
create(p0, p1, extrude) {
this.from = p0;
this.to = p1;
this.extrude = extrude;
this.node = new THREE.Object3D();
this.hidden = undefined;
let el = document.createElement("div");
el.id = this.node.id;
el.classList.add("dim");
el.style.left = "100px";
el.style.top = "100px";
el.innerHTML = "";
this.domRoot.appendChild(el);
this.domElement = el;
this.update(this.camera);
return this.node;
}
update(camera) {
this.camera = camera;
// re-create arrow
this.node.children.length = 0;
let p0 = this.from;
let p1 = this.to;
let extrude = this.extrude;
var pmin, pmax;
if (extrude.x >= 0 && extrude.y >= 0 && extrude.z >= 0) {
pmax = new THREE.Vector3(
extrude.x + Math.max(p0.x, p1.x),
extrude.y + Math.max(p0.y, p1.y),
extrude.z + Math.max(p0.z, p1.z));
pmin = new THREE.Vector3(
extrude.x < 1e-16 ? extrude.x + Math.min(p0.x, p1.x) : pmax.x,
extrude.y < 1e-16 ? extrude.y + Math.min(p0.y, p1.y) : pmax.y,
extrude.z < 1e-16 ? extrude.z + Math.min(p0.z, p1.z) : pmax.z);
} else if (extrude.x <= 0 && extrude.y <= 0 && extrude.z <= 0) {
pmax = new THREE.Vector3(
extrude.x + Math.min(p0.x, p1.x),
extrude.y + Math.min(p0.y, p1.y),
extrude.z + Math.min(p0.z, p1.z));
pmin = new THREE.Vector3(
extrude.x > -1e-16 ? extrude.x + Math.max(p0.x, p1.x) : pmax.x,
extrude.y > -1e-16 ? extrude.y + Math.max(p0.y, p1.y) : pmax.y,
extrude.z > -1e-16 ? extrude.z + Math.max(p0.z, p1.z) : pmax.z);
}
var origin = pmax.clone().add(pmin).multiplyScalar(0.5);
var dir = pmax.clone().sub(pmin);
dir.normalize();
var length = pmax.distanceTo(pmin) / 2;
var hex = 0x0;
var arrowHelper0 = new THREE.ArrowHelper(dir, origin, length, hex, this.config.headLength, this.config.headWidth);
this.node.add(arrowHelper0);
dir.negate();
var arrowHelper1 = new THREE.ArrowHelper(dir, origin, length, hex, this.config.headLength, this.config.headWidth);
this.node.add(arrowHelper1);
// reposition label
if (this.domElement !== undefined) {
let textPos = origin.project(this.camera);
let clientX = this.renderer.domElement.offsetWidth * (textPos.x + 1) / 2 - this.config.headLength + this.renderer.domElement.offsetLeft;
let clientY = -this.renderer.domElement.offsetHeight * (textPos.y - 1) / 2 - this.config.headLength + this.renderer.domElement.offsetTop;
let dimWidth = this.domElement.offsetWidth;
let dimHeight = this.domElement.offsetHeight;
this.domElement.style.left = `${clientX - dimWidth/2}px`;
this.domElement.style.top = `${clientY - dimHeight/2}px`;
this.domElement.innerHTML = `${this.config.unitsConverter(pmin.distanceTo(pmax)).toFixed(2)}${this.config.units}`;
}
}
detach() {
if (this.node && this.node.parent) {
this.node.parent.remove(this.node);
}
if (this.domElement !== undefined) {
this.domRoot.removeChild(this.domElement);
this.domElement = undefined;
}
}
}

Categories

Resources