i try to use trackballcontrols.js in my project but need some modification,and i cant understand these code ,can you give me some explanation?
var getMouseOnCircle = ( function () {
var vector = new THREE.Vector2();
return function getMouseOnCircle( pageX, pageY ) {
vector.set(
( ( pageX - _this.screen.width * 0.5 - _this.screen.left ) / ( _this.screen.width * 0.5 ) ),
( ( _this.screen.height + 2 * ( _this.screen.top - pageY ) ) / _this.screen.width ) // screen.width intentional
);
return vector;
};
}() );
This code converts the coordinate of the mouse position into the normalized 2d vector (to use it for rotation calculation).
The method expects to be passed the mouse's XY coordinate on the global screen. It returns the X component linearly interpolated between -1 and 1 and the Y component linearly interpolated between -a and a, where a is the "aspect ratio" given by the viewport height divided by the viewport width.
Related
I am trying to rotate on Y axis in javascript ( In my own 3D engine )
and i tried this function :
function rotateY(amount) {
for (var i = 0; i < points.length; i++) {
points[i].z = Math.sin(amount) * points[i].x + Math.cos(amount) * points[i].z;
points[i].x = Math.cos(amount) * points[i].x - Math.sin(amount) * points[i].z;
}
}
It is rotating, but every time it rotates it changes it's x and z scale so it is getting thinner.. Can you help me how to rotate it properly ? Thanks :)
Assuming i) the rotation is respective to the global origin and not the object itself and ii) that you want to apply a delta (if we can't take these, see below):
For each point:
1. Find the distance of the point relative to the axis.
2. Find the current angle of the point relative to the axis.
3. Use basic 2-D cos/sin polar projection, since the excluded axis is a unit vector.
function rotateY( points, deltaAngle ) {
const _points = points;
if ( ! Array.isArray( points ) ) points = [ points ];
for ( let i = 0; i < points.length; i ++ ) {
const newAngle = Math.atan2( points[ i ].z, points[ i ].x ) + deltaAngle;
const distance = ( points[ i ].x ** 2 + points[ i ].z ** 2 ) ** ( 1 / 2 );
points[ i ].x = distance * Math.cos( newAngle );
points[ i ].z = distance * Math.sin( newAngle );
}
return _points;
}
The algorithm is the same for X and Z rotation, so long as the first axis used in Math.atan2 is the same axis that uses Math.sin.
NOTE: I used the exponentiation operator. I wouldn't use this in production unless you're using Babel/something similar or don't care about IE/old users.
If assumption ii) cannot be taken, we simply want to store the original angles of the points and have newAngle defined as the original angle plus the new angle.
If assumption i) cannot be taken, it gets complicated. If the object's axes are simply offset, you can subtract that offset in newAngle and distance and add it back when setting x and z. If the axes themselves are not respectively parallel to the global axes, you'll want to switch to using a quaternion to avoid gimbal lock. I would suggest copying or at least looking three.js's implementation.
I have written a function by which i want to stop rotation of three.js object on mouse hover.
function onDocumentMouseUp( event ) {
event.preventDefault();
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera( mouse, camera );
var intersects = raycaster.intersectObjects( scene.group );
if ( intersects.length > 0 ) {
if ( INTERSECTED != intersects[ 0 ].object ) {
if (controls.AutoRotate) {
controls.autoRotate = false;
} }
}
}
Don't know why but the function is not working neither it is giving any error in the console.Can anybody tell whats the problem over here or suggest the possible solution to this problem. Its not working maybe because i am embedding DOM elements inside three.js and using css renderer.
controls.AutoRotate does not exist so it will never be equal to true.
What I'm trying to achieve is to make a specific mesh move towards a specific vector until it will eventually be stopped by the player.
So far I have managed to get the XY coordinates of the clicked canvas and project them in 3d using the following piece of code. Unfortunately I'm not sure what approach to take in order to get the direction towards the clicked position.
var vector = new THREE.Vector3();
vector.set(
( event.clientX / window.innerWidth ) * 2 - 1,
+ ( event.clientY / window.innerHeight ) * 2 + 1,
0.5 );
vector.unproject( camera );
var dir = vector.sub( camera.position ).normalize();
var distance = + camera.position.z / dir.z;
var pos = camera.position.clone().add( dir.multiplyScalar( distance ) );
This assumes a target Vector3 and a maximum distance to be moved per frame of .01.
var vec1 = target.clone(); // target
vec1.sub(mesh.position); // target - position
var dist = Math.min(vec1.length(), .01); // assume .01 is maximum movement
if (dist > 0) {
vec1.setLength(dist); // this will be the movement
mesh.position.add(vec1); // this moves the messh
}
Im currently working on an small web-application which is using threejs. I ran into the following issue:
I build a prototype which contains my threejs content and everything works well here (The canvas is in the prototype window.innerWidth and window.innerHeight => so has the same size as my Browser window. Selecting works well but I want to use the canvas on my web page application and picking of 3d surfaces needs to work as well there.
I discovered as soon as I change the margin or top via CSS of the canvas it doesn't work anymore. The web-application is based on a scroll page and the threejs canvas is inside a div container which can only be seen by scrolling through the page.
For picking I use the following logic/code -> this one works well in the "fullscreen prototype" but not in the web application page
self.renderer.domElement.addEventListener( 'click', function(event){
event.preventDefault();
//CONVERT MOUSE POSITION TO CORRECT VECTOR
var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
//TRANSLATES A 2D POINT FROM Normalized Device Coordinates TO RAYCASTER THAT CAN BE USED FOR PICKING
self.projector.unprojectVector( vector, self.camera );
//RAYCASTER IS NEEDED TO DETECT INTERACTION WITH CUBE SURFACE
var raycaster = new THREE.Raycaster( self.camera.position, vector.sub( self.camera.position ).normalize() );
var intersects = raycaster.intersectObjects( self.scene.children );
//CHANGE COLOR BASED ON INTERSECTION WITH ELEMENT
if ( intersects.length > 0 ) {
//SELECTED OBJECT
}
}, false );
I think that the calculation is wrong for the var vector but I just can't figure it out how to do it correctly.
Any help would be appreciated
Thank you
best reards
200% way
var x = event.offsetX == undefined ? event.layerX : event.offsetX;
var y = event.offsetY == undefined ? event.layerY : event.offsetY;
var vector = new THREE.Vector3();
vector.set( ( x / renderer.domElement.width ) * 2 - 1, - ( y / renderer.domElement.height ) * 2 + 1, 0.5 );
projector.unprojectVector( vector, camera );
Or see this example. Look at messages in the console.
<script src="js/controls/EventsControls.js"></script>
EventsControls = new EventsControls( camera, renderer.domElement );
EventsControls.draggable = false;
EventsControls.onclick = function() {
console.log( this.focused.name );
}
var mesh = new THREE.Mesh( geometry, material );
scene.add( mesh );
EventsControls.attach( mesh );
//
function render() {
EventsControls.update();
controls.update();
renderer.render(scene, camera);
}
If you want to use it in your webpage, you probably need to calculate the vector with the width and height from your canvas element instead of the window which is your whole browser window.
I'd like to modify the TrackballControls so that the camera only rotates on the Z-axis. However, I'm having a devil of a time understanding how the mouse/touch coordinates are mapped. The function below receives the mouse/touch x/y coordinates and a "projection" vector, which I assume is a projection of where the camera is expected to rotate, but that's not particularly clear to me either.
Basically I need to know what to do in the if statement below where it says "what goes here?" I need to essentially clip the vector so that rotation only happens on the Z axis. I know I could do this with a simple rotate, but I'd like to implement it in the TrackballControls so I can switch to "roll only" mode at will (camera only "rolls" on the Z axis). Can someone who is better at vector math give me a hand?
this.getMouseProjectionOnBall = (function(){
var objectUp = new THREE.Vector3(),
mouseOnBall = new THREE.Vector3();
return function ( pageX, pageY, projection ) {
mouseOnBall.set(
( pageX - _this.screen.width * 0.5 - _this.screen.left ) / (_this.screen.width*.5),
( _this.screen.height * 0.5 + _this.screen.top - pageY ) / (_this.screen.height*.5),
0.0
);
var length = mouseOnBall.length();
if ( _this.noRoll ) {
if ( length < Math.SQRT1_2 ) {
mouseOnBall.z = Math.sqrt( 1.0 - length*length );
} else {
mouseOnBall.z = .5 / length;
}
} else if (_this.rollOnly === true) {
// What goes here?
} else if ( length > 1.0 ) {
mouseOnBall.normalize();
} else {
mouseOnBall.z = Math.sqrt( 1.0 - length * length );
}
_eye.copy( _this.object.position ).sub( _this.target );
projection.copy( _this.object.up ).setLength( mouseOnBall.y )
projection.add( objectUp.copy( _this.object.up ).cross( _eye ).setLength( mouseOnBall.x ) );
projection.add( _eye.setLength( mouseOnBall.z ) );
return projection;
}
}());
The actual camera rotation is done in the function below every frame. This function is much more understandable to me. Just basic angles and quaternion stuff. It's the above function that boggles my mind.
this.rotateCamera = (function(){
var axis = new THREE.Vector3(),
quaternion = new THREE.Quaternion();
return function () {
var angle = Math.acos( _rotateStart.dot( _rotateEnd ) / _rotateStart.length() / _rotateEnd.length() );
if ( angle ) {
axis.crossVectors( _rotateStart, _rotateEnd ).normalize();
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 );
}
}
}
}());