0

我想在 OpenGL 中实现一个简单的例子来测试第一个透视图(不使用lookAt 工具),但这让我发疯!

我使用Processing制作了一个小原型(这个东西与OpenGL非常相似),但是当相机开始移动时我得到了奇怪的行为!

我不清楚这是转换的顺序(我已经尝试过所有组合;-))!

我在想它应该很简单,一个可能的解决方案可能是:

  • 平移到相机的位置
  • 按相机角度旋转
  • 平移每个对象的位置

在我的简单示例中,我在 (0, 0, -400) 中放置了一个框和一个网格,但它没有按预期工作。当我沿 X 或 Z 轴移动相机时,围绕 Y 轴的旋转似乎围绕错误的中心旋转!我想模拟相机围绕自己的 Y 轴旋转,就像经典的 FPS 游戏一样。

这是我的示例代码,用户可以移动相机并旋转(仅围绕 Y 轴),您可以使用 Processing 或使用OpenProcessing进行测试。只有前几行与问题相关......所以这是一个非常小的测试!

float cameraXPos = 0;
float cameraYPos = 0;
float cameraZPos = 0;
float cameraYAngle = 0;

float moveIncrement = 5;
float angleIncrement = 5;

// Keys:
//     W
//     ^
//     |
// A <- -> D 
//     |
//     V
//     S 
//
// F and R for Z+/Z-
// O and P for rotation around Y axis

void setup()
{
  size(640, 480, OPENGL);

  resetCameraPos();
}

// Reset camera
void resetCameraPos()
{
  cameraXPos = width / 2;
  cameraYPos = height / 2;
  cameraZPos = (height /2 ) / tan(PI/6);
  cameraYAngle = 0;
}


void draw() 
{
  // Clear screen
  background(0);
  // View transform
  translate(cameraXPos, cameraYPos, cameraZPos);
  rotateY(radians(cameraYAngle));
  // World transform
  translate(0, 0, -400);
  // Draw a red box and a grid in the center
  stroke(255, 0, 0);
  noFill();
  box(100);
  drawGrid();

  // Check if user is pressing some key and update the camera position
  updateCameraPos();
}

/////////////////////////////////////////////////////////////////////
// The following part is not so relevant to the problem (I hope! ;-)) 
/////////////////////////////////////////////////////////////////////
void drawGrid()
{
  // Draw a white grid (not so important thing here!)
  stroke(255, 255, 255);
  float cellSize = 40;
  int gridSize = 10;
  float cY = 100;

  for(int z = 0; z < gridSize; z++)
  {
    float cZ = (gridSize / 2 - z) * cellSize;
    for(int x = 0; x < gridSize; x++)
    {
      float cX = (x - gridSize / 2) * cellSize;
      beginShape();
      vertex(cX, cY, cZ);
      vertex(cX + cellSize, cY, cZ);
      vertex(cX + cellSize, cY, cZ - cellSize);
      vertex(cX, cY, cZ - cellSize);
      vertex(cX, cY, cZ);
      endShape();
    }
  }
}

// Just update camera position and angle rotation
// according to the pressed key on the keyboard
void updateCameraPos()
{
  if (keyPressed)
  {
    switch(this.key)
    {
    case 'w':  // Y++
      cameraYPos += moveIncrement;
      break;
    case 's':  // Y--
      cameraYPos -= moveIncrement;
      break;
    case 'a':  // X--
      cameraXPos += moveIncrement;
      break;
    case 'd':  // X++
      cameraXPos -= moveIncrement;
      break;
    case 'r':  // Z++
      cameraZPos += moveIncrement;
      break;
    case 'f':  // Z--
      cameraZPos -= moveIncrement;
      break;
    case ' ':  // RESET
      resetCameraPos();
      break;
    case 'o':  // Angle++
      cameraYAngle += angleIncrement;
      break;
    case 'p':  // Angle--
      cameraYAngle -= angleIncrement;
      break;
    }
  }
}
4

2 回答 2

0

您上面的评论似乎表明您希望您cameraYAngle围绕其当前位置旋转相机。如果是这样,您想先进行相机旋转;试试这个:

// View transform
rotateY(radians(cameraYAngle));
translate(cameraXPos, cameraYPos, cameraZPos);
// World transform
translate(0, 0, -400);

请注意,上面的内容并没有让您查看原点——也就是说,它没有做任何类似lookAt. 还记得你的相机开始向下看 Z 轴......


这就是我猜你出错的地方。即使您的相机和物体姿势是可比的,您也需要以不同的方式生成“视图变换”和“世界变换”:必须反转您的相机姿势才能生成“视图变换”。

如果您正在链接原始变换(如示例代码中所示),这意味着您的相机姿势变换需要相对于对象变换以相反的顺序以及相反的方向(也就是说,您必须否定两个翻译相机变换的矢量和旋转角度)。

更明确地说,假设您的相机和您的对象都具有可比较的位姿参数:一个位置向量以及按该顺序围绕 X、Y 和 Z 进行 3 次旋转。然后,您的转换序列可能类似于:

// View transform
rotateZ(radians(-cameraZAngle));
rotateY(radians(-cameraYAngle));
rotateX(radians(-cameraXAngle));
translate(-cameraXPos, -cameraYPos, -cameraZPos);
// Model transform
translate(objectXPos, objectYPos, objectZPos);
rotateX(radians(objectXAngle));
rotateY(radians(objectYAngle));
rotateZ(radians(objectZAngle));

作为概念检查,假设您的相机完全跟随您的对象,以便相机和对象的所有位置和位置变量完全相同。您会期望看到相同的视图,就好像它们都坐在原点没有旋转一样。

然后请注意,如果cameraXPos==objectXPoscameraYPos==objectYPos以此类推,上述变换序列中的变换都成对抵消,从中心开始 - 因此最终结果是相同的视图,就好像它们都坐在原点没有旋转一样.

于 2013-04-30T23:22:21.080 回答
0

我尝试在 C 和 OpenGL 上移植相同的示例,并且......它有效!

准确地说,它在我颠倒了旋转和平移的顺序之后才起作用(正如@comingstorm 所建议的那样,正如我以前已经尝试过的那样)。

所以我回到处理并试图弄清楚为什么会发生这个问题。我已经注意到默认的相机位置在:

(宽度/2,高度/2,(高度/2)/(PI/6))

因此,在我的代码中,我将相机移开相同的距离(以相反的方向),以便将相机对准我的对象,但它不起作用。我也尝试将相机留在原处,然后手动移动(使用键盘键)以到达我的对象,但它也不起作用。

所以我注意到在该draw()方法中没有任何转换矩阵的初始化。在所有示例中,我都没有看到过这种初始化,而且我很确定在某个地方读到了自动初始化的内容。所以我在想/确定没有必要。无论如何,我试图将其作为draw()方法的第一个声明:

resetMatrix(); // Same as glLoadIdentity in OpenGL

...现在一切正常!

(作为记录,我在 openFramework 库中也注意到了同样的问题。)

老实说,我不明白为什么他们(这些库)不将相机放在原点,最重要的是,我期望如果在每次执行draw方法时转换矩阵都不清楚,相机应该自动翻译(总结旧矩阵与新矩阵),因此它会在某个方向快速移动(或绕 Y 轴旋转)。

我不清楚在这些库中实现的管道(而且我找不到显示它的好文档),但现在修复这个问题很重要。

于 2013-05-01T15:48:44.917 回答