threejs camera movement lags - three.js

I'm playing around with threejs and want to create an rts game. So currently i want to create my own camera controller in order to move around the terrain. The problem is, that the movement lags, even though my fps is always between 35-50 FPS (60FPS works fine). I thought, the human eye shouldn't see something like lags with this framerate, am i wrong?
I've also calculated the movement in dependence of the delta time.
var translation = new Vector3();
// Move camera with keys.
if (Keyboard.IsKeyDown(Key.W))
translation.z -= (deltaTime * 200);
if (Keyboard.IsKeyDown(Key.S))
translation.z += (deltaTime * 200);
if (Keyboard.IsKeyDown(Key.D))
translation.x += (deltaTime * 200);
if (Keyboard.IsKeyDown(Key.A))
translation.x -= (deltaTime * 200);
Game.Camera.position.add(translation);
For testing purposes (But with 60 FPS everything works fine):
http://app.lypster.net
Is it possible to solve the problem or is it a WebGL thing? I can't remember this behavior in XNA.
Kind Regards
Chris

Related

Animate (walk) gltf clone objects from one position to another

I am working on a project where I imported a gltf humanoid that has animations. I am creating clones of the imported model to display in the scene, rather than creating a new one every time.
I have walk and idle animations for the loaded model. How can I animate the cloned in such a way that it appears like they are walking from one location to another another. For example, if the cloned model is at position (10, 20, 0) at time = 1s and it will be at position (13, 20, 0) at time = 2s, I would like it to appear that the model is walking between the positions. I read the new Animation System documentation and did a lot of searching but it didn't help.
Thanks for your help.
P.S: I cannot share the code from the project due to restrictions.
You can get the direction by subtracting both vectors and then normalizing it.
let direction = new THREE.Vector3().subVectors(destination.position, object.position).normalize();
Then in your render function update object position on each frame in that direction. Speed variable value is up to you (default 1).
object.position.x += direction.x * speed;
object.position.y += direction.y * speed;
object.position.z += direction.z * speed;
You would need a boolean value like isMoving or distance between objects to know when to start and stop.
object.position.distanceTo( destination.position );
https://threejs.org/docs/#api/en/math/Vector3.distanceTo
As for the animation I think you just want to call animation.play() on start and animation.stop() when you reach the destination.

Moving GameObject without transform.position through a touchscreen? (In Unity3d)

I'm developing a mobile game in Unity3d which the player needs to move a stick that is placed just a little bit higher then the finger with transform.position and block a ball that is moved with Force.Mode2D.impulse. The problem is that the ball goes through the stick if the stick is moved too fast. Could anyone please teach me how to code the stick movement with Force (or any other way that works) that still moves according to the finger position on touch screen ( A.K.A Input.mousePosition) instead of using buttons?
The code goes as such if anyone needs the info;
Stick:
float defencePosX = Mathf.Clamp( Input.mousePosition.x / Screen.width * 5.6f - 2.8f , -2.8f, 2.8f);
float defencePosY = Mathf.Clamp( Input.mousePosition.y / Screen.height * 10 - 4f, -3.3f, -0.5f);
this.transform.position = new Vector3 (defencePosX, defencePosY, 0);
Ball:
projectileSpeed = Random.Range (maxSpeed, minSpeed);
projectileSwing = Random.Range (-0.001f, 0.001f);
rb.AddForce (new Vector2 (projectileSwing * 1000, 0), ForceMode2D.Impulse);
rb.AddForce (new Vector2 (0, projectileSpeed), ForceMode2D.Impulse);
a video of the bug:
https://youtu.be/cr2LVBlP2O0
basicly if i dont move the stick it hits but if i move it fast the ball goes right through. (the bouncing sound effect doesnt work if itss too fast as well)
When working with physics objects, you'll want to use just the Rigidbody component when moving them. Otherwise, it's interpreted as a teleport and no physics is applied and no movement is calculated.
Try using Rigidbody.MovePosition instead of transform.position.
Also, make sure the Rigidbody components on your stick AND ball both have collisionDetectionMode set to 'Continuous Dynamic'. That's how you get small fast-moving physics objects to hit one another in between frames.
float defencePosX = Mathf.Clamp( Input.mousePosition.x / Screen.width * 5.6f - 2.8f , -2.8f, 2.8f);
float defencePosY = Mathf.Clamp( Input.mousePosition.y / Screen.height * 10 - 4f, -3.3f, -0.5f);
rb.MovePosition(new Vector3 (defencePosX, defencePosY, 0));
Id recommend that you set the balls force to Vector3.zero before adding force to it, or that you use the collider of your blocking movement as a bounce pad for the ball.
Please remember to check that your colliders are scaled correctly according to the blocker.
A video displaying your issue would be helpful to understand it better.

threejs raycaster cannot intersect in stereoscopic mode

