2 维 glRotatef()

发布于 2024-11-01 07:20:48 字数 1507 浏览 6 评论 0原文

(iPhone)我试图让用户可以通过在屏幕上拖动手指来旋转对象。向左或向右拖动应绕 Y 轴旋转,向上或向下拖动应绕 X 轴旋转。这是我的原始代码:

glRotatef( yAmt, 0, 1, 0 );
glRotatef( xAmt, 1, 0, 0 );

旋转非常疯狂,并且似乎朝随机方向进行。我很确定这与第二个语句依赖于第一个语句有关,但我试图用一些奇特的数学来否定这一点,但仍然无法得到正确的结果。

好吧,我部分地弄清楚了,但现在我有一个新问题(如何对两次旋转求和?)。

我的解决方案:

假设您想将立方体向左旋转 90 度,然后向下旋转 90 度。您尝试一下:

glRotatef( 90, 0, 1, 0 );
glRotatef( 90, 1, 0, 0 );

它不起作用。第二个函数的行为很奇怪,因为第一个函数交换了 X 轴和 Z 轴。所以你试试这个:

glRotatef( 90, 0, 1, 0 );
glRotatef( 90, 0, 0, 1 );

现在你得到了想要的结果,但是如果你将第一个函数中的 Y 旋转量更改为 180 或 45 或其他值,它会再次失败。所需的旋转矢量取决于第一个函数的 Y 旋转量。这样就达到了预期的结果:

glRotatef( yAmt, 0, 1, 0 );
glRotatef( xAmnt, cos(yAmt), 0, sin(yAmt) );

现在,如果您想先上下旋转,然后从左向右旋转,该怎么办?最后一个解决方案失败了,因为首先,函数的顺序错误,其次,Y 轴也依赖于 X 旋转。您必须考虑到这一点,并且必须组合这两个函数,从而得到:

glRotatef( totalAmt, xFactor*cos(yAmt), yFactor*cos(xAmt), xFactor*sin(yAmt) + yFactor*sin(xAmt) );

其中 xFactor 和 yFactor 加起来为所需的旋转向量(1,0 表示向上和向下,0,1 表示左右,sqrt(.5 ),sqrt(.5) 用于对角线旋转)。

我的问题:

当用户完成一轮旋转并开始新一轮旋转时,问题就会出现。您必须记住并“重新执行”之前的旋转,否则您会意外地“跳”回 0 旋转。一个新的旋转就可以了,我可以实现touchesEnded来记住glRotatef的参数,然后将它们插入到一个新的旋转中,如下所示:

glRotatef( amt_old, x_old, y_old, z_old );
glRotatef( totalAmt, xFactor*cos(yAmt), yFactor*cos(xAmt), xFactor*sin(yAmt) + yFactor*sin(xAmt) );

但是在第二个新的旋转中,我现在有两个旋转要“重新激活”。我无法弄清楚要为 amt_old、x_old、y_old 和 z_old 分配什么值。归根结底是...如何对两个 glRotatef 旋转求和?

(iPhone) I'm trying to make it so that the user can rotate an object by dragging his finger on the screen. Dragging left or right should rotate around the Y-axis, and dragging up or down should rotate around the X-axis. Here's my original code:

glRotatef( yAmt, 0, 1, 0 );
glRotatef( xAmt, 1, 0, 0 );

The rotation is all crazy and seems to go in random directions. I'm pretty sure it has to do with the second statement being dependent on the first statement, but I've tried to negate that with some fancy math and still couldn't get it right.

Well I partially figured it out, but now I have a new problem (how to sum two rotations?).

MY SOLUTION:

Let's say you wanted to rotate the cube left 90 then down 90. You try this:

glRotatef( 90, 0, 1, 0 );
glRotatef( 90, 1, 0, 0 );

It doesn't work. The second function behaves strangely because the first function has swapped the X and Z axes. So you try this:

glRotatef( 90, 0, 1, 0 );
glRotatef( 90, 0, 0, 1 );

Now you have the desired result, but if you change the amount of Y rotation in the first function to 180 or 45 or whatever, it fails again. The desired rotation vector is dependent of the amount of Y rotation from the first function. Desired result is achieved with this:

glRotatef( yAmt, 0, 1, 0 );
glRotatef( xAmnt, cos(yAmt), 0, sin(yAmt) );

Now what if you want to rotate up and down first and then left to right? This last solution fails because, first of all, the functions are in the wrong order, and second of all, the Y axis is also dependent on the X rotation. You have to account for this, AND you have to combine the two functions, resulting in:

glRotatef( totalAmt, xFactor*cos(yAmt), yFactor*cos(xAmt), xFactor*sin(yAmt) + yFactor*sin(xAmt) );

Where xFactor and yFactor add up to desired rotation vector (1,0 for up and down, 0,1 for left and right, sqrt(.5), sqrt(.5) for diagonal rotation).

MY PROBLEM:

