ios 投影效果

2014-08-23 20:08:14 yongyinmg 阅读数 5290
  • 计算机系统--多媒体技术

    完全掌握iOS, Android, 嵌入式Linux平台音视频开发的相关知识并能够深入运用的自己的各大项目中。 熟练使用c/c++,Posix库进行跨平台开发。课程由浅入深,让学员一步一步成为音视频领域的专家。

    575人学习 任铄
    免费试看
transform的结构如下:
struct CATransform3D
{
  CGFloat m11, m12, m13, m14;
  CGFloat m21, m22, m23, m24;
  CGFloat m31, m32, m33, m34;
  CGFloat m41, m42, m43, m44;
};

首先要实现view(layer)的透视效果(就是近大远小),是通过设置m34的:

CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / -500;

m34负责z轴方向的translation(移动),m34= -1/D,  默认值是0,也就是说D无穷大,这意味layer in projection plane(投射面)和layer in world coordinate重合了。

D越小透视效果越明显。

所谓的D,是eye(观察者)到投射面的距离。




一.概述

在iOS中使用CATransform3D这个结构体来表示三维的齐次坐标变换矩阵. 齐次坐标是一种坐标的表示方法,n维空间的坐标需要用n+1个元素的坐标元组来表示,在Quartz 2D Transform中就有关于齐次坐标的应用,那边是关于二维空间的变换,其某点的齐次坐标的最后一个元素始终设置为1。使用齐次坐标而不是简单的数学坐标是为了方便图形进行仿射变换,仿射变换可以通过仿射变换矩阵来实现,3D的仿射变换可以实现诸如 平移(translation),旋转(rotation),缩放(scaling),切变(shear)等变换。如果不用齐次坐标那么进行坐标变换可能就涉及到两种运算了,加法(平移)和乘法(旋转,缩放),而使用齐次坐标以及齐次坐标变换矩阵后只需要矩阵乘法就可以完成一切了。上面的这些如果需要深入了解就需要去学习一下图形变换的相关知识,自己对矩阵的乘法进行演算。

iOS中的CALayer的3D本质上并不能算真正的3D(其视点即观察点或者所谓的照相机的位置是无法变换的),而只是3D在二维平面上的投影,投影平面就是手机屏幕也就是xy轴组成的平面(注意iOS中为左手坐标系),那么视点的位置是如何确定的呢?可以通过CATransform3D中的m34来间接指定, m34 = -1/z,其中z为观察点在z轴上的值,而Layer的z轴的位置则是通过anchorPoint来指定的,所谓的anchorPoint(锚点)就是在变换中保持不变的点,也就是某个Layer在变换中的原点,xyz三轴相交于此点。在iOS中,Layer的anchorPoint使用unit coordinate space来描述,unit coordinate space无需指定具体真实的坐标点而是使用layer bounds中的相对位置,下图展示了一个Layer中的几个特殊的锚点, 

m34 = -1/z中,当z为正的时候,是我们人眼观察现实世界的效果,即在投影平面上表现出近大远小的效果,z越靠近原点则这种效果越明显,越远离原点则越来越不明显,当z为正无穷大的时候,则失去了近大远小的效果,此时投影线垂直于投影平面,也就是视点在无穷远处,CATransform3D中m34的默认值为0,即视点在无穷远处.

还有一个需要说明一下的就是齐次坐标到数学坐标的转换 通用的齐次坐标为 (a, b, c, h),其转换成数学坐标则为 (a/h, b/h, c/h).

二.代数解释

假设一个Layer anchorPoint为默认的 (0.5, 0.5 ), 其三维空间中一个A点 (6, 0, 0),m34 = -1/1000.0, 则此点往z轴负方向移动10个单位之后,则在投影平面上看到的点的坐标是多少呢?

A点使用齐次坐标表示为 (6, 0, 0, 1)

QuartzCore框架为我们提供了函数来算出所需要的矩阵,

    CATransform3D transform = CATransform3DIdentity;
    transform.m34 = -1/1000.0;
    transform = CATransform3DTranslate(transform, 0, 0, -10);

计算出来的矩阵为

 
{ 1,    0,    0,     0;   
  0,    1,    0,     0;   
  0,    0,    1,     -0.001;   
  0,    0,  -10,    1.01;      
}   

其实上面的变换矩阵本质上是两个矩阵相乘得到的 变换矩阵 * 投影矩阵 变换矩阵为

{1,    0,    0,    0;   
 0,    1,    0,    0;   
 0,    0,    1,    0;   
 0,    0,   -10,  1;      
}     

