The following code works fine for me, drawing the current mouse position on the canvas as an arrow using the ThreeJS ArrowHelper. What I do with the mouse direction is not so important here.
function mouseDir () {
var bbox = canvas.getBoundingClientRect();
var mouse3D = new THREE.Vector3 (
((currentMouseX - bbox.left) / bbox.width) * 2 - 1,
-((currnetMouseY - bbox.top) / bbox.height) * 2 + 1,
0.5
);
// perspective camera
var dir = mouse3D.unproject(camera).sub(camera.position).normalize();
scene.add(new THREE.ArrowHelper(dir, camera.position)); // draws arrow helper showing mouse direction
}
The drawn arrow is pointing straight ahead, so I can see only the head of the arrow, which is totally fine (1.).
As soon as I change the camera position AND set lookAt, its getting weird (2.). The arrow is not drawn anymore straight from the mouse away. Here is how I change the position and set lookAt position:
// DONT WORK
camera.position.set(500,50,150);
camera.lookAt(new THREE.Vector3(0,0,0));
camera.updateMatrixWorld(true);
mouseDir();
render();
Only setting the camera position works fine:
// WORKS
camera.position.set(500,50,150);
camera.updateMatrixWorld(true);
mouseDir();
render();
Only setting the lookAt position works fine too:
// WORKS
camera.lookAt(new THREE.Vector3(0,0,0));
camera.updateMatrixWorld(true);
mouseDir();
render();
I have also tried to draw the mouse direction after rendering the position and lookAt calls, doesnt work as well.
I am on r74. I tried to figure this out the whole day, hope anybody can tell me which direction to search.
dir should be the camera position:
var dir = camera.position;
scene.add(new THREE.ArrowHelper(dir, origin));
Related
I am using ArcGIS API v4.8 and the drawing tools to draw circle on my map.
1 issue I notice is when I draw a circle, the center of the circle moves when I move my mouse resizing the circle rather than fixed at the point of the 1st mouse click starts:
How do I fix the center regardless of how I move the radius of the circle? What is missing in my code?
const options = {view, layer: tempGraphicsLayer, pointSymbol, polylineSymbol, polygonSymbol}
let sketchViewModel = new SketchViewModel(options)
let drawCircleButton = document.getElementById('circleButton')
drawCircleButton.onclick = function () {
clear()
isDrawLine = false
sketchViewModel.create('polygon', {mode: 'click'})
sketchViewModel.create('circle')
}
EDIT:
I have found a similar sample, choose the Draw Circle tool, start drawing a circle on the map, you will notice that the center of the circle moves when you move your mouse, I want it to fix the center instead.
The problem when the center moves along with your mouse move is that the circle drawn is not accurate, as I want to start with the center of the circle I want, the circle can expand outward but the center should not move.
That is because the circle, in the given example, is being draw inside the square object. Basically your start and end point are representing corners, not the center point and outer layer of the circle. So every time you expand circle object, it expands from one corner, while the rest is dragging along your mouse.
Visual example:
There are workarounds for this of course. I've made a small sample code of one of the possible ways to draw a circle from a fixed center point.
https://jsfiddle.net/wLd46g8k/9/
Basically I used an ArcGis JS API 4.x constructor called Circle, where you pass a starting point and radius. In my example I've calculated the radius from these two points.
function drawCircle(){//draws the circle
graphicsLayer.graphics.removeAll();
var graphic = new Graphic({
geometry: new Circle({//circle constructor
center: startPoint,//pass the pointer-down event X Y as a starting point
radius: Math.floor(Math.sqrt(Math.pow(startPoint.x - endPoint.x, 2) + Math.pow(startPoint.y - endPoint.y, 2)))
}), //calculates endpoint distance from the startpoint and pass it as a radius
symbol: {//circle design
type: "simple-fill",
color: "orange",
style: "solid",
outline:{
color:"darkorange",
width:4
}
}
});
graphicsLayer.graphics.add(graphic);//adds the circle
};
Setup a simple scene here:
http://jsfiddle.net/majman/Sps3c/
I was initially trying to demonstrate a problem I was having with rotating a parent container while having the camera maintain it's relative offset position, but when setting up this example I couldn't even adjust the camera's initial position.
Current Problem:
// camera
camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 5, 150);
camera.position.z = 50; // this doesn't work?
// object to contain camera & helper
cameraContainer = new THREE.Object3D();
cameraContainer.rotation.order = "YXZ"; // maybe not necessary
// add to container
cameraContainer.add(camera);
scene.add(cameraContainer);
Now when rotating the cameraContainer, the camera's rotation follows - but I'd like the camera's position to be offset from the cameraContainer. I'm unable to modify any position properties for some reason.
Your code is working fine. You are confused because the CameraHelper is not displaying the camera in its actual position. You need to add the CameraHelper as a child of the scene.
// camera helper
cameraHelper = new THREE.CameraHelper( camera2 );
scene.add( cameraHelper );
updated fiddle: http://jsfiddle.net/Sps3c/1/
Tip: I added an OrbitController to your demo for a better view of the situation.
three.js r.66
I have a moving camera in camera container which flies arond the scene on giving paths like an airplane; so it can move to any position x,y,z positive and negative. The camera container is looking at his own future path using a spline curve.
Now I want to rotate the camera using the mouse direction but still keeping the general looking at position while moving forward with object. You could say, i want to turn my head on my body: while moving the body having the general looking at direction, i am turning my head around to lets say 220 degree up and down. So i can't look behind my body.
In my code the cameraContainer is responsible to move on a pline curve and to lookAt the moving direction. The camera is added as a child to the cameraContainer responsible for the rotation using the mouse.
What i don't get working properly is the rotation of the camera. I guess its a very common problem. Lets say the camera when moving only on x-axes moves not straight, it moves like a curve. Specially in different camera positions, the rotation seems very different. I was tryiing to use the cameraContainer to avoid this problem, but the problem seems nothing related to the world coordinates.
Here is what i have:
// camera is in a container
cameraContainer = new THREEJS.Object3D();
cameraContainer.add(camera);
camera.lookAt(0,0,1);
cameraContainer.lookAt(nextPositionOnSplineCurve);
// Here goes the rotation depending on mouse
// Vertical
var mouseVerti = 1; // 1 = top, -1 = bottom
if(window.App4D.mouse.y <= instance.domCenterPos.y) // mouse is bottom?
mouseVerti = -1;
// how far is the mouse away from center: 1 most, 0 near
var yMousePerc = Math.abs(Math.ceil((instance.domCenterPos.y - window.App4D.mouse.y) / (instance.domCenterPos.y - instance.domBoundingBox.bottom) * 100) / 100);
var yAngleDiffSide = (instance.config.scene.camera.maxAngle - instance.config.scene.camera.angle) / 2;
var yRotateRan = mouseVerti * yAngleDiffSide * yMousePerc * Math.PI / 180;
instance.camera.rotation.x += yRotateRan; // rotation x = vertical
// Horizontal
var mouseHori = 1; // 1 = top, -1 = bottom
if(window.App4D.mouse.x <= instance.domCenterPos.x) // mouse is left?
mouseHori = -1;
// how far is the mouse away from center: 1 most, 0 near
var xMousePerc = Math.abs(Math.ceil((instance.domCenterPos.x - window.App4D.mouse.x) / (instance.domCenterPos.x - instance.domBoundingBox.right) * 100) / 100);
var xAngleDiffSide = (instance.config.scene.camera.maxAngle - instance.config.scene.camera.angle) / 2;
var xRotateRan = mouseHori * xAngleDiffSide * xMousePerc * Math.PI / 180;
instance.camera.rotation.y += xRotateRan; // rotation y = horizontal
Would be really thankful if someone can give me a hint!
I got the answer after some more trial and error. The solution is to simply take the initial rotation of y in consideration.
When setting up the camera container and the real camera as child of the container, i had to point the camera to the frontface of the camera container object, in order to let the camera looking in the right direction. That lead to the initial rotation of 0, 3.14, 0 (x,y,z). The solution was to added 3.14 to the y rotation everytime i assigned (as mentioned by WestLangley) the mouse rotation.
cameraReal.lookAt(new THREE.Vector3(0,0,1));
cameraReal.rotation.y = xRotateRan + 3.14;
I am struggling in solving this problem.
On my scene, I have a camera which looks at the center of mass of an object. I have a some buttons that enable to set camera position on particular view (front view, back view,...) along a invisible sphere that surroung the object (constant radius).
When I click on the button, i would like the camera to move from its start position to the end position along the sphere surface. When camera moves I would like it to keep fixing center of mass of the object.
Has anyone have a clue on how to achieve this?
Thanks for help!
If you are happy/prefer to use basic trigonometry then in your initialisation section you could do this:
var cameraAngle = 0;
var orbitRange = 100;
var orbitSpeed = 2 * Math.PI/180;
var desiredAngle = 90 * Math.PI/180;
...
camera.position.set(orbitRange,0,0);
camera.lookAt(myObject.position);
Then in your render/animate section you could do this:
if (cameraAngle == desiredAngle) { orbitSpeed = 0; }
else {
cameraAngle += orbitSpeed;
camera.position.x = Math.cos(cameraAngle) * orbitRange;
camera.position.y = Math.sin(cameraAngle) * orbitRange;
}
Of course, your buttons would modify what the desiredAngle was (0°, 90°, 180° or 270° presumably), you need to rotate around the correct plane (I am rotating around the XY plane above), and you can play with the orbitRange and orbitSpeed until you hare happy.
You can also modify orbitSpeed as it moves along the orbit path, speeding up and slowing down at various cameraAngles for a smoother ride. This process is called 'tweening' and you could search on 'tween' or 'tweening' if you want to know more. I think Three.js has tweening support but have never looked into it.
Oh, also remember to set your camera's far property to be greater than orbitRadius or you will only see the front half of your object and, depending on what it is, that might look weird.
I'm having a problem when I try to move the content of a UIScrollView with CoreMotion.
The thing is, I have a background with approximately 5000px, inside a container, which is inside my scrollView (is a landscape app); I already set the self.scrollView.bounces = FALSE;, my value for motion is attitude.pitch * 10.0; and when I move the content inside and it reaches the edge of the pointZero or the self.scrollView.contentSize.width it doesn't respect the bounds and keep moving in a white screen like it has no limit.
So, I set a verification (the code below), but when it reaches the pointZero it was supposed to stop but still give me a little white border. I set a NSLog and I saw that the contentOffset was still going till x =-14, like the bounce was active. The pitch value is controlling that because when the pitch value is zero the content stays at pointZero, when I raise the value of the pitch ir keep going till -14.
I think that is something wrong with my verification, if anyone can help I will be really grateful!!
self.accel = attitude.pitch *10.0;
//"pointZERO"----------------
if (self.gameArea.contentOffset.x <= self.gameArea.frame.origin.x) {
NSLog(#"%2.f",self.gameArea.contentOffset.x);
self.gameArea.contentOffset = CGPointZero;
} else {
self.gameArea.contentOffset = CGPointMake(self.gameArea.contentOffset.x + self.accel,0.0);
}
//"END OF SCREEN"------------------------
if (self.gameArea.contentOffset.x + self.gameArea.frame.size.width >= self.gameArea.contentSize.width) {
NSLog(#"%2.f",self.gameArea.contentOffset.x);
self.gameArea.contentOffset = CGPointMake(self.gameArea.contentSize.width - self.gameArea.frame.size.width ,0.0);
} else {
self.gameArea.contentOffset = CGPointMake(self.gameArea.contentOffset.x + self.accel,0.0);
}