使用 gluUnProject() 在光标位置绘制一个四边形
我正在将 SDL 与 OpenGL 一起使用,到目前为止我已经在 2d 中完成了所有操作(使用 glOrtho())
现在我想尝试在 3D 中绘制东西,但是当然,因为我现在已经将第 3 维放入混合物中,所以事情变得越来越多复杂的。
我想做的是,获取光标的屏幕坐标,将它们转换为(?)世界坐标(我可以在OpenGL中使用坐标,因为我现在有了透视图等),并在那个位置(鼠标光标位于四边形的中心)
我已经阅读了一些关于 gluUnProject() 的教程,我有点明白我应该做什么,但由于我是自学的,所以很容易感到困惑并且不能正确理解我在做什么。
因此,我主要是从我找到的示例中复制的。
下面是我的代码(我去掉了错误检查等,试图将其减少一点)
如您所见,我有 mouseX、mouseY 和 mouseZ 变量,其中 mouseX 和 mouseY 从 SDL 获取它们的值。
我尝试使用 glReadPixel() 来获取 mouseZ 但我不确定我是否做得正确。
问题是,当我单击时,四边形没有绘制在正确的位置(我猜部分原因是我不知道如何正确获取 mouseZ,所以我只是在 gluUnProject() 中将其替换为 1.0?)
我在 glTranslatef() 函数中使用新的坐标(wx、wy、wz),但再次因为我不知道如何正确获取 mouseZ,我猜测这就是它无法正常工作的原因。 如果我用 -499 替换 wz 似乎工作正常,但我需要知道如何获得准确的结果,而无需手动查找正确(或几乎正确)的数字
如果有人可以告诉我我做错了什么,或者给我任何建议我们将不胜感激。
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
SDL_Surface* screen = 0;
SDL_Event event;
bool isRunning = true;
int mouseX, mouseY, mouseZ = 0;
GLint viewport[4];
GLdouble mvmatrix[16], projmatrix[16];
GLint realY; /* OpenGL y coordinate position */
GLdouble wx, wy, wz; /* returned world x, y, z coords */
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode(800, 600, 32, SDL_OPENGL);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glViewport(0, 0, 800, 600);
glClearDepth(1.f);
glClearColor(0, 0, 0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.f, 1.f, 1.f, 500.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
while(isRunning) {
while(SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT) {
isRunning = false;
}
if(event.type == SDL_MOUSEBUTTONDOWN) {
if(event.button.button == SDL_BUTTON_LEFT) {
SDL_GetMouseState(&mouseX, &mouseY);
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
realY = viewport[3] - (GLint) mouseY - 1;
glReadPixels(mouseX, realY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &mouseZ);
gluUnProject((GLdouble)mouseX, (GLdouble)realY, 1.0, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
}
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(wx, wy, wz);
glBegin(GL_QUADS);
glColor4f(1.f, 0.f, 0.f, 1.f);
glVertex3f(-20.f, -20.f, 0.f);
glColor4f(0.f, 1.f, 0.f, 1.f);
glVertex3f(-20.f, 20.f, 0.f);
glColor4f(0.f, 0.f, 1.f, 1.f);
glVertex3f(20.f, 20.f, 0.f);
glColor4f(1.f, 0.f, 1.f, 1.f);
glVertex3f(20.f, -20.f, 0.f);
glEnd();
glPopMatrix();
SDL_GL_SwapBuffers();
}
SDL_FreeSurface(screen);
return 0;
}
I am using SDL with OpenGL and up until now I have done everything in 2d (Using glOrtho())
Now I want to try drawing things in 3D but of course since I have now thrown a 3rd dimension into the mixture, things are getting more complicated.
What I want to do is, take the screen co-ordinates of the cursor, translate them to (?)world co-ordinates (Co-ordinates I can use in OpenGL since I now have perspective etc.), and draw a quad at that position (The mouse cursor being at the center of the quad)
I have read a few tutorials on gluUnProject() and I sort of understand what I am supposed to do, but since I am learning by myself it is very easy to get confused and not properly understand what I am doing.
As such, I have mainly copied from examples I have found.
Below is my code (I took out error checking etc in an attempt to cut it down a bit)
As you can see, I have mouseX, mouseY and mouseZ variables, of which mouseX and mouseY get their values from SDL.
I tried to use glReadPixel() to get mouseZ but I am not sure if I am doing it right.
The problem is that when I click, the quad is not drawn in the correct position (I guess partly due to the fact that I don't know how to get mouseZ properly, so I just replaced it in gluUnProject() with 1.0?)
I am using the new co-ordinates (wx, wy, wz) in the glTranslatef() function but once again because I don't know how to get mouseZ properly I am guessing this is the reason it doesn't work properly.
If I replace wz with -499 it seems to work ok, but I need to know how to get accurate results without manually finding the correct (Or almost correct) numbers
If anybody can tell me what I am doing wrong, or give me any advice it would be greatly appreciated.
#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
SDL_Surface* screen = 0;
SDL_Event event;
bool isRunning = true;
int mouseX, mouseY, mouseZ = 0;
GLint viewport[4];
GLdouble mvmatrix[16], projmatrix[16];
GLint realY; /* OpenGL y coordinate position */
GLdouble wx, wy, wz; /* returned world x, y, z coords */
int main(int argc, char **argv) {
SDL_Init(SDL_INIT_EVERYTHING);
screen = SDL_SetVideoMode(800, 600, 32, SDL_OPENGL);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glViewport(0, 0, 800, 600);
glClearDepth(1.f);
glClearColor(0, 0, 0, 0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90.f, 1.f, 1.f, 500.f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
while(isRunning) {
while(SDL_PollEvent(&event)) {
if(event.type == SDL_QUIT) {
isRunning = false;
}
if(event.type == SDL_MOUSEBUTTONDOWN) {
if(event.button.button == SDL_BUTTON_LEFT) {
SDL_GetMouseState(&mouseX, &mouseY);
glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
realY = viewport[3] - (GLint) mouseY - 1;
glReadPixels(mouseX, realY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &mouseZ);
gluUnProject((GLdouble)mouseX, (GLdouble)realY, 1.0, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
}
}
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glTranslatef(wx, wy, wz);
glBegin(GL_QUADS);
glColor4f(1.f, 0.f, 0.f, 1.f);
glVertex3f(-20.f, -20.f, 0.f);
glColor4f(0.f, 1.f, 0.f, 1.f);
glVertex3f(-20.f, 20.f, 0.f);
glColor4f(0.f, 0.f, 1.f, 1.f);
glVertex3f(20.f, 20.f, 0.f);
glColor4f(1.f, 0.f, 1.f, 1.f);
glVertex3f(20.f, -20.f, 0.f);
glEnd();
glPopMatrix();
SDL_GL_SwapBuffers();
}
SDL_FreeSurface(screen);
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我发现如果我添加以下内容:
然后将 glReadPixels() 从:更改
为:
然后我只需将 gluUnProject() 从:更改
为:
然后我可以获得我想要的 Z 值。
然后我只是向 wz 添加了一个小值,例如:
wz += 1;
以确保四边形出现在我单击的位置上方,并且它现在似乎按我的预期工作。I found that if I added the following:
then changed the glReadPixels() from:
to:
then I just changed gluUnProject() from:
to:
then I could get the Z value I wanted.
Then I just added a small value to wz, for example:
wz += 1;
to make sure the quad appeared above the place I clicked and it seems to work as I intended now.要猜测 Z,您需要了解此 z 的含义:
通常含义是您想要将与(相机原点,像素)对应的线与显示的 3D 对象相交。为此,您可以使用 Z 缓冲区。
如果没有(您想在没有 3D 关系的情况下将多边形粘贴到光标上),只需使用 2D 函数,您可以在同一帧中绘图时在 3D 和 2D 投影之间交替(使用投影矩阵或使用 2D 特定函数) ),因此你不需要 z。
如果您的设计中没有合理的理由,则为 Z 设置默认值是一个坏主意。
只有一个 Z 值可以为您提供正确的像素坐标。
openGL 中 2D 和 3D 坐标之间的联系是 OpenGl 使用 Z = 1 处的投影平面。
然后将像素坐标从[-1,1]缩放到像素坐标。
To guess a Z you need to have a meaning for this z :
Usually the meaning is that you want to intersect the line corresponding to (camera origin,pixel) with a 3d object with is displayed. You can use the Z buffer for this.
If not ( you want to stick a polygon to the cursor with no 3D relation ), just use the 2D functions, you can just alternate between 3D and 2D projections while drawing in the same frame (with either the projection matrix or with 2D specific functions), thus you don't need a z.
Setting a default value for Z is a bad idea if it has no rationale in your design.
There is only one value of Z which will give you correct pixel coordinates.
The link between 2D and 3D coordinates in openGL is that OpenGl uses a projection plane at Z = 1.
And then scales the pixel coordinates from [-1,1] to pixels coordinates.