I am trying to make use of Raycaster in a ThreeJS scene to create a sort of VR interaction.
Everything works fine in normal mode, but not when I enable stereo effect.
I am using the following snippet of code.
// "camera" is a ThreeJS camera, "objectContainer" contains objects (Object3D) that I want to interact with
var raycaster = new THREE.Raycaster(),
origin = new THREE.Vector2();
origin.x = 0; origin.y = 0;
raycaster.setFromCamera(origin, camera);
var intersects = raycaster.intersectObjects(objectContainer.children, true);
if (intersects.length > 0 && intersects[0].object.visible === true) {
// trigger some function myFunc()
}
So basically when I try the above snippet of code in normal mode, myFunc gets triggered whenever I am looking at any of the concerned 3d objects.
However as soon as I switch to stereo mode, it stops working; i.e., myFunc never gets triggered.
I tried updating the value of origin.x to -0.5. I did that because in VR mode, the screen gets split into two halves. However that didn't work either.
What should I do to make the raycaster intersect the 3D objects in VR mode (when stereo effect is turned on)?
Could you please provide a jsfiddle with the code?
Basically, if you are using stereo in your app, it means you are using 2 cameras, therefore you need to check your intersects on both cameras views, this could become an expensive process.
var cameras =
{ 'camera1': new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000),
'camera2': new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 1, 10000)
};
for (var cam in cameras) {
raycaster.setFromCamera(origin, cameras[cam]);
//continue your logic
}
You could use a vector object that simulates the camera intersection to avoid checking twice, but this depends on what you are trying to achieve.
I encountered a similar problem, I eventually found the reason. Actually in StereoEffect THREE.js displays the meshes on the two eyes, but in reality is actually adds only one mesh to the scene, exactly in the middle of the line left-eye-mesh <-> right-eye-mesh, hidden to the viewer.
So when you use the raycaster, you need to use it on the real mesh on the middle, not the illusion displayed on each eye !
I detailled here how to do it
Three.js StereoEffect displays meshes across 2 eyes
Hopes it solves your problem !
You can use my StereoEffect.js file in your project for resolving problem. See example of using. See my Raycaster stereo pull request also.

Zoom toward mouse (eg. Google maps)

I've written a home-brew view_port class for a 2D strategy game. The panning (with arrow keys) and zooming (with mouse wheel) work fine, but I'd like the view to also home towards wherever the cursor is placed, as in Google Maps or Supreme Commander
I'll spare you the specifics of how the zoom is implemented and even what language I'm using: this is all irrelevant. What's important is the zoom function, which modifies the rectangle structure (x,y,w,h) that represents the view. So far the code looks like this:
void zoom(float delta, float mouse_x, float mouse_y)
{
zoom += delta;
view.w = window.w/zoom;
view.h = window.h/zoom;
// view.x = ???
// view.y = ???
}
Before somebody suggests it, the following will not work:
view.x = mouse_x - view.w/2;
view.y = mouse_y - view.h/2;
This picture illustrates why, as I attempt to zoom towards the smiley face:
As you can see when the object underneath the mouse is placed in the centre of the screen it stops being under the mouse, so we stop zooming towards it!
If you've got a head for maths (you'll need one) any help on this would be most appreciated!
I managed to figure out the solution, thanks to a lot of head-scratching a lot of little picture: I'll post the algorithm here in case anybody else needs it.
Vect2f mouse_true(mouse_position.x/zoom + view.x, mouse_position.y/zoom + view.y);
Vect2f mouse_relative(window_size.x/mouse_pos.x, window_size.y/mouse_pos.y);
view.x = mouse_true.x - view.w/mouse_relative.x;
view.y = mouse_true.y - view.h/mouse_relative.y;
This ensures that objects placed under the mouse stay under the mouse. You can check out the code over on github, and I also made a showcase demo for youtube.
In my concept there is a camera and a screen.
The camera is the moving part. The screen is the scalable part.
I made an example script including a live demo.
The problem is reduced to only one dimension in order to keep it simple.
https://www.khanacademy.org/cs/cam-positioning/4772921545326592
var a = (mouse.x + camera.x) / zoom;
// now increase the zoom e.g.: like that:
zoom = zoom + 1;
var newPosition = a * zoom - mouse.x;
camera.setX(newPosition);
screen.setWidth(originalWidth * zoom);
For a 2D example you can simply add the same code for the height and y positions.

Smooth animation in Cocos2d for iOS

I move a simple CCSprite around the screen of an iOS device using this code:
[self schedule:#selector(update:) interval:0.0167];
- (void) update:(ccTime) delta {
CGPoint currPos = self.position;
currPos.x += xVelocity;
currPos.y += yVelocity;
self.position = currPos;
}
This works however the animation is not smooth. How can I improve the smoothness of my animation?
My scene is exceedingly simple (just has one full-screen CCSprite with a background image and a relatively small CCSprite that moves slowly).
I've logged the ccTime delta and it's not consistent (it's almost always greater than my specified interval of 0.0167... sometimes up to a factor of 4x).
I've considered tailoring the motion in the update method to the delta time (larger delta => larger movement etc). However given the simplicity of my scene it's seems there's a better way (and something basic that I'm probably missing).
The scheduler will try to accommodate and call your selector as per your interval but if there are other processes running, it can be earlier or later (hence why the inconsistency).
Instead, multiply your xVelocity and yVelocity by delta - this should scale the velocities into a far smoother motion.
For example:
- (void) update:(ccTime) delta {
CGPoint currPos = self.position;
currPos.x += (xVelocity * delta);
currPos.y += (yVelocity * delta);
self.position = currPos;
}
Try using the default [self scheduleUpdate] method rather than calling it directly as you are doing, see if that makes a difference. This method is designed for what you are doing and may be smoother.

Resources