在Visual Studio 2017与OpenFrameworks中判断变换后三角形的鼠标命中
问题根源
ofPushMatrix()/ofPopMatrix()仅作用于绘制管线的坐标转换,不会修改你用来定义三角形的原始顶点数据。insideTriangleArea()用的是未做任何变换的原始顶点,去匹配屏幕坐标系下的鼠标位置,自然无法对应上平移、旋转、缩放后的绘制区域——相当于你在局部坐标系里定义了三角形,却直接拿屏幕坐标去做碰撞检测,两者不在同一坐标系下。
解决方法
有两种可行的思路,核心都是让鼠标点和三角形顶点处于同一坐标系:
思路1:将鼠标坐标逆变换到三角形的局部坐标系
把屏幕鼠标点通过与绘制时相反的变换,转换到三角形未做任何变换前的局部坐标系,再用这个转换后的点去调用检测函数:
// 1. 定义原始三角形顶点(示例为以原点为中心的局部坐标) vector<ofVec2f> triangleVerts = { ofVec2f(-50, -50), ofVec2f(50, -50), ofVec2f(0, 50) }; // 2. 绘制时的变换参数 ofVec2f fPT = ofVec2f(400, 300); float fRotate = 45.0f; float fScale = 1.5f; // 3. 构建绘制时的变换矩阵并求逆 ofMatrix4x4 transformMatrix; transformMatrix.translate(fPT); transformMatrix.rotateDeg(fRotate, 0, 0, 1); // 2D旋转绕Z轴 transformMatrix.scale(fScale, fScale, 1.0f); ofMatrix4x4 inverseMatrix = transformMatrix.getInverse(); // 4. 获取鼠标屏幕坐标并转换到局部坐标系 ofVec2f mouseScreen(ofGetMouseX(), ofGetMouseY()); ofVec3f mouseLocal = inverseMatrix * ofVec3f(mouseScreen.x, mouseScreen.y, 0.0f); ofVec2f mouseLocal2D(mouseLocal.x, mouseLocal.y); // 5. 执行碰撞检测 bool isInside = insideTriangleArea(triangleVerts[0], triangleVerts[1], triangleVerts[2], mouseLocal2D);
思路2:提前计算变换后的三角形顶点
先把原始顶点通过变换矩阵转换为屏幕坐标系下的顶点,再直接用鼠标屏幕坐标做检测:
// 1. 原始顶点与变换参数同上 vector<ofVec2f> triangleVerts = { /* ... */ }; ofVec2f fPT = { /* ... */ }; float fRotate = /* ... */; float fScale = /* ... */; // 2. 构建变换矩阵 ofMatrix4x4 transformMatrix; transformMatrix.translate(fPT); transformMatrix.rotateDeg(fRotate, 0, 0, 1); transformMatrix.scale(fScale, fScale, 1.0f); // 3. 计算变换后的屏幕坐标顶点 ofVec2f vertScreen0 = transformMatrix * triangleVerts[0]; ofVec2f vertScreen1 = transformMatrix * triangleVerts[1]; ofVec2f vertScreen2 = transformMatrix * triangleVerts[2]; // 4. 用屏幕坐标直接检测 ofVec2f mouseScreen(ofGetMouseX(), ofGetMouseY()); bool isInside = insideTriangleArea(vertScreen0, vertScreen1, vertScreen2, mouseScreen);
关键注意点
- 不要依赖
ofPushMatrix()的作用域来影响碰撞检测——这个函数只是给绘制阶段的OpenGL上下文设置矩阵,不会改变你的顶点数据或鼠标坐标的坐标系。 - 两种思路的本质都是坐标系对齐:要么把鼠标转到局部坐标系,要么把顶点转到屏幕坐标系,必须保证检测时两者处于同一坐标系。
内容的提问来源于stack exchange,提问作者James C Wright
相关产品推荐
相关产品推荐

