实现鼠标对立体图的控制(1)旋转

实现鼠标对立体图的控制非常重要,比如可以要求转动鼠标使得立体图形跟着旋转,以看清立体图的全貌

首先是转动,就是拖动鼠标,图形可以跟着转

我暂时想到了两种办法可以实现这一点,第一种是不改变立体图形,改变观察点的位置,第二是不改变观察点的位置,对立体进行旋转。

我也是真的是没想到这个问题越来越复杂,说白了还是数学没学好

不过经过一天的努力,好多计划我已经放弃了,不过现在先挖几个坑,之后再填。。当然更希望CSDN上的大神可以帮帮我解决一下。。


第一种是改变观察点的位置,先上代码~~

</pre><pre name="code" class="cpp">#include<GL/GLUT.H>    
#include <windows.h>        
#include <math.h>        
#include <gl/GL.h>        

static const GLfloat vertex_list[][3] = {
	-0.5f, -0.5f, -0.5f,
	0.5f, -0.5f, -0.5f,
	0.5f, 0.5f, -0.5f,
	-0.5f, 0.5f, -0.5f,
	-0.5f, -0.5f, 0.5f,
	0.5f, -0.5f, 0.5f,
	0.5f, 0.5f, 0.5f,
	-0.5f, 0.5f, 0.5f,
};

GLfloat colors[][3] = {
	{ 1.0, 0.0, 0.0 },
	{ 1.0, 1.0, 0.0 },
	{ 0.0, 1.0, 0.0 },
	{ 0.0, 1.0, 1.0 },
	{ 1.0, 0.0, 1.0 },
	{ 0.0, 0.0, 1.0 },
	{ 0.0, 0.5, 0.0 },
	{ 0.0, 0.5, 0.5 },
};

static const GLint index_list[][4] = {
	0, 1, 2, 3,//bottem      
	0, 3, 7, 4,//left      
	2, 3, 7, 6,//front      
	1, 2, 6, 5,//right      
	0, 1, 5, 4,//back      
	4, 5, 6, 7//top      
};

float M_PI=3.14159265f;


static float c = M_PI/180.0f; //弧度和角度转换参数
static int du = 90, oldmy = -1, oldmx = -1; //du是视点绕y轴的角度,opengl里默认y轴是上方向
static float r = 1.75f, h = 0.0f; //r是视点绕y轴的半径,h是视点高度即在y轴上的坐标

void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(80.0f,1.0f, 1.0f, 1000.0f);
	glMatrixMode(GL_MODELVIEW);


	//printf("At:%.2f %.2f %.2f\n",r*cos(c*du),h,r*sin(c*du)); //这就是视点的坐标
	glLoadIdentity();
	gluLookAt(r*cos(c*du), h, r*sin(c*du), 0, 0, 0, 0, 1, 0); //从视点看远点,y轴方向(0,1,0)是上方向


	for (int i = 0; i < 6; ++i)      // 有六个面,循环六次      
	{
		glColor3f(colors[i][0], colors[i][1], colors[i][2]);
		glBegin(GL_POLYGON);
		for (int j = 0; j < 4; ++j)     // 每个面有四个顶点,循环四次      
			glVertex3fv(vertex_list[index_list[i][j]]);
		glEnd();
	}

	glColor3f(1, 0, 0);
	for (int i = 0; i < 6; ++i)      // 有六个面,循环六次      
	{
		glBegin(GL_LINE_LOOP);
		for (int j = 0; j < 4; ++j)     // 每个面有四个顶点,循环四次      
			glVertex3fv(vertex_list[index_list[i][j]]);
		glEnd();
	}

	
	glFlush();
	glutSwapBuffers();
}
void Mouse(int button, int state, int x, int y) //处理鼠标点击
{
	if (state == GLUT_DOWN) //第一次鼠标按下时,记录鼠标在窗口中的初始坐标
		oldmx = x, oldmy = y;
}
void onMouseMove(int x, int y) //处理鼠标拖动
{
	//printf("%d\n",du);
	du += x - oldmx; //鼠标在窗口x轴方向上的增量加到视点绕y轴的角度上,这样就左右转了
	h += 0.03f*(y - oldmy); //鼠标在窗口y轴方向上的改变加到视点的y坐标上,就上下转了
	//if (h>1.0f) h = 1.0f; //视点y坐标作一些限制,不会使视点太奇怪
	//else if (h<-1.0f) h = -1.0f;
	oldmx = x, oldmy = y; //把此时的鼠标坐标作为旧值,为下一次计算增量做准备
}

int main(int argc, char *argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("OpenGL");
	glutDisplayFunc(display);
	glutIdleFunc(display);  //设置不断调用显示函数
	glutMouseFunc(Mouse);
	glutMotionFunc(onMouseMove);
	glutMainLoop();
	return 0;
}

其中比较重要的是这么几个地方

首先前面的

        glLoadIdentity();
	gluLookAt(r*cos(c*du), h, r*sin(c*du), 0, 0, 0, 0, 1, 0); //从视点看远点,y轴方向(0,1,0)是上方向

static float c = M_PI/180.0f; //弧度和角度转换参数
static int du = 90, oldmy = -1, oldmx = -1; //du是视点绕y轴的角度,opengl里默认y轴是上方向

static float r = 1.75f, h = 0.0f; //r是视点绕y轴的半径,h是视点高度即在y轴上的坐标

gluLookAt函数我们在之前就介绍过了,在绕着y轴旋转的的方向可以保持物体的大小不变,这是因为对y轴的半径没变


然后就是这里

void Mouse(int button, int state, int x, int y) //处理鼠标点击
{
	if (state == GLUT_DOWN) //第一次鼠标按下时,记录鼠标在窗口中的初始坐标
		oldmx = x, oldmy = y;
}
void onMouseMove(int x, int y) //处理鼠标拖动
{
	//printf("%d\n",du);
	du += x - oldmx; //鼠标在窗口x轴方向上的增量加到视点绕y轴的角度上,这样就左右转了
	h += 0.03f*(y - oldmy); //鼠标在窗口y轴方向上的改变加到视点的y坐标上,就上下转了
	//if (h>1.0f) h = 1.0f; //视点y坐标作一些限制,不会使视点太奇怪
	//else if (h<-1.0f) h = -1.0f;
	oldmx = x, oldmy = y; //把此时的鼠标坐标作为旧值,为下一次计算增量做准备
}
第一个事件记录鼠标点击;

第二个事件记录鼠标点击后移动的偏移量

然后du和h分别是两个方向的偏移量,然后每次移动都记录偏移量,为了避免视角过于夸张,这里限制了两行,对h的大小有了一定的限制

gluLookAt(r*cos(c*du), h, r*sin(c*du), 0, 0, 0, 0, 1, 0); //从视点看远点,y轴方向(0,1,0)是上方向
这个视角其实是圆柱坐标,想要改造成球坐标只需

把刚刚那句改为

gluLookAt(r*cos(c*du)*cos(c*h), r*sin(c*h), r*sin(c*du)*cos(c*h), 0, 0, 0, 0, 1, 0); //从视点看远点,y轴方向(0,1,0)是上方向  
但是为了避免绕过北极或者南极的情况,对h也有限制

void Mouse(int button, int state, int x, int y) //处理鼠标点击  
{
	if (state == GLUT_DOWN) //第一次鼠标按下时,记录鼠标在窗口中的初始坐标  
		oldmx = x, oldmy = y;
}
void onMouseMove(int x, int y) //处理鼠标拖动  
{
	//printf("%d\n",du);  
	du += x - oldmx; //鼠标在窗口x轴方向上的增量加到视点绕y轴的角度上,这样就左右转了  
	h += (y - oldmy); //鼠标在窗口y轴方向上的改变加到视点的y坐标上,就上下转了  
	if (h > 90)
	{		h = 90;	}
	else if (h < -90)
	{		h = -90;}
	//if (h>1.0f) h = 1.0f; //视点y坐标作一些限制,不会使视点太奇怪  
	//else if (h<-1.0f) h = -1.0f;  
	oldmx = x, oldmy = y; //把此时的鼠标坐标作为旧值,为下一次计算增量做准备  
}
然后把r改成1.85即可

不过这里有第一个坑:怎样设计可以绕过北极和南极
因为sin函数在达到最大后会回去,这样不加限制会很奇怪



第二种方法是对物体进行旋转

#include<GL/GLUT.H>      
#include <windows.h>          
#include <math.h>          
#include <gl/GL.h>          
  
static const GLfloat vertex_list[][3] = {  
    -0.5f, -0.5f, -0.5f,  
    0.5f, -0.5f, -0.5f,  
    0.5f, 0.5f, -0.5f,  
    -0.5f, 0.5f, -0.5f,  
    -0.5f, -0.5f, 0.5f,  
    0.5f, -0.5f, 0.5f,  
    0.5f, 0.5f, 0.5f,  
    -0.5f, 0.5f, 0.5f,  
};  
  
GLfloat colors[][3] = {  
    { 1.0, 0.0, 0.0 },  
    { 1.0, 1.0, 0.0 },  
    { 0.0, 1.0, 0.0 },  
    { 0.0, 1.0, 1.0 },  
    { 1.0, 0.0, 1.0 },  
    { 0.0, 0.0, 1.0 },  
    { 0.0, 0.5, 0.0 },  
    { 0.0, 0.5, 0.5 },  
};  
  
static const GLint index_list[][4] = {  
    0, 1, 2, 3,//bottem        
    0, 3, 7, 4,//left        
    2, 3, 7, 6,//front        
    1, 2, 6, 5,//right        
    0, 1, 5, 4,//back        
    4, 5, 6, 7//top        
};  
  
float M_PI=3.14159265f;  
  
  
static float c = M_PI/180.0f; //弧度和角度转换参数  
static int du = 90, oldmy = -1, oldmx = -1; //du是视点绕y轴的角度,opengl里默认y轴是上方向  
static float r = 1.75f, h = 0.0f; //r是视点绕y轴的半径,h是视点高度即在y轴上的坐标  
  
void display(void)  
{  
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);  
    glEnable(GL_DEPTH_TEST);  
    glMatrixMode(GL_PROJECTION);  
    glLoadIdentity();  
    gluPerspective(80.0f,1.0f, 1.0f, 1000.0f);  
    glMatrixMode(GL_MODELVIEW);  
  
  
    //printf("At:%.2f %.2f %.2f\n",r*cos(c*du),h,r*sin(c*du)); //这就是视点的坐标  
    glLoadIdentity();  
    gluLookAt(r, 0.2, r, 0, 0, 0, 0, 1, 0); //从视点看远点,y轴方向(0,1,0)是上方向  
  
    glRotatef(30*c*du, 0, 1, 0);  
    glRotatef(-h, -1, 0, 0);  

    for (int i = 0; i < 6; ++i)      // 有六个面,循环六次        
    {  
        glColor3f(colors[i][0], colors[i][1], colors[i][2]);  
        glBegin(GL_POLYGON);  
        for (int j = 0; j < 4; ++j)     // 每个面有四个顶点,循环四次        
            glVertex3fv(vertex_list[index_list[i][j]]);  
        glEnd();  
    }  
  
    glColor3f(1, 0, 0);  
    for (int i = 0; i < 6; ++i)      // 有六个面,循环六次        
    {  
        glBegin(GL_LINE_LOOP);  
        for (int j = 0; j < 4; ++j)     // 每个面有四个顶点,循环四次        
            glVertex3fv(vertex_list[index_list[i][j]]);  
        glEnd();  
    }  
  
      
    glFlush();  
    glutSwapBuffers();  
}  
void Mouse(int button, int state, int x, int y) //处理鼠标点击  
{  
    if (state == GLUT_DOWN) //第一次鼠标按下时,记录鼠标在窗口中的初始坐标  
        oldmx = x, oldmy = y;  
}  
void onMouseMove(int x, int y) //处理鼠标拖动  
{  
    //printf("%d\n",du);  
    du += x - oldmx; //鼠标在窗口x轴方向上的增量加到视点绕y轴的角度上,这样就左右转了  
    h += (y - oldmy); //鼠标在窗口y轴方向上的改变加到视点的y坐标上,就上下转了  
    //if (h>1.0f) h = 1.0f; //视点y坐标作一些限制,不会使视点太奇怪  
    //else if (h<-1.0f) h = -1.0f;  
    oldmx = x, oldmy = y; //把此时的鼠标坐标作为旧值,为下一次计算增量做准备  
}  
  
int main(int argc, char *argv[])  
{  
    glutInit(&argc, argv);  
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);  
    glutInitWindowPosition(100, 100);  
    glutInitWindowSize(400, 400);  
    glutCreateWindow("OpenGL");  
    glutDisplayFunc(display);  
    glutIdleFunc(display);  //设置不断调用显示函数  
    glutMouseFunc(Mouse);  
    glutMotionFunc(onMouseMove);  
    glutMainLoop();  
    return 0;  
}  
这样就是把偏移量加到了物体上进行旋转

不过

    glRotatef(30*c*du, 0, 1, 0);  
    glRotatef(-h, -1, 0, 0);
这显然是错的, 第二个坑出现了因为我这里希望围绕物体内部的坐标系(局部坐标系)进行旋转,这样在绕着y进行旋转之后不是对物体进行x轴旋转,而是针对世界坐标系的x轴进行了旋转,效果很难受。。

我找了很多方法都没办法搞,首先是

glPushMatrix();以及glPopMatrix();

搞了半天不对


之后我把旋转轴改到了(cos(c*du),0,sin(c*du))还是不对,因为我想的是经过y轴旋转du*c后,原来的(1,0,0)变成了这个

结果不对。。简直了

后来我又发现了一个神奇的函数

glMultMatrixf(Mc);

这个是可以利用变换的矩阵

然后根据

http://www.bubuko.com/infodetail-435954.html这篇博文写得好

计算旋转矩阵,绕y,绕(cos(c*du),0,sin(c*du))计算不对

绕y为A,绕X为B,结果A^-1BA和ABA^-1也都不对。。。。简直了。。

#include<GL/GLUT.H>        
#include <windows.h>            
#include <math.h>            
#include <gl/GL.h>            

static const GLfloat vertex_list[][3] = {
	-0.5f, -0.5f, -0.5f,
	0.5f, -0.5f, -0.5f,
	0.5f, 0.5f, -0.5f,
	-0.5f, 0.5f, -0.5f,
	-0.5f, -0.5f, 0.5f,
	0.5f, -0.5f, 0.5f,
	0.5f, 0.5f, 0.5f,
	-0.5f, 0.5f, 0.5f,
};

GLfloat colors[][3] = {
	{ 1.0, 0.0, 0.0 },
	{ 1.0, 1.0, 0.0 },
	{ 0.0, 1.0, 0.0 },
	{ 0.0, 1.0, 1.0 },
	{ 1.0, 0.0, 1.0 },
	{ 0.0, 0.0, 1.0 },
	{ 0.0, 0.5, 0.0 },
	{ 0.0, 0.5, 0.5 },
};

static const GLint index_list[][4] = {
	0, 1, 2, 3,//bottem          
	0, 3, 7, 4,//left          
	2, 3, 7, 6,//front          
	1, 2, 6, 5,//right          
	0, 1, 5, 4,//back          
	4, 5, 6, 7//top          
};

float M_PI = 3.14159265f;


static float c = M_PI / 180.0f; //弧度和角度转换参数    
static int du = 90, oldmy = -1, oldmx = -1; //du是视点绕y轴的角度,opengl里默认y轴是上方向    
static float r = 1.75f, h = 0.0f; //r是视点绕y轴的半径,h是视点高度即在y轴上的坐标    
float id1[1][3] = {1.0,0.0,0.0};
GLfloat Mc[16] = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 };

void display(void)
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glEnable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(80.0f, 1.0f, 1.0f, 1000.0f);
	glMatrixMode(GL_MODELVIEW);

	
	//printf("At:%.2f %.2f %.2f\n",r*cos(c*du),h,r*sin(c*du)); //这就是视点的坐标    
	glLoadIdentity();
	gluLookAt(r, 0.2, r, 0, 0, 0, 0, 1, 0); //从视点看远点,y轴方向(0,1,0)是上方向  
	//Mc[0] = pow(cos(c*du), 2) + (cos(c*h)* pow(sin(c*du) , 2));
	//Mc[1] = sin(c*du)*sin(c*h);
	//Mc[2] = (cos(c*du)*sin(c*du)) - (cos(c*du)*cos(c*h)*sin(c*du)) ;
	//Mc[3] = 0;
	//Mc[4] = -(sin(c*du)*sin(c*h)) ;
	//Mc[5] = cos(c*h);
	//Mc[6] = (cos(c*du)*sin(c*h)) ;
	//Mc[7] = 0;
	//Mc[8] = (cos(c*du)*sin(c*du))  - (cos(c*du)*cos(c*h)*sin(c*du)) ;
	//Mc[9] = cos(c*du)*sin(c*h);
	//Mc[10] = pow(sin(c*du), 2) + (pow(cos(c*du) , 2) * cos(c*h));
	//Mc[11] = 0;
	//Mc[12] = 0;
	//Mc[13] = 0;
	//Mc[14] = 0;
	//Mc[15] = 1;


	Mc[0] = cos(c*du) *cos(c*du) + (cos(c*h)*sin(c*du) *sin(c*du) );
	Mc[1] = -(sin(c*du)*sin(c*h));
	Mc[2] = (cos(c*du)*cos(c*h)*sin(c*du))  - (cos(c*du)*sin(c*du)) ;
	Mc[3] = 0;
	Mc[4] = 0 ;
	Mc[5] = cos(c*h);
	Mc[6] = -cos(c*du)*cos(c*du) * sin(c*h) - sin(c*du) *sin(c*du)  * sin(c*h);
	Mc[7] = 0;
	Mc[8] = sin(c*du)*(cos(c*h) - sin(c*du) *sin(c*du) * (cos(c*h) - 1)) - cos(c*du) *cos(c*du) * sin(c*du)*(cos(c*h) - 1);
	Mc[9] = -cos(c*du)*sin(c*h);
	Mc[10] = cos(c*du)*(cos(c*h) - sin(c*du) *sin(c*du) * (cos(c*h) - 1)) + cos(c*du)*sin(c*du) *sin(c*du) * (cos(c*h) - 1);
	Mc[11] = 0;
	Mc[12] = 0;
	Mc[13] = 0;
	Mc[14] = 0;
	Mc[15] = 1;

	//Mc[0] = cos(c*du)*(cos(c*h) - cos(c*du) *cos(c*du) * (cos(c*h) - 1)) - cos(c*du)*sin(c*du)*sin(c*du) * (cos(c*h) - 1);
	//Mc[1] = -sin(c*du)*sin(c*h);
	//Mc[2] = -sin(c*du)*(cos(c*h) - cos(c*du)*cos(c*du)  * (cos(c*h) - 1)) - cos(c*du) *cos(c*du) * sin(c*du)*(cos(c*h) - 1);
	//Mc[3] = 0;
	//Mc[4] = 0;
	//Mc[5] = cos(c*h);
	//Mc[6] = -cos(c*du) *cos(c*du)  * sin(c*h) - sin(c*du) * sin(c*du) * sin(c*h);
	//Mc[7] = 0;
	//Mc[8] = sin(c*du)*(cos(c*h) - sin(c*du) *sin(c*du) * (cos(c*h) - 1)) - cos(c*du) *cos(c*du) * sin(c*du)*(cos(c*h) - 1);
	//Mc[9] = -cos(c*du)*sin(c*h);
	//Mc[10] = cos(c*du)*(cos(c*h) - sin(c*du) *sin(c*du) * (cos(c*h) - 1)) + cos(c*du)*sin(c*du)*sin(c*du) * (cos(c*h) - 1);
	//Mc[11] = 0;
	//Mc[12] = 0;
	//Mc[13] = 0;
	//Mc[14] = 0;
	//Mc[15] = 1;
	//glPushMatrix();
	//glRotatef(du, 0, 1, 0);
	//id1[0][0] = cos(-du*c)*id1[0][0]-sin(-du*c)*id1[0][2];
	//id1[0][1] = id1[0][1];
	//id1[0][2] = sin(-du*c)*id1[0][0] + cos(-du*c)*id1[0][2];
	//glGetFloatv(GL_MODELVIEW_MATRIX, Mc);
	//glPushMatrix();
	//glRotatef(h, id1[0][0], id1[0][1], id1[0][2]);
	//glPopMatrix();
	//glPopMatrix();

	glMultMatrixf(Mc);

	


	//glRotatef(-h, -cos(-30 * c*du), 0, sin(-30 * c*du));

	for (int i = 0; i < 6; ++i)      // 有六个面,循环六次          
	{
		glColor3f(colors[i][0], colors[i][1], colors[i][2]);
		glBegin(GL_POLYGON);
		for (int j = 0; j < 4; ++j)     // 每个面有四个顶点,循环四次          
			glVertex3fv(vertex_list[index_list[i][j]]);
		glEnd();
	}

	glColor3f(1, 0, 0);
	for (int i = 0; i < 6; ++i)      // 有六个面,循环六次          
	{
		glBegin(GL_LINE_LOOP);
		for (int j = 0; j < 4; ++j)     // 每个面有四个顶点,循环四次          
			glVertex3fv(vertex_list[index_list[i][j]]);
		glEnd();
	}


	glFlush();
	glutSwapBuffers();
}
void Mouse(int button, int state, int x, int y) //处理鼠标点击    
{
	if (state == GLUT_DOWN) //第一次鼠标按下时,记录鼠标在窗口中的初始坐标    
		oldmx = x, oldmy = y;
}
void onMouseMove(int x, int y) //处理鼠标拖动    
{
	//printf("%d\n",du);    
	du += (x - oldmx); //鼠标在窗口x轴方向上的增量加到视点绕y轴的角度上,这样就左右转了    
	h += (y - oldmy); //鼠标在窗口y轴方向上的改变加到视点的y坐标上,就上下转了    
	//if (h>1.0f) h = 1.0f; //视点y坐标作一些限制,不会使视点太奇怪    
	//else if (h<-1.0f) h = -1.0f;    
	oldmx = x, oldmy = y; //把此时的鼠标坐标作为旧值,为下一次计算增量做准备    
}

int main(int argc, char *argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	glutInitWindowPosition(100, 100);
	glutInitWindowSize(400, 400);
	glutCreateWindow("OpenGL");
	glutDisplayFunc(display);
	glutIdleFunc(display);  //设置不断调用显示函数    
	glutMouseFunc(Mouse);
	glutMotionFunc(onMouseMove);
	glutMainLoop();
	return 0;
}
从上面这几段就看得出来。。各种方法我都试过了。。先放放吧。暂时用方案1里的两种方法,如果有网友可以帮助我,那真是感激不尽^^

good night^^

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

拉风小宇

请我喝个咖啡呗

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值