鼠标挑选小姐

编程入门 行业动态 更新时间:2024-10-17 02:47:16
本文介绍了鼠标挑选小姐的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

在这些课程中,我对地形进行了鼠标拾取(但是使用了c ++)

I did mouse picking with terrain for these lessons (but used c++)

www.youtube/watch?v = DLKN0jExRIM& index = 29& listhLoLuZVfUksDP antongerdelan/opengl/raycasting.html

问题在于鼠标的位置与射线与地形相交的位置不对应: 垂直方向上有一个大错误,水平方向上有一个小错误. 不要看阴影,这不是经过校正的法线贴图. 有什么事吗我的代码:

The problem is that the position of the mouse does not correspond to the place where the ray intersects with the terrane: There's a big blunder on the vertical and a little horizontal. Do not look at the shadows, this is not a corrected map of normals. What can be wrong? My code:

void MousePicker::update() { view = cam->getViewMatrix(); currentRay = calculateMouseRay(); if (intersectionInRange(0, RAY_RANGE, currentRay)) { currentTerrainPoint = binarySearch(0, 0, RAY_RANGE, currentRay); } else { currentTerrainPoint = vec3(); } } vec3 MousePicker::calculateMouseRay() { glfwGetCursorPos(win, &mouseInfo.xPos, &mouseInfo.yPos); vec2 normalizedCoords = getNormalizedCoords(mouseInfo.xPos, mouseInfo.yPos); vec4 clipCoords = vec4(normalizedCoords.x, normalizedCoords.y, -1.0f, 1.0f); vec4 eyeCoords = toEyeCoords(clipCoords); vec3 worldRay = toWorldCoords(eyeCoords); return worldRay; } vec2 MousePicker::getNormalizedCoords(double xPos, double yPos) { GLint width, height; glfwGetWindowSize(win, &width, &height); //GLfloat x = (2.0 * xPos) / width - 1.0f; GLfloat x = -((width - xPos) / width - 0.5f) * 2.0f; //GLfloat y = 1.0f - (2.0f * yPos) / height; GLfloat y = ((height - yPos) / height - 0.5f) * 2.0f; //float z = 1.0f; mouseInfo.normalizedCoords = vec2(x, y); return vec2(x,y); } vec4 MousePicker::toEyeCoords(vec4 clipCoords) { vec4 invertedProjection = inverse(projection) * clipCoords; //vec4 eyeCoords = translate(invertedProjection, clipCoords); mouseInfo.eyeCoords = vec4(invertedProjection.x, invertedProjection.y, -1.0f, 0.0f); return vec4(invertedProjection.x, invertedProjection.y, -1.0f, 0.0f); } vec3 MousePicker::toWorldCoords(vec4 eyeCoords) { vec3 rayWorld = vec3(inverse(view) * eyeCoords); vec3 mouseRay = vec3(rayWorld.x, rayWorld.y, rayWorld.z); rayWorld = normalize(rayWorld); mouseInfo.worldRay = rayWorld; return rayWorld; } //********************************************************************************* vec3 MousePicker::getPointOnRay(vec3 ray, float distance) { vec3 camPos = cam->getCameraPos(); vec3 start = vec3(camPos.x, camPos.y, camPos.z); vec3 scaledRay = vec3(ray.x * distance, ray.y * distance, ray.z * distance); return vec3(start + scaledRay); } vec3 MousePicker::binarySearch(int count, float start, float finish, vec3 ray) { float half = start + ((finish - start) / 2.0f); if (count >= RECURSION_COUNT) { vec3 endPoint = getPointOnRay(ray, half); //Terrain* ter = &getTerrain(endPoint.x, endPoint.z); if (terrain != NULL) { return endPoint; } else { return vec3(); } } if (intersectionInRange(start, half, ray)) { return binarySearch(count + 1, start, half, ray); } else { return binarySearch(count + 1, half, finish, ray); } } bool MousePicker::intersectionInRange(float start, float finish, vec3 ray) { vec3 startPoint = getPointOnRay(ray, start); vec3 endPoint = getPointOnRay(ray, finish); if (!isUnderGround(startPoint) && isUnderGround(endPoint)) { return true; } else { return false; } } bool MousePicker::isUnderGround(vec3 testPoint) { //Terrain* ter = &getTerrain(testPoint.x, testPoint.z); float height = 0; if (terrain != NULL) { height = terrain->getHeightPoint(testPoint.x, testPoint.z); mouseInfo.height = height; } if (testPoint.y < height) { return true; } else { return false; } } Terrain MousePicker::getTerrain(float worldX, float worldZ) { return *terrain; }

推荐答案

在透视投影中,从眼睛位置到屏幕上一个点的光线可以定义为2个点.第一点是 eye (相机)位置,它在视图空间中为(0,0,0).第二点必须通过屏幕上的位置来计算. 屏幕位置必须转换为规范化的设备坐标,范围为(-1,-1)到(1,1).

In perspective projection, a ray from the eye position through a point on the screen can defined by 2 points. The first point is the eye (camera) position which is (0, 0, 0) in view space. The second point has to be calculated by the position on the screen. The screen position has to be converted to normalized device coordinates in range from (-1,-1) to (1,1).

w = with of the viewport h = height of the viewport x = X position of the mouse y = Y position ot the mouse GLfloat ndc_x = 2.0 * x/w - 1.0; GLfloat ndc_y = 1.0 - 2.0 * y/h; // invert Y axis

要计算光线穿过相机位置并穿过屏幕上的点的光线,必须知道视野和透视投影的纵横比:

To calculate a point on the ray, which goes through the camera position and through the point on the screen, the field of view and the aspect ratio of the perspective projection has to be known:

fov_y = vertical field of view angle in radians aspect = w / h GLfloat tanFov = tan( fov_y * 0.5 ); glm::vec3 ray_P = vec3( ndc_x * aspect * tanFov, ndc_y * tanFov, -1.0 ) );

