In this example: https://threejs.org/examples/games_fps.html
This line adds an object to the octree: worldOctree.fromGraphNode( gltf.scene );
Let's say I spawn a player body, it gets fragged and I want to remove that object from the worldOctree, so that it doesn't participate in collisions anymore. How do I remove an object from the octree?
Related
Skeletal animation issue (always plays default T-pose (keyframe 0) in (looped) animations using AnimationAction.play()).
Animations are imported from an .FBX file with a skeleton and animations using the FBXLoader.
I've trimmed the AnimationClip.tracks array() to remove the first keyframe(s), but it keeps including the base keyframe 0 T-pose during animations.
I tried emptying the AnimationClip.tracks array. If I then play() the associated AnimationAction, it still sets up some pose, suggesting the problem might not lie in the AnimationClip at all, but rather in parent Action/Mixer.
I've also tried offsetting the AnimationAction using "startAt(0.0333..)". But it still adds in the base pose during play().
//setup mixer for object
scene.mixer = new THREE.AnimationMixer( scene.obj );
// actions array (quick reference)
scene.actions = [];
for (i in scene.obj.animations) {
scene.actions.push(scene.mixer.clipAction(scene.obj.animations[ i ] ));
// offset keyframe 0 (doesnt work since it still uses the keyframe 0 "T-pose" when the animation has finished playing and optionally loops)
scene.actions[i].startAt(0.0334);
// tried trimming with subClip fn, but again it'll throw in the T-pose.
subClip(scene.actions[3].getClip(), 0.03333333432674409 /* 30 fps: skip first frame # 0.03333333432674408 */, 2);
// emptying the tracks array also doesnt work, since its still setting bones when I play/stop the AnimationAction.
scene.actions[3].getClip().tracks = [];
scene.actions[3].getClip().resetDuration();
}
function subClip(clip, start, end) {
for (i in clip.tracks) {
var track = clip.tracks[i];
// (we depend on internal behaviour of trim() which uses Array.slice,
// and doesn't modify the original array).
clip.tracks[i].trim(start, end);
// Once trim has been called, our track now has its own copies of
// times/values, and no shared data. It's now safe to modify in-place,
// which shift() does.
clip.tracks[i].shift(-start);
}
// after modifying (key)frames, reset duration to new length
clip.resetDuration();
}
I expect none of the keyframe 0 data to be used during animations. Especially on loop: they quite visibly stutter. (because of the jump in position + strange interpolation to the next pose).
Solved this by exporting all animations into one large model file instead of a seperate file for every animation. Afterwards you can manually cut them up into seperate clips and it'll work just fine.
I'm fairly new to three.js and trying to get a better understanding of ray casting. I have used it so far in a game to show when an object collides with another on the page which works perfectly. In the game I'm building this is to take health from the hero as it crashes into walls.
I am now trying to implement a target which when hovered over some objects it will auto shoot. However the target only registers a target hit once the object passes through the target mesh rather than when its ray is cast through it.
to further detail this, the ray is cast from the camera through the target, if the target is on a mesh (stored as an object array) then I want it to trigger a function.
within my update function I have this:
var ray = new THREE.Raycaster();
var crossHairClone = crossHair.position.clone();
var coards = {};
coards.x = crossHairClone.x
coards.y = crossHairClone.y
ray.setFromCamera(coards, camera);
var collisionResults = ray.intersectObjects( collidableMeshList );
if ( collisionResults.length > 0 ) {
console.log('Target Hit!', collisionResults)
}
The console log is only triggered when the collidableMeshList actually touches the target mesh rather than when it is aiming at it.
How do I extend the ray to pass through the target (which I thought it was already doing) so that if anything hits the ray then it triggers my console log.
Edit
I've added a URL to the game in progress. There are other wider issues with the game, my current focus is just the target ray casting.
Game Link
Many thanks to everyone who helped me along the way on this one but I finally solved it, only not through the means that I had expected to. Upon reading into the setFromCamera() function it looks like it is mainly used around mouse coards which in my instance was not what I wanted. I wanted a target on the page and the ray to pass through this. For some reason my Ray was shooting vertically up from the centre of the whole scene.
In the end I tried a different approach and set the Rays position and direction directly rather rely on setting it from the cameras position.
var vector = new THREE.Vector3(crossHair.position.x, crossHair.position.y, crossHair.position.z);
var targetRay = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var enemyHit = targetRay.intersectObject( enemy );
if ( enemyHit.length > 0 ) {
console.log('Target Hit!', targetRay)
}
I'll leave this up for a while before accepting this answer in case anyone has a better approach than this or has any corrections over what I have said in regards to setFromCamera().
I am writing a component that needs to access and modify position, normal, and uv attributes on a model read into A-Frame as an asset. I can get close to accessing the data, but can't quite get there. Using:
document.querySelector('a-entity').object3D.children
seems to give me an array, but trying to access the elements gives me an object with empty children and empty geometry.
My guess is that I'm trying to access the data through the wrong door and while:
console.log(document.querySelector('a-entity').object3D.children);
shows me an array size=1 with a populated Object element
console.log(document.querySelector('a-entity').object3D.children[0]);
gives me the element with the empty geo, etc. What is the right mechanism or syntax to use to get at the data?
There are two three.js classes you'll need to know about here: Geometry and BufferGeometry. The former already has properties for geometry.vertices and geometry.faces (see documentation there). Vertices are an array of THREE.Vertex3 objects, and easy to work with.
If you have a BufferGeometry, then instead you have geometry.attributes.position which is not an array of THREE.Vertex3, but instead contains a flat array of floats, like [x1, y1, z1, x2, y2, ...]. This is more efficient, but harder to modify manually.
If you have BufferGeometry but would rather work with Geometry, then you can convert either way:
var geometry = Geometry.fromBufferGeometry( mesh.geometry );
mesh.geometry = BufferGeometry.fromGeometry( geometry );
An A-Frame specific note, usually you'll get a reference to the mesh by doing el.getObject3D('mesh'). For custom models that might be a nested group, in which case:
el.object3D.traverse(function(node) {
if (node.geometry) { /* ... */ }
});
(three.js r84)
I think the problem might be because it's a loaded object and not a "created" geometry, but I want to be able to select an object and show that it is selected, like in this example.
I load multiple objects in and I keep track of an index for each object (so the first object loaded has objIndex = 0, etc.) and I know that my code recognizes when I "mouse down" from the console. However, it says that intersects.length = 0 so the rest of the function is skipped.
I'm also not sure what "intersects.length" is actually taking the length of.
So I suppose my questions are:
What is "intersects.length" taking the length of?
Why do my objects have an "intersects.length" of 0?
What are some things I could do so that the objects are recognized?
Here's the relevant code:
function onDocumentMouseDown(event) {
event.preventDefault();
// default action of event will not be triggered
var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5).unproject(camera);
// used to pass 3D positions and directions
var raycaster = new THREE.Raycaster(camera.position,
vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(objects);
console.log('Mouse is down.');
console.log(intersects.length);
if (intersects.length > 0) {
controls.enabled = false;
SELECTED = intersects[0].object;
var intersects = raycaster.intersectObjects(plane);
offset.copy(intersects[0].point).sub(plane.position);
container.style.cursor = 'move';
console.log('Clicked object: ' + object.name);
}
}
If you need to see more, let me know! Thank you. :)
Answering your question:
Here is an interesting read on raycast to help clarify raycasting:
http://soledadpenades.com/articles/three-js-tutorials/object-picking/
So what raycasting basically do is to (really) cast an imaginary ray. When you "mouse down" your program will, so called, cast a straight-line array into the scene. Now to answer your question:
For question one(1) and two(2) : Now when you cast a ray, it may or may not intersect an object. For example if you click into an empty space, the ray will not catch an object. However, as the name suggest, a raycast cast a ray and it may also hits multiple objects along the way. For example if you have one object and another object positioned directly behind the first object, casting a ray into the first object will also intersects the second object. The ray cast will "catch" both objects and put in the two objects into into the array "intersects". Therefore, the command
if (intersects.length > 0)
stated that if the raycast "catches" and object, do these. Moreover, it keeps on calling intersects[0] to refer to the first objects in the intersects array. In this case the most front object that the raycast catches. You can test my answer by creating hundreds of objects and state that, for every member in the intersects array, you change the color to red(for example). You will see that if the raycast catches multiple objects, all the objects will turn into that color. Hope for the first two question!
I am not sure of what you are asking for the third question. Can you clarify further? One way for the object to be recognized is to put them into the scene and put a raycast on the scene. However, I am not too sure of what you are asking to give you answer that I think you want.
G'day all,
In short, I'm using a for loop to create a bunch of identical sprites that I want to bounce around the screen. The problem is how do I write a collision detection process for the sprites. I have used the process of placing rectangles around sprites and using the .intersects method for rectangles but in that case I created each sprite separately and could identify each one uniquely. Now I have a bunch of sprites but no apparent way to pick one from another.
In detail, if I create an object called Bouncer.cs and give it the movement instructions in it's update() method then create a bunch of sprites using this in Game.cs:
for (int i = 1; i < 5; ++i)
{
Vector2 position = new Vector2(i * 50, i * 50);
Vector2 direction = new Vector2(i * 10, i * 10);
Vector2 velocity = new Vector2(10);
Components.Add(new Bouncer(this, position, direction, velocity, i));
}
base.Initialize();
I can draw a rectangle around each one using:
foreach (Bouncer component1 in Components)
{
Bouncer thing = (Bouncer)component1;
Rectangle thingRectangle;
thingRectangle = new Rectangle((int)thing.position.X, (int)thing.position.Y, thing.sprite.Width, thing.sprite.Height);
But now, how do I check for a collision? I can hardly use:
if (thingRectangle.Intersects(thingRectangle))
I should point out I'm a teacher by trade and play with coding to keep my brain from turning to mush. Recently I have been working with Python and with Python I could just put all the sprites into a list:
sprites[];
Then I could simply refer to each as sprite[1] or sprite[2] or whatever its index in the list is. Does XNA have something like this?
Please let me know if any more code needs to be posted.
Thanks,
Andrew.
One solution, which I use in my game engine, is to have a Logic code run inside the objects for every game Update, ie. every frame. It seems you already do this, according to the variable names, which indicate you run some physics code in the objects to update their positions.
You might also want to create the collision rectangle inside the Bouncer's constructor so it's more accessible and you make good use of object oriented programming, maybe even make it an accessor, so you can make it update every time you call it instead of manually updating the bounding/collision box. For example:
public Rectangle #BoundingBox {
get { return new Rectangle(_Position.X, _Position.Y, width, height); }
}
Whichever way works, but the collision checks can be run inside the Bouncer object. You can either make the reference list of the Bouncer objects static or pass it to the objects itself. The code for collisions is very simply:
foreach(Bouncer bouncer in Components) //Components can be a static List or you can pass it on in the constructor of the Bouncer object
{
if (bouncer.BoundingBox.Intersects(this.BoundingBox))
{
//they collided
}
}