Disable collision of body in Cannon.js - javascript

I have a bunch of planes that fit together to form terrain. Each individual plane has it's own cannon.js body (I use three.js for rendering visuals) for collision. Due to memory constraints I de-render each object when the player moves to far away from the object. I can de-render objects easily in three.js just by turning them invisible, but there's no clear way to do this in cannon.js. Basically I want to disable a cannon.js object without deleting it outright.
I've already looked through the docs and there's basically nothing on how to do this. I've also seen no questions on any form on this topic.
Example code below to show you how I want to implement this.
//terrain generation
for (z=0; z<6; z++) {
for (x=0; x<6; x++) {
//cannon.js hitbox creation
var groundShape = new CANNON.Box(new CANNON.Vec3(2,0.125,2));
var groundBody = new CANNON.Body({ mass: 0, material: zeromaterial});
groundBody.addShape(groundShape);
groundBody.position.set(x*4,0,z*4);
world.addBody(groundBody);
maparray.push(groundBody);
//three.js plane creation
grassmesh = new THREE.Mesh(grassgeometry, grassmaterial);
grassmesh.castShadow = true;
grassmesh.receiveShadow = true;
grassmesh.position.set(x*4,0,z*4);
scene.add(grassmesh);
maparray.push(grassmesh);
}
}
...
function animate() {
//detect if player is outside of loadDistance of object
for(i=0; i<maparray; i++){
if(Math.abs(maparray[i].position.x - player.position.x) <
loadDistance && Math.abs(maparray[i].position.z -
player.position.z) < loadDistance) {
//code here magically turns off collisions for object.
}
}
}
animate();

To exclude a CANNON.Body from the simulation, run the following:
world.removeBody(groundBody);
To add it back again, run:
world.addBody(groundBody);
It’s perfectly fine to remove and add it back like this. It will help you get better performance when running word.step().

Related

three.js: How can I target object's position to another (grouped) object, while allowing rotation to follow AR camera?

I'm using an augmented reality library that does some fancy image tracking stuff. After learning a whole lot about this project, I'm now beyond my current ability and could use some help. For our purposes, the library creates an (empty) anchor point at the center of an IRL image target in-camera. Then moves the virtual world around the IRL camera.
My goal is to drive plane.rotation to always face the camera, while keeping plane.position locked to the anchor point. Additionally, plane.rotation values will be referenced later in development.
const THREE = window.MINDAR.IMAGE.THREE;
document.addEventListener('DOMContentLoaded', () => {
const start = async() => {
// initialize MindAR
const mindarThree = new window.MINDAR.IMAGE.MindARThree({
container: document.body,
imageTargetSrc: '../../assets/targets/testQR.mind',
});
const {renderer, scene, camera} = mindarThree;
// create AR object
const geometry = new THREE.PlaneGeometry(1, 1.25);
const material = new THREE.MeshBasicMaterial({color: 0x00ffff, transparent: true, opacity: 0.5});
const plane = new THREE.Mesh(geometry, material);
// create anchor
const anchor = mindarThree.addAnchor(0);
anchor.group.add(plane);
// start AR
await mindarThree.start();
renderer.setAnimationLoop(() => {
renderer.render(scene, camera);
});
}
start();
});
Everything I've tried so far went into the solutions already massaged into the (functioning draft) code. I have, however, done some research and found a couple avenues that might or might not work. Just tossing them out to see what might stick or inspire another solution. Skill-wise, I'm still in the beginner category, so any help figuring this out is much appreciated.
identify plane object by its group index number;
drive (override lib?) object rotation (x, y, z) to face camera;
possible solutions from dev:
"You can get those values through the anchor object, e.g. anchor.group.position. Meaning that you can use the current three.js API and get those values but without using it for rendering i.e. don't append the renderer.domElement to document."
"You can hack into the source code of mindar (it's open source)."
"Another way might be easier for you to try is to just create another camera yourself. I believe you can have multiple cameras, and just render another layer on top using your new camera."
I think it may be as simple as calling lookAt in the animation loop function:
// start AR
await mindarThree.start();
renderer.setAnimationLoop(() => {
plane.lookAt(new THREE.Vector3());
renderer.render(scene, camera);
});
This assumes the camera is always located at (0,0,0) (i.e., new THREE.Vector3()). This seems to be true from my limited testing. I found it helpful to debug by copy-pasting the MindAR three.js example into this codepen and printing some relevant values to the console.
Also note that, internally, MindAR's three.js module seems to directly modify the world matrix of the anchor.group object without modifying the position/rotation/scale parameters.

