在OpenGL中,关于使用glRotatef实现绕各个坐标轴的独立旋转问题

yyfzy 2005-03-18 03:50:42
例如:我们以ogl默认的坐标轴为例子,如果鼠标在屏幕上有上下位移变化的话,我就想场景绕x轴(也就是从左到右的方向)转一个角度,同样,如果鼠标在水平方向上有位移变化的话,我就想场景,或者说是模型,饶y轴(也就是从下向上的方向)转个角度.而且始终是这个效果,也就是说,旋转轴好象是一直固定的原坐标轴,而不是后面的旋转受前一个旋转的影响.


该如何实现?谢谢!
...全文
5661 23 打赏 收藏 转发到动态 举报
写回复
用AI写文章
23 条回复
切换为时间正序
请发表友善的回复…
发表回复
寻开心 2005-03-24
  • 打赏
  • 举报
回复
你要的结果不就是围绕物体自身坐标系的x,y,z轴独立旋转嘛

当yRange=90时,会把原来的x方向旋转到了-z方向,因此对原来x轴的旋转,看似围绕-z方向在旋转
这个结果是一致的啊。
yyfzy 2005-03-22
  • 打赏
  • 举报
回复
To:happy__888([顾问团]寻开心)
我是用物体饶自己中心旋转,而不是饶世界坐标系统的原点旋转,所有是先平移到目标位置才旋转的
寻开心 2005-03-22
  • 打赏
  • 举报
回复
..........
glLoadIdentity();
glPushMatrix();
glTranslatef(0, 0, -z); // 1 ?????????????? 在做什么 ?????

// 2 ??????????? ??????????????
glGetFloatv(GL_MODELVIEW_MATRIX, m);
VevtorMultMatrix(x, m);
glRotatef(xRange, x[0], x[1], x[2]);
// 上面三行没有必要
// 直接 glRotatef(xRange, 1, 0, 0) 就可以了

glGetFloatv(GL_MODELVIEW_MATRIX, m);
VevtorMultMatrix(y, m);
glRotatef(yRange, y[0], y[1], y[2]);
//
Draw();
glPopMatrix();
.........
yyfzy 2005-03-22
  • 打赏
  • 举报
回复
现在还是有一个问题,我现在是如下处理的
render()
{
GLfloat m[16] = {0};
float x[4] = {1, 0, 0, 0};
float y[4] = {0, 1, 0, 0};
float z[4] = {0, 0, 1, 0};

..........
glLoadIdentity();
glPushMatrix();
glTranslatef(0, 0, -z);
glGetFloatv(GL_MODELVIEW_MATRIX, m);
VevtorMultMatrix(x, m);
glRotatef(xRange, x[0], x[1], x[2]);
//
glGetFloatv(GL_MODELVIEW_MATRIX, m);
VevtorMultMatrix(y, m);
glRotatef(yRange, y[0], y[1], y[2]);
//
Draw();
glPopMatrix();
.........
}
这样饶y轴的效果是正确的,因为能正确转换到新的坐标系下.但是绕x轴转的还是有问题,因为转x轴之前取出来的是单位矩阵,也就是说向量x[4]始终是{1,0,0,0}.但是实际的效果是:当yRange=90时,这个时候是饶原来的-z方向旋转的,也就是说把x轴从默认的位置旋转到了垂直显示器向里的方向.

理论上讲,先旋转的轴是不受其他旋转的影响的,因为每次旋转都是从默认的世界坐标系统开始旋转的,矩阵为单位矩阵,所以应该x角度不该受y的影响,这个问题我几天一直搞不明白,也有的地方说opengl中的变化顺序和函数调用顺序是反的,也就是说上面的这个顺序是先旋转的y轴.不知道到底是怎么回事??

谢谢!

寻开心 2005-03-22
  • 打赏
  • 举报
回复
是的
yyfzy 2005-03-22
  • 打赏
  • 举报
回复
To:happy__888([顾问团]寻开心)
我明白你的意思了,你是说取去当前矩阵,将向量(0,1,0)乘以该矩阵,就得到原来y轴在当前坐标系下的投影,然后饶新的向量旋转就相当于是绕原y轴旋转的,对吧?

我试试先
寻开心 2005-03-22
  • 打赏
  • 举报
回复
因为现在都是围绕坐标轴原点的旋转,不涉及到平移变换
所以对向量的变换和对点的变换是等价的

用mx变换阵,作用这个点(0,1,0)得到的新的点,这个点保存在vy这个变量当中
它的物理意义就是,在mx这个旋转矩阵的作用下,原来的物体的y坐标轴,变换后的位置
围绕物体自己的y坐标轴的旋转,和经过mx变换后,围绕这个vy轴旋转是一样的了
yyfzy 2005-03-22
  • 打赏
  • 举报
回复
上面所说的2和3中
“用mx变换 0 1 0 向量,结果保存在 vy向量当中”
是什么意思?
正常的第二步应该是:
glRotate(angle_y, 0, 1, 0 );
同样,底三步应该是
glRotate(angle_z, 0, 0, 1 );
你说的“mx变换0 1 0 向量”和“my变换 0 0 1 向”是指什么?

谢谢!
寻开心 2005-03-22
  • 打赏
  • 举报
回复
常规说来,顺序的调用多个glRotatef函数,这些旋转效果就会是很和叠加的
不是独立的了

这也是为什么一般的物体的姿态不是使用围绕x,y,z各自的转轴角度来表达
而是使heading, pitch和rolling三个姿态角度来表达的原因
因为姿态角度是固定了顺序的三次独立的转动形成的,无需前面给出的那么复杂的旋转方式
寻开心 2005-03-22
  • 打赏
  • 举报
回复


固定旋转的优先级顺序

1. glLoadIdentity(); //重置当前Modelview矩阵
glRotatef(v_x, 1, 0, 0)
把这个变换矩阵保存起来,留待后面使用,假定矩阵维 mx
2 用mx变换 0 1 0 向量,结果保存在 vy向量当中
glRotate(v_y, vy.x, vy.y, vy.z )
保存当前矩阵到 my当中留待后用
3 用 my变换 0 0 1 向量,结果保存在 vz向量当中
glRotate(v_z, vz.x, vz.y, vz.z)
4 平移
glTranslate();
只有这样做,才能保持各个转轴的独立
yyfzy 2005-03-22
  • 打赏
  • 举报
