Частицы, не ориентированные на камеру

У меня есть очень простая система частиц, которая отображает частицы на экране и перемещает их вокруг осей X, Y и Z. Проблема в том, что частицы не всегда ориентированы на камеру.

glRotatef(g_fX, 1.0f, 1.0f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glBindTexture(GL_TEXTURE_2D, texCircle);

glColor3f (1.0f, 0.0f, 0.0f);

for (x = -1; x <= 1; x += 0.25)
{
for (y = -1; y <= 1; y += 0.25)
{
for (z = -1; z <= 1; z += 0.25)
{
glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex3f(x+0.5f,y+0.5f,z);
glTexCoord2d(0,1); glVertex3f(x-0.5f,y+0.5f,z);
glTexCoord2d(1,0); glVertex3f(x+0.5f,y-0.5f,z);
glTexCoord2d(0,0); glVertex3f(x-0.5f,y-0.5f,z);
glEnd();
}
}
}

glEnable(GL_DEPTH_TEST);
glDisable(GL_BLEND);

Что я должен изменить в коде?

0

Решение

Вы должны нарисовать частицы в плоскости, которая ортогональна к области просмотра. Эта плоскость задается осями X и Y текущей обратной матрицы модели.
Угловые точки прямоугольника должны быть рассчитаны, как показано в следующем псевдокоде:

X = X-Axis of the inverse modelview matrix
Y = Y-Axis of the inverse modelview matrix

TL = (x, y, z) - 0.5 * X + 0.5 * Y
TR = (x, y, z) + 0.5 * X + 0.5 * Y
BL = (x, y, z) - 0.5 * X - 0.5 * Y
BR = (x, y, z) + 0.5 * X - 0.5 * Y

Обратите внимание, что матрица преобразования обычно выглядит так:

( X-axis.x, X-axis.y, X-axis.z, 0 )
( Y-axis.x, Y-axis.y, Y-axis.z, 0 )
( Z-axis.x, Z-axis.y, Z-axis.z, 0 )
( trans.x,  trans.y,  trans.z,  1 )

Вы должны использовать библиотеку как GLM для вычисления матриц, но если вы еще не использовали, вы также можете прочитать текущую матрицу просмотра модели с помощью glGetFloatv(GL_MODELVIEW_MATRIX, ptr) (увидеть Как вы получаете модели и матрицы проекций в OpenGL?).
Чтобы нарисовать в плоскости, которая ортогональна к области просмотра, вы должны нарисовать прямоугольник, выровненный по оси матрицы обратного вида (см. Inverse matrix). Я использую GLM :: обратная для вычисления матрицы обратного просмотра, но любая другая библиотека тоже будет уместна. Смотрите также ответы на вопрос Stackoverflow инвертирование матрицы 4х4.

void InverseMat44( const GLfloat m[], GLfloat im[] )
{
// here you can put in a function, of any other library , which calculates a inverse 4*4 matrix.
glm::mat4 glm_m = glm::make_mat4(m);
glm::mat4 glm_im = glm::inverse(glm_m);
memcpy( im, glm::value_ptr( glm_im ), 16 * sizeof( GLfloat ) );
}

GLfloat vm[16], ivm[16];
glGetFloatv(GL_MODELVIEW_MATRIX, vm );
InverseMat44( vm, ivm );

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

GLfloat scaleX = sqrt( ivm[0]*ivm[0] + ivm[1]*ivm[1] + ivm[2]*ivm[2] );
GLfloat scaleY = sqrt( ivm[4]*ivm[4] + ivm[5]*ivm[5] + ivm[6]*ivm[6] );

GLfloat lenX = 0.5f, lenY = 0.5f;
lenX = lenX / scaleX;
lenY = lenY / scaleY;

Рисунок прямоугольника должен выглядеть примерно так:

GLfloat xx = ivm[0] * lenX, xy = ivm[1] * lenX, xz = ivm[2] * lenX;
GLfloat yx = ivm[4] * lenY, yy = ivm[5] * lenY, yz = ivm[6] * lenY;

glBegin(GL_TRIANGLE_STRIP);

glTexCoord2d(1,1); glVertex3f( x + xx + yx, y + xy + yy, z + xz + yz );
glTexCoord2d(0,1); glVertex3f( x - xx + yx, y - xy + yy, z - xz + yz );
glTexCoord2d(1,0); glVertex3f( x + xx - yx, y + xy - yy, z + xz - yz );
glTexCoord2d(0,0); glVertex3f( x - xx - yx, y - xy - yy, z - xz - yz );

glEnd();

Смотрите также ответы на следующие вопросы:

Решение с использованием матрицы вида модели

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

GLfloat scaleX = sqrt( ivm[0]*ivm[0] + ivm[1]*ivm[1] + ivm[2]*ivm[2] );
GLfloat scaleY = sqrt( ivm[4]*ivm[4] + ivm[5]*ivm[5] + ivm[6]*ivm[6] );
GLfloat scaleZ = sqrt( ivm[8]*ivm[8] + ivm[9]*ivm[9] + ivm[10]*ivm[10] );

GLfloat len = 0.5f;
for (x = -1; x <= 1; x += 0.25)
{
for (y = -1; y <= 1; y += 0.25)
{
for (z = -1; z <= 1; z += 0.25)
{
GLfloat rm[16] = {
ivm[0]/scaleX, ivm[1]/scaleX, ivm[2]/scaleX,  0.0f,
ivm[4]/scaleY, ivm[5]/scaleY, ivm[6]/scaleY,  0.0f,
ivm[8]/scaleZ, ivm[9]/scaleZ, ivm[10]/scaleZ, 0.0f,
0.0f,          0.0f,          0.0f,           1.0f
};

glPushMatrix();
glTranslated( x, y, z );
glMultMatrixf( rm );

glBegin(GL_TRIANGLE_STRIP);
glTexCoord2d(1,1); glVertex3f(  len,  len, 0.0f );
glTexCoord2d(0,1); glVertex3f( -len,  len, 0.0f );
glTexCoord2d(1,0); glVertex3f(  len, -len, 0.0f );
glTexCoord2d(0,0); glVertex3f( -len, -len, 0.0f );
glEnd();

glPopMatrix();
}
}
}

Обратите внимание, что для любого решения вы должны знать текущую матрицу вида модели и рассчитывать обратную матрицу вида модели.

Альтернативная функция для вычисления обратной матрицы будет выглядеть следующим образом (см. инвертирование матрицы 4х4):

bool InverseMat44( const GLfloat m[16], GLfloat invOut[16] )
{
float inv[16], det;
int i;

inv[0]  =  m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
inv[4]  = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
inv[8]  =  m[4] * m[9]  * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
inv[12] = -m[4] * m[9]  * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
inv[1]  = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
inv[5]  =  m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
inv[9]  = -m[0] * m[9]  * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
inv[13] =  m[0] * m[9]  * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
inv[2]  =  m[1] * m[6]  * m[15] - m[1] * m[7]  * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7]  - m[13] * m[3] * m[6];
inv[6]  = -m[0] * m[6]  * m[15] + m[0] * m[7]  * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7]  + m[12] * m[3] * m[6];
inv[10] =  m[0] * m[5]  * m[15] - m[0] * m[7]  * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7]  - m[12] * m[3] * m[5];
inv[14] = -m[0] * m[5]  * m[14] + m[0] * m[6]  * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6]  + m[12] * m[2] * m[5];
inv[3]  = -m[1] * m[6]  * m[11] + m[1] * m[7]  * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9]  * m[2] * m[7]  + m[9]  * m[3] * m[6];
inv[7]  =  m[0] * m[6]  * m[11] - m[0] * m[7]  * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8]  * m[2] * m[7]  - m[8]  * m[3] * m[6];
inv[11] = -m[0] * m[5]  * m[11] + m[0] * m[7]  * m[9]  + m[4] * m[1] * m[11] - m[4] * m[3] * m[9]  - m[8]  * m[1] * m[7]  + m[8]  * m[3] * m[5];
inv[15] =  m[0] * m[5]  * m[10] - m[0] * m[6]  * m[9]  - m[4] * m[1] * m[10] + m[4] * m[2] * m[9]  + m[8]  * m[1] * m[6]  - m[8]  * m[2] * m[5];

det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
if (det == 0) return false;
det = 1.0 / det;

for (i = 0; i < 16; i++)
invOut[i] = inv[i] * det;

return true;
}
3

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector