I would like to use camera.getWorldDirection() and access to the head-mounted display directions. I was able to do this with the previous webVR API. When I use the new HelioWebXRPolyfill.js from THREE, I am not able to receive current positions.
According to the WebXR Device API, this should be done using the XRViewerPose object.
This feature is only working using HTTPS.
It seems that calling renderer.xr.getCamera() isn't fully copying the various camera member properties that camera.getWorldDirection() is expecting to find. I'm not sure where this problem originates (perhaps the polyfill?), but you can get around it by computing direction yourself :
let xrCamera = this.renderer.xr.getCamera(sceneCamera)
let e = xrCamera.matrixWorld.elements
let direction = new THREE.Vector3(-e[8], -e[9], -e[10]).normalize()
I came up with a simple fix. Just parent a box to the camera and use the camera box in place of the camera.
camera.add( camerabox );
This doesn't work:
var direction = new THREE.Vector3();
camera.getWorldDirection( direction );
This DOES work:
var direction = new THREE.Vector3();
camerabox.getWorldDirection( direction );
global variable
var cameraVector = new THREE.Vector3(); //define once and reuse it!
in your render loop
let xrCamera = renderer.xr.getCamera(camera);
xrCamera.getWorldDirection(cameraVector);
//heading vector for webXR camera now within cameraVector
Related
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().
Im trying to make portals with ThreeJS. I found this page Mini-Portals That explains how to make portals with OpenGL. So i tried to replicate the portal view function in TJS. Now this is my result:
The left portal(right camera) is normal camera and right portal(left camera) is the view matrix gotten from tutorial. As you can see the portal view on the right is quite weird.
The main issue here is that the scaling of the images is all wrong and the angle im seeing the images in portal is wrong. Currently its flat and show where i pointed the camera, but what i want is portal where the scaling is correct(image on portal is same scale as the world itself) and what is see in portal depends on the angle where im watching.
What am i doing wrong and what should i do to fix it?
For people who want a great Portal system with Three.js :
https://github.com/markotaht/Portals
Its been a while. But i have found a way to do what i needed. The 4th parameter in not needed. Basically i send camera, and my 2 portal objects(Meshes) to my function. Instead of using the matrix multiplication way(does not work in ThreeJS because ThreeJS does some weird stuff with it) I split the matrices into pieces. Then manually calculate the new position and rotation and construct the new matrix from it. And i set this new matrix as my cameras worldMatrix. Voila a working portal. Next step is oblique view fusrum, because we want our nearplane to be the portal otherwise we can have some objects between the camera and portal.
And the rendering procedure itself uses stencil buffer to render the portals correctly. If anyone needs, this will help you: https://th0mas.nl/2013/05/19/rendering-recursive-portals-with-opengl/
function portal_view(camera, src_portal, dst_portal, kordaja) {
src_portal.updateMatrixWorld()
dst_portal.updateMatrixWorld()
camera.updateMatrixWorld()
var camerapos = new THREE.Vector3();
var camerarot = new THREE.Quaternion();
var camerascale = new THREE.Vector3();
camera.matrix.decompose(camerapos,camerarot,camerascale);
var srcpos = new THREE.Vector3();
var srcquat = new THREE.Quaternion();
var srcscale = new THREE.Vector3();
src_portal.matrix.decompose(srcpos, srcquat, srcscale);
var destquat = new THREE.Quaternion();
var destpos = new THREE.Vector3();
var destscale = new THREE.Vector3();
dst_portal.matrix.decompose(destpos,destquat,destscale);
var diff = camerapos.clone().sub(srcpos);
var ydiff = src_portal.rotation.y - dst_portal.rotation.y - Math.PI;
diff.applyAxisAngle(new THREE.Vector3(0,1,0),-ydiff);
var newcampos = diff.add(destpos);
var yrotvec = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,1,0),-ydiff);
console.log(yrotvec)
srcquat = srcquat.multiply(destquat.inverse());
camerarot = camerarot.multiply(yrotvec);
var inverse_view_to_source = new THREE.Matrix4();
inverse_view_to_source.compose(newcampos,camerarot,camerascale);
return inverse_view_to_source;
}
NOTE:
I moved my answer to the answers so i can mark an answer.
I have a Box Mesh where I subtract another Box with Three.CSG to create a wall with a window.
After doing so, there are tiny holes in the Mesh alongside the cut. They are not visible alle the time, but show up when moving around.
How to close these holes?
This is part of the code how I am creating the Mesh:
var wallBsp = new ThreeBSP( myWallMesh );
var subMesh = new THREE.Mesh( mygeo );
var subBsp = new ThreeBSP( subMesh );
var subtract_bsp = wall_bsp.subtract( subBsp );
var result = subtract_bsp.toMesh();
result.material.shading = THREE.FlatShading;
result.geometry.computeVertexNormals();
Update
I have created a jsfiddle, but it is difficult to reproduce the error, I couldnt make it visible there: http://jsfiddle.net/L0rdzbej/23/
However, you can see the full application here.
Like #gaitat suggested, geometry.mergeVertices() does not look like it changes anything for me. Chandler Prall hinted at the source where precisionPoints, which is a variable inside the mergeVertices function, could solve this. Depending on the scale of the scene its value should be lower or negative, but I had no success so far.
If someone could help me solve a problem. I wantto get a JSON with animation, traveling at a certain path.
var up = new THREE.Vector3(0,1,0);
var pt,radians,tangent;
var axis = new THREE.Vector3();
var pot = new THREE.SplineCurve3([
new THREE.Vector3(640,360,510),
new THREE.Vector3(650,360,520),
new THREE.Vector3(0,20,0)]);
....
pt = pot.getPoint(stevec);
meshK.position.set(pt.x,pt.y,pt.z);
tangent=pot.getTangent(stevec).normalize();
axis.crossVectors(up,tangent).normalize();
radians=Math.acos(up.dot(tangent));
meshK.quaternion.setFromAxisAngle(axis,radians);
//meshK.eulerOrder='ZYX';
stevec+=0.001;
I'm trying to get a plane like object to fly a certain path.
Thanks
The solution was to add the initial rotation after quaternion is set. I also had to export the JSON with flipYZ flag.
I've just started learning THREE and have been messing about with the three.js example of controllable MD2 characters to try and fashion it into a 3rd person shooter kind of game. I've been trying to write a simple algorithm for the enemy characters and I'm pretty sure that ray-casting would be ideal.The whole idea is that the enemies should stop rotating once they're facing the player. But Here's the problem that's giving me sleepless nights! :
Let's say, the enemy object is the origin for the ray caster ray. No matter what direction I set for the direction of that ray ( even, for example (1,0,0) - the positive x-axis), the ray's direction is always pointing towards the center of the scene!!!
Please help! haven't been able to find any Example online for this kind of use for the ray caster (apart from collision detection which I really don't need at the moment).
If all you want is for enemies to stop rotating when they are looking at the player, I would consider just checking the direction between them, as it's a lot faster than casting a ray to see if it intersects:
// Assuming `enemy` is a THREE.Mesh
var targetDir = enemy.position.clone().sub(player.position).normalize();
var currentDir = (new THREE.Vector3()).applyMatrix4(enemy.matrixWorld).sub(enemy.position).normalize();
var amountToRotate = currentDir.sub(targetDir);
var offset = amountToRotate.length();
Then rotate each axis no more than the value for that axis in amountToRotate if offset is greater than some threshold.
That said, here is how you use a Raycaster, given the variables above:
var raycaster = new THREE.Raycaster(enemy.position, targetDir);
var intersections = raycaster.intersectObject(player);
Note that if you are running any of the above code in an animation loop, it will create a lot of garbage collection churn because you are constantly creating a bunch of new objects and then immediately throwing them away. A better pattern, which is used a lot in the library itself, is to initialize objects once, copy values to them if you need to, and then use those copies for computation. For example, you could create a function to do your raycasting for you like this:
var isEnemyLookingAtPlayer = (function() {
var raycaster = new THREE.Raycaster();
var pos = new THREE.Vector3();
return function(enemy) {
raycaster.ray.origin.copy(enemy.position);
raycaster.ray.direction.copy(pos.copy(enemy.position).sub(player.position).normalize());
return !!raycaster.intersectObject(player).length;
};
})();