2013-04-30 50 views
0

我想在OpenGL中实现一个简单的例子来测试第一个透视图(不使用看设备),但它让我疯狂!第一视角透视:旋转让我疯狂

我用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; 
    } 
    } 
} 
+0

你能更清楚地描述问题吗?另外,如果你使用'lookAt',会发生什么?那它有用吗? – Xymostech 2013-04-30 18:44:20

+0

@Xymostech似乎当我在X或Z轴上移动摄像头(所以我改变cameraXPos或cameraZPos)时,围绕Y轴的旋转不是围绕摄像头轴进行的,而是围绕另一个中心进行的。我不知道如何使用lookAt,并且我在考虑对于这个简单的测试,它不是必要的......不是吗? – 2013-04-30 18:56:00

回答

0

我试图在C和OpenGL上移植相同的例子,并且...它的工作原理!

确切地说,它反转了旋转和平移的序列后就起作用了(正如@comingstorm和我之前已经尝试的那样)。

所以我回到Processing并试图找出为什么发生这个问题。我已经注意到,默认的摄像头位置是:

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

所以在我的代码正在将相机移开相同的距离(相反方向),以便将相机对准我的物体,但不起作用。我也尝试将相机放在原来的位置,然后手动移动(使用键盘按键)到达我的物体,但它也不起作用。

所以我注意到在draw()方法中没有任何变换矩阵的初始化。 在我看到的所有例子中,都没有做这个初始化,而且我非常肯定已经读过了自动初始化的地方。所以我在想/确定它没有必要。 反正我试图把作为第一个语句draw()方法:

resetMatrix(); // Same as glLoadIdentity in OpenGL 

......现在一切工作!

(根据记录,我注意到了同样的问题在openFramework库)。

说实话,我不明白为什么他们(这些库)不要把相机中的起源和高于一切我期待如果在每次执行draw方法时转换矩阵都不清晰,相机应该自动转换(将旧矩阵与新矩阵相加),因此它会在某个方向上快速移动(或绕Y轴旋转)。

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

0

以上您的评论似乎表明您希望您的cameraYAngle可以在相机当前位置旋转相机。如果是这样,你首先要做相机旋转;试试这个:

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

注意上面的什么也不做,让你看产地 - 也就是说,它不会做任何事情一样lookAt。还记得,你的相机开始了向下看Z轴...


这里就是我想你了问题。即使你的相机和物体姿势是可比较的,你需要以不同的方式生成“视图变换”和“世界变换”:你的相机姿势必须是倒置以生成“视图变换”。

如果你链接的原始变换(如您的示例代码),这意味着你的相机姿势变换需要在相反的顺序相对于你的对象转换,以及在反方向(也就是说,您必须否定摄像机变换的平移矢量和旋转角度)。为了更加明确,假设你的相机和你的物体都具有可比较的姿态参数:一个位置矢量和3个绕X,Y和Z顺序旋转。然后,你的转型序列可能是这样的:

// 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==objectXPos,cameraYPos==objectYPos等等,上述变换序列中的变换都从中心开始成对地取消 - 这样最终结果是相同的视图,就好像它们都坐在一起在起源没有旋转。

+0

感谢您的回复,您的建议是正确的,请参阅我的自动回答了解更多详情。 – 2013-05-01 15:49:50