📜 ⬆️ ⬇️

Pseudo 3D effect

Recently, I paid attention to the videos of the programs that implement the so-called pseudo-3D effect: when the picture of the application changes depending on the user's position relative to the phone. Or phone relative to the user: depending on which side you are from :). To achieve this effect, you can use either sensors or track the position of the user's eyes (so-called head tracking). The second method is somewhat more complicated, although it gives a more plausible result.

As an experiment, we decided to try to make such a 3D background in the Deluxe Moon Pro program (In the version on the market, this effect has not yet been realized!).

Here is an example of what we did:

')
So, let's begin.

In order to achieve the 3D effect, it is necessary to divide the image into “layers” and, depending on the accelerometer reading, displace each layer by a certain amount.

It would seem simple, but there are a few problems.

  1. Hand shake causes flickering pictures
  2. The phone is kept tilted. Therefore, when starting the program, it is better to assume that in this position the user's gaze was directed normal to the plane of the phone, and all sensor changes are counted from this initial value.

Thus, the general approach to solving this problem is as follows:

  1. Split the background into several layers that will move relative to each other. This can be text, background images or special elements created to give "depth".
  2. Subscribe to accelerometer events.
  3. When changing the accelerometer:
  4. Correct sensor readings relative to initial values.
  5. Smooth vibrations from shaking hands
  6. Shift each layer by its size.
  7. Make the sensors optional: not all users might like this surprise.

So, in our case, we have a background image, + 2 layers of stars, + layers of various screen elements.

For filtering, we set some constants:
#define kUpdateFrequency 240.0 //   #define kCutoffFrequency 5.0 //  #define kAccDataScale 2.2 //  

When starting the program, we initialize the low-pass filter in order to remove background rattling caused by hand-shake.
you can read about it here
and download the Apple implementation example here
 -(void)awakeFromNib { filter = [[LowpassFilter alloc] initWithSampleRate:kUpdateFrequency/10 cutoffFrequency:kCutoffFrequency]; //    if ([Options instance].useSensors) { [self performSelector:@selector(startAcc) withObject:nil afterDelay:4]; //              } [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didGoToBG:) name:UIApplicationDidEnterBackgroundNotification object:nil]; //    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didResume:) name:UIApplicationDidBecomeActiveNotification object:nil]; //   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(useSensorsChanged) name:@"useSensors" object:nil]; //    } 

I think it’s not worth describing the reaction to changing the option by turning on / off the 3D background effect and folding the program into the background, everything is trivial

Now consider the function that runs all this beauty.
PS ARC is used because no retain or release
 -(void)startAcc { @try { if (!acc) { startY = 100; //     Y          acc = [UIAccelerometer sharedAccelerometer]; acc.updateInterval = 1/kUpdateFrequency; acc.delegate = self; } } @catch (NSException *exception) { NSLog(@"startAcc %@",exception); } } 

To stop the whole thing
 -(void)stopAcc { @try { if (acc) { acc.delegate = nil; acc = nil; [self resetState]; } } @catch (NSException *exception) { NSLog(@"stopAcc %@",exception); } } 

Then we just have to catch the accelerometer update event.
 - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { @try { [filter addAcceleration:acceleration]; //    «»  double x = filter.x*kAccDataScale; //  double y = filter.y*kAccDataScale; if (startY == 100) { startY = acceleration.y*kAccDataScale; //     Y } //    X if (x > 1) { x = 1; } else if (x < -1) { x = -1; } //    Y if (y > 1) { y = 1; } else if (y < -1) { y = -1; } //    y = (y - startY); //   [self setOffsetElementForX:x Y:y]; } @catch (NSException *exception) { NSLog(@"accelerometer %@",exception); } } @end 

And finally, in the shift function, we move different layers to different fixed values. Therefore, the upper elements move at a slower speed than the background, which creates the 3D effect. In this case, all elements must move in the direction of rotation of the device.
 -(void)setOffsetElementForX:(double)x Y:(double)y { @try { allEll.transform = CGAffineTransformMakeTranslation(-8.5*x, 11.5*y); movingButtonsView.transform = CGAffineTransformMakeTranslation(-8.5*x, 11.5*y); arcView.transform = CGAffineTransformMakeTranslation(-8.5*x, 11.5*y); bgView.transform = CGAffineTransformMakeTranslation(-17*x, 23*y); bgStar1View.transform = CGAffineTransformMakeTranslation(-13*x, 18*y); bgStar2View.transform = CGAffineTransformMakeTranslation(-10*x, 13*y); allEll2.transform = CGAffineTransformMakeTranslation(-17*x, 21*y); } @catch (NSException *exception) { NSLog(@"offsetElementForX %@",exception); } } 

These 4 simple steps will make the program more attractive, more interesting and more innovative. 21st century after all. Remember that a spectacular and stylish design can positively affect the evaluation of your application by reviewers, as well as distinguish them from hundreds of thousands of competitors. We at Lifeware Solutions (http://www.lifewaresolutions.com/) are actively engaged in research and will be happy if our experience will be useful to you. I would be very grateful for your feedback.

Source: https://habr.com/ru/post/162081/


All Articles