3D-движение LWJGL испорчено

Я пытаюсь создать 3D-игру, используя исключительно LWJGL и Slick-util, и я намерен сделать ее игрой от первого лица, поэтому мне нужен способ навигации по карте с использованием 3D-движения. У меня есть позиция Vector3f и другой вектор acc для хранения ускорения. Я установил следующие методы, привязанные (в другом классе) к W, A, S и D:

public void walkForward()
{
    acc.x += walkSpeed * (float) Math.sin(Math.toRadians(yaw)); // Calculations for 3D Movement (please correct me if wrong)
    acc.z -= walkSpeed * (float) Math.cos(Math.toRadians(yaw));
}

public void walkBackward()
{
    acc.x -= walkSpeed * (float) Math.sin(Math.toRadians(yaw));
    acc.z += walkSpeed * (float) Math.cos(Math.toRadians(yaw));
}

public void strafeLeft()
{
    acc.x += walkSpeed * (float) Math.sin(Math.toRadians(yaw - 90));
    acc.z -= walkSpeed * (float) Math.cos(Math.toRadians(yaw - 90));
}

public void strafeRight()
{
    acc.x += walkSpeed * (float) Math.sin(Math.toRadians(yaw + 90));
    acc.z -= walkSpeed * (float) Math.cos(Math.toRadians(yaw + 90));
}

Где walkSpeed — положительное число с плавающей запятой. Кроме того, в моем методе move(), где фактически обрабатывается движение, у меня есть следующее:

void move()
{

    acc.y = 0.0f;  // Keep the player's height stable, for testing purposes.

    getPosition().x += acc.x; // Add current velocity to the position.
    getPosition().y += acc.y;
    getPosition().z += acc.z;

    if(acc.x > 0.0f)        // Gradually bring player's velocity to 0.
        acc.x -= 0.01f;
    else if(acc.x < 0.0f)
        acc.x += 0.01f;

    if(acc.y > 0.0f)
        acc.y -= 0.01f;
    else if(acc.y < 0.0f)
        acc.y += 0.01f;

    if(acc.z > 0.0f)
        acc.z -= 0.01f;
    else if(acc.z < 0.0f)
        acc.z += 0.01f;
}

Наконец, в методе render(), где в игру фактически вносятся преобразования, у меня есть это:

public void render()
{
    move();

    glRotatef(pitch, 1.0f, 0.0f, 0.0f);
    glRotatef(yaw, 0.0f, 1.0f, 0.0f);
    glTranslatef(-position.x, -position.y, -position.z);
}

Ожидаемый результат: обычное 3D-движение, правильное направленное движение и т. д.

Фактический результат: игрок движется в общем направлении, скорость изменяется в зависимости от рыскания и тангажа, отпускание всех клавиш (отладка подтверждает, что НИКАКОЙ ввод не поступает к методам walk(), вызывает дрожание и странное движение в случайных направлениях, скорость которых изменяется в зависимости от рыскания). и тангажа, удерживая одновременно W+A или W+D вызывает сильное увеличение горизонтальной скорости и т.д.

У меня есть ощущение, что это может быть связано с отсутствием всплывающего окна или толчка в матрице или с забывчивостью где-то инициализировать личность. Любая помощь будет оценена по достоинству. Заранее спасибо!


person Michael Shift    schedule 07.01.2015    source источник


Ответы (1)


Методы, управляющие устаревшим стеком матриц OpenGL, такие как glRotatef() и glTranslatef(), объединяют указанное преобразование с преобразованием, которое в данный момент находится в стеке матриц. Поскольку вы никогда не сбрасываете/не восстанавливаете преобразование, вы просто продолжаете объединять больше преобразований каждый раз, когда вызывается render().

Чтобы избежать этого, вы можете либо сбросить трансформацию, прежде чем начать применять текущую трансформацию:

glLoadIdentity();
glRotatef(pitch, 1.0f, 0.0f, 0.0f);
glRotatef(yaw, 0.0f, 1.0f, 0.0f);
glTranslatef(-position.x, -position.y, -position.z);

или сохранить предыдущую матрицу в начале, и восстановить в конце:

glPushMatrix();
glRotatef(pitch, 1.0f, 0.0f, 0.0f);
glRotatef(yaw, 0.0f, 1.0f, 0.0f);
glTranslatef(-position.x, -position.y, -position.z);
glPopMatrix();

Преимущество второго подхода в том, что он будет работать правильно, если у вас уже есть матрица в стеке (например, преобразование представления), которую вы также хотите применить, в то время как первый сбрасывает все предыдущие преобразования.

Также обратите внимание, что преобразования применяются к вершинам в обратном порядке. Таким образом, ваша последовательность преобразования сначала переместит вершины, затем применит вращение по рысканию, а затем вращение по высоте. Если ты этого хочешь, то все хорошо. В противном случае вам нужно будет изменить порядок.

person Reto Koradi    schedule 07.01.2015
comment
Думаю, мне следовало включить это, и мне очень жаль, что я этого не сделал, но метод, вызывающий этот, Main.render(), действительно вызывает как glPushMatrix(), так и glPopMatrix() до и после (соответственно) метода Player.render(), поэтому я м не ближе к выяснению этого. - person Michael Shift; 08.01.2015