在iOS利用动画实现全景视图

干货,干货,这个绝对是干货,研究了很久,参考了网上的代码,终于明白了如何利用CATransform3D实现一个全景的观看模式。

整个全景类的项目有两个难点,一是搭建一个正方体的场景,二是通过滑动改变观看的视角

如何搭建一个正方体的场景呢,我们使用CATransform3D里面的透视动画制作

代码如下:

    //image1(前)
    
	//获取一个标准默认的CATransform3D仿射变换矩阵
	CATransform3D transform3D = CATransform3DIdentity;
    //image与六面体中心的角度为(0,0)(hAngel为点与水平位置的角度,vAngle为点与竖直位置的角度。
	CGFloat tempHAngle=_hAngle;
	CGFloat tempVAngle=_vAngle;
    //初始化
	transform3D = CATransform3DIdentity;
    //透视效果
    /*
     CGFloat m11(x缩放), m12(y切变), m13(旋转), m14();
     CGFloat m21(x切变), m22(y缩放), m23(), m24();
     CGFloat m31(旋转), m32(), m33(), m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果。正直/负值都有意义);
     CGFloat m41(x平移), m42(y平移), m43(z平移), m44();
     
     m34的默认值是0,我们可以通过设置m34为-1.0 / d来应用透视效果,d代表了想象中视角相机和屏幕之间的距离
     */
    transform3D.m34 = 1 / -_zoomFactor;
    
    //_referenceSide中心点size
    
    /*
     对于tz来说,值越大,那么图层就越往外(接近屏幕),值越小,图层越往里(屏幕里)。
     
     CATransform3D CATransform3DTranslate (CATransform3D t, CGFloat tx, CGFloat ty, CGFloat tz);
     
     在某个transform3D变换的基础上进行平移变换,t是上一个transform3D,tx,ty,tz对应x,y,z轴的平移
     
     */
    
    //(obj,-referenceSide,0,0),平移
	transform3D=CATransform3DTranslate(transform3D,
									   _referenceSide*sin(-tempHAngle),
									   -_referenceSide*cos(-tempHAngle)*sin(-tempVAngle),
									   -(_referenceSide*cos(-tempHAngle)*cos(-tempVAngle)-_zoomFactor)
									   );
    /*
     angle参数是旋转的角度,为弧度制 0-2π
     x,y,z决定了旋转围绕的中轴,取值为-1——1之间,例如(1,0,0),则是绕x轴旋转(0.5,0.5,0),则是绕x轴与y轴中间45度为轴旋转,依次进行计算
     CATransform3D CATransform3DMakeRotation (CGFloat angle, CGFloat x, CGFloat y, CGFloat z);
     
     在一个transform3D的基础上进行旋转变换,其他参数如上
     
     CATransform3D CATransform3DRotate (CATransform3D t, CGFloat angle, CGFloat x, CGFloat y, CGFloat z);
     
     */
    //绕y轴旋转0度
	transform3D=CATransform3DRotate(transform3D, tempHAngle, 0, 1, 0);
    if (_imageOver1.image != nil) _imageOver1.layer.transform=CATransform3DRotate(transform3D, tempVAngle, cos(tempHAngle), 0, sin(tempHAngle));
    //将3D信息赋值给image
	_image1.layer.transform=CATransform3DRotate(transform3D, tempVAngle, cos(tempHAngle), 0, sin(tempHAngle));
    
    
    //iamge2(右)
    //image2与六面体中心的角度为(-PI/2,0)(hAngel为点与水平位置的角度,vAngle为点与竖直位置的角度。
	tempHAngle=_hAngle-(M_PI/2);
	tempVAngle=_vAngle;
	transform3D = CATransform3DIdentity;
    transform3D.m34 = 1 / -_zoomFactor;
    //(obj,referenceside,0,0)
	transform3D=CATransform3DTranslate(transform3D,
									   _referenceSide*sin(-tempHAngle),
									   -_referenceSide*cos(-tempHAngle)*sin(-tempVAngle),
									   -(_referenceSide*cos(-tempHAngle)*cos(-tempVAngle)-_zoomFactor)
									   );
    //绕y轴旋转-90度
	transform3D=CATransform3DRotate(transform3D, tempHAngle, 0, 1, 0);
    if (_imageOver2.image != nil) _imageOver2.layer.transform=CATransform3DRotate(transform3D, tempVAngle, cos(tempHAngle), 0, sin(tempHAngle));
	_image2.layer.transform=CATransform3DRotate(transform3D, tempVAngle, cos(tempHAngle), 0, sin(tempHAngle));
	
    
    //image3(后)
    //image3与六面体中心的角度为(-PI,0)(hAngel为点与水平位置的角度,vAngle为点与竖直位置的角度。
	tempHAngle=_hAngle-(M_PI);
	tempVAngle=_vAngle;
	transform3D = CATransform3DIdentity;
    transform3D.m34 = 1 / -_zoomFactor;
	transform3D=CATransform3DTranslate(transform3D,
									   _referenceSide*sin(-tempHAngle),
									   -_referenceSide*cos(-tempHAngle)*sin(-tempVAngle),
									   -(_referenceSide*cos(-tempHAngle)*cos(-tempVAngle)-_zoomFactor)
									   );
	transform3D=CATransform3DRotate(transform3D, tempHAngle, 0, 1, 0);
    if (_imageOver3.image != nil) _imageOver3.layer.transform=CATransform3DRotate(transform3D, tempVAngle, cos(tempHAngle), 0, sin(tempHAngle));
	_image3.layer.transform=CATransform3DRotate(transform3D, tempVAngle, cos(tempHAngle), 0, sin(tempHAngle));

    //image4(左)
    //image4与六面体中心的角度为(-3*PI/2,0)(hAngel为点与水平位置的角度,vAngle为点与竖直位置的角度。
    tempHAngle=_hAngle-(3*M_PI/2);
	tempVAngle=_vAngle;
	transform3D = CATransform3DIdentity;
    transform3D.m34 = 1 / -_zoomFactor;
	transform3D=CATransform3DTranslate(transform3D,
									   _referenceSide*sin(-tempHAngle),
									   -_referenceSide*cos(-tempHAngle)*sin(-tempVAngle),
									   -(_referenceSide*cos(-tempHAngle)*cos(-tempVAngle)-_zoomFactor)
									   );
    //绕y轴旋转180
	transform3D=CATransform3DRotate(transform3D, tempHAngle, 0, 1, 0);
    if (_imageOver4.image != nil) _imageOver4.layer.transform=CATransform3DRotate(transform3D, tempVAngle, cos(tempHAngle), 0, sin(tempHAngle));
	_image4.layer.transform=CATransform3DRotate(transform3D, tempVAngle, cos(tempHAngle), 0, sin(tempHAngle));
	
    
    //image5(上)
    //image5与六面体中心的角度为(0,-PI/2)(hAngel为点与水平位置的角度,vAngle为点与竖直位置的角度
	tempHAngle=_hAngle;
	tempVAngle=_vAngle-(M_PI/2);
	transform3D = CATransform3DIdentity;
    transform3D.m34 = 1 / -_zoomFactor;
	transform3D=CATransform3DTranslate(transform3D,
									   0,
									   -_referenceSide*sin(-tempVAngle),
									   -(_referenceSide*cos(-tempVAngle)-_zoomFactor)
									   );
	
	transform3D=CATransform3DRotate(transform3D, tempVAngle, 1,0,0);
    if (_imageOver5.image != nil) _imageOver5.layer.transform=CATransform3DRotate(transform3D, tempHAngle, 0, 0, 1);
	_image5.layer.transform=CATransform3DRotate(transform3D, tempHAngle, 0, 0, 1);
    
    
    //image6(下)
    //image6与六面体中心的角度为(0,PI/2)(hAngel为点与水平位置的角度,vAngle为点与竖直位置的角度
    tempHAngle=_hAngle;
	tempVAngle=_vAngle+(M_PI/2);
	transform3D = CATransform3DIdentity;
    transform3D.m34 = 1 / -_zoomFactor;
	transform3D=CATransform3DTranslate(transform3D,
									   0,
									   -_referenceSide*sin(-tempVAngle),
									   -(_referenceSide*cos(-tempVAngle)-_zoomFactor)
									   );
	
	transform3D=CATransform3DRotate(transform3D, tempVAngle, 1,0,0);
    if (_imageOver6.image != nil) _imageOver6.layer.transform=CATransform3DRotate(transform3D, -tempHAngle, 0, 0, 1);
	_image6.layer.transform=CATransform3DRotate(transform3D, -tempHAngle, 0, 0, 1);