回复
To:happy__888([顾问团]寻开心)
这些我都清楚,但是实际情况和我们想象有差别,每一次glRotatef都有积累,第二次glRotatef的时候就是在上次旋转的基础上进行的,所以3个旋转有相关性。
例如:默认的x轴是水平从左到右的,,但是我先来对y轴旋转一个90后,x就是垂直显示器向里了(也就是原来的-z方向),这个时候再执行glRotatef(x轴, v_x角度)的效果就是绕-z旋转的效果,而不是饶原x轴(也就是水平从显示左边到右边)的效果了。

你有时间可以做个小例子看看效果,令人不解的是先旋转的角度也会受到后旋转的影响,虽然我在每帧开始都调用了glLoadIdentity();
寻开心 2005-03-22
  • 打赏
  • 举报
回复
关键是你的处理流程是把鼠标的控制,直接施加在三个角度的变量上
然后一次调用
glLoadIdentity(); //重置当前Modelview矩阵
glRotatef(x轴, v_x角度)
glRotatef(y轴, v_x角度)
glRotatef(z轴, v_x角度)
glTranslatef(-1.5f, 0.0f, -10.0f);
来完成任务的。
注意这个调用的顺序很重要
寻开心 2005-03-22
  • 打赏
  • 举报
回复
opengl和D3D实质上对物体的姿态控制是一样的——都是通过world矩阵来进行的

opengl当中那glRotatef也是把作用施加在当前的矩阵上的

无非是D3DX这个辅助工具包当中提供了直接根据三个姿态角度生成矩阵的函数而已,而这个函数的实际实现过程还是独立的旋转

你可以自己写一个类似这样的函数来完成它

你可以通过三次调用,
glRotatef(x轴, v_x角度)
glRotatef(y轴, v_x角度)
glRotatef(z轴, v_x角度)
来达到同样的目的

这些不是影响效果的关键
关键是你的处理流程是把鼠标的控制,直接施加在三个角度的变量上
然后一次调用
glRotatef(x轴, v_x角度)
glRotatef(y轴, v_x角度)
glRotatef(z轴, v_x角度)
来完成任务的。
yyfzy 2005-03-22
  • 打赏
  • 举报
回复
To: happy__888([顾问团]寻开心)
OpenGL和D3D里不一样,旋转是通过glRotatef(angle, v_x, v_y, v_z)实现的,如果通过绕三个坐标轴旋转的话只能是调用3次glRotatef。我现在要的就使用glRotatef函数来实现D3D里GenRotate这个函数的功能。

To:gRempCH_eNter(龙争四舞)
你还没有明白我的意思
yyfzy 2005-03-21
  • 打赏
  • 举报
回复
To:syy64(太平洋)
那样的话就只有最后一次的旋转起作用,因为每次glPopMatrix后坐标又回到默认的样子了.

这个你不信可以试试
gRempCH_eNter 2005-03-21
  • 打赏
  • 举报
回复
void SceneShow(GLvoid)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //清屏和清除深度缓冲区
glLoadIdentity(); //重置当前Modelview矩阵
glTranslatef(-1.5f, 0.0f, -10.0f); //向左移动1.5个单元,向屏幕里移动6.0个单元
glRotatef(rtri, 0.0f, 1.0f, 0.0f); //三角形Y轴旋转
glBegin(GL_TRIANGLES); //绘制三角形
glColor3f(1.0, 0.0f, 0.0f); //设为红色
glVertex3f(0.0f, 1.0f, 0.0f); //顶
glColor3f(0.0, 1.0f, 0.0f); //设为绿色
glVertex3f(-1.0f, -1.0f, 0.0f); //左下
glColor3f(0.0, 0.0f, 1.0f); //设为蓝色
glVertex3f(1.0f, -1.0f, 0.0f); //右下
glEnd( ); //结束三角形绘制
glTranslatef(3.0f, 0.0f, 0.0f); //右移三个单元
glRotatef(rquad, 1.0f, 0.0f, 0.0f); //矩形X轴旋转
glColor3f(0.5f, 0.5f, 1.0f); //设为蓝色
glBegin(GL_QUADS); //绘制矩形
glVertex3f(-1.0f, 1.0f, 0.0f); //左上
glVertex3f(1.0f, 1.0f, 0.0f); //右上
glVertex3f(1.0f, -1.0f, 0.0f); //右下
glVertex3f(-1.0f, -1.0f, 0.0f); //左下
glEnd( ); //完成矩形绘制
rtri +=0.8f; //旋转
rquad -=1.5f;
}
寻开心 2005-03-21
  • 打赏
  • 举报
回复
class Object {
public:
CPoint3D pos;
float fHeading;
float fPicth;
float fRoll;
Matrix worldMatrix;
public:
void Render();
}

void Object::Render()
{
worldMatrix.Indentify(); // 单位化矩阵
worldMatrix.GenRotate(fHeading ,fPitch, fRoll); // 生成变换矩阵
Display(); // 显示
};
滚动的时候,鼠标水平移动,对应
object.fHeading += dAngle;
鼠标垂直移动,对应
object.fPitch += dAngle;
。。。
object.Render();

这样就可以了
syy64 2005-03-21
  • 打赏
  • 举报
回复
OnDraw里面你可以加鼠标状态变量控制呀。
syy64 2005-03-20
  • 打赏
  • 举报
回复
这好说:每次旋转前用glPushMatrix函数对模型矩阵进行压栈,每次旋转完后用glPopMatrix弹出栈,这样每次旋转之间互不干扰。
chijingde 2005-03-18
  • 打赏
  • 举报
回复
好像以前有人问过

红皮书上也有相关描述
加载更多回复(3)
视点变换,旋转,加速减速,星空背景 太阳,光晕 各行星纹理 #include #include #include #include #include #include #include #pragma comment(lib, "winmm.lib") #pragma comment(lib,"wininet") // 纹理图像结构 typedef struct { int imgWidth; // 纹理宽度 int imgHeight; // 纹理高度 unsigned char byteCount; // 每个象素对应的字节数,3:24位图,4:带alpha通道的24位图 unsigned char *data; // 纹理数据 }TEXTUREIMAGE; // BMP文件头 #pragma pack(2) typedef struct { unsigned short bfType; // 文件类型 unsigned long bfSize; // 文件大小 unsigned short bfReserved1; // 保留位 unsigned short bfReserved2; // 保留位 unsigned long bfOffBits; // 数据偏移位置 }BMPFILEHEADER; #pragma pack() // BMP信息头 typedef struct { unsigned long biSize; // 此结构大小 long biWidth; // 图像宽度 long biHeight; // 图像高度 unsigned short biPlanes; // 调色板数量 unsigned short biBitCount; // 每个象素对应的位数,24:24位图,32:带alpha通道的24位图 unsigned long biCompression; // 压缩 unsigned long biSizeImage; // 图像大小 long biXPelsPerMeter;// 横向分辨率 long biYPelsPerMeter;// 纵向分辨率 unsigned long biClrUsed; // 颜色使用数 unsigned long biClrImportant; // 重要颜色数 }BMPINFOHEADER; // 定义窗口的标题、宽度、高度、全屏布尔变量 #define WIN_TITLE "模拟太阳系各星球的转动" const int WIN_WIDTH = 800; const int WIN_HEIGHT = 600; BOOL isFullScreen = FALSE; // 初始不为全屏 #define DEG_TO_RAD 0.017453 float angle=0.0; static GLdouble viewer[]= {0,0,0,0,0}; // 初始化视角 GLUquadricObj *quadric; // 建立二次曲面对象 GLfloat angle_Z; // 星空旋转角度 bool g_bOrbitOn = true; // 控制转动暂停 float g_fSpeedmodifier = 1.0f; // 时间控制 float g_fElpasedTime; double g_dCurrentTime; double g_dLastTime; GLfloat LightAmbient[] = { 1.0f, 1.0f, 1.0f, 0.0f }; // 环境光参数 GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 0.0f }; // 漫射光参数 GLfloat LightPosition[] = { 0.0f, 0.0f, 0.0f, 1.0f }; // 光源的位置 // 纹理图象 TEXTUREIMAGE skyImg; TEXTUREIMAGE sunImg; TEXTUREIMAGE rayImg; TEXTUREIMAGE mercuImg; TEXTUREIMAGE venusImg; TEXTUREIMAGE earthImg; TEXTUREIMAGE marsImg; TEXTUREIMAGE jupiterImg; TEXTUREIMAGE saturnImg; TEXTUREIMAGE uranusImg; TEXTUREIMAGE neptuneImg; TEXTUREIMAGE moonImg; GLuint texture[12]; // 纹理数组 // 星球速度定义 static float fSunSpin = 0.0f; // 太阳自转速度 static float fMercuSpin = 0.0f; // 水星自转速度 static float fMercuOrbit = 0.0f; // 水星公转速度 static float fVenusSpin = 0.0f; // 金星自转速度 static float fVenusOrbit = 0.0f; // 金星公转速度 static float fEarthSpin = 0.0f; // 地球自转速度 static float fEarthOrbit = 0.0f; // 地球公转速度 static float fMarsSpin = 0.0f; // 火星自转速度 static float fMarsOrbit = 0.0f; // 火星公转速度 static float fJupiterSpin = 0.0f; // 木星自转速度 static float fJupiterOrbit = 0.0f; // 木星公转速度 static float fSaturnSpin = 0.0f; // 土星自转速度 static float fSaturnOrbit = 0.0f; // 土星公转速度 static float fUranusSpin = 0.0f; // 天王星自转速度 static float fUranusOrbit = 0.0f; // 天王星公转速度 static float fNeptuneSpin = 0.0f; // 海王星自转速度 static float fNeptuneOrbit = 0.0f; // 海王星公转速度 static float fMoonSpin = 0.0f; // 月亮自转速度 static float fMoonOrbit = 0.0f; // 月亮公转速度 void MakeTexture(TEXTUREIMAGE textureImg, GLuint * texName) //转换为纹理 { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //对齐像素字节函数 glGenTextures(1,texName); //第一个参数指定表明获取多少个连续的纹理标识符 glBindTexture(GL_TEXTURE_2D , *texName); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, textureImg.imgWidth,textureImg.imgHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, textureImg.data); } // 初始化OpenGL void InitGL(void) { glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //设置黑色背景 glClearDepth(2.0f); // 设置深度缓存 glEnable(GL_DEPTH_TEST); //启动深度测试 glDepthFunc(GL_LEQUAL); //深度小或相等的时候渲染 glShadeModel(GL_SMOOTH); //启动阴影平滑 glEnable(GL_CULL_FACE); //开启剔除操作效果 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); //使用质量最好的模式指定颜色和纹理坐标的插值质量 glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // 设置环境光 glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // 设置漫反射光 glEnable(GL_LIGHTING); // 打开光照 glEnable(GL_LIGHT1); // 打开光源1 // 载入纹理 glEnable(GL_TEXTURE_2D); // 开启2D纹理映射 MakeTexture(skyImg, &texture;[0]); MakeTexture(sunImg, &texture;[1]); MakeTexture(rayImg, &texture;[2]); MakeTexture(mercuImg, &texture;[3]); MakeTexture(venusImg, &texture;[4]); MakeTexture(earthImg, &texture;[5]); MakeTexture(marsImg, &texture;[6]); MakeTexture(jupiterImg, &texture;[7]); MakeTexture(saturnImg, &texture;[8]); MakeTexture(uranusImg, &texture;[9]); MakeTexture(neptuneImg, &texture;[10]); MakeTexture(moonImg, &texture;[11]); quadric = gluNewQuadric(); // 建立一个曲面对象指针 gluQuadricTexture(quadric, GLU_TRUE); // 建立纹理坐标 gluQuadricDrawStyle(quadric, GLU_FILL); // 面填充 } void Display(void) { glLoadIdentity(); // 设置观察点的位置和观察的方向 gluLookAt(viewer[0],viewer[1],viewer[2],viewer[3],viewer[4],-5,0,1,0); //摄像机x,摄像机y,摄像机z, 目标点x,目标点y,目标点z, 摄像机顶朝向x,摄像机顶朝向y,摄像机顶朝向z // 获得系统时间使太阳系有动态效果 g_dCurrentTime = timeGetTime(); g_fElpasedTime = (float)((g_dCurrentTime - g_dLastTime) * 0.0005); g_dLastTime = g_dCurrentTime; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode( GL_MODELVIEW ); //指定GL_MODELVIEW是下一个矩阵操作的目标 glTranslatef(0.0f, 0.0f, -5.0f); // 将坐标系移入屏幕5.0f glRotatef(10, 1.0f ,0.0f, 0.0f); // 将坐标系x轴旋转10度 glEnable(GL_LIGHT0); // 打开光源0 /**********************************绘制背景星空********************************************/ glPushMatrix (); // 当前模型矩阵入栈 glTranslatef(-10.0f, 3.0f, 0.0f); glRotatef(angle_Z, 0.0f, 0.0f, 1.0f); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, texture[0]); // 星空纹理 glBegin(GL_QUADS); glNormal3f( 0.0f, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-50.0f, -50.0f, -50.0f); glTexCoord2f(6.0f, 0.0f); glVertex3f( 50.0f, -50.0f, -50.0f); glTexCoord2f(6.0f, 6.0f); glVertex3f( 50.0f, 50.0f, -50.0f); glTexCoord2f(0.0f, 6.0f); glVertex3f(-50.0f, 50.0f, -50.0f); glEnd(); glBegin(GL_QUADS); glNormal3f( 0.0f, 0.0f, -1.0f); glTexCoord2f(6.0f, 6.0f); glVertex3f(-50.0f, -50.0f, 50.0f); glTexCoord2f(0.0f, 6.0f); glVertex3f( 50.0f, -50.0f, 50.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 50.0f, 50.0f, 50.0f); glTexCoord2f(6.0f, 0.0f); glVertex3f(-50.0f, 50.0f, 50.0f); glEnd(); glBegin(GL_QUADS); glNormal3f( 0.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-50.0f, -50.0f, -50.0f); glTexCoord2f(6.0f, 6.0f); glVertex3f( 50.0f, -50.0f, 50.0f); glTexCoord2f(6.0f, 0.0f); glVertex3f( 50.0f, -50.0f, -50.0f); glTexCoord2f(0.0f, 6.0f); glVertex3f(-50.0f, -50.0f, 50.0f); glEnd(); glBegin(GL_QUADS); glNormal3f( 0.0f, -1.0f, 0.0f); glTexCoord2f(6.0f, 6.0f); glVertex3f(-50.0f, 50.0f, -50.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f( 50.0f, 50.0f, 50.0f); glTexCoord2f(0.0f, 6.0f); glVertex3f( 50.0f, 50.0f, -50.0f); glTexCoord2f(6.0f, 0.0f); glVertex3f(-50.0f, 50.0f, 50.0f); glEnd(); glBegin(GL_QUADS); glNormal3f( 1.0f, 0.0f, 0.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-50.0f, -50.0f, -50.0f); glTexCoord2f(6.0f, 6.0f); glVertex3f(-50.0f, 50.0f, 50.0f); glTexCoord2f(0.0f, 6.0f); glVertex3f(-50.0f, -50.0f, 50.0f); glTexCoord2f(6.0f, 0.0f); glVertex3f(-50.0f, 50.0f, -50.0f); glEnd(); glBegin(GL_QUADS); glNormal3f( -1.0f, 0.0f, 0.0f); glTexCoord2f(6.0f, 6.0f); glVertex3f(50.0f, -50.0f, -50.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(50.0f, 50.0f, 50.0f); glTexCoord2f(6.0f, 0.0f); glVertex3f(50.0f, -50.0f, 50.0f); glTexCoord2f(0.0f, 6.0f); glVertex3f(50.0f, 50.0f, -50.0f); glEnd(); glPopMatrix (); // 当前模型矩阵出栈 /**********************************绘制太阳************************************************/ glBindTexture(GL_TEXTURE_2D, texture[2]); // 光晕纹理 glEnable(GL_BLEND); // 开启混合 glDisable(GL_DEPTH_TEST); // 关闭深度测试 // 绘制太阳光晕 glDisable(GL_LIGHTING); // 关闭光照 glBlendFunc(GL_SRC_ALPHA,GL_ONE); // 半透明混合函数 glColor4f(1.0f, 0.5f, 0.0f, 0.5f); // 设置RGBA值 glBegin(GL_QUADS); glNormal3f( 0.0f, 0.0f, 1.0f); glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f); glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 0.0f); glEnd(); glDisable(GL_BLEND); // 关闭混合 glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); // 开启光照 glLightfv(GL_LIGHT1, GL_POSITION, LightPosition); // 设置光源1位置 glBindTexture(GL_TEXTURE_2D, texture[1]); // 太阳纹理 // 将坐标系Y轴旋转fSunSpin角度,控制太阳自转 glRotatef(fSunSpin,0.0,1.0,0.0); gluSphere(quadric, 0.3f, 32, 32); // 绘制太阳球体 /**********************************绘制水星************************************************/ glDisable(GL_LIGHT0); glEnable(GL_TEXTURE_2D ); // 开启纹理 glPushMatrix (); // 当前模型视图矩阵入栈 // 将坐标系Y轴旋转fMercuOrbit角度,控制水星公转 glRotatef(fMercuOrbit, 0.0f, 1.0f, 0.0f); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); // 将坐标系X轴旋转-90度 glTranslatef(0.5f, 0.0f, 0.0f); // 将坐标系右移0.5f glBindTexture(GL_TEXTURE_2D, texture[3]); // 水星纹理 // 将坐标系Z轴旋转fMercuSpin角度 控制水星自转 glRotatef(fMercuSpin , 0.0f, 0.0f, 1.0f); gluSphere(quadric, 0.04f, 32, 32); // 水星球体 glPopMatrix (); // 当前模型视图矩阵出栈 // 绘制轨道 glBegin(GL_LINE_LOOP); for(angle=0;angle<=360;angle++) glVertex3f(0.5f*sin(DEG_TO_RAD*angle),0,0.5f*cos(DEG_TO_RAD*angle)); glEnd(); /**********************************绘制金星************************************************/ glDisable(GL_LIGHT0); glEnable(GL_TEXTURE_2D ); // 开启纹理 glPushMatrix (); // 当前模型视图矩阵入栈 // 将坐标系Y轴旋转fVenusOrbit角度,控制金星公转 glRotatef(fVenusOrbit , 0.0f, 1.0f, 0.0f); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);// 将坐标系X轴旋转-90度 glTranslatef(0.8f, 0.0f, 0.0f); // 将坐标系右移0.8f glBindTexture(GL_TEXTURE_2D, texture[4]); // 金星纹理 // 将坐标系Z轴旋转fVenusSpin角度,控制金星自转 glRotatef(fVenusSpin , 0.0f, 0.0f, 1.0f); gluSphere(quadric, 0.06f, 32, 32); // 金星球体 glPopMatrix (); glBegin(GL_LINE_LOOP); for(angle=0;angle<=360;angle++) glVertex3f(0.8f*sin(DEG_TO_RAD*angle),0,0.8f*cos(DEG_TO_RAD*angle)); glEnd(); /**********************************绘制地球************************************************/ glDisable(GL_LIGHT0); glEnable(GL_TEXTURE_2D ); // 开启纹理 glPushMatrix (); // 当前模型视图矩阵入栈 // 将坐标系Y轴旋转fEarthOrbit角度,控制地球公转 glRotatef(fEarthOrbit , 0.0f, 1.0f, 0.0f); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);// 将坐标系X轴旋转-90度 glTranslatef(1.1f, 0.0f, 0.0f); // 将坐标系右移1.1f glBindTexture(GL_TEXTURE_2D, texture[5]); // 地球纹理 // 将坐标系Z轴旋转fEarthSpin角度,控制地球自转 glRotatef(fEarthSpin , 0.0f, 0.0f, 1.0f); gluSphere(quadric, 0.08f, 32, 32); // 地球球体 glPopMatrix (); glBegin(GL_LINE_LOOP); for(angle=0;angle<=360;angle++) glVertex3f(1.1f*sin(DEG_TO_RAD*angle),0,1.1f*cos(DEG_TO_RAD*angle)); glEnd(); /**********************************绘制火星************************************************/ glDisable(GL_LIGHT0); glEnable(GL_TEXTURE_2D ); // 开启纹理 glPushMatrix (); // 当前模型视图矩阵入栈 // 将坐标系Y轴旋转fMarsOrbit角度,控制火星公转 glRotatef(fMarsOrbit , 0.0f, 1.0f, 0.0f); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); // 将坐标系X轴旋转-90度 glTranslatef(1.4f, 0.0f, 0.0f); // 将坐标系右移1.4f glBindTexture(GL_TEXTURE_2D, texture[6]); // 火星纹理 // 将坐标系Z轴旋转fMarsSpin角度,控制火星自转 glRotatef(fMarsSpin , 0.0f, 0.0f, 1.0f); gluSphere(quadric, 0.04f, 32, 32); // 火星球体 glPopMatrix (); glBegin(GL_LINE_LOOP); for(angle=0;angle<=360;angle++) glVertex3f(1.4f*sin(DEG_TO_RAD*angle),0,1.4f*cos(DEG_TO_RAD*angle)); glEnd(); /**********************************绘制木星************************************************/ glDisable(GL_LIGHT0); glEnable(GL_TEXTURE_2D ); // 开启纹理 glPushMatrix (); // 当前模型视图矩阵入栈 // 将坐标系Y轴旋转fJupiterOrbit角度,控制木星公转 glRotatef(fJupiterOrbit , 0.0f, 1.0f, 0.0f); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); // 将坐标系X轴旋转-90度 glTranslatef(1.7f, 0.0f, 0.0f); // 将坐标系右移1.7f glBindTexture(GL_TEXTURE_2D, texture[7]); // 木星纹理 // 将坐标系Z轴旋转fJupiterSpin角度,控制木星自转 glRotatef(fJupiterSpin , 0.0f, 0.0f, 1.0f); gluSphere(quadric, 0.13f, 32, 32); // 木星球体 glPopMatrix (); glBegin(GL_LINE_LOOP); for(angle=0;angle<=360;angle++) glVertex3f(1.7f*sin(DEG_TO_RAD*angle),0,1.7f*cos(DEG_TO_RAD*angle)); glEnd(); /**********************************绘制土星************************************************/ glDisable(GL_LIGHT0); glEnable(GL_TEXTURE_2D ); // 开启纹理 glPushMatrix (); // 当前模型视图矩阵入栈 // 将坐标系Y轴旋转fSaturnOrbit角度,控制土星公转 glRotatef(fSaturnOrbit , 0.0f, 1.0f, 0.0f); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); // 将坐标系X轴旋转-90度 glTranslatef(1.9f, 0.0f, 0.0f); // 将坐标系右移1.9f glBindTexture(GL_TEXTURE_2D, texture[8]); // 土星纹理 // 将坐标系Z轴旋转fSaturnSpin角度,控制土星自转 glRotatef(fSaturnSpin , 0.0f, 0.0f, 1.0f); gluSphere(quadric, 0.1f, 32, 32); // 土星球体 glPopMatrix (); glBegin(GL_LINE_LOOP); for(angle=0;angle<=360;angle++) glVertex3f(1.9f*sin(DEG_TO_RAD*angle),0,1.9f*cos(DEG_TO_RAD*angle)); glEnd(); /**********************************绘制天王星**********************************************/ glDisable(GL_LIGHT0); glEnable(GL_TEXTURE_2D ); // 开启纹理 glPushMatrix (); // 当前模型视图矩阵入栈 // 将坐标系Y轴旋转fUranusOrbit角度,控制天王星公转 glRotatef(fUranusOrbit , 0.0f, 1.0f, 0.0f); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); // 将坐标系X轴旋转-90度 glTranslatef(2.1f, 0.0f, 0.0f); // 将坐标系右移2.1f glBindTexture(GL_TEXTURE_2D, texture[9]); // 天王星纹理 // 将坐标系Z轴旋转fUranusSpin角度,控制天王星自转 glRotatef(fUranusSpin , 0.0f, 0.0f, 1.0f); gluSphere(quadric, 0.1f, 32, 32); // 天王星球体 glPopMatrix (); glBegin(GL_LINE_LOOP); for(angle=0;angle<=360;angle++) glVertex3f(2.1f*sin(DEG_TO_RAD*angle),0,2.1f*cos(DEG_TO_RAD*angle)); glEnd(); /**********************************绘制海王星**********************************************/ glDisable(GL_LIGHT0); glEnable(GL_TEXTURE_2D ); // 开启纹理 glPushMatrix (); // 当前模型视图矩阵入栈 // 将坐标系Y轴旋转fNeptuneOrbit角度,控制海王星公转 glRotatef(fNeptuneOrbit , 0.0f, 1.0f, 0.0f); glRotatef(-90.0f, 1.0f, 0.0f, 0.0f); // 将坐标系X轴旋转-90度 glTranslatef(2.3f, 0.0f, 0.0f); // 将坐标系右移2.3f glBindTexture(GL_TEXTURE_2D, texture[10]); // 海王星纹理 // 将坐标系Z轴旋转fNeptuneSpin角度,控制海王星自转 glRotatef(fNeptuneSpin , 0.0f, 0.0f, 1.0f); gluSphere(quadric, 0.08f, 32, 32); // 海王星球体 glPopMatrix (); glBegin(GL_LINE_LOOP); for(angle=0;angle<=360;angle++) glVertex3f(2.3f*sin(DEG_TO_RAD*angle),0,2.3f*cos(DEG_TO_RAD*angle)); glEnd(); /**********************************绘制月亮************************************************/ glDisable(GL_LIGHT0); glEnable(GL_TEXTURE_2D ); // glBindTexture(GL_TEXTURE_2D, texture[11]); // 月亮纹理 glPushMatrix (); // 将坐标系Y轴旋转fEarthOrbit角度,控制月亮跟随地球 glRotatef(fEarthOrbit , 0.0f, 1.0f, 0.0f); glTranslatef(1.1f, 0.0f, 0.0f); // 将坐标系右移1.1f // 将坐标系Y轴旋转fMoonOrbit角度,控制月亮公转 glRotatef(fMoonOrbit , 0.0f, 1.0f, 0.0f); glTranslatef(0.15f, 0.0f, 0.0f); // 将坐标系Y轴旋转fMoonSpin角度,控制月亮自转 glBindTexture(GL_TEXTURE_2D, texture[11]); glRotatef(fMoonSpin , 0.0f, 1.0f, 0.0f); gluSphere(quadric, 0.02, 32, 32); // 月亮球体 glPopMatrix (); // 控制各星球转动的速度 if( g_bOrbitOn == true ) { fSunSpin -= g_fSpeedmodifier * (g_fElpasedTime * 10.0f); fMercuSpin -= g_fSpeedmodifier * (g_fElpasedTime * 15.0f); fMercuOrbit -= g_fSpeedmodifier * (g_fElpasedTime * 40.0f); fVenusSpin -= g_fSpeedmodifier * (g_fElpasedTime * 10.0f); fVenusOrbit -= g_fSpeedmodifier * (g_fElpasedTime * 30.0f); fEarthSpin -= g_fSpeedmodifier * (g_fElpasedTime * 100.0f); fEarthOrbit -= g_fSpeedmodifier * (g_fElpasedTime * 20.0f); fMarsSpin -= g_fSpeedmodifier * (g_fElpasedTime * 30.0f); fMarsOrbit -= g_fSpeedmodifier * (g_fElpasedTime * 50.0f); fJupiterSpin -= g_fSpeedmodifier * (g_fElpasedTime * 90.0f); fJupiterOrbit -= g_fSpeedmodifier * (g_fElpasedTime * 35.0f); fSaturnSpin -= g_fSpeedmodifier * (g_fElpasedTime * 90.0f); fSaturnOrbit -= g_fSpeedmodifier * (g_fElpasedTime * 25.0f); fUranusSpin -= g_fSpeedmodifier * (g_fElpasedTime * 70.0f); fUranusOrbit -= g_fSpeedmodifier * (g_fElpasedTime * 15.0f); fNeptuneSpin -= g_fSpeedmodifier * (g_fElpasedTime * 40.0f); fNeptuneOrbit -= g_fSpeedmodifier * (g_fElpasedTime * 5.0f); fMoonSpin -= g_fSpeedmodifier * (g_fElpasedTime * 50.0f); fMoonOrbit -= g_fSpeedmodifier * (g_fElpasedTime * 200.0f); } angle_Z += 0.01f; // 星空旋转 glutSwapBuffers(); // 交换双缓存 glFlush(); } void Reshape(int width, int height) { if (height==0) height=1; // 改变窗口 glViewport(0,0,width,height); // 设置视口 // 设置投影矩阵 glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(viewer[0],viewer[1],viewer[2],viewer[3],viewer[4],-5,0,1,0); } void keyboard(unsigned char key, int x, int y) { switch(key) { case 'r': case 'R': // 视点上下左右移动 if(viewer[0]=-6.0) viewer[0]-=0.5; break; case 'u': case 'U': if(viewer[1]=-6.0) viewer[1]-=0.1; break; case'+': case '=': // 加速,减速,暂停 g_fSpeedmodifier+=1.0f; glutPostRedisplay(); break; case ' ': g_bOrbitOn = !g_bOrbitOn; glutPostRedisplay(); break; case'-': //按'-'减小运行速度 g_fSpeedmodifier-=1.0f; glutPostRedisplay(); break; case VK_ESCAPE: // 按ESC键时退出 exit(0); break; default: break; } } void special_keys(int s_keys, int x, int y) { switch(s_keys) { case GLUT_KEY_F1: // 按F1键时切换窗口/全屏模式 if(isFullScreen) { glutReshapeWindow(WIN_WIDTH, WIN_HEIGHT); glutPositionWindow(30, 30); isFullScreen = FALSE; } else { glutFullScreen(); isFullScreen = TRUE; } break; case GLUT_KEY_RIGHT: // 视角上下左右旋转 if(viewer[3]=-3.0) viewer[3]-=0.1; break; case GLUT_KEY_UP: if(viewer[4]=-4.5) viewer[4]-=0.1; break; default: break; } } void mouse(int btn, int state, int x, int y) // 远近视角 { if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) viewer[2]+=0.3; if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN&&viewer;[2]>=-3.9) viewer[2]-=0.3; } void LoadBmp(char *filename, TEXTUREIMAGE *textureImg) // 载入图片 { int i, j; FILE *file; BMPFILEHEADER bmpFile; BMPINFOHEADER bmpInfo; int pixel_size; // 初始化纹理数据 textureImg->imgWidth = 0; textureImg->imgHeight = 0; if (textureImg->data != NULL) { delete []textureImg->data; } // 打开文件 file = fopen(filename, "rb"); if (file == NULL) { return; } // 获取文件头 rewind(file); fread(&bmpFile;, sizeof(BMPFILEHEADER), 1, file); fread(&bmpInfo;, sizeof(BMPINFOHEADER), 1, file); // 验证文件类型 if (bmpFile.bfType != 0x4D42) { return; } // 获取图像色彩数 pixel_size = bmpInfo.biBitCount >> 3; // 读取文件数据 textureImg->data = new unsigned char[bmpInfo.biWidth * bmpInfo.biHeight * pixel_size]; for(i = 0 ; i < bmpInfo.biHeight; i++) { fseek(file, bmpFile.bfOffBits + (bmpInfo.biHeight - i - 1) * bmpInfo.biWidth * pixel_size, SEEK_SET); for (j = 0; j data + (i * bmpInfo.biWidth + j) * pixel_size + 2, sizeof(unsigned char), 1, file); // 绿色分量 fread(textureImg->data + (i * bmpInfo.biWidth + j) * pixel_size + 1, sizeof(unsigned char), 1, file); // 蓝色分量 fread(textureImg->data + (i * bmpInfo.biWidth + j) * pixel_size + 0, sizeof(unsigned char), 1, file); // Alpha分量 if (pixel_size == 4) { fread(textureImg->data + (i * bmpInfo.biWidth + j) * pixel_size + 3, sizeof(unsigned char), 1, file); } } } // 记录图像相关参数 textureImg->imgWidth = bmpInfo.biWidth; textureImg->imgHeight = bmpInfo.biHeight; textureImg->byteCount = pixel_size; fclose(file); } // 程序主函数 void main(int argc, char** argv) { //读图片 LoadBmp("Picture//Sky.bmp" , &skyImg;); LoadBmp("Picture//Sun.bmp" , &sunImg;); LoadBmp("Picture//Ray.bmp" , &rayImg;); LoadBmp("Picture//Mercu.bmp" , &mercuImg;); LoadBmp("Picture//Venus.bmp" , &venusImg;); //金星 LoadBmp("Picture//Earth.bmp" , &earthImg;); LoadBmp("Picture//Mars.bmp" , &marsImg;); //火星 LoadBmp("Picture//Jupiter.bmp" , &jupiterImg;); //木星 LoadBmp("Picture//Saturn.bmp" , &saturnImg;); //土星 LoadBmp("Picture//Uranus.bmp" , &uranusImg;); //天王星 LoadBmp("Picture//Neptune.bmp" , &neptuneImg;); //海王星 LoadBmp("Picture//Moon.bmp" , &moonImg;); glutInit(&argc;, argv); // 初始化GLUT库 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); // 初始化显示模式 glutInitWindowSize(WIN_WIDTH, WIN_HEIGHT); // 初始化窗口大小 glutInitWindowPosition(20,20); // 初始化窗口位置 GLuint window = glutCreateWindow(WIN_TITLE); // 建立窗口 InitGL(); // 初始化OpenGL glutDisplayFunc(Display); glutReshapeFunc(Reshape); glutKeyboardFunc(keyboard); glutSpecialFunc(special_keys); glutMouseFunc(mouse); glutIdleFunc(Display); // 设置窗口空闲时的处理函数 glutMainLoop(); // 进入事件处理循环 }
基于视频序列捕获人体运动和人体运动分析 如何制作一个可控制的人体骨骼模型 描述:本文提供一种将骨架动作矢量映射到人体骨架模型的一种方法,通过输入各个骨骼的当前方向,反馈给骨架模型,这样就实现了动画的效果。 实验开发工具是VC6.0在OpenGL平台上开发完成。 阅读对象: 假定读者已经熟悉OpenGL编程,就算不熟悉,只要了解基本的旋转,平移,堆栈操作就好。 假定读者已经了解基本的c++编程,其需要了解递归的算法,递归的方法请参考一下数据结构吧。 制作过程: 第一步,3D模型准备 这一步骤的目的是提供分解的骨骼模型,它需要导出多个组成身体结构的文件,模型可以不用自己制作,只要到网上找找吧,应该很多,最好是是人体模型,如果用动物的模型也可以,不过需要自己定义映射骨架了,比如图的骷髅模型是我从人体动画软件poser 5.0找到的。然后使用3d max 将身体的各个部位导出为3ds文件,这个步骤很简单,也不需要有什么3d max的基础。这里有一个小的技巧就是可以选多个部分作为一个3ds模型导出,比如我需要将左右肩胛骨与脊椎骨肋骨作为同一个部分导出,这样可以将它命名为身体躯干(body)。这样我们就准备了各个3ds文件了,分别是: 身体躯干 BODY.3DS 头部 HEAD.3DS 左臂 LSHOULDER.3DS 右臂 RSHOULDER.3DS 左小臂 LELBOW.3DS 右小臂 RELBOW.3DS 左大腿 LTHIGH.3DS 右大腿 RTHIGH.3DS 左小腿 LFEET.3DS 右小腿 RFEET.3DS 这样这些组成部分就可以灵活的拼接出一个人体来了。 第二步,定义相关的核心数据结构 为了得到运动的各个身体部分数据信息,我们需要存储一些运动信息,主要有: 骨骼ID 骨骼关节的当前位置;r_x,r_y,r_z 骨骼之间的关系,例如手臂是躯干的延伸,而左小臂是左臂的延伸;PID,CID 我们可以通过下图来了解骨骼之间的结构关系 存放3ds文件位置;file_name_3ds 3ds模型的初始化方向;这个是比较抽象一点的概念,它是指从父节点指向子节点的方向,例如左小臂的初始位置是平放向下,那么对应的矢量就是 (-0.2,-1,0) 以下是数据结构部分: class bone { public: int y; int x; int r_z; //现实世界z坐标 int r_y; int r_x; int rotated_X; //旋转后的坐标 int rotated_Y; int is_marked; //是否已经标记 int PID; //父节点 int CID; //子节点,目前针对轴关节和膝盖有效 float start_arc_x,end_arc_x; //相对父节点的x 左右方向转动角度限制 float start_arc_y,end_arc_y; //相对父节点的y 上下方向转动角度限制 float start_arc_z,end_arc_z; //相对父节点的z 前后方向转动角度限制 double LengthRatio; char name[80]; //名称 char file_name_3ds[180]; //3ds文件名称 int ID; bone(int ID,char *name,int PID); virtual ~bone(); float bone_init_x,bone_init_y,bone_init_z; //初始化骨骼的矢量方向,3d max 模型 }; 第三步,初始化骨架结构 在定义了bone的结构以后,我们定义一个skeleton类来在第一次初始化时加载这些结构, obone = bone (2,"head",1); //定义一个bone strcpy(obone.file_name_3ds,"head.3DS"); //设置它的3ds文件名 obone.bone_init_x = 0; //初始化骨骼的矢量方向 obone.bone_init_y = 1; obone.bone_init_z = 0; bonevec.push_back (obone); //放入vector结构,这里用到了STL编程技术的vector 以下是实现的部分代码: skelecton::skelecton() { float fy = 0.56f ; float ftx = 0.19f; float ffx = 0.08f; bone obone = bone (1,"neck",0); bonevec.push_back (obone); obone = bone (2,"head",1); strcpy(obone.file_name_3ds,"head.3DS"); obone.bone_init_x = 0; obone.bone_init_y = 1; obone.bone_init_z = 0; bonevec.push_back (obone); obone = bone (3,"rShoulder",1); bonevec.push_back (obone); obone = bone (4,"lShoulder",1); bonevec.push_back (obone); obone = bone (5,"rElbow",3); strcpy(obone.file_name_3ds,"rShoulder.3DS"); obone.bone_init_x = fy; obone.bone_init_y = -1; obone.bone_init_z = 0; obone.CID = 7; bonevec.push_back (obone); obone = bone (6,"lElbow",4); strcpy(obone.file_name_3ds,"lShoulder.3DS"); obone.bone_init_x = -fy; obone.bone_init_y = -1; obone.bone_init_z = 0; obone.CID = 8; bonevec.push_back (obone); //.............太长只给出部分的代码.......................... } 第四步,学习3ds公共的类CLoad3DS,可以用来载入显示模型 这个类是公用一个类,详细的类CLoad3DS的接口信息可以到一个open source项目里参考。http://scourge.sourceforge.net http://scourge.sourceforge.net/api/3ds_8h-source.html 实际上在使用这个类时候,我做了一些修改,加了得到最大顶点的方法。这个在第五步会说明。 我们定义一个OpenGL的类来做模型控制类,负责载入模型, CLoad3DS* m_3ds; int OpenGL::Load3DS(int ID, char *filename) { if(m_3ds!=NULL) m_3ds->Init(filename,ID); return 0; } 然后在显示时候调用 int OpenGL::show3ds(int ID) { m_3ds->show3ds(ID,0,0,0,2); return 0; } 第五步,使用递归方法分层次载入模型 这里是重点的内容了,让我们思考一些问题实现骨骼会随着输入的方向而改变方向,需要做那些事情呢? 首先针对一块骨骼来考虑: 第一,我们需要让骨骼着它的节点旋转到输入的方向上 第二,我们需要知道骨骼目前节点的位置,才能旋转。可是我们知道骨骼会跟着它的父骨骼转动的,例如左小臂会跟着左臂转动,当身体转动时左臂也会跟着身体转动的,这里看起来像是有一个父子连动的关系,所以当前节点的位置会与它的父骨骼有关,父骨骼转动的角度,子骨骼也必须转动,所以这里自然想到了递归模型了,至于如何存储这些转动过程呢,还好openGL提供了glPushMatrix();glPopMatrix();那么所有的子骨骼必须包含在父骨骼的glPushMatrix();glPopMatrix();好了,这个变成 //递归实现3d现实 int skelecton::Render_skeleton_3D(int ID) { glPushMatrix(); //开始记录堆栈 joint_point = pgl->get_joint_point(ID); //找到节点位置 glTranslatef(joint_point.x,joint_point.y,joint_point.z); //坐标移到节点位置 pgl->rotate_bone (vt1,vt2,vto); //旋转骨骼到指定的方向 glTranslatef(-joint_point.x,-joint_point.y,-joint_point.z);//坐标移回来 pgl->show3ds(ID); //显示模型 //遍历子节点 for (theIterator = bonevec.begin(); theIterator != bonevec.end(); theIterator++) { pbone = theIterator; if((pbone->PID == ID) ) { Render_skeleton_3D(pbone->ID); //递归调用 } } glPopMatrix(); //退出记录堆栈 } 剩下需要解决的问题就是如何找到节点位置。 寻找节点位置, 我们看到上面代码 get_joint_point(ID)就是找到节点了,其实如果不追求高的准确度,我们可以假设每个模型的最高的点即为骨骼的节点,当然这个假设前提是人体模型是正面站立的,手臂自然垂下,这样可以近似认为每个模型的最高的点即为骨骼的节点,这样函数就很简单了,这个方法是修改了Cload3ds类的方法,如下: Vector3f CLoad3DS::get_joint_point(int j0) { CVector3 LastPoint; Vector3f vect; LastPoint.y = -1000 ; if(j0==2) LastPoint.y = 1000 ;//头部节点朝下 // 遍历模型所有的对象 for(int l = 0; l < g_3DModel[j0].numOfObjects; l++) {if(g_3DModel[j0].pObject.size() <= 0) break;// 如果对象的大小小于0,则退出 t3DObject *pObject = &g_3DModel[j0].pObject[l];// 获得当前显示的对象 for(int j = 0; j < pObject->numOfFaces; j++) // 遍历所有的面 { for(int tex = 0; tex < 3; tex++) // 遍历三角形的所有点 { int index = pObject->pFaces[j].vertIndex[tex]; // 获得面对每个点的索引 if(j0==2) { if(pObject->pVerts[index].y < LastPoint.y ) LastPoint = pObject->pVerts[index]; } else { if(pObject->pVerts[index].y > LastPoint.y ) LastPoint = pObject->pVerts[index]; } } } } vect.x = LastPoint.x ; vect.y = LastPoint.y ; vect.z = LastPoint.z ; return vect; } 比较特殊的是头部节点是通过脖子连接的,所以它是取最低的点。 现在解决最后的问题了,如何旋转了,具体来讲就是骨骼从原来自然的状态旋转到目前的方向,例如手臂从自然垂下变成抬起,垂下和抬起两个状态的矢量是不同的方向的,如何旋转呢? 这里就要用到了空间几何里的点积和叉积的概念了,简单来讲就是利用点积来求矢量夹角余弦,利用叉积来求两个矢量的法向量,如果你忘记了这些概念,可以回去参考一下高等数学书,这个连接也提供了一些资料,可以帮助理解http://www.gameres.com/Articles/Program/Visual/Other/shiliang.htm 然后呢,我们知道了两个矢量的夹角与它们的法向量,下面的事情就变得简单了,我们让骨骼原来的矢量以法向量为旋转轴,旋转一定角度,这个角度就是两个矢量的夹角,这样问题就解决了,所以这里的代码如下: int OpenGL::rotate_bone(Vector3f vVector1, Vector3f vVector2, Vector3f vVectorOrgin) { Vector3f vt1 = Vector3f(vVector1.x,vVector1.y,vVector1.z); Vector3f vt2 = Vector3f(vVector2.x,vVector2.y,vVector2.z); Vector3f vt4 = vt2-vt1; double arc12 = AngleBetweenVectors(vVectorOrgin,vt4); double rarc12 = 180*arc12/pi; float len= Distance(vt1,vt2); Vector3f vt3 = Cross(vVectorOrgin,vt4); glRotatef ((float)rarc12,vt3.x,vt3.y,vt3.z); return 0; } 好了所有问题解决了,我们可以松一口气了。这里我提供一个参考的代码,因为这个模型的运行需要输入矢量方向,我目前还不能把它从我的其他系统程序完整提取出来,只是提供所有的代码,供读者参考。 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/hardVB/archive/2005/08/10/449922.aspx

8,303

社区成员

发帖
与我相关
我的任务
社区描述
游戏开发相关内容讨论专区
社区管理员
  • 游戏开发
  • 呆呆敲代码的小Y
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