Three.js adding a rigged, animated Asset to an existing Scene

I'm working on a Tamagotchi like browser app in three.js at the moment. But currently I'm stuck with implementing a hand, that pets the avatar when clicked.
The Hand is a rigged Blender model with 2 animations, idle and the poking animation. In the gltf Viewer the model works fine with both animations.
But when added in js, the hand is either completely distorted, or rendered correctly but, positions aren't recognized(for movement with the cursor).
Most of the examples I looked at only added a general scene, but not just one animated model. In both versions of those animations, I get an animation error.
Code for the distorted version:
loader.load('resources/models/gltf/Hand.gltf', function(gltf) {
gltf.scene.traverse(function(node) {
if (node.isMesh) hand = node;
});
//hand.material.morphTargets = true;
scene.add(hand);
mixer = new THREE.AnimationMixer(hand);
clips = hand.animations;
hand = gltf;
scene.add(hand.scene);
});
The second version, where the Hand is rendered correctly, but positions for event handling aren't recognized.
loader.load('resources/models/gltf/Hand.gltf', function(gltf) {
var hand = gltf.scene;
var animations = gltf.animations;
mixer = new THREE.AnimationMixer(hand);
for (var i = 0; i < animations.length; i++) {
mixer.clipAction(animations[i]).play();
}
scene.add(hand);
});
function for idle animation:
function idleAnim() {
var idleClip = THREE.AnimationClip.findByName(clips, "Idle");
var action = mixer.clipAction(idleClip);
action.play();
console.log("idling");
}
Link: https://github.com/JoeJoe49/AnimTest
Thanks in advance and greetings.
In your first example, you're pulling the "hand" object out of your import scene, adding it to your render scene, Then adding the rest of the import scene to your render scene.
My guess is that you need to pull out "hand" from higher in the hierarchy. It probably has a few parent objects that need to come along with to preserve the correct hierarchy for the animation.
It's worth doing a scene.traverse((o)=>{console.log(o)} to get a clear picture of how your scene is being exported. I've found with the blender gltf exporter for instance, there are usually 2 separate parent nodes, one for positioning and one for scaling+rotation, so.. it's worth looking at because it might not be exactly what you expect.
fwiw I grabbed your repo and opened the gltfs in my model previewer, but I didn't seem to see any animations on them. My previewer is set to play all animations it finds, in sequence.. so not sure what's going on there. I'm guessing these are skinnedmeshes and not morphtargets?

Cesium - why is scene.pickPositionSupported false

