Physijs collision events - javascript

I have two boxes. One spawns on the ground and the other is dropped on top of it. Gravity is turned on. I am trying to get the collision event listener to fire on the bottom box which is resting on the ground. However, nothing is logged.
var c = new Physijs.BoxMesh( new THREE.CubeGeometry( 5, 5, 5 ), new THREE.MeshBasicMaterial({ color: 0x888888 }) );
c.__dirtyPosition = true;
c.position.set(10, 0,-5);
c.addEventListener('collision', function(object){
console.log("hello world"); // NOT FIRING
});
scene.add(c);
var p = c.clone();
p.__dirtyPosition = true;
p.position.y = 50;
scene.add(p);
I can't figure out what I'm doing wrong - could it be because of __dirtyPosition?
EDIT: I tested it without clone() and creating the second box anew, but it doesn't make a difference.
EDIT 2: It's worth mentioning that the simulation runs fine I just can't get the listener to work.

Relevant GitHub Issue
It looks like the clone method is part of THREEjs, not Physijs. So your code just clones the physical material, not the physical mesh. You're just going to have to create another BoxMesh using the same code you did for c.

Related

How to play a tween animation on key press multiple times

I am trying to make a robot that can perform certain animations when keys are pressed.
When I press the "J" key I would like the robot to jump up and down.
I am using Three.js and Tween.js to accomplish this. So far I have a scene made with light and a camera. I am creating the different parts of the robot through functions. I have an example of one of these functions below.
function createHead() {
const head = new THREE.Mesh( new THREE.BoxGeometry(30, 30, 30),
new THREE.MeshLambertMaterial({ color: 0x669999 }));
head.position.y = 30;
head.position.z = -250;
head.rotation.y = 5;
scene.add(head);
var jumpTween = new TWEEN.Tween(head.position).to({y: head.position.y+20}, 1000).repeat(1).yoyo(true).start();
}
Here is my function for updating
function update (event) {
if (String.fromCharCode(event.keyCode) == "J" || isJumping)
{
isJumping = true;
TWEEN.update();
}
// Draw!
renderer.render(scene, camera);
// Schedule the next frame.
requestAnimationFrame(update);
}
When I press "J" my robot jumps once and only once. I cannot press "J" again to get the robot to perform another jump. I was hoping there would be away to just simply "call" a tween on command and have it play on command. However, it seems like TWEEN.update() is the only function that actually runs the tween and in this case, it only runs once. I have been reading the documentation for Tween.js but I am not finding anything helpful.
Edit: I have also tried adding this to my tween.
.onComplete(() => {isJumping = false})
so that it would set isJumping back to false when the animation completes but this did not work.
Thanks for the help.

In A-Frame: How do I get the VR camera

