干货,干货,这个绝对是干货,研究了很久,参考了网上的代码,终于明白了如何利用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上面的。
这个透视原理不难,最恶心的还是三角函数的计算。。。