Add smoothing to camera mover - unity3d

Hi I have a script that adjusts the distance of an camera in unity to make sure an object is always fully in the view of the camera. I do this like so:
Vector3 characterSize = UpdateBounds(totalPoints).size;
float objectSize = Mathf.Max(Mathf.Max(characterSize.x / 2, characterSize.y / 2), characterSize.z / 2);
float cameraView = 2f * Mathf.Tan(0.5f * Mathf.Deg2Rad * Camera.main.fieldOfView);
float rigRadius = cameraPadding * objectSize / cameraView;
In this case the rigRadius is the distance from the subject to make sure the camera view contains the total object.
The problem i am having is that when the object has a big change in size over a relativly small time period. The camera movement feels jerky and not smooth at all.
So how do i adjust this code to add some sort of a smoothing value? I just can't seem to figure it out.
As far as i managed to figure out I need to smooth the rigRadius value but i dont know how :(

Have a target radius that your current radius smoothly moves towards.
For best(-ish) results, use a formula where the "speed" of the smoothing is dependent on how far the current situation is from target situation (Note: In this case, situation = radius). In other words, zoom speed depends on the current zoom state rather than a fixed starting point.
So really far (for example after a big, fast change) = really fast (the start of the smoothing is quick), but really close = really slow (so the end of the smoothing is slow).
Here's a decent tutorial on this for 2D: https://youtu.be/AvnrywsoTe0
Note how the lerp uses current camera ortho size rather than a fixed "starting" ortho size to apply the zoom, effectively making the effect I described, where zooming speed depends on current zoom and its "distance" to target zoom.

Related

AR place an object with same size

I am building an AR application. I have some points which are real worlds coordinates.
I can geolocate these points through Mapbox. My problem is that when I got far away from the points, they are looking getting smaller. I want to see them as the same size independently from the distance.
Here is an example of how to visualize the points:
So, if I near the points I see them in normal sizes. Even though I got 400 KMs away from the point, I want to see it in the same size. Is it possible?
You can try to scale the lables by some value * distance to object.
If you are standing in device and the target is in target it would be:
float experimentalScale = 0.5f
This is the amplifier of the distance. If you increase the value, the lable will get bigger by greater distance. Try out what works best for you.
float scaleFactor = Vector3.Distance(device.transform.position, target.transform.position) * experimentalScale;
target.transform.localScale(scaleFactor,scaleFactor,scaleFactor)
This only works if your Objects scale is 1. If it is something else, just multiply the scale with scaleFactor.

Camera: "Linear" zoom

I want to move a camera closer to an object in Unity, so that the zooming is linear. Take a look at the zooming in the Scene window in the Unity Editor. The camera isn't moving with a constant speed. The more zoomed in you are, the slower the camera moves. And I do want to move the camera, I don't want to change the FOV.
First off, yes do not use the FOV to do that, it would be a massive pain to control the movement. Being in low FOV, would mean you are focus on a tiny part and movement would be hard to control since one unit would be a large movement in small FOV. Also, a large FOV creates fish eye effect. So nope.
One way you could achieve this fast to slow effect is to use a distance to define the amount of movement
Let's consider you use the mouse wheel to zoom in and out, you listens to the value and create a movement based on that.
float movement = Input.GetAxis("Mouse ScrollWheel");
if(movement == 0)
{
return;
}
Transform camTr = Camera.main.transform;
float distance = Vector3.Distance(camTr.position, origin.position) + 1;
camTr.Translate(camTr.forward * distance * movement * Time.deltaTime * speed);
speed variable is meant to control how fast regardless of the distance. Distance gets a plus 1 so you can still move while real close to the origin.
The origin position needs to be defined, it could be based on a raycast going forward from the camera and hitting at y = 0. Just an idea. It could also be a focused object, that all depends on what you are doing.
The whole point here is that your camera will move faster if you are far from the focus point. Also, you may want to clamp the movement so that begin far away does not result in gigantic movement.
i propose you to use FOV (because player feel good)
1- use Transform.localPosition to change distance of camera to near or far - you should change z axis to changing distance of camera
2- use camera rendertotexture and in GUI change scale of it ( isn't good because need pro unity license and get allot of memory);
but can't know whats reason for you want forget changing FOV
One step of perspective projection of a point is the division by distance of that point. This means that the projected size of any object does not change linearly with its distance.
projectedSize = originalSize / distance
So if you want to approach an object in a way that its projected size grows linearly, you'll have to change your distance non-linearly.
We do this by also dividing the distance by some value f. The exact value of f depends on the stepSize and (I think) the FoV of your camera.
By using FixedUpdate() instead of Update() we make sure we have a constant stepSize which allows us to assume f as being constant as well.
void FixedUpdate()
{
newDistance = oldDistance / f;
}
For the definition of f you can use any value bigger than, but close to 1. For example f = 1.01f. This will approximate the desired behaviour quite well. If you want it to be perfectly linear, you'll have to dig deeper into the calculations behind perspective projection and calculate the exact value of f yourself: https://en.wikipedia.org/wiki/3D_projection#Perspective_projection

Projectile Motion in Unity

So my friend and I are making some 2D game, we are using some custom character controller, so we are not using rigidbody2D. Now we have some sort of catapult which needs to eject the player in a projectile-motion style.
We've done it for the catapult which shoots the player straight up
In inspector you can decide how much units do you want player to jump and how much does it need to get to reach max height.
So here is the code for the catapult that shoots the player up.
float ejectInicialY = (jumpHeight - ( player.physics.gravity * Mathf.Pow(timeToReachMaxHeight, 2) / 2)) / timeToReachMaxHeight;
float ejectVelocityY = ejectInicialY + player.physics.gravity * Time.deltaTime;
player.physics.playerVelocity = new Vector2(ejectVelocityY, 0f);
I tried to apply the same formulas for the X coordinate, but it doesn't work well.
Any help would be greatly appreciated.
This is ultimately a physics problem.
You are calculating current velocities by determining the acceleration of the object. Acceleration of an object can be determined from the net force acting on the object (F) and the mass of the object (m) through the formula a = F / m. I highly recommend reading some explanations of projectile motion and understanding the meaning of the motion equations you are using.
Vertical Direction
For the vertical direction, the net vertical force during the jump (assuming no air drag, etc.) is player.physics.gravity. So you apply your motion formulas assuming a constant acceleration of player.physics.gravity, which you've seemed to have accomplished already.
Horizontal Direction
Becausegravity does not commonly act in the horizontal direction, the net horizontal force during the jump (assuming no air drag, etc.) is 0. So again you can apply your motion formulas, but this time using 0 as your acceleration. By doing this, you should realize that velocityX does not change (in the absence of net horizontal force). Therefore the X coordinate can be determined through (in pseudo-code) newPositionX = startPositionX + Time.deltaTime * velocityX

How many pixels is an impulse in box2d

I have a ball that you blow on with air. I want the ball to be blown more if it is close to the blower and blown less if it is farther away from the blower. I am using box2d and I am using the impulse function."body->ApplyLinearImpulse(force, body->GetPosition())". I can't seem to find a formula or a way to accomplish this. If I want the ball to blow to a total distance of 300 pixels right, how could I accomplish this? Please help.
If you want to calculate the distance before simulation you have to take a look at box2d sources. When simulating the velocity of the body is modified according to gravity, extra applied forces, linear damping, angular damping and possibly something more. Also velocity relies on velocity iterations.
But I think if you want a really smooth motion (like from a blow) you'd better use applyForce function instead of impulse. But be sure you are applying the force each simulation step.
EDIT:
Also you can simulate the air resistance as:
Fa = -k*V*V. I've simulated movement in the pipe this way. Worked great.
So each step you can make something like this:
BlowForce = k1 / distance; // k1 - coefficient
Resistance = -k2 * V * V; //k2 - another coefficient
TotalForce = BlowForce + Resistance;
body->ApplyForce(TotalForce);
I am not a box 2d expert but what i would do is create a small box which is actually invisible and let the ball hit the box...if the blower is blowing more i would give more speed to the box in opposite direction. As far as 300 pixel length is concerned you have to adjust the forces and velocity such that the ball goes
300/<your_rendering_window_to_physics_world_ratio>
in physical world.
Force = mass * acceleration, so take the mass you set your body to, calculate the acceleration you want (remember to divide 300px by PTM_RATIO) and then multiply the two together.

Smoothing out didAccelerate messages

I'm working on something similar to an inclinometer. I rotate an image based on the angle calculated in didAccelerate (from UIAccelerometerDelegate) using the passed in UIAcceleration variable. The image is jittery or twitchy. Even when the phone is laying on its back and not moving. There are some inclinometers in the app store that are super smooth. I've tried to smooth it out by checking the last reading and if it is within a range, don't do anything. That stops some of the twitching but then you get into something that looks like stop animation. How can I get a smoother affect?
I would suggest smoothing using a 'critically damped spring'.
Essentially what you do is calculate your target rotation (which is what you have now).
Instead of applying this directly to the image rotation, you attach the image rotation to the target rotation with a spring, or piece of elastic. The spring is damped such that you get no oscillations.
You will need one constant to tune how quickly the system reacts, we'll call this the SpringConstant.
Basically we apply two forces to the rotation, then integrate this over time.
The first force is that applied by the spring, Fs = SpringConstant * DistanceToTarget.
The second is the damping force, Fd = -CurrentVelocity * 2 * sqrt(SpringConstant)
The CurrentVelocity forms part of the state of the system, and can be initialised to zero.
In each step, you multiply the sum of these two forces by the time step.
This gives you the change in the value of the CurrentVelocity.
Multiply this by the time step again and it will give you the displacement.
We add this to the actual rotation of the image.
In c++ code:
float CriticallyDampedSpring( float a_Target,
float a_Current,
float & a_Velocity,
float a_TimeStep )
{
float currentToTarget = a_Target - a_Current;
float springForce = currentToTarget * SPRING_CONSTANT;
float dampingForce = -a_Velocity * 2 * sqrt( SPRING_CONSTANT );
float force = springForce + dampingForce;
a_Velocity += force * a_TimeStep;
float displacement = a_Velocity * a_TimeStep;
return a_Current + displacement;
}
I imagine you have two dimensions of rotation. You just need to use this once for each dimension, and keep track of the velocity of each dimension separately.
In systems I was working with 5 was a good value for the spring constant, but you will have to experiment for your situation. Setting it too high will not get rid of the jerkiness, setting it too low it will react too slowly.
Also, you might be best to make a class that keeps the velocity state rather than have to pass it into the function over and over.
I hope this is helpful :)