I'm ultimately trying to draw a polygon on top of my house. I can do that.
The problem is that on zoom-out, zoom-in, and rotation (or camera move) the polygon doesn't stick to the top of my house. I received great help from this answer. So, now I'm trying to go through the sample code but there is a lot of Cesium methods and functionality that I need to learn.
The sample code I am trying to follow is located in the gold standard that appears to be baked into the existing camera controller here.
I call testMe with the mousePosition as Cartesian3 and the SceneMode is 3D, so pickGlobe is executed.
Here is my code:
var pickedPosition;
var scratchZoomPickRay = new Cesium.Ray();
var scratchPickCartesian = new Cesium.Cartesian3();
function testMe(mousePosition) {
if (Cesium.defined(scene.globe)) {
if(scene.mode !== Cesium.SceneMode.SCENE2D) {
pickedPosition = pickGlobe(viewer, mousePosition, scratchPickCartesian);
} else {
pickedPosition = camera.getPickRay(mousePosition, scratchZoomPickRay).origin;
}
}
}
var pickGlobeScratchRay = new Cesium.Ray();
var scratchDepthIntersection = new Cesium.Cartesian3();
var scratchRayIntersection = new Cesium.Cartesian3();
function pickGlobe(viewer, mousePosition, result) {
var globe = scene.globe;
var camera = scene.camera;
if (!Cesium.defined(globe)) {
return undefined;
}
var depthIntersection;
if (scene.pickPositionSupported) {
depthIntersection = scene.pickPosition(mousePosition, scratchDepthIntersection);
}
var ray = camera.getPickRay(mousePosition, pickGlobeScratchRay);
var rayIntersection = globe.pick(ray, scene, scratchRayIntersection);
var pickDistance;
if(Cesium.defined(depthIntersection)) {
pickDistance = Cesium.Cartesian3.distance(depthIntersection, camera.positionWC);
} else {
pickDistance = Number.POSITIVE_INFINITY;
}
var rayDistance;
if(Cesium.defined(rayIntersection)) {
rayDistance = Cesium.Cartesian3.distance(rayIntersection, camera.positionWC);
} else {
rayDistance = Number.POSITIVE_INFINITY;
}
var scratchCenterPosition = new Cesium.Cartesian3();
if (pickDistance < rayDistance) {
var cart = Cesium.Cartesian3.clone(depthIntersection, result);
return cart;
}
var cart = Cesium.Cartesian3.clone(rayIntersection, result);
return cart;
}
Here is my problem:
Here is the result:
Here are my questions to get this code working:
1. How do I get the scene.pickPositionSupported set to true? I'm using Chrome on Windows 10. I cannot find in the sample code anything about this and I haven't had much luck with the documentation or Google.
2. Why is rayIntersection not getting set? ray and scene have values and scratchRayIntersection in an empty Cartesian3.
I think if I can get those two statements working, I can probably get the rest of the pickGlobe method working.
WebGLGraphics Report:
I clicked on Get WebGL and the cube is spinning!
Picking positions requires that the underlying WebGL implementation support depth textures, either through the WEBGL_depth_texture or WEBKIT_WEBGL_depth_texture extensions. scene.pickPositionSupported is returning false because this extension is missing. You can verify this by going to http://webglreport.com/ and looking at the list of extensions; I have both of the above listed there. There is nothing you can do in your code itself to make it suddenly return true, it's a reflection of the underlying browser.
That being said, I know for a fact that Chrome supports the depth texture and it works on Windows 10, so this sounds like a likely video card driver issue. I full expect downloading and installing the latest drivers for your system to solve the problem.
As for rayIntersection, from a quick look at your code I only expect it to be defined if the mouse is actually over the globe, which may not always be the case. If you can reduce this to a runnable Sandcastle example, it would be easier for me to debug.
OK. So it turned out that I had a totally messed up Cesium environment. I had to delete it and reinstall it in my project (npm install cesium --save-dev). Then I had to fix a few paths and VOILA! It worked. Thanks to both of you for all your help.

Phaser - How to properly implement Arcade Physics Collisions with Phaser.js