在世界空间中,可以通过以下位置(P0)和归一化方向(dir)定义从相机位置到屏幕上某个点的光线:

A ray from the camera position through a point on the screen can be defined by the following position (P0) and normalized direction (dir), in world space:

view = view matrix glm::mat4 invView = glm::inverse( view ); glm::vec3 P0 = invView * glm::vec3(0.0f, 0.0f, 0.0f); // = glm::vec3( view[3][0], view[3][1], view[3][2] ); glm::vec3 dir = glm::normalize( invView * ray_P - P0 );

在这种情况下,以下问题的答案也会很有趣:

In this case, the answers to the following questions will be interesting too:

  • 如何在给定视图空间深度值和ndc xy的情况下恢复视图空间位置
  • 是否可以在OpenGL中单击立方体的哪个表面?
  • 如何在片段着色器中使用gl_FragCoord.z在现代OpenGL中线性渲染深度?
  • GLSL聚光灯投影量
  • How to recover view space position given view space depth value and ndc xy
  • Is it possble get which surface of cube will be click in OpenGL?
  • How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?
  • GLSL spotlight projection volume

应用于您的代码会导致以下更改:

透视投影矩阵如下:

r = right, l = left, b = bottom, t = top, n = near, f = far 2*n/(r-l) 0 0 0 0 2*n/(t-b) 0 0 (r+l)/(r-l) (t+b)/(t-b) -(f+n)/(f-n) -1 0 0 -2*f*n/(f-n) 0

它遵循:

aspect = w / h tanFov = tan( fov_y * 0.5 ); p[0][0] = 2*n/(r-l) = 1.0 / (tanFov * aspect) p[1][1] = 2*n/(t-b) = 1.0 / tanFov

从屏幕(鼠标)坐标转换为标准化的设备坐标:

Convert from screen (mouse) coordinates to normalized device coordinates:

vec2 MousePicker::getNormalizedCoords(double x, double y) { GLint w, h; glfwGetWindowSize(win, &width, &height); GLfloat ndc_x = 2.0 * x/w - 1.0; GLfloat ndc_y = 1.0 - 2.0 * y/h; // invert Y axis mouseInfo.normalizedCoords = vec2(ndc_x, ndc_x); return vec2(ndc_x, ndc_x); }

计算从照相机位置到世界空间中屏幕上某个点(鼠标位置)的光线:

Calculate A ray from the camera position through a point on the screen (mouse position) in world space:

vec3 MousePicker::calculateMouseRay( void ) { glfwGetCursorPos(win, &mouseInfo.xPos, &mouseInfo.yPos); vec2 normalizedCoords = getNormalizedCoords(mouseInfo.xPos, mouseInfo.yPos); ray_Px = normalizedCoords.x / projection[0][0]; // projection[0][0] == 1.0 / (tanFov * aspect) ray_Py = normalizedCoords.y / projection[1][1]; // projection[1][1] == 1.0 / tanFov glm::vec3 ray_P = vec3( ray_Px, ray_Py, -1.0f ) ); vec3 camPos = cam->getCameraPos(); // == glm::vec3( view[3][0], view[3][1], view[3][2] ); glm::mat4 invView = glm::inverse( view ); glm::vec3 P0 = camPos; glm::vec3 dir = glm::normalize( invView * ray_P - P0 ); return dir; }

更多推荐

鼠标挑选小姐

本文发布于:2023-11-29 20:12:47,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1647509.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:鼠标   小姐

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!