原文作者: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模型操作的前期踏脚石的更多相关文章

  1. OpenGl 导入读取多个3D模型 并且添加鼠标控制移动旋转

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11627508.html 前言: 因为接下来的项目需求是要读取多个3D模型,并且移动拼接,那么我 ...

  2. OpenGl读取导入3D模型并且添加鼠标移动旋转显示

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11543828.html 最近实习要用到opengl库就是跟opencv 有点像的那个,然后下了 ...

  3. c# winform用sharpGL(OpenGl)解析读取3D模型obj

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11783026.html 自己写了个简单的类读取解析obj模型,使用导入类,然后new个对象,在 ...

  4. 【Unity】鼠标指向某物体,在其上显示物体的名字等等等等信息

    之前一直用NGUI HUD Text插件做这个功能,感觉一个小功能就导一个插件进来简直丧心病狂.然后就自己写了一个~ Camera cam;//用于发射射线的相机 Camera UIcam;//UI层 ...

  5. OpenGL编程(七)3D模型的深度(z轴)检测

    下图是我们要修改后的效果图: 一.深度检测 1.模型Z轴显示有问题: 上一次试验中,如果认真留意,会发现一个问题.当控制锥体在左右或上下旋转时,你会发现锥体看起来是在+-180度之间来回摆动,而不是3 ...

  6. OpenGL编程(六)通过三角形绘画出3D模型

    使用三角形绘制3D模型 三角形是基本的多边形,任何多变形都能由三角形组成.三角形是由三个顶点的连线组成.三个点分别是v0:v1:v2. 1.绕法 从某个顶点开始,有两种连线的方法,顺时针和逆时针,这是 ...

  7. bullet物理引擎与OpenGL结合 导入3D模型进行碰撞检测 以及画三角网格的坑

    原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/11681069.html 一.初始化世界以及模型 /// 冲突配置包含内存的默认设置,冲突设置. ...

  8. Unity在UI界面上显示3D模型/物体,控制模型旋转

    Unity3D物体在UI界面的显示 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- ...

  9. js 运动函数篇 (一) (匀速运动、缓冲运动、多物体运动、多物体不同值运动、多物体多值运动)层层深入

    前言:         本人纯小白一个,有很多地方理解的没有各位大牛那么透彻,如有错误,请各位大牛指出斧正!小弟感激不尽.         本篇文章为您分析一下原生JS写 匀速运动.缓冲运动.多物体运 ...

随机推荐

  1. svn checkout 单个文件

    $ svn co --depth=empty file:///usr/local/svn/calc calc_new $ cd calc_new $ svn up readme.txt 其中,calc ...

  2. JAVA 泛型中的通配符 T,E,K,V,?

    前言 Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许开发者在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所操作的数据 ...

  3. POJ-1847 Tram( 最短路 )

    题目链接:http://poj.org/problem?id=1847 Description Tram network in Zagreb consists of a number of inter ...

  4. gulp的介绍和手动安装

    gulp, 前端自动化工具, 文件操作, 项目上线之前,将碎片文件合并,将ES6转成ES5,文件压缩,快速搭建服务器... gulp基于node环境 gulp就是node的一个非内置的小模块 gulp ...

  5. Jmeter基础教程图文版(二)- 核心组件

    ⚪Jmeter Apache JMeter 是 Apache 组织开发的基于 Java 的压力测试工具.用于对软件做压力测试,它最初被设计用于 Web 应用测试,但后来扩展到其他测试领域. 它可以用于 ...

  6. SpringBoot集成Zipkin实现分布式全链路监控

    目录 Zipkin 简介 Springboot 集成 Zipkin 安装启动 zipkin 版本说明 项目结构 工程端口分配 引入 Maven 依赖 配置文件.收集器的设置 编写 Controller ...

  7. 【Spring】 IOC Base

    一.关于容器 1. ApplicationContext和BeanFactory 2. 配置文件 XML方式 Java-configuration 方式 @Configuration 3. 初始化容器 ...

  8. python科学计算与可视化视频教程

    目录: 下载链接:https://www.yinxiangit.com/616.html 第一单元TVTK入门-1.mp4第一单元TVTK入门-2.mp4第一单元TVTK入门-3.mp4 第一单元TV ...

  9. 线上LVM磁盘挂载

    ESC云服务器磁盘扩容 日常运行中,容器服务所在目录由于container-log.image的增加需要占用大量的磁盘空间,所以对/var/lib/docker/目录进行扩容挂载LVM数据盘. 首先查 ...

  10. ExpandableListView 可折叠的下拉listview

    ExpandableListView用法如下 1.定义布局文件main.xml文件 <?xml version="1.0" encoding="utf-8" ...