# Non-linear zoom for 2D

This topic is 833 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hello,

quick question, I'm using zoom to show sprites in a big state (16.0f = 1600%, or even higher), and then reduce the zoom down to 1.0f over time to get an effect of the sprite shrinking. However the problem with this is, that for the first % zoom that are being taking away, the sprite appears to shrink very slowly, while for the last few frames, the zoom appears to speed up.

This can easily be explained, as in the range of 1.0f to say 2.0f, the size nearly doubles, while for like 100.0f to 101.0f, its a mere 1% more size, while it takes my linear zoom function the same time for both values.

const float zoomX = (xLeft / timeLeft) * dt;
const float zoomY = (yLeft / timeLeft) * dt;

pZoom->x += zoomX;
pZoom->y += zoomY;

xLeft -= zoomX;
yLeft -= zoomY;
timeLeft -= dt;


So what I'm looking for a formula that takes into account the actual amount of reduction in size, so that 1.0f to 2.0f takes just as long as 2.0f to 4.0f (as both result in the same relative reduction of size). It doesn't need to utilize the values about, I actually have given before starting calculations:

- current/target zoom

- duration of the zoom process

If there is no good formula for this (I already searched and tried to make somthing up my self, but **** math), I'd be also glad with something that at least simulates a constant zoom speed (I dont' know if you guys can just imagine what it looks like currently, if you need some visual hint let me know), or some hint into how it could be done Any ideas?

##### Share on other sites

The following code will do what you want assuming you have a constant update tick.

float Size = 16.0f;

then in the update

const float RateDecay = 0.99f;

Size = Size*RateDecay;

If you don't have a fixed timestep you can do the same using exponential function

size = size * log(dt * kConstant)

##### Share on other sites

Do linear interpolation in logarithmic domain instead.

Calculate the logarithm of your start and end values, whatever they represent. Any log-base is fine.
Linearly interpolate between the two logarithms as usual.
For every step in your animation/interpolation, calculate the inverse of the chosen logarithm to determine the instantaneous linear scale.

The natural log() and exp() functions work just fine for step 1 and 3, respectively.

The following code will do what you want assuming you have a constant update tick.

float Size = 16.0f;

then in the update

const float RateDecay = 0.99f;

Size = Size*RateDecay;

Also thanks for the suggestion, I do happen to have a constant timestep, yet it appears that it is easier with brother bobs code since I need the change to happen in a specific timeframe.

##### Share on other sites

Simplest solution is to just try it with a simulation.

From the timeframe and the timestep, you know the number of iterations.

Fold the shrinking computation in a 'for' loop with the above number of iterations, and let it run.

print the final size.

If too big, increase the constant, if too small decrease the constant.

Repeat until happy with the result

##### Share on other sites

float originalSize = ...;

float scaleRate = 1.1f;

//game loop

...

float scale = 1.0f + pow(scaleRate, dt);

float curSize = originalSize * scale;

...

Does this work? It looks like it should work...

This might be more reliable since it never changes the original size (thus avoiding cumulative floating point errors)

Edited by Waterlimon

##### Share on other sites

Does this work? It looks like it should work...

This might be more reliable since it never changes the original size (thus avoiding cumulative floating point errors)

IDK, but brother bobs solution already works without floating point errors, since I changed from storing "zoomLeft" to just storing zoomStart & zoomEnd, and interpolating those in the process.

if(timeLeft - dt <= 0.0f)
{
pZoom->x = exp(vEndZoomLog.x);
pZoom->y = exp(vEndZoomLog.y);

CallOutput(0);
}
else
{
const math::Vector2f vCurrentZoomLog = (vEndZoomLog - vStartZoomLog) * (1.0f - (timeLeft / time)) + vStartZoomLog;

pZoom->x = exp(vCurrentZoomLog.x);
pZoom->y = exp(vCurrentZoomLog.y);

timeLeft -= dt;

SetLocal<float>(2, timeLeft);
}


I appreciate every additional input but I don't see it becoming simpler and more functional like this :D

##### Share on other sites

This topic is 833 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.