Im trying to rotate a BoxMesh around its Axis.
Without Physijs.Scene.simulation() rotateOnAxis works, but with the simulation it doesn't work. With the simulation it does move around its position.
this.player.__dirtyPosition = true;
// move forwards/backwards/left/right
if ( this.keyboard.pressed("W") )
this.player.translateZ( -moveDistance );
if ( this.keyboard.pressed("S") )
this.player.translateZ( moveDistance );
if ( this.keyboard.pressed("Q") )
this.player.translateX( -moveDistance );
if ( this.keyboard.pressed("E") )
this.player.translateX( moveDistance );
// rotate left/right/up/down
if ( this.keyboard.pressed("A") )
{
this.player.rotateOnAxis( new THREE.Vector3(0,1,0), rotateAngle);
}
if ( this.keyboard.pressed("D") )
{
this.player.rotateOnAxis( new THREE.Vector3(0,1,0), -rotateAngle);
}
So W,S,Q,E works but A,D doesn't work with Physijs.Scene.simulation(), A,D does work without Physijs.Scene.simulation(). Any ideas?
sourcecode
**Edit solved:
It is obvious that this.player.__dirtyPosition = true; only allows you to change the position, but not the rotation, i looked inside the code and searched for something similar so i found that there is also a this.player.__dirtyRotation = true; which solved my problems! =)
It is obvious that this.player.__dirtyPosition = true; only allows you to change the position, but not the rotation, i looked inside the code and searched for something similar so i found that there is also a this.player.__dirtyRotation = true; which solved my problems! =)
Related
I am using the same general purpose code to load basic mesh objects (no textures) from OBJ files (obtained free from sites on the web).
Some objects render OK in that different faces reflect light with different intensities towards the camera. But other objects just render a uniform matt color and so their form cannot be seen.
I have looked inside the files and noticed various differences. For example one successful file contains records with the following initial characters v, vt, vn, f, s (vertex, vertext texture, vertex normal, face, smooth). An example of an unsuccessful file has these initial characters: v, vt, f.
Here is the code which I am using.
function F_Load_OBJ_Model ( givenFilespec, givenName, givenScene, givenHexColorStr, posX, posY, posZ, rotX, rotY, rotZ, scaleX, scaleY, scaleZ )
{
var OBJLoader = new THREE.OBJLoader();
OBJLoader.load( givenFilespec, F_make_LoadedOBJ_Handler ( givenName, givenScene, givenHexColorStr, posX, posY, posZ, rotX, rotY, rotZ, scaleX, scaleY, scaleZ ) );
}
function F_make_LoadedOBJ_Handler( givenName, givenScene, givenHexColorStr, posX, posY, posZ, rotX, rotY, rotZ, scaleX, scaleY, scaleZ )
{
//... See Tapio's answer (callback factory for use in loops)
//... at http://stackoverflow.com/questions/10920372/associate-loaded-json-files-with-a-name-for-later-access
//... This is useful in case have a loop loading multiple objects asynchronously.
return function ( object )
{
//... Note that <object> is a THREE Object3D which can have 1 or more child meshes.
//... But I will assume that there is only one child mesh.
//var material = new THREE.MeshBasicMaterial();
//eval( givenName + " = new THREE.Mesh( geometry, material );" );
//eval ( " var thisMeshOb =" + givenName );
//eval( givenName + " = object.children[0];" ); //....OK alias
eval( givenName + " = object.children[0].clone();" );//... also OK
//object.delete(); //... not possible or neccy, javascript will delete any object which cannot be referred to again.
eval ( " var thisMeshOb =" + givenName );//... alias used for following common local commands
thisMeshOb.position.set( posX, posY, posZ );
thisMeshOb.rotation.set( rotX, rotY, rotZ );
thisMeshOb.name = givenName;
thisMeshOb.scale.set( scaleX, scaleY, scaleZ );
givenScene.add( thisMeshOb );
//xxx thisMeshOb.material.type = THREE.MeshLambertMaterial();
thisMeshOb.material.color.setHex( givenHexColorStr ) ;//...("0xff0000");
thisMeshOb.geometry.computeFaceNormals(); //...no effect
thisMeshOb.geometry.normalsNeedUpdate = true; //... no effect
//... for PHONG ... floorGeometry.computeVertexNormals();
thisMeshOb.updateMatrix(); //... without this the next is not effective!?
xxx = SOW_F_grob_Add_to_Target_Set( thisMeshOb );
};
}//... EOF F_make_LoadedOBJ_Handler.
I guessed that it might be something to do with missing vertex normals. But adding the code to update them had no effect on the end result.
So is there a problem with the files or can I do something in THREE.js to make them render properly?
You've found correctly that the flat-looking files have no "vn" info.
"vn" means "vertex normal" -- that is, the direction that the (smoothed) normal is facing.
You can try calling something like thisMeshOb.geometry.computeFaceNormals(); and possibly follow it with thisMeshOb.geometry.computeVertexNormals(); -- then set thisMeshOb.geometry.normalsNeedUpdate = true; -- this will calculate a new set of normals directly inside THREE.
You only need to call this once per session, at read-in time, btw -- no need to recalculate every frame.
I've tried finding an answer to this question but I couldn't. I am still very bad at WebGL and I only use Three.js to do my work. Do Three.js Mesh Constructors support the use of ANGLE_instanced_arrays to do Geometry Instancing?
If there is browser support for the ANGLE_instanced_array is there a way to create the THREE.Mesh() with Geometry Instancing rather than relying on "Pseudo Instancing" ?
Thanks in advance.
Yes it does (at least in r72). There are several examples that use the ANGLE_instanced_arrays extension like: http://threejs.org/examples/#webgl_buffergeometry_instancing, http://threejs.org/examples/#webgl_buffergeometry_instancing_billboards, http://threejs.org/examples/#webgl_buffergeometry_instancing_dynamic, http://threejs.org/examples/#webgl_buffergeometry_instancing_interleaved_dynamic
It doesn't appear that way. I've been looking for an authoritative answer to this question and haven't been able to find confirmation, but given that a search for the constant "ANGLE_instanced_arrays" on github yields no matches my guess is that it is not implemented.
THREE 's WebGLRenderer.supportsInstancedArrays() is now WebGLRenderer.extensions.get( 'ANGLE_instanced_arrays' ).
DeprecatedList
var geo = new THREE.InstancedBufferGeometry();
// src/core/InstancedBufferGeometry.js
isInstancedBufferGeometry: true,...
// src/renderers/WebGLRenderer.js
if ( geometry && geometry.isInstancedBufferGeometry ) {
if ( geometry.maxInstancedCount > 0 ) { renderer.renderInstances( geometry, drawStart, drawCount );
......
//src/renderers/webgl/WebGLIndexedBufferRenderer.js
function renderInstances( geometry, start, count ) {
var extension = extensions.get( 'ANGLE_instanced_arrays' );
I am trying to build a virtual tour inside a building (the whole building is an obj model) using three.js. Everything loads fine and the library is pretty straightforward. My most critical issue is that I can't implement collision detection with the camera, I tried using rays but I couldn't find a suitable example for my case.
My model load:
var loader = new THREE.OBJMTLLoader();
loader.addEventListener( 'load', function ( event ) {
var newModel = event.content;
newModel.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.castShadow = true;
child.receiveShadow = true;
}
} );
scene.add( newModel );
objects.push( newModel );
});
loader.load( 'model/model.obj', 'model/model.mtl' );
The camera creation (I don't know if it is relevant to the issue)
camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
1,
10000
);
camera.position.set( 0, 25, 0 );
camera.lookAt( 0, 0, 0 );
NOTE: The camera moves inside the model, I don't want to detect collision between two separate obj models, I want to detect collision (and stop the camera from passing through walls) inside one single model.
Any help will be greatly appreciated
Looking at the documentation for Raycaster in Three.js at http://threejs.org/docs/58/#Reference/Core/Raycaster, you can create a ray like Raycaster( origin, direction, near, far ). Perhaps for you this would look something like
var ray = new THREE.Raycaster(camera.position, cameraForwardDirection, camera.position, collisionDistance);
Where cameraForwardDirection is the direction in front of you camera. I think you can get this by doing something like:
var cameraForwardDirection = new THREE.Vector3(0,0,-1).applyMatrix4(camera.matrixWorld);
This should work because the camera points in the negative Z direction (hence the 0,0,-1) and we want to apply the orientation of the camera to this vector. This assumes you are only moving forward. If you wanted to check for collisions in other directions, you could cast rays in other directions.
collisionDistance would be the minimum distance for a collision. You can experiment with this to find what works with respect to the scale of things in your scene.
Once you have cast this ray, you will need to check for intersections. You can use the ray.intersectObject( object, recursive ) method. Since it seems like you just have that one model, it might look something like:
var intersects = ray.intersectObject(newModel, true);
if(intersects.length>0){
// stop the camera from moving farther into the wall
}
My ray.intersectObjects works really well with the objects in my scene until I dynamically modify the geometry of the object. Although the renderer is showing the objects as being modified (vertices moved and faces changed), when an intersect is tried on the modified object, it produces strange results. I need the intersect to work even on the modified geometry!
To help debug and track how the intersect is working in my scene, I've added a function: makeMiniSphere(). This makes a new sphere object in the scene at the point where the intersection occurs. Using this, you can see that after the cube is modified, sometimes the intersect hits the cube and sometimes it goes right through (mostly the faces that have been modified). It isn't a random problem, but the more you click around the modified cube, the more you can see a pattern develop. It is almost as if the renderer for the visuals of the scene know which direction the cube was modified, but the ray.intersectObjects thinks that it has been modified in a different direction!
Here is a link to the test website: http://www.littledrop.net/html/cadiverse/HelloWorld.html
Directions to show problem:
Left click on cube to show intersect points. Mini spheres will be created wherever Three.js sees an intersect. The color of the selected object will change to yellow if not already selected.
Click on any face of the cube. This will A. Turn it yellow if it isn't already yellow. B. It will select the face of the cube, although the selected face won't look any different from the rest of the cube.
Press the "Right" arrow key to move the selected face to the right. This will dynamically change the geometry of the cube.
Now try to click on the cube--especially in the area that it has been modified. Again the Mini spheres will show where the software thinks the intersects are occurring.
Here is the intersect code:
function onDocumentMouseDown (event)
{
// the following line would stop any other event handler from firing
// (such as the mouse's TrackballControls)
//event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
document.getElementById('message1').innerHTML = window.innerHeight;
var isinworkingarea = window.innerHeight-menubarh;
if (event.clientY<=isinworkingarea)
{
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );
//var ray = new THREE.ReusableRay();
var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
// create an array containing all objects in the scene with which the ray intersects
// use this to select anything in the scene:
var intersects = ray.intersectObjects( scene.children );
if ( intersects.length > 0 )
{
if (cadjectNow)
cadjects[cadjectNow].material.color.setHex(cadjects[cadjectNow].oldColor);
if (intersects[0].object.cadNum)
cadjectNow = intersects[0].object.cadNum;
SELECTEDface=intersects[0].face;
if (cadjectNow)
cadjects[cadjectNow].material.color.setHex( selectColor );
document.getElementById('message1').innerHTML = cadjects[cadjectNum].cadNum;
///// Information about selected /////
var facestring = intersects[0].face.a + " " + intersects[0].face.b + " " + intersects[0].face.c;
if(intersects[0].face instanceof THREE.Face4)
{
facestring=facestring + " " + intersects[0].face.d;
}
copyGeometry=cadjects[cadjectNow].geometry;
//makeCopy(copyGeometry,cadjects[cadjectNow].position.x,cadjects[cadjectNow].position.y,cadjects[cadjectNow].position.z);
makeMiniSphere(intersects[0].point.x, intersects[0].point.y, intersects[0].point.z);
document.getElementById('message1').innerHTML = facestring;
//document.getElementById('message2').innerHTML = cadjects[cadjectNow].geometry.vertices[SELECTEDface.a].x + " " + cadjects[cadjectNow].geometry.vertices[intersects[0].face.a].y + " " + cadjects[cadjectNow].geometry.vertices[intersects[0].face.a].z;
document.getElementById('message2').innerHTML = intersects[0].point.x + " " + intersects[0].point.y + " " + intersects[0].point.z;
}
}
}
Here is the modify code:
if ( keyboard.pressed("right"))
{
document.getElementById('message1').innerHTML = mouseMode;
cadjects[cadjectNow].geometry.vertices[SELECTEDface.a].x+=10;
cadjects[cadjectNow].geometry.vertices[SELECTEDface.b].x+=10;
cadjects[cadjectNow].geometry.vertices[SELECTEDface.c].x+=10;
if(SELECTEDface instanceof THREE.Face4)
{
cadjects[cadjectNow].geometry.vertices[SELECTEDface.d].x+=10;
}
cadjects[cadjectNow].geometry.verticesNeedUpdate = true;
cadjects[cadjectNow].geometry.elementsNeedUpdate = true;
cadjects[cadjectNow].geometry.normalsNeedUpdate = true;
}
Thank you to everyone who has posted past questions and given the answers. By perusing past questions, I've been able to get this far---so you guys have already been a great help. Thanks in advance for help on this one. (As this is my first question to post here, any suggestions on how to better present a question are also more than welcome.)
Update (3/21/13)--I've migrated to r57 as suggested and the updated code is shown above. I've also debugged it so that it is working at least as well as it was before. So now the geometry is still visually being changed dynamically, but the intersect is not detecting the change properly. Thanks #WestLangley for the encouraging posts so far.
Now working correctly. Here is how I did it (thanks to Westlangley for guidance).
Upgrade Three.js to latest revision (r57 from r49).
Migrate my present code to work with r57.
Remove all former code attempting to update the object.
Added the following code to "modify object" section:
cadjects[cadjectNow].geometry.verticesNeedUpdate = true;
cadjects[cadjectNow].geometry.normalsNeedUpdate = true;
cadjects[cadjectNow].geometry.computeFaceNormals();
cadjects[cadjectNow].geometry.computeVertexNormals();
cadjects[cadjectNow].geometry.computeBoundingSphere();
I was having a similar issue with a modified BufferGeometry.
I got raycasting working by calling geometry.computeBoundingSphere() and geometry.computeBoundingBox() after modifying the array with vertex positions.
Setting verticesNeedUpdate was not needed.
Running r112.
I'm attempting to modify TrackballControls.js so that its rotation is like that of OrbitControls.js, where the horizon stays flat, but maintain the ability to rotate over and around a scene (specifically, a collada building model). I've been trying to figure this out for the better part of a day now, but I'm a designer, not a programmer. :-) I'm not even sure if I should be focusing on this.rotateCamera and/or this.update.
(BTW, I would just use OrbitControls.js, but it doesn't support panning, which is necessary when looking at large collada building models.)
Any help would be much appreciated.
It's been awhile since this question was asked, but I ran into the same problem and didn't find much discussion online, so I thought I'd post my solution.
If you must use TrackballControls and you want to a flat horizon, you can simply edit the TrackballControls.js library by adding the following line to the end of the 'this.rotateCamera' method
this.object.up = new THREE.Vector3(0,1,0);
This locks the camera up direction in the (0,1,0) direction (i.e in the y direction). The entire modified method function would then read:
this.rotateCamera = function () {
var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );
if ( angle ) {
var axis = ( new THREE.Vector3() ).crossVectors( _rotateStart, _rotateEnd ).normalize();
quaternion = new THREE.Quaternion();
angle *= _this.rotateSpeed;
quaternion.setFromAxisAngle( axis, -angle );
_eye.applyQuaternion( quaternion );
_this.object.up.applyQuaternion( quaternion );
_rotateEnd.applyQuaternion( quaternion );
if ( _this.staticMoving ) {
_rotateStart.copy( _rotateEnd );
} else {
quaternion.setFromAxisAngle( axis, angle * ( _this.dynamicDampingFactor - 1.0 ) );
_rotateStart.applyQuaternion( quaternion );
}
}
// Lock the camera up direction
this.object.up = new THREE.Vector3(0,1,0);
};