原文作者:aircraft
原文链接:https://www.cnblogs.com/DOMLX/p/11620088.html
前言:
因为接下来的项目需求是要读取多个3D模型,并且移动拼接,那么我就先实现鼠标控制两个物体移动互不干扰来当踏脚石。
在我之前网上的博客都只有移动单个物体的, 导致我根本查不到有关的资料,只能自己写了。
前人栽树,后人乘凉。
技术就是要分享出来,大家共同进步,我们走过的坑没有必要让后来人再走一次。
多模型的在这:
OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转
一.鼠标控制函数准备
我们需要对鼠标信息的获取,那么必然需要一个鼠标事件的响应函数来控制,很好opengl已经有内部的鼠标控制函数了,我们直接拿来使用就行了。
glutMouseFunc( (void*)Func(int button, int state, int x, int y) );
glutMouseFunc
这个是调用鼠标函数的入口,func是我们给鼠标处理函数的命名, 三个参数分别是鼠标响应的事件类型,比如左键点击,右键点击之类,x,y则是当前鼠标在窗口的位置坐标。
下面这个是处理鼠标移动时候的调用函数
glutMotionFunc(&func(int x,inty)); // 鼠标移动的时候的函数 x,y当前鼠标坐标
反正调用起来非常的简单只要自己写好一个鼠标点击类事件处理函数和一个鼠标移动事件处理函数,然后传入进去就行了,调用函数放在main函数里。反正后面代码有。
比如:
// 鼠标运动时
void onMouseMove(int x, int y) {
//当鼠标状态为按下时进入后续判断
if (mousetate) {
//x对应y是因为对应的是法向量
if (choose == ) {
movX1 = (x - x1) / width1;
glutPostRedisplay();
movY1 = -((y - Y1) / height1);
glutPostRedisplay();
std::cout << " 移动 x1 = " << x << " y1 = " << y << std::endl;
}
else {
std::cout << "not choose" << std::endl;
}
if (choose == ) {
movX2 = (x - x2) / width2;
glutPostRedisplay();
movY2 = -((y - y2) / height2);
glutPostRedisplay();
std::cout << " 移动 x2 = " << x << " y2 = " << y << std::endl;
}
else {
std::cout << "not choose" << std::endl;
}
}
} glutMotionFunc(&onMouseMove); // 鼠标移动的时候的函数调用
二.一些鼠标的响应事件
if(state == GLUT_DOWN) //相当于“如果某个鼠标键被按下”
if(state == GLUT_UP) //相当于“如果某个鼠标键被放开”
if(button == GLUT_LEFT_BUTTON) //相当于“如果鼠标左键被按下或者被放开”
if(button == GLUT_RIGHT_BUTTON) //相当于“如果鼠标右键被按下或被放开”
if(button == GLUT_MIDDLE_BUTTON) //相当于“如果鼠标中键被按下或者被放开”
还有鼠标的滚轮事件
GLUT_WHEEL_UP
GLUT_WHEEL_DOWN
这两个可能有时候会遇到自己gult库没有定义,那么就是版本比较老的缘故,不想麻烦下新版本或者下了新版本还是没有解决的话就直接像这样定义在文件头部:
#define GLUT_WHEEL_UP 3 //定义滚轮操作
#define GLUT_WHEEL_DOWN 4
三.实现过程介绍
首先我们要画出多个物体,那么这个是入门就不讲了。
其次我们鼠标要点击选取一个物体,当我们鼠标按住移动时,物体跟随我们的鼠标移动。按住鼠标点击选取的范围可以是这个物体中心为定点坐标,以边长为d的一个矩形区域,当鼠标点击在这个区域时,我们则判定选取了这个物体。
当两个物体重叠时,我们优先选取画出的第一个物体进行移动。
那么问题就来了,选取了物体后,如何实现物体跟随我们鼠标移动呢?
非常简单,水平方向上,只要在鼠标移动时将移动后的坐标减去移动前的坐标然后除以物体的宽度或者长度 ,就得到了移动的法向量。movX1 = (x - x1) / width1;
垂直方向上,同理可得movY1 = -((y - Y1) / height1); 为什么这里多个负号,是因为向下移动是负数,向上是正数。
然后将移动后改变的移动法向量,让程序调用窗口重新绘制一次即可。如果出现闪烁问题,可以使用双缓冲。
鼠标点击事件处理代码:
整个代码唯一的坑就在两行上,理解这两行,那么就毫无难度了 x1 = 400; Y1 = 400;
// 鼠标交互
void myMouse(int button, int state, int x, int y)
{ //鼠标左键按下或者松开
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
mousetate = ;
if (!choose) {
if (x<(x1 + chooseWidth) && x>(x1 - chooseWidth)) {
if (y<(Y1 + chooseHeight) && y>(Y1 - chooseHeight)) {
x1 = ;
Y1 = ;
movX1 = (x - x1) / width1;
movY1 = -((y - Y1) / height1);
choose = ;
}
}
else if (x<(x2 + chooseWidth) && x>(x2 - chooseWidth)) {
if (y<(y2 + chooseHeight) && y>(y2 - chooseHeight)) {
x2 = ;
y2 = ;
movX2 = (x - x2) / width2;
movY2 = -((y - y2) / height2);
choose = ;
}
} }
std::cout << "x = " << x << " y = " << y << std::endl;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
if (choose == ) {
x1 += (movX1*width1);
Y1 += -(movY1*height1);
}
if (choose == ) {
x2 += (movX2*width2);
y2 += -(movY2*height2);
}
mousetate = ;
choose = ;
std::cout << "x = " << x1 << " y = " << Y1 << std::endl;
} //滚轮事件
//scale 增加就是放大 减小就是缩小
//currentfile 对不同的模型用不用的scale
if (state == GLUT_UP && button == GLUT_WHEEL_UP) { }
else scale = 0.2;
if (state == GLUT_UP && button == GLUT_WHEEL_DOWN) { }
else scale = 0.2;
//glutPostRedisplay();//促使主程序尽快的重绘窗口
}
鼠标移动处理程序代码:
// 鼠标运动时
void onMouseMove(int x, int y) {
//当鼠标状态为按下时进入后续判断
if (mousetate) {
//x对应y是因为对应的是法向量
if (choose == ) {
movX1 = (x - x1) / width1;
glutPostRedisplay();
movY1 = -((y - Y1) / height1);
glutPostRedisplay();
std::cout << " 移动 x1 = " << x << " y1 = " << y << std::endl;
}
else {
std::cout << "not choose" << std::endl;
}
if (choose == ) {
movX2 = (x - x2) / width2;
glutPostRedisplay();
movY2 = -((y - y2) / height2);
glutPostRedisplay();
std::cout << " 移动 x2 = " << x << " y2 = " << y << std::endl;
}
else {
std::cout << "not choose" << std::endl;
}
}
}
我们预览程序运行,分别控制两个正方体的移动。
移动前:
移动后:
这个就是我们本文实现的内容,后面就可以用于读取多个3d模型分别进行移动。
后面读取多个3d模型(我光照还没有设置好QAQ。。。)
移动前位置:
移动后位置:
项目完整代码,配置好Opengl环境可以直接运行,更多项目分享以及学习教程,请关注在下!!!!:
#include <GL/glut.h>
#include <iostream> // 绘制立方体 // 将立方体的八个顶点保存到一个数组里面 static GLfloat vertex_list[][] = {
-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,
}; // 将要使用的顶点的序号保存到一个数组里面 static GLint index_list[][] = {
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
, , , ,
}; #define GLUT_WHEEL_UP 3 //定义滚轮操作
#define GLUT_WHEEL_DOWN 4 const int windowsWidth = ;
const int windowsHeight = ;
GLfloat scale = 0.2; GLfloat movX1 = -1.0f, movX2 = 1.0f, movY1 = 0.0f, movY2 = 0.0f;
GLfloat width1 = (windowsWidth / 2.0)*scale,height1 = (windowsHeight / )*scale;
GLfloat width2 = (windowsWidth / )*scale, height2 = (windowsHeight / )*scale;
GLfloat x1 = (windowsWidth / )+(width1*movX1), x2 = (windowsWidth / ) + (width1*movX2), Y1 = (windowsHeight / )+(height1*movY1), y2 = (windowsHeight / ) + (height1*movY2), z1 = 0.0f, z2 = 0.0f;
GLfloat chooseWidth = ,chooseHeight = ;
GLfloat dx = , dy = ;
bool mousetate = ;
int choose = ;
// 鼠标交互
void myMouse(int button, int state, int x, int y)
{ //鼠标左键按下或者松开
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
mousetate = ;
if (!choose) {
if (x<(x1 + chooseWidth) && x>(x1 - chooseWidth)) {
if (y<(Y1 + chooseHeight) && y>(Y1 - chooseHeight)) {
x1 = ;
Y1 = ;
movX1 = (x - x1) / width1;
movY1 = -((y - Y1) / height1);
choose = ;
}
}
else if (x<(x2 + chooseWidth) && x>(x2 - chooseWidth)) {
if (y<(y2 + chooseHeight) && y>(y2 - chooseHeight)) {
x2 = ;
y2 = ;
movX2 = (x - x2) / width2;
movY2 = -((y - y2) / height2);
choose = ;
}
} }
std::cout << "x = " << x << " y = " << y << std::endl;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
if (choose == ) {
x1 += (movX1*width1);
Y1 += -(movY1*height1);
}
if (choose == ) {
x2 += (movX2*width2);
y2 += -(movY2*height2);
}
mousetate = ;
choose = ;
std::cout << "x = " << x1 << " y = " << Y1 << std::endl;
} //滚轮事件
//scale 增加就是放大 减小就是缩小
//currentfile 对不同的模型用不用的scale
if (state == GLUT_UP && button == GLUT_WHEEL_UP) { }
else scale = 0.2;
if (state == GLUT_UP && button == GLUT_WHEEL_DOWN) { }
else scale = 0.2;
//glutPostRedisplay();//促使主程序尽快的重绘窗口
} // 鼠标运动时
void onMouseMove(int x, int y) {
//当鼠标状态为按下时进入后续判断
if (mousetate) {
//x对应y是因为对应的是法向量
if (choose == ) {
movX1 = (x - x1) / width1;
glutPostRedisplay();
movY1 = -((y - Y1) / height1);
glutPostRedisplay();
std::cout << " 移动 x1 = " << x << " y1 = " << y << std::endl;
}
else {
std::cout << "not choose" << std::endl;
}
if (choose == ) {
movX2 = (x - x2) / width2;
glutPostRedisplay();
movY2 = -((y - y2) / height2);
glutPostRedisplay();
std::cout << " 移动 x2 = " << x << " y2 = " << y << std::endl;
}
else {
std::cout << "not choose" << std::endl;
}
}
} // 绘制立方体 void DrawCube(void)
{
glPushMatrix();
glFrontFace(GL_CCW);//逆时针
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
int i, j; glBegin(GL_QUADS); //glBegin(GL_LINES);
for (i = ; i < ; ++i) // 12 条线段 {
for (j = ; j < ; ++j) // 每条线段 2个顶点 {
glVertex3fv(vertex_list[index_list[i][j]]);
}
}
glEnd(); } static float rotate = ;
static int times = ; void renderScene2(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glColor3f(, , );
glScalef(0.3, 0.3, 0.3); // 缩放
glPushMatrix(); //glTranslatef(-0.2, 0, 0); // 平移 //glScalef(2, 1, 1); // 缩放 times++;
if (times > )
{
times = ;
} if (times % == )
{
rotate += 0.3;
} glPushMatrix(); glTranslatef(-, , ); // 平移
glRotatef(rotate, , , );
glRotatef(rotate, , , );
DrawCube();
glPopMatrix(); glTranslatef(, , ); // 平移
glRotatef(rotate, , , );
glRotatef(rotate, , , );
//glScalef(0.5, 0.5, 0.5); // 缩放
DrawCube(); glPopMatrix();
glutSwapBuffers();
}
void renderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glScalef(scale, scale, scale); // 缩放
glPushMatrix();
glColor3f(, , );
glTranslatef(movX1, movY1, );
DrawCube();
glPopMatrix(); glPushMatrix();
glColor3f(, , );
glTranslatef(movX2, movY2, );
DrawCube();
glPopMatrix();
glutSwapBuffers();
} void main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(, );
glutInitWindowSize(windowsWidth, windowsHeight);
glutCreateWindow("GLDemo");
glutMouseFunc(&myMouse); //鼠标点击处理函数
glutMotionFunc(&onMouseMove); // 鼠标移动的时候的函数
glutDisplayFunc(&renderScene);
glutIdleFunc(&renderScene); glutMainLoop();
}
若有兴趣交流分享技术,可关注本人公众号,里面会不定期的分享各种编程教程,和共享源码,诸如研究分享关于c/c++,python,前端,后端,opencv,halcon,opengl,机器学习深度学习之类有关于基础编程,图像处理和机器视觉开发的知识
OpenGl 实现鼠标分别移动多个物体 ----------移动一个物体另外一个物体不动--读取多个3d模型操作的前期踏脚石的更多相关文章
-
OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11627508.html 前言: 因为接下来的项目需求是要读取多个3D模型,并且移动拼接,那么我 ...
-
OpenGl读取导入3D模型并且添加鼠标移动旋转显示
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11543828.html 最近实习要用到opengl库就是跟opencv 有点像的那个,然后下了 ...
-
c# winform用sharpGL(OpenGl)解析读取3D模型obj
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11783026.html 自己写了个简单的类读取解析obj模型,使用导入类,然后new个对象,在 ...
-
【Unity】鼠标指向某物体,在其上显示物体的名字等等等等信息
之前一直用NGUI HUD Text插件做这个功能,感觉一个小功能就导一个插件进来简直丧心病狂.然后就自己写了一个~ Camera cam;//用于发射射线的相机 Camera UIcam;//UI层 ...
-
OpenGL编程(七)3D模型的深度(z轴)检测
下图是我们要修改后的效果图: 一.深度检测 1.模型Z轴显示有问题: 上一次试验中,如果认真留意,会发现一个问题.当控制锥体在左右或上下旋转时,你会发现锥体看起来是在+-180度之间来回摆动,而不是3 ...
-
OpenGL编程(六)通过三角形绘画出3D模型
使用三角形绘制3D模型 三角形是基本的多边形,任何多变形都能由三角形组成.三角形是由三个顶点的连线组成.三个点分别是v0:v1:v2. 1.绕法 从某个顶点开始,有两种连线的方法,顺时针和逆时针,这是 ...
-
bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html 一.初始化世界以及模型 /// 冲突配置包含内存的默认设置,冲突设置. ...
-
Unity在UI界面上显示3D模型/物体,控制模型旋转
Unity3D物体在UI界面的显示 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...
-
js 运动函数篇 (一) (匀速运动、缓冲运动、多物体运动、多物体不同值运动、多物体多值运动)层层深入
前言: 本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽. 本篇文章为您分析一下原生JS写 匀速运动.缓冲运动.多物体运 ...
随机推荐
-
Sublime Text 3关闭自动更新
Sublime Text 3关闭自动更新 第一步:help->enter license 这有两个: -– BEGIN LICENSE -– Michael Barnes Single User ...
-
Vue H5 History 部署IIS上404问题
背景简介 vue使用vue-router时,默认的地址并不美观,以#进行分割,例如:http://www.xxx.com/#/main. 为了访问地址能像正常的url一样,例如:http://www. ...
-
Xampp相关命令
http://www.upwqy.com/details/5.html 1 启动关闭 需要切换目录: # cd /opt/lampp/ 启动 XAMPP # ./lampp start 停止 XAMP ...
-
计算机网络--差错检测(帧检验序列FCS计算方法)
我们知道数据链路层广泛使用循环冗余检验CRC的检验技术 现在我们知道要发送的数据M=101001(长度为k=6) 在我们每次发送数据的时候需要在M后面添加一个N位的冗余码,一共发送(k+N)位数据 ...
-
利用Python制作简单的小程序:IP查看器
前言 说实话,查看电脑的IP,也挺无聊的,但是够简单,所以就从这里开始吧.IP地址在操作系统里就可以直接查看.但是除了IP地址,我们也想通过IP获取地理地址和网络运营商情况.IP地址和地理地址并没有固 ...
-
Django HTTP_X_FORWARDED_FOR 和 REMOTE_ADDR
使用django来获取用户访问的IP地址,如果用户是正常情况下 request.META['REMOTE_ADDR'] 可以获得用户的IP地址.但是有些网站服务器会使用ngix等代理http,或者是该 ...
-
使用RegSetValueEx修改注册表时遇到的问题(转)
原文转自 http://blog.csdn.net/tracyzhongcf/article/details/4076870 1.今天在使用RegSetValueEx时发现一个问题: RegSetVa ...
-
Eclipse与Android源码中ProGuard工具的使用(代码混淆)
由于工作需要,这两天和同事在研究android下面的ProGuard工具的使用,通过查看android官网对该工具的介绍以及网络上其它相关资料,再加上自己的亲手实践,算是有了一个基本了解.下面将自己的 ...
-
ubuntu 18.4 鼠标右键菜单 添加文件
执行以下指令,在template文件夹中,增加一个空文件 touch ~/Templates/Empty\ Document
-
Django rest framework + Vue简单示例
构建vue项目参考这篇文章https://segmentfault.com/a/1190000008049815 一.创建Vue项目 修改源:npm config set registry https ...