XNA — повороты и переводы дерева рендеринга

На этой неделе я начал работать с XNA, в настоящее время создаю хорошее ядро, которое смогу использовать в будущих играх.

Я не могу завершить свое дерево рендеринга, потому что не знаю, как кодировать следующее:

(Я привык много работать с OpenGL, поэтому ищу самый быстрый аналог этого кода)

public void DrawRecursively( GameTime deltaTime )
{
    glPushMatrix();

    /* these 3 lines are what i didn't figure out with XNA */
    glTranslate3f( position[0], position[1], position[2] );
    glRotatef( theta, 0.0f, 1.0f, 0.0f );
    glRotatef( phi, 1.0f, 0.0f, 0.0f );

    this.Draw( deltaTime );

    foreach ( ComponentInterface child in childs )
    {
        child.DrawRecursively( deltaTime );
    }

    glPopMatrix();
}

Моя текущая попытка выглядит примерно так:

public void DrawRecursively( GameTime deltaTime, Matrix worldMatrix )
{
    Matrix backup = worldMatrix;

    // TRANSLATE HERE.
    // ROTATE HERE.

    this.Draw( deltaTime );

    foreach ( ComponentInterface child in childs )
    {
        child.DrawRecursively( deltaTime, worldMatrix );
    }

    worldMatrix = backup;
}

Я понимаю, что к worldMatrix нельзя получить неявный доступ откуда угодно и что вы должны иметь ссылку на него. Как тогда перевести и повернуть? И является ли моя резервная копия worldMatrix правильным способом сделать эквивалент блока glPushMatrix/PopMatrix?

Спасибо,

Ник


РЕДАКТИРОВАТЬ:

Я думаю, что мне удалось сделать несколько шагов вперед, при этом он все еще не работает. Боже, я скучаю по openGL и всей подробной документации, MSDN не даст мне много информации... Вот мой последний подход:

public void DrawRecursively( GameTime deltaTime, BasicEffect effect )
{
    Matrix worldMatrix = effect.World;
    Matrix backup = worldMatrix;

    worldMatrix = worldMatrix * Matrix.CreateTranslation( position.ToVector3() );
    worldMatrix = worldMatrix * Matrix.CreateRotationY( theta );
    worldMatrix = worldMatrix * Matrix.CreateRotationX( phi );
    effect.Parameters["xWorld"].SetValue( worldMatrix );

    this.Draw( deltaTime );

    foreach ( ComponentInterface child in childs )
    {
        child.DrawRecursively( deltaTime, effect );
    }

    effect.Parameters["xWorld"].SetValue( backup );
}

effect.Parameters["xWorld"] возвращает мне нулевой указатель, поэтому SetValue, очевидно, выдает мне ошибку нарушения прав доступа. Я дважды проверил, и экземпляр эффекта правильно инициализирован, согласно отладчику.

Это правильный способ сделать это?


РЕДАКТИРОВАТЬ СНОВА:

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

public void DrawRecursively( GameTime deltaTime, BasicEffect effect )
    {
        Matrix worldMatrix = effect.World;
        Matrix backup = worldMatrix;

        effect.World = worldMatrix  * Matrix.CreateScale( scale )
                                    * Matrix.CreateRotationX( orientation.X )
                                    * Matrix.CreateRotationX( orientation.Y )
                                    * Matrix.CreateRotationX( orientation.Z )
                                    * Matrix.CreateTranslation( position.ToVector3() );

        this.Draw( deltaTime );

        foreach ( ComponentInterface child in childs )
        {
            child.DrawRecursively( deltaTime, effect );
        }

        effect.World = backup;
    }

person NGauthier    schedule 19.04.2011    source источник


Ответы (1)


В BasicEffect есть геттеры и сеттеры для матриц World, View и Projection, но сам шейдер сохраняет одну матрицу WorldViewProj, поэтому effect.Parameters["xWorld"] не работает. Придерживайтесь сеттеров, а BasicEffect позаботится обо всем остальном.

Matrix worldMatrix = effect.World;
Matrix backup = worldMatrix;

worldMatrix *= Matrix.CreateTranslation( position.ToVector3() );
worldMatrix *= Matrix.CreateRotationY( theta );
worldMatrix *=  Matrix.CreateRotationX( phi );
effect.World = worldMatrix;
person Kyte    schedule 19.04.2011
comment
Сбоя больше нет, но мой тестовый треугольник не вращается, как предполагалось. Я увеличиваю тета в функции обновления, и отладчик действительно показывает, что CreateRotation вызывается с допустимым увеличивающимся значением тета. - person NGauthier; 20.04.2011
comment
@NGauthier: вы используете CreateRotationX три раза для разных ориентаций. Вы можете использовать CreateFromYawPitchRoll(y, x, z), чтобы сохранить некоторые матричные умножения. - person Kyte; 20.04.2011