Bug 31895 - No perspective when using CATransform3D.MakeRotation
Summary: No perspective when using CATransform3D.MakeRotation
Alias: None
Product: iOS
Classification: Xamarin
Component: Xamarin.iOS.dll ()
Version: XI 8.10
Hardware: Macintosh Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
Depends on:
Reported: 2015-07-13 16:49 UTC by Jon Goldberger [MSFT]
Modified: 2015-07-15 11:47 UTC (History)
3 users (show)

Is this bug a regression?: ---
Last known good build:

Test Project (XI and Xcode) (256.91 KB, application/zip)
2015-07-13 16:49 UTC, Jon Goldberger [MSFT]

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description Jon Goldberger [MSFT] 2015-07-13 16:49:06 UTC
Created attachment 12006 [details]
Test Project (XI and Xcode)

## Description

When trying to rotate a UIView.Layer using CATransform3D.MakeRotation, no perspective is shown. 

In iOS one should be able to rotate a UIVew.Layer with perspective using the following code in Obj-C:

>UIView *myView = [[self subviews] objectAtIndex:0];
>CALayer *layer = myView.layer;
>CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
>rotationAndPerspectiveTransform.m34 = 1.0 / -500;
>rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 45.0f * M_PI / 180.0f, 0.0f, 1.0f, 0.0f);
>layer.transform = rotationAndPerspectiveTransform;

However in Xamarin iOS, the static method:
CATransform3D.MakeRotation(nfloat angle, nfloat x, nfloat y, nfloat z);
does not take a transform object as the objective-C static method does, so I see no way to set the m34 value. Setting it after creating the rotation does not apply perspective. E.g.:

>CALayer layer = image.Layer; // image is a UIImage object
>var rotateX = CATransform3D.Identity;
>rotateX = CATransform3D.MakeRotation((float)(75 * Math.PI / 180.0f), 1, 0, 0);
>rotateX.m34 = 1f / -500f;
>layer.Transform = rotateX;

And setting it before also does not apply perspective. E.g.:

>CALayer layer = image.Layer; // image is a UIImage object
>var rotateX = CATransform3D.Identity;
>rotateX.m34 = 1f / -500f;
>rotateX = CATransform3D.MakeRotation((float)(75 * Math.PI / 180.0f), 1, 0, 0);
>layer.Transform = rotateX;

It seems to me, though of course I could be missing something, that one would need to have the m34 value set and then pass the transform with that value set into the CATransform3D.MakeRotation(...) method. If my thinking is in error, then an example of how to do this properly would be greatly appreciated. Google was not helpful. 

I tested this with both a Classic API and Unified API project (test project attached) and got the same results on both. 

## Steps to reproduce:

1. Open attached test solution

2. Deploy either of the projects (one is Classic API, the other is Unified API) to an iOS device/simulator.

Expected result: The image will be rotated along the X axis by 75 degrees and will show perspective (narrower on top or bottom)

Actual result: Image is rotated along the X axis but without any perspective (Top and bottom of image are same length)

## Notes

I provided an Xcode project Obj-C example of the 3D transform with perspective using the same values as in the Xamarin iOS projects. 

Screenshot of expected image after transform (From Obj-C example): http://screencast.com/t/xvGGmi0AzAJ

Screenshot of actual results in Xamarin iOS: http://screencast.com/t/T4nYcL9AXlRR

## My Environment

=== Xamarin Studio ===

Version 5.9.4 (build 5)
Installation UUID: 2dc9022f-f9a8-424f-8284-bf224cbbfde0
	Mono 4.0.2 ((detached/c99aa0c)
	GTK+ 2.24.23 (Raleigh theme)

	Package version: 400020005

=== Xamarin.Android ===

Version: (Business Edition)
Android SDK: /Users/apple/Library/Developer/Xamarin/android-sdk-mac_x86
	Supported Android versions:
		2.3    (API level 10)
		4.0.3  (API level 15)
		4.1    (API level 16)
		4.2    (API level 17)
		4.3    (API level 18)
		4.4    (API level 19)
		4.4.87 (API level 20)
		5.0    (API level 21)
Java SDK: /usr
java version "1.7.0_79"
Java(TM) SE Runtime Environment (build 1.7.0_79-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)

=== Xamarin Android Player ===

Version: Unknown version
Location: /Applications/Xamarin Android Player.app

=== Apple Developer Tools ===

Xcode 6.4 (7720)
Build 6E35b

=== Xamarin.iOS ===

Version: (Business Edition)
Hash: 8b265d6
Branch: master
Build date: 2015-06-30 15:19:13-0400

=== Xamarin.Mac ===

Version: (Business Edition)

=== Build Information ===

Release ID: 509040005
Git revision: 8010a90f6e246b32364e3fb46ef2c9d1be9c9a2b
Build date: 2015-06-08 16:52:06-04
Xamarin addins: 7e93e9c3503f28770f23ce1b7eafd829919f18e8

=== Operating System ===

Mac OS X 10.10.4
Darwin Jons-iMac.local 14.4.0 Darwin Kernel Version 14.4.0
    Thu May 28 11:35:04 PDT 2015
    root:xnu-2782.30.5~1/RELEASE_X86_64 x86_64
Comment 3 Florian Haider 2015-07-15 08:21:28 UTC
I was finally able to solve this problem like this:

var transform = CoreAnimation.CATransform3D.Identity;
transform.m34 = new nfloat(1f / -500f);
transform = transform.Rotate(new nfloat(45f * Math.PI / 180f), 1, 0, 0);
layer.Transform = transform;

First it is important to set m34 before doing any rotating (as explained here http://stackoverflow.com/questions/10913676/why-does-a-calayers-transform3ds-m34-need-to-be-modified-before-applying-the-r).

Then use the Rotate() method of the CATransform3D object itself to apply a rotation to an existing matrix. The static method CATransform3D.MakeRotation() does not offer the possibility to pass an existing transformation matrix to it (like CATransform3DRotate() does in objective C).

And that's it, works for me :-)
Comment 4 Rolf Bjarne Kvinge [MSFT] 2015-07-15 11:47:50 UTC
I'll close this then.

I'm glad you could make it work and thanks for getting back to us with the answer.