I've scanned the web for some tutorials and looked at the documentation but it just seems to get me more confused.
The problem:
All sprites have their physics initialised in this code:
// Store all Sprites in an Array for easy access
var x64_guys = [Player, Dave, EvilDave];
// Sprite physics properties. Give the little guys some life.
hal.physics.arcade.enable(x64_guys, Phaser.Physics.ARCADE);
for(var j=0; j<x64_guys.length;j++){
x64_guys[j].body.collideWorldBounds = true;
x64_guys[j].body.bounce.x = true;
x64_guys[j].body.bounce.y = true;
}
Where hal is equal to new Phaser.Game(window.innerWidth, window.innerHeight, Phaser.AUTO, "stage", { preload: preload, create: create, update: update });
Now I am assuming this works fine to initialise physics like this?
If so then I am rather confused on how to detect Player and EvilDave collisions, and also launch a function on collide (e.g. Player death or EvilDave getting hurt). (Chars are 64x64 pixels)
If anyone could help me I'd be grateful.
Are Player, EvilDave, etc instances of Sprites? You don't show the code so it's hard to be sure.
The call to enable physics should be like this:
hal.physics.arcade.enable(x64_guys);
Although I would get out of the practise of using 'hal' at all and instead use 'this'. You don't need the constant as the 2nd argument because you're enabling direct on the Arcade Physics manager anyway.
Is all of the above code happening in the create function? If not, it should be.
This is also wrong: body.bounce.x = true; Bounce is a Phaser.Point object, not a boolean, so it expects a value to be assigned to it. If you want to enable 100% fully reflective bouncing then set it to 1: body.bounce.x = 1;
To check collision between Player and EvilDave you need to add this to your update function:
function update() {
// object1, object2, collideCallback, processCallback, callbackContext
game.physics.arcade.collide(Player, EvilDave, collisionHandler, null, this);
}
function collisionHandler (obj1, obj2) {
// The two sprites are colliding
game.stage.backgroundColor = '#992d2d';
}
You can see the full code for this in the Sprite vs. Sprite example on the site. Would be well worth looking over that carefully.

Three.js skinned animation mesh disappears when material skinning is true

I've exported an animated model from Blender which doesn't seem to have any issue instantiating. I'm able to create the THREE.Animation and model, but I was finding there was no animation. I realized I needed to set skinning true on each material, but when I do that the entire mesh goes missing.
Below is my (quick and messy) code trying to get everything to work.
function loadModel() {
var loader = new THREE.JSONLoader();
loader.load('assets/models/Robot.js', function(geom, mat) {
_mesh = new THREE.Object3D();
_scene.add(_mesh);
geom.computeBoundingBox();
ensureLoop(geom.animation);
THREE.AnimationHandler.add(geom.animation);
for (var i = 0; i < mat.length; i++) {
var m = mat[i];
//m.skinning = true; <-- Uncommenting this makes the model disappear
//m.morphTargets = true; <-- This causes all sorts of WebGL warnings
m.wrapAround = true;
}
var mesh = new THREE.SkinnedMesh(geom, new THREE.MeshFaceMaterial(mat));
mesh.scale.set(400, 400, 400);
mesh.position.set(0, -200, 0);
mesh.rotation.set(Utils.toRadians(-90), 0, 0);
_mesh.add(mesh);
_robot = mesh;
Render.startRender(loop);
var animation = new THREE.Animation(mesh, geom.animation.name);
animation.JITCompile = false;
animation.interpolationType = THREE.AnimationHandler.LINEAR;
animation.play();
});
}
I believe I'm updating the AnimationHandler correctly in my loop
function loop() {
_mesh.rotation.y += 0.01;
var delta = 0.75 * _clock.getDelta();
THREE.AnimationHandler.update(delta);
}
In the section metadata of the exported JSON file the number of morphTargets and bones are both greater than 0?
I think that you followed the example here:
http://threejs.org/examples/#webgl_animation_skinning_morph
in which the animated model uses Morph Target and Skeletal Animation (see Wikipedia for the theoretical concepts).
If the animated model uses only Skeletal Animation as in this example http://alteredqualia.com/three/examples/webgl_animation_skinning_tf2.html
you have to instantiate a THREE.SkinnedMesh Object and then set only the m.skinning property to true.
I was having the same problem just now. What worked for me was to remake the model with applied scale and have keyframes for LocRotScale, not just location.
lately, I've encoutered a similar issue of mesh disapearing while exporting blender skinning animation to json. It turned out, the mesh I was using had double vertex (one vertice hidding another). All looks good While creating the vertex groups and the animations in blender, but when I imported the mesh via three.js, it kept disapearing as soon as the animation started. In other words, If 1 vertice from your mesh is omitted from the vertex groups, you will experience this disapearing behavior. To prevent this issue, I now use the "remove doubles" function from blender to validate the mesh integrity before exporting it to json. You might have encountered the same issue and redoing your mesh work fix it... Anyways, the question is pretty old, but the topic is still valid as of today, so I hope this fresh info will help someone out there...
Peace INF1

Categories

Resources