In this example:
https://glitch.com/~query-aframe-cameras
I have registered a component which launches a projectile in the direction the user is looking (with a little boost for elevation)
Spacebar or Screen Tap to launch - be sure to be looking above the horizon!
It fails in mobile vr (stereo camera) mode:
Projectiles continue to fire, but from the default orientation of the mono, not the stereo camera
I'm using:
var cam = document.querySelector('a-scene').camera.el.object3D;
var camVec = new THREE.Vector3();
var camDir = cam.getWorldDirection(camVec);
to get the camera information and spit the projectiles back
QUERY:
HOW DO I GET THE STEREO CAMERA INFORMATION
The problem will be due to this bug in THREE.js.
https://github.com/mrdoob/three.js/issues/18448
Following the documented workaround, the code here works with correct direction tracking on my Quest 2.
https://cuddly-endurable-soap.glitch.me
(there's a couple of other changes in here: to test this on my VR headset I also had to upgrade to A-Frame 1.1.0, and make the code fire the balls on a timer, since I don't have any keys to press when using it! Neither of these was enough to fix the problem, though).
This code will set up CamDir as you need it.
var camQ = new THREE.Quaternion();
cam.updateMatrixWorld();
camQ.setFromRotationMatrix(cam.matrixWorld);
var camDir = new THREE.Vector3(0, 0, 1);
camDir.applyQuaternion(camQ);
The following code also works (and is more efficient), but is less easy to understand.
var camDir = new THREE.Vector3();
var e = cam.matrixWorld.elements;
camDir.set(e[ 8 ], e[ 9 ], e[ 10 ]).normalize();
I picked it up from here:
https://lace-fern-ghost.glitch.me/
Which I found a link to from here:
https://github.com/aframevr/aframe/issues/4412
(but I can't find any reference to explain why these components matrixWorld.elements are the right ones to use here to get the direction).

How do you implement drag controls in the AutoDesk forge viewer?

I am trying to implement drag controls on this text geometry that I am creating in the viewer. I create the text like so:
createText(params) {
const textGeometry = new TextGeometry(params.text,
Object.assign({}, {
font: new Font(FontJson),
params
}));
const geometry = new THREE.BufferGeometry;
geometry.fromGeometry(textGeometry);
const material = this.createColorMaterial(
params.color);
const text = new THREE.Mesh(
geometry, material);
text.scale.set(params.scale, params.scale, params.scale);
text.position.set(
params.position.x,
params.position.y,
10);
this.intersectMeshes.push(text);
this.viewer.impl.scene.add(text);
this.viewer.impl.sceneUpdated(true);
return text;
}
This works great, the meshes get added to the viewer, I can see them. Fantastic! Thus far, it is good. Now, I want to be able to drag them around with my mouse after I have added them. I noticed that Three.js already has drag controls built in, so I just implemented them like so:
enableDragging(){
let controls = new THREE.DragControls( this.viewer, this.viewer.impl.camera.perspectiveCamera, this.viewer.impl.canvas );
controls.addEventListener( 'dragstart', dragStartCallback );
let startColor;
controls.addEventListener( 'dragend', dragendCallback );
function dragStartCallback(event) {
startColor = event.object.material.color.getHex();
event.object.material.color.setHex(0x000000);
}
function dragendCallback(event) {
event.object.material.color.setColor(startColor);
}
}
After a big of debugging, I have seen where the problem occurs. For some reason, when I click on one of the meshes, the raycaster doesn't find any intersections. I.E. the array I get back is empty. No matter where I click on these objects.
Is my implementation wrong, or did I provision these meshes wrong to make them draggable? I have gotten the drag controls to work outside of the viewer, just not within it.
This will not work, looking at the code of DragControls, the viewer implementation is too different in the way it implements the camera. You would need to either implement a custom version of DragControls or take a look at my transform tool and adapt it for custom meshes:
Moving visually your components in the viewer using the TransformTool

Three.js r89 memory leak with STL models

I'm having a bit of trouble with a page I'm building. I think it's fairly simple, but I'm quickly running into issues from what I think is a memory leak.
First off, I've spent the majority of the day searching for an answer, so if I've missed something obvious I'm sorry, I promise I tried. Everything I've found has pointed me to the method I'm currently using, I'm at a loss now.
I have 30 STL models, all 120kb or less that I swap between. Only 3 are on screen at a time and the viewer can swap them out to customize the complete model.
I currently change the colors of the models using:
var selectedObject = scene.getObjectByName(object);
newMaterial = '#'+matHex[newMaterial-1];
newMaterial = hexToRgb(newMaterial);
selectedObject.material.color = newMaterial;
That part works just fine and doesn't seem to slow anything down.
When it comes to replacing the model I use:
var mesh = scene.getObjectByName(object);
if (mesh instanceof THREE.Mesh)
{
scene.remove(mesh);
mesh.geometry.dispose();
mesh.geometry = null;
mesh.material.dispose();
mesh.material = null;
mesh = null;
}
After that I call a function that adds the model back into the scene:
function addHandle(){
loader.load( stlPath+'Handle'+handleID+'.stl', function ( geometry ) {
material = '0x'+matHex[handleMat-1]; //set color hex from array
var handleMaterial = new THREE.MeshPhongMaterial( { color: parseInt(material), specular: specular, shininess: shininess } );
var handleMesh = new THREE.Mesh( geometry, handleMaterial );
handleMesh.position.set( 0, 0, 0 );
handleMesh.rotation.set( Math.PI/2, - Math.PI/2, 0 );
handleMesh.scale.set( .008, .008, .008 );
handleMesh.name = "Handle";
handleMesh.id = handleID;
handleMesh.castShadow = true;
handleMesh.receiveShadow = true;
scene.add( handleMesh );
updateHandle(); //check if Handle needs to rotate
} );
}
From everything I have been able to find this is the proper method for disposing of meshes but after running through about a dozen of them the camera rotation starts to slow down, it takes slightly longer to load the next model, etc. It's especially noticeable on mobile devices.
Hopefully someone out there is able to notice something obvious that I'm missing, it would be hugely appreciated!
I think I solved the problem, and it was my fault like I suspected. I discovered that I was calling animate(); every time a model was replaced. After removing those it is running much much smoother. I'll report back if it ends up not being fixed!

Babylon.js OnIntersectionEnterTrigger not triggering with camera

I'm using Babylon.js 2.4.0.
I have a mesh (in the shape of a couch) loaded from a .obj file, and a camera set up like this:
let camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 2, 0), scene);
camera.checkCollisions = true;
camera.applyGravity = true;
camera.ellipsoid = new BABYLON.Vector3(1, 1, 1);
camera.attachControl(canvas, false);
camera.speed = 0.5;
camera.actionManager = new BABYLON.ActionManager(scene);
I want to set up an event so that when I walk through the couch, "intersection" is logged to the console:
let action = new BABYLON.ExecuteCodeAction(
{ trigger: BABYLON.ActionManager.OnIntersectionEnterTrigger, parameter: { mesh: couchMesh }},
(evt) => {
console.log("intersection");
}
);
this.camera.actionManager.registerAction(action);
When I walk through the mesh, nothing is logged to the console.
I've created an example on the Babylon.js Playground using an example that they provide to check that it wasn't a problem with my mesh or camera set up, and it doesn't appear to be (the playground doesn't work either).
A camera in Babylon.js has no action manager, so even if you set one it won't really work.
To get this to work using action managers, you could define an invisible box around the camera, with a predefined size and attach the action manager to the mesh created. then set the mesh's parent to be the camera, and you are done. Here is your playground with those changes - http://www.babylonjs-playground.com/#KNXZF#3
Another solution is to use the internal collision system of babylon js, and set the camera's onCollide function to actually do something :) Here is en example - http://www.babylonjs-playground.com/#KNXZF#4
Notice that in the second playground, the camera won't go throug the box, as the collision system prevents it from doing so. I am not sure about your usecase, so it is hard to say which one of the two will work better.
If you need a "gate" system (knowing when a player moved through a gate, for example), use the 1st method. The 2nd is much cleaner, but has its downsides.

Categories