I have a possibly beginner question regarding camera rotation in threejs, I am beginning to work on a first person game, the camera controls however have a small issue: if I look up and down they seem to work fine, but if I step to the side of my object and use them then the object (cube) does a circle around the center of my screen.
A breakdown of my code:
Pointer lock tells me when the mouse moves, and I use it for back and forth movement:
camera.rotation.y += movementX;
this works fine, because the y axis will always be up and down, but it doesn't work for side to side:
camera.rotation.x += movementY;
like I said, if I don't move from the starting position then it works fine, otherwise it gets messed up.
I am basically looking for something like:
camera.rotateX(a number);
which is like translateX(), it uses local object axis, not parallel to world axis.
I know about first person controls, but I would prefer to not use them, I would prefer code that is longer but more understandable (if possible/necessary).
Sorry For length of question :)
Related
I'm working on a 3rd person RPG style game using Three.js and Blender. The world terrain is tiled and endlessly loops in all directions, getting triggered when the player obj nears an edge defined along z or x. I'm using the FBX importer, and things work fine on most platforms.
On IOS devices when I move the player object any significant distance from the scene root, the surface materials start to jitter and break apart. The further from root, the worse it gets. It's apparently related to how IOS devices handle floating point calcs, as referenced in these related threads:
GitHub Three.js
Related (from '04)
Related from '07
If working solutions have been figured out, no specific/applied examples have been given that I could find.
I've tried multiple approaches, but unsuccessfully. I don't really want to move the world instead of the player. When I've tried, I'm just not smart enough to figure it out. Moving along z isn't bad, but I can't get object rotations on y or shifting pivot points to work, no matter what groups or parent/child relations are established, or what gets copied and set from what. Matrix transforms of the mesh haven't worked well either.
This is likely a really dumb question, but is there a simpler way to just reset an origin or scene root to wherever the players current position is? Like gets done with cameras, lights, positions and rotations?
I'd really like to get this project working on IOS devices.
Thanks in advance for any suggestions.
When you run into floating-point precision issues, you have two choices:
Make your world smaller. Let's say if your main character is 1000 units tall, you're "wasting" a lot of precision. You could make it 10 or 1 unit tall, and also scale everything else down so you never reach values high enough to encounter the bug.
You could simply nest your environment separately from your main character, and move that instead. Something like this:
scene = new THREE.Scene();
// Instead of adding environment features to scene,
// you add them to the environment group
environment = new THREE.Group();
environment.add(trees);
environment.add(streets);
environment.add(buildings);
character = new THREE.Mesh(geometry, material);
// Add environment separately from your character
scene.add(environment);
scene.add(character);
// Instead of moving your character,
// move the environment in the opposite direction
environment.position.set(-x, -y, -z);
This way, everything that's visible is close to 0, 0, 0. If you need to perform rotations, use the same rule: apply it to the environment, but in the opposite direction.
I am trying to implement a collision system for my three js racing game. I am following this guide to implement the system which calculates the final linear and angular velocities following a collision between two cars.
https://www.myphysicslab.com/engine2D/collision-en.html#resting_contact
However I have troubling when it comes to finding the correct direction for the normal. According to the link: Let the vector n be normal (perpendicular) to the edge of body B that is being impacted, and pointing outward from body B. I am using the following method for finding this normal.
How do I calculate the normal vector of a line segment?
Finding the numerical value of the normal is easy but I have trouble making my program use the correct direction. For instance i want the blue normal and not the red one.
Here is a picture that explains what i mean more clearly I hope:
No formula can guess what side of the surface you are interested in, so it is up to you to provide this hint.
You can select the right orientation that by using one of Rap x Rbp or Rbp x Rap, but it is up to you to choose depending on the orientation conventions used in your model. (With the little information provided, I can't tell you more.)
Question:
I've been working on a first-person maze game with Threejs. I have recently included DeviceOrientationControls to start moving it towards VR, but my previous system for moving the camera is separated from the camera. The camera no longer moves with the arrow keys.
How can I move my camera using arrow keys again while the camera is updated with DeviceOrientationControls?
If possible, how can I automate forward movement relative to the camera's perspective?
Update:
Alex Fallenstedt found a perfect example of what I wanted.
However, I have some questions;
How does the script make the camera move?
How can I simplify this and/or implement this into my work?
Resources:
How to control camera both with keyboard and mouse - three.js
Detecting arrow key presses in JavaScript
How to move camera along a simple path
How to control camera movement with up,down,left,right keys on the keyboard
Comparison:
Here's how it behaved prior (with working controls)
http://orenda.ga/stackoverflow/Nonvr.mp4
Here's how it behaves now (with Orientation)
http://orenda.ga/stackoverflow/VR.mp4
Note:
I've not included my script since I think that it isn't needed for this question. If you need it, please ask and I will insert it here.
To answer you two questions:
1) How does the script make the camera move?
Lets break the script up to its fundamentals. The script begins by adding a bit of state to determine if the user is moving forward.. This state changes when the user interacts with W,A,S,D. We add event listeners that will change this state when a user presses a key or lifts up from a key.. Now, every single frame that is rendered, we can add velocity in specific directions depending on the state of what keys are pressed. This happens here. We now have a concept of velocity. You should console log the velocity values in animate() and checkout how it changes as you move around.
So how does this velocity variable actually move the camera? Well, this script is also using an additional script called PointerLockControls. You can see the full script for PointerLockControls here. Notice how PointerLockControls' only argument is a camera. In order to move the camera, we need to use some nifty functions in PointerLockControls like getObject.. This returns the THREE.js object that you passed into PointerLockControls (aka the camera).
Once we can obtain the camera, we can then move the camera by translating its x, y, and z values by the velocity we created earlier in our animate function.. You can read more about translating objects with these methods in in the Object3D documentation.
2) How can I simplify this and/or implement this into my work?
This is probably the easiest way to implement first person controls to a camera. Everything else in the script example I shared with your earlier is for checks. Like if the user is in a threeJS object, allow them to jump. Or adding a concept of mass and gravity to always pull the user down after they jump. One thing that you might find very useful is to check if the pointer is in the browser's window!. Take the example, break it down to its simplest components, and build from there.
Here is a codepen example that shows you how to move the camera forward smoothly, without pointerlockcontrols, Start at line 53 https://codepen.io/Fallenstedt/pen/QvKBQo
I've been working on an application with a JavaScript/HTML5 canvas. Here's a JSFiddle with some code to show you kind of what I'm doing: JSFiddle
As you can see on the fiddle, after you create two points the cursor starts snapping to 90° and 180°, respectively. But there's a bug, and I don't know how to fix it. It snaps perfectly to 90°, except when you get too close to the last created point, and then it wobbles a bit. And the 180° snapping is the same, except that it gets wobbly a lot farther away than the 90° does. They both use the same code, so I don't know why they behave differently, and I don't know how to get rid of that wobble either way. So there's the problem, let me try to explain some of my code a bit.
The part that I think is messed up is right at the top, the checkAngle and snapMouseToAngle functions.
checkAngle is pretty straight forward, it takes the last two created points and the point where the mouse cursor is, measures the length of their sides, and measures the current angle using the Law of Cosines (Also, I'm no mathematician, if there's a better way to do this, then please enlighten me).
snapMouseToAngle is a little more complex. First it checks if the current mouse preview is horizontal or vertical. Then it checks the angle, adds 8 pixels (or one foot, as I call it) to the current preview coordinates, and then checks the angle again. Then it goes through the snap function (that huge block of logic), which checks if the mouse is within the angleSnapDistance. If it is, then it subtracts the angle that it's supposed to snap to from the current angle, and puts that value inside of leftOver. leftOver is then divided by the difference, leaving us with a number to subtract from the mouse position.
So what am I doing wrong? I don't know what's causing it to wobble like that, but I sure would be indebted to any of you who could tell me how to fix it. Thanks!
Setting pxPerFoot = 1 removes the wobble. Is the pxPerFoot really necessary? It adds jitter to the observed mouse coordinates. Nice work, though!
I'm trying to record exactly where the mouse moves on a web page (to the pixel). I have the following code, but there are gaps in the resulting data.
var mouse = new Array();
$("html").mousemove(function(e){
mouse.push(e.pageX + "," + e.pageY);
});
But, when I look at the data that is recorded, this is an example of what I see.
76,2 //start x,y
78,5 //moved right two pixels, down three pixels
78,8 //moved down three pixels
This would preferably look more like:
76,2 //start x,y
77,3 //missing
78,4 //missing
78,5 //moved right two pixels, down three pixels
78,6 //missing
78,7 //missing
78,8 //moved down three pixels
Is there a better way to store pixel by pixel mouse movement data? Are my goals too unrealistic for a web page?
You can only save that information as fast as it's given to you. The mousemove events fires at a rate that is determined by the browser, usually topping at 60hz. Since you can certainly move your pointer faster than 60px/second, you won't be able to fill in the blanks unless you do some kind of interpolation.
That sounds like a good idea to me, imagine the hassle (and performance drag) of having 1920 mousemove events firing at once when you jump the mouse to the other side of the screen - and I don't even think the mouse itself polls fast enough, gaming mice don't go further than 1000hz.
See a live framerate test here: http://jsbin.com/ucevar/
On the interpolation, see this question that implements the Bresenham's line algorithm which you can use to find the missing points. This is a hard problem, the PenUltimate app for the iPad implements some amazing interpolation that makes line drawings look completely natural and fluid, but there is nothing about it on the web.
As for storing the data, just push an array of [x,y] instead of a string. A slow event handler function will also slow down the refresh rate, since events will be dropped when left behind.
The mouse doesn't exist at every pixel when you move it. During the update cycle, it actually jumps from point to point in a smooth manner, so to the eye it looks like it hits every point in between, when in fact it just skips around willy-nilly.
I'd recommend just storing the points where the mouse move event was registered. Each interval between two points creates a line, which can be used for whatever it is you need it for.
And, as far as processing efficiency goes...
Processing efficiency is going to depend on a number of factors. What browser is being used, how much memory the computer has, how well the code is optimized for the data-structure, etc.
Rather than prematurely optimize, write the program and then benchmark the slow parts to find out where your bottlenecks are.
I'd probably create a custom Point object with a bunch of functions on the prototype and see how it performs
if that bogs down too much, I'd switch to using object literals with x and y set.
If that bogs down, I'd switch to using two arrays, one for x and one for y and make sure to always set x and y values together.
If that bogs down, I'd try something new.
goto 4
Is there a better way to store pixel by pixel mouse movement data?
What are your criteria for "better"?
Are my goals too unrealistic for a web page?
If your goal is to store a new point each time the cursor enters a new pixel, yes. Also note that browser pixels don't necessarily map 1:1 to screen pixels, especially in the case of CRT monitors where they almost certainly don't.