The problem comes in when the user finishes one rotation and starts a new one. You have to remember and "reinact" the previous rotation, otherwise you get an undesired "jump" back to 0 rotation. One new rotation is fine, I can implement touchesEnded to remember the parameters of glRotatef and then plug them in to a new rotation like this:

glRotatef( amt_old, x_old, y_old, z_old );
glRotatef( totalAmt, xFactor*cos(yAmt), yFactor*cos(xAmt), xFactor*sin(yAmt) + yFactor*sin(xAmt) );

But on the second new rotation, I now have two rotations to "reinact". I can't figure out what values to assign to amt_old, x_old, y_old, and z_old. What it boils down to is...how do you sum two glRotatef rotations?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

So尛奶瓶 2024-11-08 07:20:48

xAmtyAmt 是以像素为单位吗? glRotatef 的输入是以度为单位的(编辑:当然,我指的是弧度)?如果是,则乘以一个小数;尝试 (float)(M_PI/180) 每度一个像素。

两个旋转不可交换。如果您足够烦恼,您可以尝试计算组合旋转轴(标准化矢量,选择垂直轴,然后旋转长度
原始向量),但是对于足够小的旋转来说,这是可以忽略不计的。


编辑:也许您需要 glGetMatrix() 和 glLoadMatrix()。

Are xAmt and yAmt in pixels? Is the input to glRotatef in degrees (EDIT: I meant radians, of course)? If so, multiply by a small number; try (float)(M_PI/180) for one-pixel-per-degree.

The two rotations are not commutative. If you're sufficiently bothered, you can try to calculate a combined axis of rotation (normalize the vector, pick a perpendicular one, and rotate by the length
of the original vector), but this is negligible for sufficiently small rotations.


EDIT: Perhaps you want glGetMatrix() and glLoadMatrix().

芸娘子的小脾气 2024-11-08 07:20:48

从另一个论坛上的用户那里得到了答案:

// 初始化矩阵

... 查看 init 方法

theCurrentMatrix = CATransform3DIdentity;

...

// 在用户触摸屏时计算旋转 :

- (void) rotateX:(float)inX Y:(float)inY
{
     GLfloat lAngle=sqrt(inX*inX+inY*inY);

 if (lAngle != 0.0f)
 {
      static const float _degToRad = M_PI / 180.0;
            // we compute a rotation matrix (in radians)
      CATransform3D lRotation = CATransform3DMakeRotation(lAngle * _degToRad, inX, inY, 0.0f);

            // apply the rotation to the current matrix (cumulative effect)
            // order is important
      theCurrentMatrix = CATransform3DConcat(theCurrentMatrix, lRotation);
 }

}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
     // Get touch
     UITouch *touch = [[touches allObjects] objectAtIndex:0];

     if ([touches count] == 1)
     {
          UITouch *touch = [[touches allObjects] objectAtIndex:0];
          CGPoint location = [touch locationInView:touch.view];
      CGPoint previousLocation = [touch previousLocationInView:touch.view];

      CGFloat lDeltaX = (location.x - previousLocation.x)*1.0;
      CGFloat lDeltaY = (location.y - previousLocation.y)*1.0;

      // rotate the current matrix
      [self rotateX:lDeltaYY:lDeltaX];
 }

}

// 应用旋转
……

glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();


 glTranslatef(0.0f,0.0f,-100.0f);   // move a little to see the object


 glMultMatrixf(theCurrenMatrixPtr]);

画出你的物体

Got the answer from a user on another forum:

// init the matrix

... view init method

theCurrentMatrix = CATransform3DIdentity;

...

// computing rotation when user touch screen :

- (void) rotateX:(float)inX Y:(float)inY
{
     GLfloat lAngle=sqrt(inX*inX+inY*inY);

 if (lAngle != 0.0f)
 {
      static const float _degToRad = M_PI / 180.0;
            // we compute a rotation matrix (in radians)
      CATransform3D lRotation = CATransform3DMakeRotation(lAngle * _degToRad, inX, inY, 0.0f);

            // apply the rotation to the current matrix (cumulative effect)
            // order is important
      theCurrentMatrix = CATransform3DConcat(theCurrentMatrix, lRotation);
 }

}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
     // Get touch
     UITouch *touch = [[touches allObjects] objectAtIndex:0];

     if ([touches count] == 1)
     {
          UITouch *touch = [[touches allObjects] objectAtIndex:0];
          CGPoint location = [touch locationInView:touch.view];
      CGPoint previousLocation = [touch previousLocationInView:touch.view];

      CGFloat lDeltaX = (location.x - previousLocation.x)*1.0;
      CGFloat lDeltaY = (location.y - previousLocation.y)*1.0;

      // rotate the current matrix
      [self rotateX:lDeltaYY:lDeltaX];
 }

}

// Applying the rotation(s)
...

glMatrixMode(GL_MODELVIEW);
 glLoadIdentity();


 glTranslatef(0.0f,0.0f,-100.0f);   // move a little to see the object


 glMultMatrixf(theCurrenMatrixPtr]);

... draw your objects

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文