I think two canvas on a page, load the two models, right hand slide, can compare, but now found a problem, fingers sliding at the same time, the program will mistake is magnified model, rather than rotating model?
So, I think of a way , a canvas, placed two camera, two models, fingers sliding, control both the location of the camera, make the model with rotating frequency, but the specific implementation, found that the model is relatively rotating, not with the effect of the rotation frequency?
I changed the location of the number of touches in the OrbitControls file to solve the problem of both fingers sliding and amplifying the model
function onTouchStart( event ) {
// debugger;
if ( scope.enabled === false ) return;
// switch ( event.touches.length ) {
switch ( event.targetTouches.length ) {
}
}
Related
In Three.js, I have a group of meshes that is loaded from outside with help of FBX loader. The group has six meshes inside. My task is to make this meshes follow pointer when they get hovered. More precisely, I'd like to have a sort of magnetic effect (just like navbar items in this pen, but with meshes in Three.js).
I think, firstly, I have to detect, where currently pointer is, i.e. get position of cursor in world coordinates system, and then translate meshes towards it. But when I try to get the position of cursor, it seems to be wrong.
Having said that, I have two questions:
How to get proper cursor's position relative to the world coordinates?
How to change position of each of the group's meshes so that they get translated against the cursor?
Here is what have I done so far:
Hi everyone.
In Three.js, I have a group of meshes that is loaded from outside with help of FBX loader. The group has six meshes inside. My task is to make this meshes follow pointer when their canvas get hovered. More precisely, I'd like to have a sort of magnetic effect (just like navbar items in this pen, but with meshes of Three.js).
I think, firstly, I have to detect, where currently pointer on canvas is, i.e. get position of cursor in world coordinates system, and then translate meshes towards it. But when I try to get the position of cursor, it seems to be wrong.
Having said that, I have two questions:
How to get proper cursor's position relative to the world coordinates?
How to change position of each of the group's meshes so that they get translated against the cursor?
Here is what have I done so far. Function that translates meshes isn't written yet. Mousemove callback returns pretty big digits, though:
// Load object and play a third-party animation
loader.load("Object_001.fbx", (object) => {
mixer = new THREE.AnimationMixer(object);
const action = mixer.clipAction(object.animations[0]);
action.play();
object.traverse((child) => {
if (child.isMesh) {
child.material.map = texture;
child.material.needsUpdate = true;
}
});
scene.add(object);
});
// log coordinates of the pointer
const mouse = new THREE.Vector3();
const position = new THREE.Vector3();
function onMouseMove(event) {
mouse.set(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1,
0.5
);
mouse.unproject(camera);
mouse.sub(camera.position).normalize();
const distance = -camera.position.z / mouse.z;
position.copy(camera.position).add(mouse.multiplyScalar(distance));
console.log(position);
}
wrapperElement.addEventListener("mousemove", onMouseMove);
Thanks in advance.
Made a codepen here:
https://codepen.io/cdeep/pen/YzxPPZQ
The cursor only exists in the canvas dom element which is a rendering of the camera view frustum.
The easiest way to make the object follow a mouse is to get the point of intersection of the mouse with another object in the 3d scene and set the object position to the intersection point. The above codepen showcases that.
raycaster.setFromCamera( mouse, camera );
const intersects = raycaster.intersectObjects([ground]);
if(intersects.length) {
const { point } = intersects[0];
cube.position.copy(point.setY(0.5));
}
You could also position it at a fixed distance from the mouse but it looks odd in my opinion:
const distance = 10;
raycaster.setFromCamera( mouse, camera );
const { origin, direction } = raycaster.ray;
cube.position.copy(origin.clone().add(direction.multiplyScalar(distance)));
Documentation for raycaster:
https://threejs.org/docs/index.html?q=ray#api/en/core/Raycaster
Raycasting is used for mouse picking (working out what objects in the
3d space the mouse is over) amongst other things.
I have This Example , as you can see - the event that used for adding decals to the object is 'pointerup', like in the following function :
window.addEventListener( 'pointerup', function ( event ) {
if ( moved === false ) {
checkIntersection( event.clientX, event.clientY );
if ( intersection.intersects ) shoot();
}
} );
I wonder how can i add decals while the mouse/ pointer are pressed - so if i could do it - it will be like the action of drawing - which is what i want to achieve...
The problem is that i cant figure out which event and function should i use for repeatedly track each move and append it...
The problem is that i cant figure out which event and function should i use for repeatedly track each move and append it...
You can do this by combining pointerdown, pointerup and pointermove event listeners. Use the first and second one to manage a boolean variable e.g. drawing. On pointerdown, you set it to true. On pointerup, you set it to false. You then know when the interaction is in the drawing state.
In the pointermove event listener, you check for drawing. If set to true, you execute the actual drawing logic. The official three.js example webgl_materials_texture_canvas demonstrates this workflow. The idea of the example is to draw on a canvas which is used as a texture for a cube.
I have two different threejs scenes and each has its own camera. I can control each camera individually with a corresponding TrackballControls instance.
Is there a reliable way to 'lock' or 'bind' these controls together, so that manipulating one causes the same camera repositioning in the other? My current approach is to add change listeners to the controls and update both cameras to either's change, but this isn't very neat as, for one, both controls can be changing at once (due to dampening).
I believe it should work if you set the matrices of the second camera to the values of the first and disable automatic matrix-updates of both cameras:
camera2.matrix = camera1.matrix;
camera2.projectionMatrix = camera1.projectionMatrix;
camera1.matrixAutoUpdate = false;
camera2.matrixAutoUpdate = false;
But now you need to update the matrix manually in your renderloop:
camera1.updateMatrix();
That call will take the values for position, rotation and scale (that have been updated by the controls) and compose them into camera1.matrix, which per assignment before is also used as the matrix for the second camera.
However, this feels a bit hacky and can lead to all sorts of weird problems. I personally would probably prefer the more explicit approach you have already implemented.
Question is why are you even using two camera- and controls-instances? As long as the camera isn't added to the scene you can just render both scenes using the same camera.
Is it possible to use the Observer or Publisher design patterns to control these objects?
It seems that you are manipulating the cameras with a control. You might create an object that has the same control interface, but when you pass a command to the object, it repeats that same command to each of the subscribed or registered cameras.
/* psuedo code : es6 */
class MasterControl {
constructor(){
this.camera_bindings = [];
}
control_action1(){
for( var camera of this.camera_bindings ){
camera.control_action1();
}
}
control_action2( arg1, arg2 ){
for( var camera of this.camera_bindings ){
camera.control_action2( arg1, arg2 );
}
}
bindCamera( camera ){
if( this.camera_bindings.indexOf( camera ) === -1 ){
this.camera_bindings.push( camera );
}
}
}
var master = new MasterControl();
master.bindCamera( camera1 );
master.bindCamera( camera2 );
master.bindCamera( camera3 );
let STEP_X = -5;
let STEP_Y = 10;
//the following command will send the command to all three cameras
master.control_action2( STEP_X, STEP_Y );
This binding is self created rather than using native three.js features, but it is easy to implement and can get you functional quickly.
Note: I wrote my psuedocode in es6, because it is simpler and easy to communicate. You can write it in es5 or older, but you must change the class definition into a series of functional object definitions that create the master object and its functionality.
I have a model with a skeleton, all set up.
I've added the animations and Animation Helper to see the model move.
The result is odd - the bones are moving (according to animation helper rendering), but the actual model itself does not.
It's better explained with an gif:
Animation is attached to the mesh using:
animation = new THREE.Animation( mesh, geometry.animation );
Any suggestions on what might be wrong?
The solution was pretty simple actually:
for ( var k in materials ) {
materials[k].skinning = true;
}
I'm trying to animate sprites along a path in Three.js using Tween.js by chaining the animations in order to have something like this :
----#----#----#----#----#---- etc
Every sprite has its own tween animation, and I just delay each tween animation at the beginning. Each sprite has in fact N animations along the path (that is not a straight line) and I chain them to have a loop effect.
Everything goes well if the FPS is perfectly stable, but my problem is that if at some point I have a FPS drop, the animations of the different sprites are not in sync anymore, and the space between sprites is not equal anymore. I potentially end up with something like this :
---#--#----#-#-#-----#--- etc
I was wondering if there is a better approach for this, like having only one tween animation for all the sprites, but I don't know how to introduce the offset between each sprite on many line segments.
I cannot post the exact code has it is part of a bigger app, and won't be usable as is, but it looks like this :
// create animations
for each (sprite) {
for each (segment) {
var currentAnimation = new TWEEN.Tween(sprite.position).to({
x : segment.endpoint.x,
y : segment.endpoint.y,
z : segment.endpoint.z
}, animationTime).easing(TWEEN.Easing.Linear.None);
currentAnimation.delay(delayTime * currentSpriteNumber);
previousAnimation.chain(currentAnimation);
}
lastAnimation.chain(firstAnimation);
lastAnimation.onComplete(onEachSpriteAnimationCompleted);
}
// start the animations
for each (sprite) {
spriteFirstAnimation.start();
}
// to remove the delay when each sprite animation has made one loop,
// and instantly replace the sprite at the beginning of the path
// (my paths are not closed)
var onEachSpriteAnimationCompleted = function() {
sprite.position.set(starting position);
for each (sprite animation) {
animation.delay(0);
}
}