gpt4 book ai didi

c++ - 为什么我必须除以 Z?

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:29:44 24 4
gpt4 key购买 nike

我需要在 3D 环境中实现“选择对象”。因此,我没有采用稳健、准确的方法(例如光线转换),而是决定采用简单的方法。首先,我将对象世界位置转换为屏幕坐标:

glm::mat4 modelView, projection, accum;
glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat*)&projection);
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&modelView);
accum = projection * modelView;
glm::mat4 transformed = accum * glm::vec4(objectLocation, 1);

接着是一些简单的代码,将 opengl 坐标系转换为普通窗口坐标,并进行简单的鼠标距离检查。 但是 这不太奏效。为了从世界空间转换到屏幕空间,我需要在上面显示的函数末尾添加一个计算:

transformed.x /= transformed.z;
transformed.y /= transformed.z;

我不明白为什么我必须这样做。我的印象是,一旦你的顶点乘以累积的 modelViewProjection 矩阵,你就有了你的屏幕坐标。但我必须除以 Z 才能使其正常工作。在我的 openGL 3.3 着色器中,我从来不需要除以 Z。这是为什么?

编辑:从 opengl 坐标系转换为屏幕坐标的代码是这样的:

int screenX = (int)((trans.x + 1.f)*640.f); //640 = 1280/2
int screenY = (int)((-trans.y + 1.f)*360.f); //360 = 720/2

然后我测试鼠标是否在该点附近:

float length = glm::distance(glm::vec2(screenX, screenY), glm::vec2(mouseX, mouseY));
if(length < 50) {//you can guess the rest

编辑#2
此方法在鼠标单击事件时调用:

glm::mat4 modelView;
glm::mat4 projection;
glm::mat4 accum;
glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat*)&projection);
glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&modelView);
accum = projection * modelView;
float nearestDistance = 1000.f;
gameObject* nearest = NULL;
for(uint i = 0; i < objects.size(); i++) {
gameObject* o = objects[i];
o->selected = false;
glm::vec4 trans = accum * glm::vec4(o->location,1);
trans.x /= trans.z;
trans.y /= trans.z;
int clipX = (int)((trans.x+1.f)*640.f);
int clipY = (int)((-trans.y+1.f)*360.f);
float length = glm::distance(glm::vec2(clipX,clipY), glm::vec2(mouseX, mouseY));
if(length<50) {
nearestDistance = trans.z;
nearest = o;
}
}
if(nearest) {
nearest->selected = true;
}

mouseRightPressed = true;

整个代码不完整,但与我的问题相关的部分工作正常。 “objects” vector 只包含一个用于我的测试的元素,因此循环根本不会妨碍。

最佳答案

我想通了。正如 David Lively 先生指出的那样,

Typically in this case you'd divide by .w instead of .z to get something useful, though.

我的 .w 值非常接近我的 .z 值,所以在我的代码中我更改了语句:

transformed.x /= transformed.z;
transformed.y /= transformed.z;

到:

transformed.x /= transformed.w;
transformed.y /= transformed.w;

它仍然像以前一样工作。

https://stackoverflow.com/a/10354368/2159051解释 w 除以 w 将在稍后的管道中完成。显然,因为我的代码只是将矩阵相乘,所以没有“后来的管道”。从某种意义上说,我只是很幸运,因为我的 .z 值与我的 .w 值非常接近,所以有一种它正在工作的错觉。

关于c++ - 为什么我必须除以 Z?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21007614/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com