2009-11-04 6 views
1

Я работаю над текущим проектом, где я хочу выровнять звенья цепи так, чтобы она соответствовала контурам кривой Безье. В настоящее время я выполняю следующие шаги.Как повернуть объект вокруг локальной оси в OpenGL?

  1. Рисование кривой.
  2. Используйте список отображения, чтобы создать одну ссылку на цепочку.
  3. Используйте цикл FOR для многократного вызова функции, которая вычисляет угол между двумя точками на кривой, возвращает угол и ось, вокруг которой должна быть повернута линия.
  4. Поверните на угол «a» и переведите на новое место, поместите ссылку в новое положение.

Редактировать: Я также должен сказать, что центры двух полутор должны лежать на кривой Безье. Также я знаю, что метод, который я использую для рисования тора, я утомительно, позже я буду использовать TRIANGLE_FAN или QUAD_STRIP, чтобы более эффективно рисовать тор.

Хотя на первый взгляд эта логика выглядит так, что она будет правильно изображать цепочку, конечный результат - это не то, что я себе представлял. Вот картина того, как выглядит цепочка.

gold_chain

Я читал, что вы должны перевести объект в начало координат до поворота? Я бы просто вызвал glTranslate (0,0,0), а затем выполнил шаг 4 сверху?

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

/* this function calculates the angle between two vectors oldPoint and new point contain the x,y,z coordinates of the two points,axisOfRot is used to return the x,y,z coordinates of the rotation axis*/ 
double getAxisAngle(pointType oldPoint[], 
pointType newPoint[],pointType axisOfRot[]){ 

float tmpPoint[3]; 

float normA = 0.0,normB = 0.0,AB = 0.0,angle=0.0; 
int i; 

axisOfRot->x= oldPoint->y * newPoint->z - oldPoint->z * newPoint->y; 
axisOfRot->y= oldPoint->z * newPoint->x - oldPoint->x * newPoint->z; 
axisOfRot->z= oldPoint->x * newPoint->y - oldPoint->y * newPoint->x; 


normA=sqrt(oldPoint->x * oldPoint->x + oldPoint->y * oldPoint->y + oldPoint->z * 
oldPoint->z); 
normB=sqrt(newPoint->x * newPoint->x + newPoint->y * newPoint->y + newPoint->z *  
newPoint->z); 

tmpPoint[0] = oldPoint->x * newPoint->x; 
tmpPoint[1] = oldPoint->y * newPoint->y; 
tmpPoint[2] = oldPoint->z * newPoint->z; 

for(i=0;i<=2;i++) 
AB+=tmpPoint[i]; 

AB /= (normA * normB); 


    return angle = (180/PI)*acos(AB); 
} 

/* this function calculates and returns the next point on the curve give the 4 initial points for the curve, t is the tension of the curve */ 
    void bezierInterpolation(float t,pointType cPoints[], 
    pointType newPoint[]){ 

newPoint->x = pow(1 - t, 3) * cPoints[0].x +3 * pow(1 - t , 2) * t * cPoints[1].x + 3 
* pow(1 - t, 1) * pow(t, 2) * cPoints[2].x + pow(t, 3) * cPoints[3].x; 

newPoint->y = pow(1 - t, 3) * cPoints[0].y +3 * pow(1 - t , 2) * t * cPoints[1].y + 3 
* pow(1 - t, 1) * pow(t, 2) * cPoints[2].y + pow(t, 3) * cPoints[3].y; 

newPoint->z = pow(1 - t, 3) * cPoints[0].z +3 * pow(1 - t , 2) * t * cPoints[1].z + 3 
* pow(1 - t, 1) * pow(t, 2) * cPoints[2].z + pow(t, 3) * cPoints[3].z; 

} 

/* the two lists below are used to create a single link in a chain, I realize that creating a half torus using cylinders is a bad idea, I will use GL_STRIP or TRIANGLE_FAN once I get the alignment right 
*/ 
torusList=glGenLists(1); 

glNewList(torusList,GL_COMPILE); 
for (i=0; i<=180; i++) 
{ 
    degInRad = i*DEG2RAD; 
    glPushMatrix(); 
    glTranslatef(cos(degInRad)*radius,sin(degInRad)*radius,0); 
    glRotated(90,1,0,0); 
    gluCylinder(quadric,Diameter/2,Diameter/2,Height/5,10,10); 
    glPopMatrix();  
} 

glEndList(); 

    /*! create a list for the link , 2 half torus and 2 columns */ 

linkList = glGenLists(1); 

glNewList(linkList, GL_COMPILE); 
glPushMatrix(); 
glCallList(torusList); 
glRotatef(90,1,0,0); 
glTranslatef(radius,0,0); 
gluCylinder(quadric, Diameter/2, Diameter/2, Height,10,10); 
glTranslatef(-(radius*2),0,0); 
gluCylinder(quadric, Diameter/2, Diameter/2, Height,10,10); 
glTranslatef(radius,0, Height); 
glRotatef(90,1,0,0); 
glCallList(torusList); 
glPopMatrix(); 
glEndList(); 

Наконец вот код для создания трех звеньев в цепи

t=0.031; 
bezierInterpolation(t,cPoints,newPoint); 
a=getAxisAngle(oldPoint,newPoint,axisOfRot); 
glTranslatef(newPoint->x,newPoint->y,newPoint->z); 
    glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z);  
    glCallList(DLid); 
    glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
glTranslatef(-newPoint->x,-newPoint->y,-newPoint->z); 

oldPoint[0]=newPoint[0]; 
bezierInterpolation(t+=GAP,cPoints,newPoint); 
a=getAxisAngle(oldPoint,newPoint,axisOfRot); 
glTranslatef(newPoint->x,newPoint->y,newPoint->z); 
    glRotatef(90,0,1,0); 
    glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z);  
    glCallList(DLid); 
    glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
    glRotatef(90,0,1,0); 
glTranslatef(-newPoint->x,-newPoint->y,-newPoint->z); 

oldPoint[0]=newPoint[0]; 
bezierInterpolation(t+=GAP,cPoints,newPoint);  
    a=getAxisAngle(oldPoint,newPoint,axisOfRot); 
    glTranslatef(newPoint->x,newPoint->y,newPoint->z);  
    glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
    glCallList(DLid); 
    glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
    glTranslatef(-newPoint->x,-newPoint->y,newPoint->z); 

ответ

3

Следует отметить, что функция glTranslate основывается на предыдущих переводах. И.Е. a glTranslatef (0,0,0,0,0,0); не пойдет к происхождению, он просто переместит «перо» в никуда. К счастью, «перо» начинается с начала координат. если вы переводите на 1.0,1.0,1.0, попробуйте glTranslatef (0.0.0.0.0.0); вы все равно будете рисовать 1.0,1.0,1.0;

Кроме того, вы, кажется, понимаете тот факт, что openGL после умножает матрицы. С этой целью вы правильно «отменяете» свои матричные операции после ничьей. Я вижу только одно место, где вы могли бы потенциально быть выключен здесь, и что в этом заявлении:

glRotatef(90,0,1,0); 
    glRotatef(a,axisOfRot->x,axisOfRot->y,axisOfRot->z);  
    glCallList(DLid); 
    glRotatef(-a,axisOfRot->x,axisOfRot->y,axisOfRot->z); 
    glRotatef(90,0,1,0); 

Здесь вы правильно отменить второй поворот, но первый из них вы, кажется, вращается еще вокруг оси у. последний glRotatef должен прочитать glRotatef (-90,0,1,0); если вы хотите уничтожить это вращение.

1

я посмотрел на свой код, и если предположить, что код исполняющей bezierInterp и угол оси является правильным. На основании кода у меня есть следующие предложения:

  1. Способ создания одной ссылки выглядит очень дорого. Поскольку вы используете gluCylinder в 180 раз. Это создаст много вершин для небольшой ссылки. Вы можете создать один тор и применить масштаб, чтобы он выглядел как ссылка!

  2. Всякий раз, когда вы выполняете операцию с матрицей, рекомендуется установить режим раньше. Это важно, прежде чем делать push и pop. В вашем списке отображения у вас есть push и pop без настройки какого-либо режима, и он не установлен в вызывающем. Это не очень хорошая практика и приведет к множеству ошибок/проблем. Вы можете удалить push и pop из списка вызовов и сохранить в нем только геометрию.

  3. Вы слышали совет, предлагающий перевод на происхождение перед ротацией как перевод * вращение! = вращение * перевод. Так как можно было бы написать рендеринг цикла является:

    // Set matrix mode 
    glMatrixMode(GL_MODELVIEW); 
    
    for(number of links) { 
    
    glLoadIdentity();  // makes model view matrix identity - default location` 
    glTranslatef(x,y,z); // Translate to a point on beizer curve 
    glRotatef(..);  // Rotate link 
    glCallList(link);  // can be simple torus, only geometry centered at origin 
    } 
    

Приведенных выше кода делает ссылку повторяющуюся в указанном месте. Прочтите OpenGL Red book's chapter 3 - Пример 3.6 (планетарная система), чтобы понять, как правильно разместить каждую ссылку в другом месте.

+0

Моя программа уже содержит инструкцию MODELVIEW, которая задана в функции main(). Как я уже отметил в комментарии к этому отображению Список «Я понимаю, что создание полутора тора с использованием цилиндров - это плохая идея, я буду использовать GL_STRIP или TRIANGLE_FAN, как только я получу выравнивание справа ". Использование только тора не сделает цепочку реалистичной, поэтому вы можете создать цепочку, используя два полутора тора и два цилиндра. Для упрощения этой статьи я упростил программу, забрав цикл for и большую часть функции main(). благодарит за вашу помощь. – NeatRobot

+0

Так вы правильно определили способ перевода и ротации? – Ketan

+0

Нет, я попробовал Переместить исходную ссылку на начало координат с помощью glTranslatef (0,0,0); а затем вызов glRotate(); за которым следует glTranslate() в исходное положение, а затем передавая ссылку, но у меня по-прежнему есть та же проблема, что и центры двух половинных торов, не находящиеся на кривой. – NeatRobot

Смежные вопросы