1

そのため、カメラ変換用のローカル フレームを作成するカメラ クラスを手動で作成する方法を見つけようとしています。OpenGL SuperBible の GLFrame クラスに基づいてプレーヤー オブジェクトを作成しました。

MoveUp、MoveRight、MoveForward 関数にマッピングされたキーボード キーを取得し、水平方向と垂直方向のマウスの動きは xRot 変数とrotateLocalY 関数にマッピングされています。これは、FPS スタイルのカメラを作成するために行われます。

ただし、RotateLocalY に問題があります。平行移動は正常に機能し、マウスの垂直方向の移動も正常に機能しますが、水平方向の移動では、すべてのオブジェクトが奇妙な方法で縮小または拡大されます。スケーリングに加えて、回転も 180 度に制限されているようで、プレイヤーのローカル位置ではなく、ワールドの原点 (0.0) を中心に回転します。

スケーリングはベクトルの正規化と関係があると考えましたが、GLframe クラス (参照用に使用) はベクトルを正規化しておらず、そのクラスは問題なく動作します。私のベクトルのほとんどを正規化してもスケーリングが解決されただけで、他のすべての問題はまだ残っていたので、1 つのコードがこれらすべての問題を引き起こしていると考えていますか?

問題がどこにあるのかわからないようです。適切なコードをすべてここに投稿し、スケーリングを示すスクリーンショットを掲載します。

プレーヤー オブジェクト

Player::Player()
{
    location[0] = 0.0f; location[1] = 0.0f; location[2] = 0.0f;
    up[0] = 0.0f; up[1] = 1.0f; up[2] = 0.0f;
    forward[0] = 0.0f; forward[1] = 0.0f; forward[2] = -1.0f;
}

// Does all the camera transformation. Should be called before scene rendering!
void Player::ApplyTransform()
{
    M3DMatrix44f cameraMatrix;
    this->getTransformationMatrix(cameraMatrix);

    glRotatef(xAngle, 1.0f, 0.0f, 0.0f);
    glMultMatrixf(cameraMatrix);
}

void Player::MoveForward(GLfloat delta)
{
    location[0] += forward[0] * delta;
    location[1] += forward[1] * delta;
    location[2] += forward[2] * delta;
}

void Player::MoveUp(GLfloat delta)
{
    location[0] += up[0] * delta;
    location[1] += up[1] * delta;
    location[2] += up[2] * delta;
}

void Player::MoveRight(GLfloat delta)
{
    // Get X axis vector first via cross product
    M3DVector3f xAxis;
    m3dCrossProduct(xAxis, up, forward);

    location[0] += xAxis[0] * delta;
    location[1] += xAxis[1] * delta;
    location[2] += xAxis[2] * delta;
}

void Player::RotateLocalY(GLfloat angle)
{
    // Calculate a rotation matrix first
    M3DMatrix44f rotationMatrix;
    // Rotate around the up vector
    m3dRotationMatrix44(rotationMatrix, angle, up[0], up[1], up[2]); // Use up vector to get correct rotations even with multiple rotations used.

    // Get new forward vector out of the rotation matrix
    M3DVector3f newForward;
    newForward[0] = rotationMatrix[0] * forward[0] + rotationMatrix[4] * forward[1] + rotationMatrix[8] * forward[2]; 
    newForward[1] = rotationMatrix[1] * forward[1] + rotationMatrix[5] * forward[1] + rotationMatrix[9] * forward[2];
    newForward[2] = rotationMatrix[2] * forward[2] + rotationMatrix[6] * forward[1] + rotationMatrix[10] * forward[2];

    m3dCopyVector3(forward, newForward);
}

void Player::getTransformationMatrix(M3DMatrix44f matrix)
{
    // Get Z axis (Z axis is reversed with camera transformations)
    M3DVector3f zAxis;
    zAxis[0] = -forward[0];
    zAxis[1] = -forward[1];
    zAxis[2] = -forward[2];

    // Get X axis
    M3DVector3f xAxis;
    m3dCrossProduct(xAxis, up, zAxis);

    // Fill in X column in transformation matrix
    m3dSetMatrixColumn44(matrix, xAxis, 0); // first column
    matrix[3] = 0.0f; // Set 4th value to 0

    // Fill in the Y column
    m3dSetMatrixColumn44(matrix, up, 1); // 2nd column
    matrix[7] = 0.0f;

    // Fill in the Z column
    m3dSetMatrixColumn44(matrix, zAxis, 2); // 3rd column
    matrix[11] = 0.0f;

    // Do the translation
    M3DVector3f negativeLocation; // Required for camera transform (right handed OpenGL system. Looking down negative Z axis)
    negativeLocation[0] = -location[0];
    negativeLocation[1] = -location[1];
    negativeLocation[2] = -location[2];
    m3dSetMatrixColumn44(matrix, negativeLocation, 3); // 4th column
    matrix[15] = 1.0f;
}