投影矩阵为

 
{1,    0,    0,    0;   
 0,    1,    0,    0;   
 0,    0,    1, -0.001;   
 0,    0,    0,    1;   
}     

上面的两个矩阵相乘则会得到最终的变换矩阵(如果忘记矩阵乘法的可以去看下线性代数复习下),所以一个矩阵就可以完成变换和投影。

将A点坐标乘上最终的变换矩阵,则得到 {6, 0 , -10, 1.01}, 转换成数学坐标点为 {6/1.01, 0, 10/1.01},则可以知道其在投影平面上的投影点为 {6/1.01, 0, 0} 也就是我们看到的变换后的点。其比之前较靠近原点。越往z轴负方向移动,则在投影平面上越靠近原点。

三.几何解释

将上面的例子使用几何的方式来进行解释分析,当我们沿着y轴的正方向向下看时候,可以得到如下的景象

虚线为投影线,其和x轴的交点即为A点的投影点。 由相似三角形的定理我们很容易算出投影的点,

1000/(1000 + 10) = x/6,则x = 6*1000/1010 = 6/1.01


2014-09-29 12:16:20 herramadeus 阅读数 1495
  • 计算机系统--多媒体技术

    完全掌握iOS, Android, 嵌入式Linux平台音视频开发的相关知识并能够深入运用的自己的各大项目中。 熟练使用c/c++,Posix库进行跨平台开发。课程由浅入深,让学员一步一步成为音视频领域的专家。

    575人学习 任铄
    免费试看

使用下面的代码,既可以获得某个CATransform3DMake...()方法获取的变换的透视投影效果。

最后,将该函数的返回值赋给某个UIView或者其子类对象的layer属性的transform属性即可。


// 实现带透视投影缩放效果的三维变换。

CATransform3D get3DPerspectiveTransform(CATransform3D t, CGPoint center, float disZ)

{

    /**************************************************************

    *   CATransform3DConcat(CATransform3D a, CATransform3D b)的含义

    * 是先进行a变换,再进行b变换。b变换在a变换的基础上进行。

    **************************************************************/

    

    

    // 将某个view移动到坐标系原点的变换矩阵。

    CATransform3D transToOrigin = CATransform3DMakeTranslation(-center.x, -center.y, 0);

    

    // view移动回初始位置的变换矩阵。

    CATransform3D transBack = CATransform3DMakeTranslation(center.x, center.y, 0);

    

    // 计算透视缩放矩阵。

    // 透视投影的m34即表示透视缩放系数。这个值越小,则透视效果越明显(即越近越大,越远越小)。

    CATransform3D scale = CATransform3DIdentity;

    // 注意这里是-1,从而保证从坐标轴正方向向负方向看去,逆时针旋转为正。

    scale.m34 = -1.0f/disZ;

    

    // 获取完整的透视变换矩阵。

    CATransform3D perspTrans = CATransform3DConcat(CATransform3DConcat(transToOrigin, scale), transBack);


    // iOS的标准正投影添加透视投影变换效果。

    CATransform3D result = CATransform3DConcat(t, perspTrans);

    

    return result;

}




例:在某个ViewController的viewDidLoad中,初始化一个计时器,每1/60秒调用一次:

[NSTimer scheduledTimerWithTimeInterval:1/60

                                     target:self

                                   selector:@selector(callFuncPerFrame:)

                                   userInfo:nil

                                    repeats:YES];



#pragma mark - 定时器回调方法,实现动态效果。

- (void)callFuncPerFrame:(NSTimer *)timer

{

    static float angle = 0.0f;

    CATransform3D t = get3DPerspectiveTransform(CATransform3DMakeRotation(angle, 0, 1, 0),

                                                CGPointZero,

                                                500);

    

    [imgView.layer setTransform:t];

    

    angle += 0.01f;

    angle = (angle == 360.0f ? 0.0f : angle);

}



最终效果如下图所示:




2017-09-07 15:59:57 qq_33608748 阅读数 2323
  • 计算机系统--多媒体技术

    完全掌握iOS, Android, 嵌入式Linux平台音视频开发的相关知识并能够深入运用的自己的各大项目中。 熟练使用c/c++,Posix库进行跨平台开发。课程由浅入深,让学员一步一步成为音视频领域的专家。

    575人学习 任铄
    免费试看

