Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make perspective transformation look exactly same on iOS and Android #18302

Closed
wants to merge 3 commits into from

Conversation

syaau
Copy link
Contributor

@syaau syaau commented Mar 9, 2018

Summary:
There is a variation in iOS and Android output while performing perspective transformation. The variation exists even when used in Android devices with different screen density.

Test Plan:
I carried out tests on multiple devices with different perspective value and varying rotation X angle, and back calculated the Camera Distance value from the screen shots. On iOS the values were almost equal to the Pixel Density * Perspective value wheres on Android devices the Distance would always come out to be approximately 2.24 * Perspective value irrespective of the device screen density. I used the following code to use perspective transformation and verified that output matched exactly on all platforms.

const PERSPECTIVE = Platform.OS === 'ios' ? P : (P * PixelRatio.get()) / Math.sqrt(5);

The code was then translated to the BaseViewManager.java and verified that the output matched on all platforms.

Changelog:
[ANDROID] [BUGFIX] [Perspective Transformation] - Corrected perspective transformation to look exactly same on iOS and Android devices.

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Mar 9, 2018
@pull-bot
Copy link

pull-bot commented Mar 9, 2018

Warnings
⚠️

📋 Changelog - This PR appears to be missing Changelog. Please add a section called "changelog" and format it as explained in the contributing guidelines.

Generated by 🚫 dangerJS

@hramos hramos added Android Platform: iOS iOS applications. and removed Android labels Mar 13, 2018
@react-native-bot react-native-bot added Android Ran Commands One of our bots successfully processed a command. labels Mar 16, 2018
@react-native-bot react-native-bot added Platform: Android Android applications. Ran Commands One of our bots successfully processed a command. labels Mar 18, 2018
@facebook-github-bot
Copy link
Contributor

@syaau I tried to find reviewers for this pull request and wanted to ping them to take another look. However, based on the blame information for the files in this pull request I couldn't find any reviewers. This sometimes happens when the files in the pull request are new or don't exist on master anymore. Is this pull request still relevant? If yes could you please rebase? In case you know who has context on this code feel free to mention them in a comment (one person is fine). Thanks for reading and hope you will continue contributing to the project.

@cpojer
Copy link
Contributor

cpojer commented Jan 29, 2019

@syaau thanks for this PR. Unfortunately it is a bit hard through the test plan and code to understand what is changing here. Would you be able to provide some before/after screenshots that helps us understand your change? Thank you.

@syaau
Copy link
Contributor Author

syaau commented Jan 29, 2019

Here is an example code, that rotates a 200x200 square by 45deg on x-axis with a very near perspective distance (120 units).

import React from 'react';
import { StyleSheet, View, Platform, PixelRatio } from 'react-native';

const PERSPECTIVE = 120;
const perspective = PERSPECTIVE;
// const perspective = Platform.OS === 'ios' ? PERSPECTIVE : (PERSPECTIVE * PixelRatio.get()) / Math.sqrt(5);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: '#F5FCFF',
  },
  ref: {
    position: 'absolute',
    width: 200,
    height: 200,
    backgroundColor: 'yellow',
  },
  perspective: {
    position: 'absolute',
    width: 200,
    height: 200,
    backgroundColor: 'red',
    opacity: 0.5,
    transform: [
      { perspective },
      { rotateX: '45deg' },
    ],
  },
});

const App = () => (
  <View style={styles.container}>
    <View style={styles.ref} />
    <View style={{ position: 'absolute', justifyContent: 'center', alignItems: 'center' }}>
      <View style={styles.perspective} />
    </View>
  </View>
);

export default App;

iPhone Output (same irrespective of pixel density of the phone)
simulator screen shot - iphone x - 2019-01-30 at 00 08 09

Android Output (on a iphone5x, pixel density of 2.625)
screenshot_1548787040

Android Output (on Pixel 2 XL, pixel density of 3.5)
screenshot_1548788035
The output went below the screen with the same perspective value

Android Output (after applying the fix, Use the commented line on above code)
screenshot_1548787625

@syaau
Copy link
Contributor Author

syaau commented Jan 29, 2019

@cpojer Please check the screenshots above, where you could see that the perspective values didn't work correctly in between the android devices with different pixel densities. After applying the fix, the output looks exactly the same with the iOS and irrespective of the Pixel Density. Above in the example code, I have applied the fix on the perspective value itself, whereas this pull request implements the same thing in android.

I am not sure why the magic number 5 had been used previously to calculate the camera distance.
private static final float CAMERA_DISTANCE_NORMALIZATION_MULTIPLIER = 5;.

I guess it has got something to do with the matrix that has been used for transformation. But sqrt(5) produced the same output as iOS.

@facebook-github-bot facebook-github-bot added the Import Started This pull request has been imported. This does not imply the PR has been approved. label Jan 30, 2019
Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cpojer is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

Copy link
Contributor

@cpojer cpojer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the thorough explanation and the screenshots. I added a link to this Pull Request as a comment so that people can find more information if they come across this.

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cpojer is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

syaau and others added 2 commits January 30, 2019 15:52
The perspective projection didn't match with iOS output and also
differed on devices with different pixel density. While back
calculating the perspective value from the generated output
mathematically, the Camera Distance was coming out to be approx.
2.24 (sqrt 5) times the given perspective value (irrespective of
the display density). After correcting the values, the perspective
output matched exactly with the ios output with any screen density.
Before this fix, as a work around I had to back-calculate the
perspective value on android as:
  const PERSPECTIVE = Platform.OS === 'ios' ? P : P * PixelRatio.get() / 2.236;
@cpojer
Copy link
Contributor

cpojer commented Jan 30, 2019

Having a bit of a hiccup with the import right now but I'm gonna rebase this PR and will get it landed as soon as possible.

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cpojer is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

Copy link
Contributor

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cpojer is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

@react-native-bot
Copy link
Collaborator

@syaau merged commit 4c10f93 into facebook:master.

@facebook facebook locked as resolved and limited conversation to collaborators Jan 30, 2019
@react-native-bot react-native-bot added the Merged This PR has been merged. label Jan 30, 2019
@hramos hramos removed Import Started This pull request has been imported. This does not imply the PR has been approved. labels Feb 6, 2019
matt-oakes pushed a commit to matt-oakes/react-native that referenced this pull request Feb 7, 2019
…acebook#18302)

Summary:
There is a variation in iOS and Android output while performing perspective transformation. The variation exists even when used in Android devices with different screen density.
Pull Request resolved: facebook#18302

Differential Revision: D13877483

Pulled By: cpojer

fbshipit-source-id: e48be047a8047c7562722923a67666cb098243d8
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. Platform: Android Android applications. Platform: iOS iOS applications. Ran Commands One of our bots successfully processed a command.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants