RT,具体表现为鼠标拖动向一个方向转的过程中,物体的转动方向会突然变反,就像整个坐标系突然反过来一样(x,y,z全反,往哪个方向拖都不正常),有时第一次打开程序也会出现这种情况,无解,调两天多了,试了N种方法,请大师讲解问题产生的原因和解决方案。
注意:拖动速度越快,越容易出现反向;
反向之后不定什么时候就又正向了;
坐标等我已经打印到屏幕上了,从坐标和矩阵等上面看,变换后的坐标是正确的,旋转角度也是正确的,但是旋转方向不对,本来该是右手的结果变成左手;
试着用每次移动1-2度,短期内没有发现问题,每次移动1度转了好几圈也没有出现问题。用坐标左乘矩阵,原则上得到的是当前法向量在当前视角下的屏幕平面的投影?我验算了一下,数值都是正确的,但结果就是不对,从现象观察的结果看,是OpenGL转的方向有时反掉了。还有时OpenGL转的图在那往复运动,很搞笑的那种,但是结果不正确啊。总不能就1度1度旋转吧?代码是VC6MFC的,View的头文件和代码文件,只改了这两个文件,下面是改的地方:
OpenGL_HW_1View.hstruct llocsave
{
double datax;
double datay;
double dataz;
llocsave *next;
};
struct glAxisf
{
double x;
double y;
double z;
};
public:// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(COpenGL_HW_1View)
public:
virtual void OnDraw(CDC* pDC);  // overridden to draw this view
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
//}}AFX_VIRTUAL// Implementation
public:
// Below are OpenGL View Point Definition
double m_far;// How far is in view of camera
double m_near;// How near is in view of camera
double m_fovy;// Degree of view angle of camera
double m_eyeX;
double m_eyeY;
double m_eyeZ;
double m_centerX;
double m_centerY;
double m_centerZ;
double m_upX;
double m_upY;
double m_upZ;
double m_neworginx;
double m_neworginy;
double m_neworginz;
double m_rotateX;
double m_rotateY;
double m_rotateZ;// Rotate Z to be degree
double m_rotateX_SAVE;
double m_rotateY_SAVE;
double m_rotateZ_SAVE;
bool m_InitDisplay;
GLfloat m_f[16];public:
// State control part
bool m_Left_Btn_Down;
CPoint m_Left_Last_Pt;
CPoint m_Move_Last_Pt;
int m_Move_dx;
int m_Move_dy;
double m_Rotate_Degree;
llocsave m_HEAD;
llocsave * m_TAIL;public:
CString DoubleToString(double sp);
glAxisf ExchangeAxis(double X,double Y,double Z);
void createMatrixBuffer();
void DrawBezier();
void BezierShift(double pt[][3], double retpt[], double t);
void BezierFace(double pt[][3], double shift[], double retpt[], double t);
int m_viewHeight;
int m_viewWidth;
CPoint m_drawEndPt;
CPoint m_drawStartPt;
CPoint m_EndPt;
CPoint m_StartPt;
void RenderScene();
bool SetupPixelFormat();
bool InitializeOpenGL();
virtual ~COpenGL_HW_1View();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif后面的cppCOpenGL_HW_1View::COpenGL_HW_1View()
{
// TODO: add construction code here
this->m_StartPt.x=0xFFFF;
this->m_StartPt.y=0xFFFF;
this->m_EndPt.x=0xFFFF;
this->m_EndPt.y=0xFFFF;

this->m_drawStartPt.x=0xFFFF;
this->m_drawStartPt.y=0xFFFF;
this->m_drawEndPt.x=0xFFFF;
this->m_drawEndPt.y=0xFFFF;

this->m_fovy=30.0;// Degree of view angle of camera
this->m_near=0.0;// How near is in view of camera
this->m_far=100.0;// How far is in view of camera m_eyeX=0.0;
m_eyeY=0.0;
m_eyeZ=40.0;
m_centerX=0.0;
m_centerY=0.0;
m_centerZ=0.0;
m_upX=0.0;
m_upY=1.0;
m_upZ=0.0;
m_neworginx=0.0;
m_neworginy=0.0;
m_neworginz=0.0; m_rotateX=0.0;
m_rotateY=0.0;
m_rotateZ=0.0; m_Move_dx=0;
m_Move_dy=0; m_HEAD.datax=m_HEAD.datay=m_HEAD.dataz=0.0;
m_HEAD.next=NULL;
m_TAIL=&m_HEAD; this->m_Left_Btn_Down=false; m_InitDisplay=false;

for(int i=0;i<16;i++)
m_f[i]=0;
m_f[0]=m_f[5]=m_f[10]=m_f[15]=1.0;
}void COpenGL_HW_1View::OnDraw(CDC* pDC)
{
COpenGL_HW_1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here

glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
RenderScene();
glFinish();
SwapBuffers(m_pDC->GetSafeHdc());
pDC->SetTextColor(RGB(255,255,255));
pDC->SetBkColor(RGB(0,0,0));
GLfloat m[16];
glGetFloatv(GL_MODELVIEW_MATRIX,m);
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
pDC->TextOut(5+j*80,5+i*20,this->DoubleToString(m[j*4+i]));
}
}
pDC->TextOut(5,5+80,DoubleToString(this->m_rotateX));
pDC->TextOut(5+80,5+80,DoubleToString(this->m_rotateY));
pDC->TextOut(5+160,5+80,DoubleToString(this->m_rotateZ));
glAxisf newaxis=ExchangeAxis(this->m_rotateX,this->m_rotateY,0.0);
pDC->TextOut(5,5+100,DoubleToString(newaxis.x));
pDC->TextOut(5+80,5+100,DoubleToString(newaxis.y));
pDC->TextOut(5+160,5+100,DoubleToString(newaxis.z));
pDC->TextOut(5,5+120,DoubleToString(this->m_eyeX));
pDC->TextOut(5+80,5+120,DoubleToString(this->m_eyeY));
pDC->TextOut(5+160,5+120,DoubleToString(this->m_eyeZ));
pDC->TextOut(5,5+140,DoubleToString(this->m_centerX));
pDC->TextOut(5+80,5+140,DoubleToString(this->m_centerY));
pDC->TextOut(5+160,5+140,DoubleToString(this->m_centerZ));
}
void COpenGL_HW_1View::OnSize(UINT nType, int cx, int cy) 
{
CView::OnSize(nType, cx, cy);
GLdouble aspect_ratio;
if(cx<0 || cy<0)
return;
glViewport(0,0,cx,cy);
aspect_ratio = (GLdouble)cx/(GLdouble)cy;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(this->m_fovy, aspect_ratio, this->m_near, this->m_far);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
this->m_viewWidth=cx;
this->m_viewHeight=cy;
}
bool COpenGL_HW_1View::InitializeOpenGL()
{
m_pDC = new CClientDC(this);
if(m_pDC == NULL)
return false;
if(!SetupPixelFormat())
return false;
m_hRC = wglCreateContext(m_pDC->GetSafeHdc());
if(m_hRC == NULL)
return false;
if(wglMakeCurrent(m_pDC->GetSafeHdc(),m_hRC)==false)
return false;
glClearColor(0.0f,0.0f,0.0f,0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
return true;
}
bool COpenGL_HW_1View::SetupPixelFormat()
{
static PIXELFORMATDESCRIPTOR pfd={sizeof(PIXELFORMATDESCRIPTOR),1,PFD_DRAW_TO_WINDOW|PFD_SUPPORT_OPENGL|PFD_DOUBLEBUFFER,PFD_TYPE_RGBA,24,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,PFD_MAIN_PLANE,0,0,0,0};
int m_nPixelFormat = ChoosePixelFormat(m_pDC->GetSafeHdc(),&pfd);
if(m_nPixelFormat == 0)return false;
if(SetPixelFormat(m_pDC->GetSafeHdc(),m_nPixelFormat,&pfd) == false)return false;
return true;
}
int COpenGL_HW_1View::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
InitializeOpenGL();
return 0;
}void COpenGL_HW_1View::OnLButtonDown(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
if(!OPENGL_OPERATION_MODE_3D)
{
if(this->m_StartPt.x==0xFFFF)
this->m_StartPt=point;
else
{
this->m_drawStartPt=m_StartPt;
this->m_drawEndPt=point;
this->m_StartPt.x=0xFFFF;
}
}
m_rotateX_SAVE=m_rotateX;
m_rotateY_SAVE=m_rotateY;
m_rotateZ_SAVE=m_rotateZ;
m_rotateX=0.0;
m_rotateY=0.0;
m_rotateZ=0.0;
m_TAIL->datax=m_rotateX_SAVE;
m_TAIL->datay=m_rotateY_SAVE;
m_TAIL->dataz=m_rotateZ_SAVE;
m_TAIL->next=new llocsave();
m_TAIL=m_TAIL->next;
m_Left_Btn_Down=true;
m_Left_Last_Pt=point;
m_Move_Last_Pt=point;
this->Invalidate(FALSE);
CView::OnLButtonDown(nFlags, point);
}void COpenGL_HW_1View::OnLButtonUp(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
m_Left_Btn_Down=false;
m_rotateX=0.0;
m_rotateY=0.0;
m_rotateZ=0.0;
this->Invalidate(FALSE);
CView::OnLButtonUp(nFlags, point);
}
void COpenGL_HW_1View::OnMouseMove(UINT nFlags, CPoint point) 
{
// TODO: Add your message handler code here and/or call default
if(m_Left_Btn_Down && OPENGL_OPERATION_MODE_3D)
{
double dx=point.x-m_Left_Last_Pt.x;
double dy=-(point.y-m_Left_Last_Pt.y);
double dlen=sqrt(dx*dx+dy*dy);
//while(dlen>0)
{
m_rotateZ=dlen;
//if(dlen>2.5)
// m_rotateZ=2.5;
m_rotateZ+=1.1;
m_rotateZ=(int)m_rotateZ;
m_rotateZ/=5;
this->m_rotateX=0;
this->m_rotateY=0;
// Calculate xth
double xylen=sqrt(dx*dx+dy*dy);
if(dx==0)this->m_rotateX=1;
else if(dy==0)this->m_rotateY=1;
else
{
if(fabs(dy)>fabs(dx))
{
this->m_rotateX=1.0;
this->m_rotateY=fabs((double)dx/(double)dy);
}
else
{
this->m_rotateY=1.0;
this->m_rotateX=fabs((double)dy/(double)dx);
}
}
if(dy>0)this->m_rotateX=-fabs(m_rotateX);
else this->m_rotateX=fabs(m_rotateX);
if(dx>0)this->m_rotateY=fabs(this->m_rotateY);
else this->m_rotateY=-fabs(this->m_rotateY); double r=sqrt(m_rotateX*m_rotateX+m_rotateY*m_rotateY);
m_rotateX=m_rotateX/r;
m_rotateY=m_rotateY/r; m_Move_Last_Pt=point;
m_Left_Last_Pt=point;
this->Invalidate(FALSE);
dlen-=2.5;
}
}
CView::OnMouseMove(nFlags, point);
}void COpenGL_HW_1View::RenderScene()
{
glColor4f(0.7,0.7,1,0.5);
// Test 3d code
glLoadIdentity();
// Set camera
gluLookAt(m_eyeX,m_eyeY,m_eyeZ,m_centerX,m_centerY,m_centerZ,m_upX,m_upY,m_upZ);
// glTranslatef: Move current origin point to (x,y,z). View point is not moved.
glTranslatef(m_neworginx,m_neworginy,m_neworginz);
GLfloat m[16] = {0};
glGetFloatv(GL_MODELVIEW_MATRIX,m);
for(int i=0;i<11;i++)
{
if((i+1)%4==0)
continue;
m[i]=m_f[i];
}
glLoadMatrixf(m);
m_InitDisplay=true;
glAxisf newaxis;
llocsave *tmp=&m_HEAD;
newaxis=ExchangeAxis(this->m_rotateX,this->m_rotateY,0.0);
glRotatef(m_rotateZ,newaxis.x,newaxis.y,newaxis.z);
glGetFloatv(GL_MODELVIEW_MATRIX,m_f);
glutWireSphere(1.0f,20,20);
}glAxisf COpenGL_HW_1View::ExchangeAxis(double X,double Y,double Z)
{
GLfloat m[16] = {0};
glGetFloatv(GL_MODELVIEW_MATRIX,m);
double na[4];
double nr[4];
glAxisf f;
na[0]=X;
na[1]=Y;
na[2]=Z;
na[3]=0.0;
int i,j;
for(i=0;i<4;i++)
{
nr[i]=0;
for(j=0;j<4;j++)
{
nr[i]+=na[j]*m[j+i*4];
}
}
f.x=nr[0];
f.y=nr[1];
f.z=nr[2];
return f;
}