//一般大家都会这样设置 你会发现投影效果并没有呈现出来

    UIView *samall = [[UIViewalloc]initWithFrame:CGRectMake(100,350,100,100)];

    samall.backgroundColor = [UIColorredColor];

    samall.layer.cornerRadius =10;

    samall.layer.masksToBounds =YES;

    [self.viewaddSubview:samall];

    samall.layer.shadowOffset =CGSizeMake(5,5);

    samall.layer.shadowColor = [UIColorlightGrayColor].CGColor;

    samall.layer.shadowRadius =10;

    samall.layer.shadowOpacity =1;

    samall.layer.cornerRadius =10;

//原因是因为

clipsToBounds 指的是视图上的子视图,如果超出父视图部分就会被裁剪掉

masksToBounds 指的是视图图层上的子视图,如果超出父图层部分就会被裁剪掉



试一试下边的方法吧

方法1

UIView *view = [[UIViewalloc]initWithFrame:CGRectMake(100,100,100,100)];

view.backgroundColor = [UIColorredColor];

view.layer.cornerRadius =10;

view.layer.masksToBounds=YES;    

UIView *bgShadowView = [[UIViewalloc]initWithFrame:view.frame];

[self.viewaddSubview:bgShadowView];

bgShadowView.layer.shadowColor = [UIColorlightGrayColor].CGColor;

bgShadowView.layer.shadowOffset =CGSizeMake(5,5);

bgShadowView.layer.shadowOpacity =1;

bgShadowView.layer.shadowRadius =9.0;

bgShadowView.layer.cornerRadius =9.0;

bgShadowView.clipsToBounds =NO;

[bgShadowView addSubview:view];


方法2


    

    UIView *view = [[UIView alloc]initWithFrame:CGRectMake(50, 100, 200,100)];

    view.backgroundColor = LColor(250, 88, 88);

    [self.view addSubview:view];

    view.layer.cornerRadius = 20;

    view.layer.masksToBounds = NO;

    view.layer.shadowOffset = CGSizeMake(1, 5);

    view.layer.shadowRadius = 5;

    view.layer.shadowColor = [UIColor grayColor].CGColor;

    view.layer.shadowOpacity = 0.9;




2018-05-09 15:52:05 xiaoqi307 阅读数 2031
  • 计算机系统--多媒体技术

    完全掌握iOS, Android, 嵌入式Linux平台音视频开发的相关知识并能够深入运用的自己的各大项目中。 熟练使用c/c++,Posix库进行跨平台开发。课程由浅入深,让学员一步一步成为音视频领域的专家。

    575人学习 任铄
    免费试看

小弟不才,基础薄弱,只能每天记录一些学会的小知识,今天看UI出的效果图,需要一个View给个阴影效果,所以上网搜索,总结,会的话什么都简单,不会1+1也是难的,哈哈,不多bb上代码

 

   UIView *cornerView = [UIView new];
    cornerView.backgroundColor = [UIColor whiteColor];
    cornerView.layer.shadowOpacity = 1; 阴影透明度
    cornerView.layer.cornerRadius = 4;
    cornerView.layer.shadowColor = BackGrayColor.CGColor; 阴影的颜色
    cornerView.layer.shadowRadius = 4; 阴影的圆角
    cornerView.layer.shadowOffset = CGSizeMake(4, 4); 阴影偏移量
    [headSection addSubview:cornerView];
    [cornerView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(10);
        make.left.right.bottom.mas_equalTo(0);
    }];
    可能有的小伙伴,都设置但是没有效果,非常抱歉,我今天用的也不行。如果你的也不行请添加代码
    cornerView.clipsToBounds = NO;
    给大家传递了不可用的知识,非常抱歉。请见谅




2016-10-11 09:35:45 hw_2396611405 阅读数 3785
  • 计算机系统--多媒体技术

    完全掌握iOS, Android, 嵌入式Linux平台音视频开发的相关知识并能够深入运用的自己的各大项目中。 熟练使用c/c++,Posix库进行跨平台开发。课程由浅入深,让学员一步一步成为音视频领域的专家。

    575人学习 任铄
    免费试看

在布局中我们为了使得一些界面拥有更加好的UI设计效果,突出层级关系,我们常常做一些阴影效果。

    _imageView.layer.shadowColor = [UIColor blackColor].CGColor;//shadowColor阴影颜色
   _imageView.layer.shadowOffset = CGSizeMake(2,6);//shadowOffset阴影偏移,x向右偏移2,y向下偏移6,默认(0, -3),这个跟shadowRadius配合使用
    _imageView.layer.shadowOpacity = 0.7;//阴影透明度,默认0       _imageView.layer.shadowRadius = 2;//阴影半径,默认3

iOS开发之阴影效果

阅读数 429