在这个教程中,你将学到用OpenGL ES 2.0和GLKit通过触摸来旋转一个3D物体。
我们先从简单开始,首先向你介绍随着用户的拖拽,怎样通过沿着x轴或y轴旋转一定数量的度数来旋转一个3D物体。然后使用四元数介绍一个更高级的技术。
这个教程会从Beginning OpenGL ES 2.0 with GLKit Tutorial提取示例工程,如果你没有准备好这个工程请下载
请牢记我是自学的,我的数学相当生疏,所以如果犯了错或者没有很正确的解释一些事情请抱歉。如果有人有更好的或更正确的方法来说明,请指出!
言归正传,让我们开始旋转。
开始,运行sample project,你会看到立方体已经在固定的旋转了。
如果你打开HelloGLKitViewController.m,找到update方法,你会发现下面的代码进行了固定的旋转
_rotation += 90 * self.timeSinceLastUpdate; modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(25), 1, 0, 0); modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, GLKMathDegreesToRadians(_rotation), 0, 1, 0);
我们的目标是替换上面代码,使用户能通过拖动鼠标来旋转立方体,而不是一成不变的旋转。
我们首先尝试一下通过移动旋转模型到一个实例变量,将它改为用户拖拽的方式。对HelloGLKitViewController.m作以下修改:
// Add to HelloGLKitViewController private variables GLKMatrix4 _rotMatrix; // Add to bottom of setupGL _rotMatrix = GLKMatrix4Identity; // In update, replace the 3 rotation lines shown in the previous snippet with this modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, _rotMatrix); // Remove everything inside touchesBegan - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { } // Add new touchesMoved method - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch * touch = [touches anyObject]; CGPoint location = [touch locationInView:self.view]; CGPoint lastLoc = [touch previousLocationInView:self.view]; CGPoint diff = CGPointMake(lastLoc.x - location.x, lastLoc.y - location.y); float rotX = -1 * GLKMathDegreesToRadians(diff.y / 2.0); float rotY = -1 * GLKMathDegreesToRadians(diff.x / 2.0); GLKVector3 xAxis = GLKVector3Make(1, 0, 0); _rotMatrix = GLKMatrix4Rotate(_rotMatrix, rotX, xAxis.x, xAxis.y, xAxis.z); GLKVector3 yAxis = GLKVector3Make(0, 1, 0); _rotMatrix = GLKMatrix4Rotate(_rotMatrix, rotY, yAxis.x, yAxis.y, yAxis.z); }
好了,这里我们初始化旋转模型到本体(没有变化),随着用户的拖拽,我们利用GLKMatrix4Rotate来对立方体进行一定度数的旋转。用户每移动一个像素,立方体旋转1/2度。
记住x轴是水平穿过屏幕的,y轴是垂直的。所以当用户从左拖到右,我们实际上是想要围着y轴旋转(rotY),反过来也是这样。
编译运行,你会注意到立方体刚开始旋转正常,但是不久后它就脱离了你的预期,奇怪的往斜方向旋转。
简单旋转:尝试2当你对一个物体运用变换,你可以把它当作物体到一个世界新空间的活动坐标系。
要理解我所说的,运行app,从立方体的右上角扫过立方体中间。你已经按如下方法有效的修改了物体的坐标系统,使其位于不同的世界空间:
_rotMatrix是一种将物体移动到新空间的变换。当用户移动时代码会修改_rotMatrix,所以当我们告诉它围着x轴或y轴旋转,它就会在物体空间围着x或y轴旋转。
尝试着自己实现它:做另外一个移动,从右到左(注意不是上移或下移),你会看到它是怎么围绕新的y轴旋转的。
但是如果我们是想沿着世界空间x轴和y轴旋转,而不是物体空间的x轴和y轴,怎样计算新坐标系统世界的x轴和y轴?
答案是简单的:如果_rotMatrix转换一个物体向量到它应该在世界空间的位置,_rotMatrix反变换转换一个世界向量到世界空间。
你可以看下面的等式来帮助理解:
_rotMatrix * object vector = world vector
两边同时乘以 (_rotMatrix)-1 (与 _rotMatrix相反), 结果如下:
(_rotMatrix)-1 * _rotMatrix * object vector = (rotMatrix-1) * world vector
由于(_rotMatrix)-1 * _rotMatrix = 1, 结果为:
object vector = (_rotMatrix)-1 * world vector
让我们试着实现!将touchesMoved修改成下面这样
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { UITouch * touch = [touches anyObject]; CGPoint location = [touch locationInView:self.view]; CGPoint lastLoc = [touch previousLocationInView:self.view]; CGPoint diff = CGPointMake(lastLoc.x - location.x, lastLoc.y - location.y); float rotX = -1 * GLKMathDegreesToRadians(diff.y / 2.0); float rotY = -1 * GLKMathDegreesToRadians(diff.x / 2.0); bool isInvertible; GLKVector3 xAxis = GLKMatrix4MultiplyVector3(GLKMatrix4Invert(_rotMatrix, &isInvertible), GLKVector3Make(1, 0, 0)); _rotMatrix = GLKMatrix4Rotate(_rotMatrix, rotX, xAxis.x, xAxis.y, xAxis.z); GLKVector3 yAxis = GLKMatrix4MultiplyVector3(GLKMatrix4Invert(_rotMatrix, &isInvertible), GLKVector3Make(0, 1, 0)); _rotMatrix = GLKMatrix4Rotate(_rotMatrix, rotY, yAxis.x, yAxis.y, yAxis.z); }
编译运行,现在是按照预期运行了!
四元数弧球旋转 概述另外一种流行的易于旋转3D对象的方式是由Ken Shoemake普及的弧球旋转算法
让我来告诉你一种简单的关于弧球旋转算法的基本信息:
1.映射到球体。创建一个你想要旋转对象的虚拟球体。当使用者触摸时,你要计算出所处范围内最近的点,与触摸的点相一致(开始),且和触摸移动的点(当前)相似。
2.计算当前的旋转。从开始到当前范围内的一个旋转的点,你可以认为它是通过转旋坐标轴或者一些角度而得到的。计算旋转/坐标轴从开始/当前的位置。
3.更新全部的旋转。更新全部由第三步得到当前旋转的对象
步骤3最神奇的地方是把数学概念里的四元数引入进来。我不打算在后面讨论它们,但是我想指出3个四元数的高等级属性:
1. Quaternion=axis+angle of rotation.四元数可以代表一个坐标轴和一个旋转的角度。一个四元数可以代表任何旋转。
2. Multiply quaternion = combine rotations.如果你要使2个四元数相乘,它们代表旋转的联合
3. Can convert quaternion to matrices.通过一些数学方法你可以使一个四元数转换到一个旋转矩阵里去。
一个关于GLKit的有意思的事情是你可以使用四元数而不需要明白它的后台是如何工作和运转的。你可以象下面这样使用它的功能:
GLKQuaternionMakeWithAngleAndVector3Axis:
创建一个坐标轴或旋转角度的quaternion
GLKQuaternionMultiply:
一个四元数乘以另外一个四元数(联合旋转)
GLKMatrix4MakeWithQuaternion:
把quaternion转换成一个旋转矩阵
如果你仍然有一些小困惑关于它是如何工作的,不用担心,我们将在下面的章节里一步一步的告诉你!
1) 映射到球体.
假设在我们的对象周围有一个虚拟的范围,半径有屏幕的1/3之宽。这个范围的中心就是我们选中对象的中心。我们想让使用者“grab and drag”这些范围来旋转对象。所以第一步是要计算出将一个2D的点转换成一个虚拟3D范围内的点。这里有一个最简单的方式。首先,让我们来学习一些基础的东西。
我们知道x和y的位置是用户点击的那个点,所以我们能够通过Pythagorean Theorem计算出斜边的长度
我们现在知道范围的中心到用户点击的x和y坐标的矢量距离,但是不知道z坐标。
然后,我们知道z坐标必须和范围相交,如果你绘制一条线段从范围的中心到任意一点,它会有一条半径。
目前,我们有另外一个正确的三角形可以通过pythagorean thorem来解决它!我们可以得到:
r^2 = (sqrt(p.x^2 + p.y^2))^2 + z^2
r^2 = (p.x^2 + p.y^2) + z^2
r^2 - (p.x^2 + p.y^2) = z^2
这里有个小技巧是如果用户点击到了半径的范围之外,如果真的发生了,那么我们只能用离它最近的点去替代它。
让我们看下面代码里的方法!并添加正确的方法在touchesBegan之前:
- (GLKVector3) projectOntoSurface:(GLKVector3) touchPoint { float radius = self.view.bounds.size.width/3; GLKVector3 center = GLKVector3Make(self.view.bounds.size.width/2, self.view.bounds.size.height/2, 0); GLKVector3 P = GLKVector3Subtract(touchPoint, center); // Flip the y-axis because pixel coords increase toward the bottom. P = GLKVector3Make(P.x, P.y * -1, P.z); float radius2 = radius * radius; float length2 = P.x*P.x + P.y*P.y; if (length2 <= radius2) P.z = sqrt(radius2 - length2); else { P.x *= radius / sqrt(length2); P.y *= radius / sqrt(length2); P.z = 0; } return GLKVector3Normalize(P); }
这个数学方法和我们上面讨论的一样,注意在结尾我们要使用规格化的矢量,因为当计算旋转时方向是大于长度的。现在我们开始移动它。在HelloGLKitViewController.m里做如下的改变:
// Add to the private interface GLKVector3 _anchor_position; GLKVector3 _current_position; // Add to bottom of touchesBegan UITouch * touch = [touches anyObject]; CGPoint location = [touch locationInView:self.view]; _anchor_position = GLKVector3Make(location.x, location.y, 0); _anchor_position = [self projectOntoSurface:_anchor_position]; _current_position = _anchor_position; // Add to bottom of touchesMoved _current_position = GLKVector3Make(location.x, location.y, 0); _current_position = [self projectOntoSurface:_current_position];
现在我们开始规则化开始和结束范围内的点以此来和用户鼠标移动的动作保持一致。现在我们使用他们来计算坐标和旋转的角度
2) 计算当前旋转
计算坐标和旋转的角度,我们可以使用我们的dot product和cross product。如果这里你没有弄太明白,我强烈建议你去读David Rosen写的《Linear Algebra for Game Developers》。这篇文章介绍了大量的基础东西。但是如果你不想这么做,我可以给你在这里做一个简单的总结:
corss product允许你有2各矢量,它会给矢量一个垂直矢量。这将是旋转的坐标,但是现在我们需要计算出从一个矢量到另外一个旋转的数量。
长话短说,你可以使用dot product来帮助你决定2个矢量之间的角度。这个角度是acos(如果A和B不是相同矢量的话)。并且请记住在projectOntoSurface里规格化它们。
一旦我们决定了坐标和角度,我们就可以创造一个四元数来存储它们通过使用GLKit GLKQuaternionMakeWithAngleAndVector3Axis功能。让我们来试试吧,在HelloGLKitViewController.m里做如下修改:
// Add new method above touchesBegan - (void)computeIncremental { GLKVector3 axis = GLKVector3CrossProduct(_anchor_position, _current_position); float dot = GLKVector3DotProduct(_anchor_position, _current_position); float angle = acosf(dot); GLKQuaternion Q_rot = GLKQuaternionMakeWithAngleAndVector3Axis(angle * 2, axis); Q_rot = GLKQuaternionNormalize(Q_rot); // TODO: Do something with Q_rot... } // Call it at end of touchesEnded [self computeIncremental];
现在我们有一个四元数来代替旋转的对象,从开始的触摸点到当前的触摸点
3) 更新全部旋转
最后一步,我们需要应用旋转的对象,这么做时我们需要追踪2个旋转:原始的旋转对象和当前的旋转对象
这是非常简单的,在HelloGLKitViewController.m里做如下改变:
// Add new variables to private interface GLKQuaternion _quatStart; GLKQuaternion _quat; // Initialize them at bottom of setupGL _quat = GLKQuaternionMake(0, 0, 0, 1); _quatStart = GLKQuaternionMake(0, 0, 0, 1); // Set _quat at bottom of computeIncremental _quat = GLKQuaternionMultiply(Q_rot, _quatStart); // Set _quatStart at bottom of touchesBegan _quatStart = _quat; // In update, replace GLKMatrix4Multiply(modelViewMatrix, rotation) line with this: GLKMatrix4 rotation = GLKMatrix4MakeWithQuaternion(_quat); modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, rotation);
这里_quatStart代表原始的旋转对象(在用户没有触碰之前),_quat时当前的旋转对象。
在computeIncremental的最后,我们把原始的与当前的进行相乘(点的数据是2者相乘的乘积)。
我们把四元数转成一个旋转矩阵,把它应用到视觉模型矩阵里。编译并运行,现在可以旋转这个立方体了
额外奖励: 另一个可选择的projectOntoSurface方法注意,按照目前的实现,如果你在球体外部拖拽,它会映射到在球体上最近的点,而不是继续旋转。为了使旋转可以继续,将projectOntoSurface方法中的else部分替换成下面的代码:
P.z = radius2 / (2.0 * sqrt(length2)); float length = sqrt(length2 + P.z * P.z); P = GLKVector3DivideScalar(P, length);额外奖励: 四元数的更多乐趣
你可能会想弄明白用四元数能做其它什么事情。一件很酷的事情是:它们可以提供一种简单的方法在两个旋转位置间随着时间推移进行插值。
为了弄清楚我说的,让我们来试试看,加一些代码令我们双击后,让立方体执行动画旋转回最初的方向。按照下面修改HelloGLKitViewController.m:
// Add new private instance variables BOOL _slerping; float _slerpCur; float _slerpMax; GLKQuaternion _slerpStart; GLKQuaternion _slerpEnd; // Add to bottom of setupGL UITapGestureRecognizer * dtRec = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)]; dtRec.numberOfTapsRequired = 2; [self.view addGestureRecognizer:dtRec]; // Add new method - (void)doubleTap:(UITapGestureRecognizer *)tap { _slerping = YES; _slerpCur = 0; _slerpMax = 1.0; _slerpStart = _quat; _slerpEnd = GLKQuaternionMake(0, 0, 0, 1); } // Add inside update method, right before declaration of modelViewMatrix if (_slerping) { _slerpCur += self.timeSinceLastUpdate; float slerpAmt = _slerpCur / _slerpMax; if (slerpAmt > 1.0) { slerpAmt = 1.0; _slerping = NO; } _quat = GLKQuaternionSlerp(_slerpStart, _slerpEnd, slerpAmt); }
当用户双击后,我们将起始旋转位置设置为当前方向(_quat),将最终旋转位置设置为恒等式旋转(没有任何旋转)。
然后在update方法中,判断如果当前状态是睡眠,我们先获得动画目前所处的进度。随后,我们使用内置的GLK四元数lerp方法,根据当前时间计算出slerpStart和slerpEnd之间的合适的旋转角度。
编译运行,旋转物体,然后双击使其旋转回初始位置。这个技术通常用于3D物体的关键帧动画和其它类似的地方。
从这里可以去什么地方?
这里有一个示例工程,包含了此教程中所有的代码。
希望这篇教程可以帮助到那些想学习一些触摸旋转3D物体方面的知识,以及复习一些3D数学概念的人。
如果任何人有疑问,更正或是更好更简单的办法来解释事情,请加入下面的论坛讨论!
转载自:
http://article.ityran.com/archives/1354
http://www.raywenderlich.com/5223/beginning-opengl-es-2-0-with-glkit-part-1
http://www.raywenderlich.com/5235/beginning-opengl-es-2-0-with-glkit-part-2
当硬件发展走到尽头,一个行业的创新速度将大幅降低,PC就是这样一个过程,不过PC走了10年的硬件升级道路,智能手机5年就走完了。那么智能手机硬件发展到头了吗?以后再没有硬件差异化了吗?
手机硬件十年来一直发展缓慢,2003年前后,微软推出了smartphone,手机开始堆硬件。
2007年,苹果手机的出现大大加快了堆硬件的速度,Android的跟进更是让堆硬件登峰造极。
2007年的iPhone,CPU性能相当于早期的奔腾2,屏幕连VGA都没有达到。
2012年,四核环蛇核心已经追近双核的Ahtlon64和酷睿,屏幕即将达到1080P,显卡性能也向第二代游戏机的水平挺进。
PC走了10年的硬件升级道路,智能手机5年就走完了。手机硬件发展到头了吗?以后再没有硬件差异化了吗?
从现在的一些趋势看,似乎还有差一点点,让我们来展望一下未来手机硬件的发展方向
一、处理器
手机处理器目前的总体性能已经过剩,四核心处理器得到软件的支持不好,也没有杀手级的应用推动四核甚至八核,16核。除了跑分软件和超高清视频的软解压,很少应用需要四核全开。这个PC遇到的瓶颈是一样的。
未来真正影响到体验速度的是单核心的性能,就是说,单个核心性能无论如何提高都是不过分。无论是主频提升还是单位效能提升,都可以带来更流畅的体验。
苹果5自己设计了新的架构,用1Ghz的主频达到了A9核心1.5Ghz左右才有的理论性能,也只用了双核没有用四核。对A6核心的猜测很多,有人猜是像高通一样介于A9和A15之间,但是从一般经验看,A15走的高频长流水线路线,和A6的表现并不吻合,A6更像是缩短流水线,或者大幅提高分支预测性能的 A9改进版。而不是A9和A15的混合体。
Intel发布了2.0ghz的手机用ATOM,不过做为后来者,兼容性和性能都被打了折扣。但是核心没有进步靠工艺优势拉高频率也是提升单核心性能的有效手段。
从苹果A6、高通环蛇和Intel的处理器来看,内存接口的带宽越来越受到重视,从体验看,无论是Windows还是Android、iOS,处理器达到一定水平,内存和IO的瓶颈更明显,它们的提升对速度和流畅的体验影响更大。
所以,未来优秀的处理器,核心数增加意义不大,而单核心效能和内存带宽会越来越被重视,拉高主频,改变ARM的标准核心,缩短流水线增加执行单元,改进分支预测算法、超出ARM标准指令集推出自己的高效能新指令集都有可能出现。
性能需求无止境,但是核心数到了一定程度就不会再往上堆了。
二、内存
受到功耗和成本的限制,现在手机的内存带宽还比较低,32bit还有,64bit主流,128bit算高性能,而电脑早在10年前就是128bit了。手机还是DDR2为主流,电脑显卡早就用上GDDR5了,而手机的显卡集成在SOC里面,同样需要系统内存,内存性能往往成为GPU型性能的瓶颈,为什么手机不能用快一点的内存。
所以,未来手机的内存会向今天的电脑和显卡发展,更多通道、更快频率、更先进的规格会成为发展方向,受到功耗的显示,频率会有限制。
三、GPU
手机的GPU发展和电脑很类似,几代产品之后,就进入了堆执行单元的竞赛,谁塞的多谁频率高,谁性能强大。标准有公开的。只是受制于功耗不能堆太多频率提太高。其实,游戏性、画面品质很大程度依赖于编程。用资源很多的3d游戏未必是好玩的游戏。而手机的屏幕和外形限制注定它只是便携游戏机,而不是桌面游戏主机。
所以GPU会跟着摩尔定律发展,不会有什么突破性的东西。
四、屏幕
受到人类手掌大小,和手机使用环境的限制,5寸左右的1080P屏幕基本到头了。尺寸和分辨率再提升意义不大。电脑发展到22寸、24寸以后,30寸没有成为主流,桌面大小限制死了。手机也一样。手机的限制是手掌大小。
但是效果上手机屏幕还有很大发展余地,LCD屏幕,目前主流色域还是72%的NTSC,100%的产品还没有普及。对比度还是1000:1左右的水平,比 OLED理论上可以无限大也有很大差异,还有一个发展点是降低功耗,4.5寸的屏幕,在亮度最高的情况下,耗电远远大于四核处理器,成为限制手机续航的主要敌人。现在要推出的RGBW排列屏幕其实就是为了功耗的努力。
OLED屏幕效果理论上远好于LCD,但是技术还不成熟,最强的三星一样受制于不同颜色OLED材料的发光效率和寿命,产品偏色而不敢调节。因为工艺极限,做不到LCD的高PPI,虽然三星在NoteII做了很多努力改进这个问题,效果如何还要时间验证。此外,OLED在显示浅色画面时,功耗比LCD还高,对手机续航也是大问题。
所以,以后LCD的发展方向是提升色域、对比度、降低功耗,OLED的发展方向是提高PPI,寿命、提高OLED材料的发光效率,降低功耗。
五、摄像头
手机摄像头受到体积制约,800万的1/3.2规格维持很长时间了,单个像素1.4um也很难突破,因为追求更高像素,面积不变只会让画质更烂。其实这个1.4um能有不错的画质也是BSI技术的功劳。
从基础技术看,索尼推出了层叠式CMOS,可以进一步加大同样面积感光元件的效率,也许成熟后,1.1um也会有不错的画质。
其实从日常拍摄、记录生活的实用角度来说,800万像素1/3.2寸BSI在镜头品质合格的情况下够用了。但是对于追求画质的小众发烧用户而言,还有更高的要求。
诺基亚在拍摄方面做了很多尝试,808尝试了大感光元件,并且由卡尔蔡司实验室研发出了能装进手机的配套镜头。在920上尝试了光学防抖,对高感也做了尝试,试图在低光下求的更好的效果。
但是受制于诺基亚自身的产业链,它没有索尼的新技术BSI CMOS。PUERVIEW是个很好的技术,但是诺基亚没有能力把它用到视频上,其实对于照片来说,Pureview的活后期电脑也能做。而视频才是PUERVIEW技术的用武之地。
现在手机也好,相机也好,拍摄视频只能用到CMOS上一点点面积,1080p只有200万像素,总面积只有单位像素面积乘以像素数那么大,再大的底也无用武之地。如果能用上Pureview 技术,把CMOS面积用足,808只有1/1.2寸大小的CMOS,足以超越5DmarkII,因为5DmarkII 只用了1/10的面积拍摄视频。
可能的话,未来理想的手机摄像头是1寸的索尼层叠式CMOS,加上诺基亚808镜头的改进版,加上920的光学防抖技术,视频用Pureview技术提高CMOS的利用率。
而大众产品会停留在1/3.2,像素会有提升,但是进步不会那么快了。
六、闪存
闪存其实可说的不多,速度更快、容量更大,人类对储存的需求永无止境。软件会越来越大,音乐会有24bit、192K的wav原生,视频过了1080P,还有2160P。总之,新东西、高品质的东西都是空间杀手。只有供给就会有人用。
七、触摸屏
触摸屏一体化是趋势,无论是oncell还是incell,以后显示屏幕、保护玻璃、触摸屏只用一块玻璃也是正常的,新的感应技术其实早就有了,没有量产而已。体验越来越好是必然的。
八、无线连接
4G已经到了瓶颈,3g+以后就没有杀手级应用需要那么大的带宽了。4g以后再加带宽的意义在哪还需要技术发展来解答。其实苹果iPhone出现之前,3G的高带宽都没有用武之地,wap网页,edge足够了。
蓝牙会倾向于低功耗,数据传输功能会逐渐被wifi直连取代、NFC随着产业链的完善会得到发展成为标配。
九、3D技术
裸眼3D严重影响屏幕的PPi,但是400多PPi的屏幕普及后将不是问题,摄像头到了瓶颈后,双摄像头3D拍摄可以成为一个卖点。3D视频的效果还是很明显的。但是这个是小众的玩具,不会出现在所有机型上。
十、电池技术
革命性的电池技术,喊了10多年,只见论文不见产品。能看到产品的就是安全性好一点的锂聚合物电池,提高电池电压是加大电量的一个办法,LG做了尝试。不过随着结构设计的进步和电池屏幕的加大、工艺的发展,手机已经可以给电池留出更大的空间。小米2有3000mzh的厚电、OPPO t29做到了3150mah可更换、razr maxx做到了3300mah,innos D9做到了4160mah可更换,传说还有厂商要做4800mah的手机。
其实,尽管智能手机的耗电在加大,但是那是高强度应用的时候,待机功耗并没有增加很大,而结构设计带来的电容容量进步事实上提升了轻度用户的续航时间。razr maxx事实远比当年的诺基亚的7710耐用,尽管7710更大更厚重。
转帖自台湾的朋友
http://blog.xuite.net/michaelr/linux/22165100
常在听mp3或其他格式音乐的朋友,有时会有特别喜欢的片段,例如副歌的部份会想拿来做手机的铃声。这时候就需要一些处理音效的软体,例如之前提过的Audacity。其实还有更简便的方法,只要系统中有安装好的ffmpeg,一行指令就OK了,相当简单。让我们分成两步骤来完成他吧!
第一步先用播放软体将想要处理的音乐档桉听一次,把想独立出来部份的时间记下来,看是几分几秒到几分几秒。记好后,第一步也就完成了。
第二步就是下指令了。
# ffmpeg -i input.mp3 -ss hh:mm:ss -t hh:mm:ss -acodec copy output.mp3
参数说明:
-ss : 指定从那裡开始
-t : 指定到那裡结束
-acodec copy : 编码格式和来源档桉相同(就是mp3)
这方法不只是MP3可以用,其他的许多格式也都适用,只是输出档桉的副档名就要跟着改一改了。
以下举个例子,如果我想把aa.mp3中的1分12秒到1分42秒的地方切出来,然后存成bb.mp3,指令如下
# ffmpeg -i aa.mp3 -ss 00:01:12 -t 00:01:42 -acodec copy bb.mp3
就是这么简单,而且处理速度超级快。一下子完成了。