glRotatef в чистом C

У меня проблема с написанием альтернативной функции для glRotatef на чистом C. Мне нужно реализовать функцию, аргументами которой являются: список точек, угол и вектор поворота. Функция должна возвращать список точек после поворота. Моя функция выглядит так:

void rotate(float * current, float a, float x, float y, float z)
{
    float sina = sinf(a);
    float cosa = cosf(a);
    float rotateMatrix[9] = //creating rotate matrix
    {
        x*x*(1-cosa) + cosa,    x*y*(1-cosa) - z*sina,  x*z*(1-cosa) + y*sina,
        y*x*(1-cosa) + z*sina,  y*y*(1-cosa) + cosa,    y*z*(1-cosa) - x*sina,
        z*x*(1-cosa) - y*sina,  z*y*(1-cosa) + x*sina,  z*z*(1-cosa) + cosa
    };
    float *resultVertexList = current; //temporary help
    int i;
    for(i=0;current[i] != 0;i++) //multiplying CURRENT_MATRIX * ROTATE_MATRIX
    {
        int currentVertex = (i/3) * 3;
        int rotateColumn = i%3;
        resultVertexList[i] =
        current[currentVertex] * rotateMatrix[rotateColumn] +
        current[currentVertex+1] * rotateMatrix[rotateColumn+3] +
        current[currentVertex+2] * rotateMatrix[rotateColumn+6];
    }
    current = resultVertexList;
}

Я называю это как здесь: rotate(current, M_PI/10, 0, 1, 0);

После этого я беру current список точек и просто нарисовать их с OpenGL. Для тестирования я попытался повернуть список точек, представляющих куб. Он вращается, но с каждым вызовом rotate функция сжимается. Понятия не имею почему. Смотрите некоторые скриншоты:

  1. без каких-либо вращающихся, передняя сторона куба

  2. когда я вращаюсь, она сжимается

После многих призваний rotate Функция сжимается до одной точки.

Что я делаю неправильно?

2 ответа

Решение

Эта строка кода:

float *resultVertexList = current; //temporary help

не копирует ваш список вершин. Вы только копируете указатель на список, поэтому после этого у вас есть два указателя, указывающих на один и тот же список. Из-за этого следующий цикл использует уже повернутые координаты x/y для вычисления новых координат y/z, что, очевидно, неверно.

Я также интересуюсь вашим условием прекращения:

current[i] != 0

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

Я бы также повернул на каждую вершину, а не на координату, это просто более естественно и легче понять:

void rotate(float * current, int vertexCount, float a, float x, float y, float z)
{
    float sina = sinf(a);
    float cosa = cosf(a);
    float rotateMatrix[9] =
    {
        x*x*(1 - cosa) + cosa, x*y*(1 - cosa) - z*sina, x*z*(1 - cosa) + y*sina,
        y*x*(1 - cosa) + z*sina, y*y*(1 - cosa) + cosa, y*z*(1 - cosa) - x*sina,
        z*x*(1 - cosa) - y*sina, z*y*(1 - cosa) + x*sina, z*z*(1 - cosa) + cosa
    };

    int i;
    for (i = 0; i < vertexCount; ++i)
    {
        float* vertex = current + i * 3;

        float x = rotateMatrix[0] * vertex[0] + rotateMatrix[1] * vertex[1] + rotateMatrix[2] * vertex[2];
        float y = rotateMatrix[3] * vertex[0] + rotateMatrix[4] * vertex[1] + rotateMatrix[5] * vertex[2];
        float z = rotateMatrix[6] * vertex[0] + rotateMatrix[7] * vertex[1] + rotateMatrix[8] * vertex[2];

        vertex[0] = x;
        vertex[1] = y;
        vertex[2] = z;
    }
}

То, как вы реализуете матричный вектор-мультипликацию, очень грубое и, что более важно, просто неверное.

Проблема в том, что вы перезаписываете данные, которые вам все еще нужны. Таким образом, в самом первом случае вы эффективно пишете current[0] (и ваш resultVertexList Указатель не поможет вообще. Он указывает на вашу единственную копию данных, перезаписывая их на месте. В следующих двух итерациях новое значение для current[0] будет использоваться вместо оригинального.

Я предлагаю вам просто реализовать прямолинейный mat3 * vec3 функция, которая может быть легко вызвана в цикле и которая заботится о том, чтобы не перезаписывать нужные данные.

Другие вопросы по тегам