这样就能够通过透视动画搭建一个正方体了(里面基本都是用的三角函数的知识)

下一步是怎么实现物体能够随手势进行平移

#pragma mark GestureRecognizers
//平移手势
- (void)didPan:(UIPanGestureRecognizer *)gestureRecognizer {
    if (gestureRecognizer.state==UIGestureRecognizerStateBegan) {
        if (_delegate && _delegateBeginPan) {
            [_delegate panoViewWillBeginPanning:self];
        }
	}
	if (gestureRecognizer.state==UIGestureRecognizerStateBegan ||
		gestureRecognizer.state==UIGestureRecognizerStateChanged) {
		CGPoint translation=[gestureRecognizer translationInView:self];
		CGFloat newHAngle = self.hAngle-(translation.x/(_zoomFactor/1.5));
		CGFloat newVAngle = self.vAngle+(translation.y/(_zoomFactor/1.5));
		if (newHAngle>0 && _rightLimit!=0) {
			if (newHAngle>_rightLimit) {
				newHAngle=_rightLimit;
			}
		}else if (newHAngle<0 && _leftLimit!=0) {
			// negative angle to the left, but limit is always positive (absolute value)
			if (newHAngle<(-_leftLimit)) {
				newHAngle=-_leftLimit;
			}
		}
		if (newVAngle>0 && _upLimit!=0) {
			if (newVAngle>_upLimit) {
				newVAngle=_upLimit;
			}
		}else if (newVAngle<0 && _downLimit!=0) {
			// negative angle to the bottom, but limit is always positive (absolute value)
			if (newVAngle<(-_downLimit)) {
				newVAngle=-_downLimit;
			}
		}
		_hAngle=newHAngle;
		_vAngle=newVAngle;
		[self render];
		[gestureRecognizer setTranslation:CGPointZero inView:self];
        if (_delegate && _delegateDidPan) {
            [_delegate panoViewDidPan:self];
        }
	}
    if (gestureRecognizer.state==UIGestureRecognizerStateEnded) {
        if (_delegate && _delegateEndPan) {
            [_delegate panoViewDidEndPanning:self];
        }
	}
}

至于捏合,放大手势就自己写吧,如果想要完整的代码,我近期会上传到github上面的。

这个透视原理不难,最恶心的还是三角函数的计算。。。



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值