プレーヤー オブジェクト ヘッダー

class Player
{
public:
    //////////////////////////////////////
    // Variables
    M3DVector3f location;
    M3DVector3f up;
    M3DVector3f forward;
    GLfloat xAngle; // Used for FPS divided X angle rotation (can't combine yaw and pitch since we'll also get a Roll which we don't want for FPS)
    /////////////////////////////////////
    // Functions
    Player();
    void ApplyTransform();
    void MoveForward(GLfloat delta);
    void MoveUp(GLfloat delta);
    void MoveRight(GLfloat delta);
    void RotateLocalY(GLfloat angle); // Only need rotation on local axis for FPS camera style. Then a translation on world X axis. (done in apply transform)

private:
    void getTransformationMatrix(M3DMatrix44f matrix);
};

変換がうまくいかなかった

変換の適用

// Clear screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();

// Apply camera transforms
player.ApplyTransform();


// Set up lights
...

// Use shaders
...

// Render the scene
RenderScene();

// Do post rendering operations
glutSwapBuffers();

とマウス

float mouseSensitivity = 500.0f;

float horizontal = (width / 2) - mouseX;
float vertical = (height / 2) - mouseY;

horizontal /= mouseSensitivity;
vertical /= (mouseSensitivity / 25);

player.xAngle += -vertical;
player.RotateLocalY(horizontal);

glutWarpPointer((width / 2), (height / 2));
4

1 に答える 1

1

正直なところ、あなたは問題に対して複雑なアプローチを取っていると思います。カメラを作成するには多くの方法があります。私のお気に入りは R3-Vector と Quaternion を使用することですが、R3-Vector と 2 つのフロート (ピッチとヨー) を使用することもできます。

2 つの角度を使用したセットアップは簡単です。

glLoadIdentity();
glTranslatef(-pos[0], -pos[1], -pos[2]);
glRotatef(-yaw, 0.0f, 0.0f, 1.0f);
glRotatef(-pitch, 0.0f, 1.0f, 0.0f);

ここで難しいのはカメラの移動です。次の行に沿って何かを行う必要があります。

flaot ds = speed * dt;
position += tranform_y(pich, tranform_z(yaw, Vector3(ds, 0, 0)));

変換を行う方法、私はそれを調べる必要がありますが、回転行列を使用してそれを行うことができます

回転は簡単です。ピッチとヨーの値を加算または減算するだけです。

オリエンテーションにクォータニオンを使用するのが好きです。これは一般的であり、移動スキームに依存しないカメラ (エンティティ) があるためです。この場合、次のようなカメラがあります。

class Camera
{
public:
   // lots of stuff omitted

   void setup();

   void move_local(Vector3f value);

   void rotate(float dy, float dz);

private:
    mx::Vector3f position;
    mx::Quaternionf orientation;
};

次に、セットアップ コードは恥知らずに gluLookAt を使用します。そこから変換行列を作成することはできますが、正しく機能することはありませんでした。

void Camera::setup()
{
    // projection related stuff

    mx::Vector3f eye     = position;
    mx::Vector3f forward = mx::transform(orientation, mx::Vector3f(1, 0, 0));
    mx::Vector3f center  = eye + forward;
    mx::Vector3f up      = mx::transform(orientation, mx::Vector3f(0, 0, 1));
    gluLookAt(eye(0), eye(1), eye(2), center(0), center(1), center(2), up(0), up(1), up(2));
}

ローカル フレームでのカメラの移動も簡単です。

void Camera::move_local(Vector3f value) 
{
    position += mx::transform(orientation, value);
}

回転もまっすぐです。

void Camera::rotate(float dy, float dz)
{
    mx::Quaternionf o = orientation;
    o = mx::axis_angle_to_quaternion(horizontal, mx::Vector3f(0, 0, 1)) * o;
    o = o * mx::axis_angle_to_quaternion(vertical, mx::Vector3f(0, 1, 0));   
    orientation = o;
}

(恥知らずのプラグ):

私が使用している数学ライブラリを尋ねている場合、それはmatexです。私はそれを書きました...

于 2013-02-06T13:02:04.127 に答える