呼吁OpenGL的老人......我在检测鼠标点击纹理平面上的相对位置时遇到了很大问题。
我正在制作一个游戏,我正在绘制一个大的正方形,并使用大量生成的地图纹理对其进行纹理处理。视图始终自上而下,您当前只能移动该方块的X Y和Z坐标。
OpenGL init
screenRatio = (float)screenW / (float)screenH;
System.out.println("init");
glu = new GLU();
GL2 gl2 = drawable.getGL().getGL2();
gl2.glShadeModel( GL2.GL_SMOOTH );
gl2.glHint( GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL2.GL_NICEST );
gl2.glClearColor( 0f, 0f, 0f, 1f );
gl2.glDepthMask(false);
gl2.glEnable(GL2.GL_DEPTH_TEST);
设置相机位置
gl2.glViewport(0, 0, 1024, 768);
gl2.glMatrixMode( GL2.GL_PROJECTION );
gl2.glLoadIdentity();
glu.gluPerspective( 45, screenRatio, 1, 100 );
glu.gluLookAt( 0, 0, 3, 0, 0, 0, 0, 1, 0 );
gl2.glMatrixMode(GL2.GL_MODELVIEW);
gl2.glLoadIdentity();
移动位置以开始绘制地图
// typical camera coord example:
// CENTRE: 0.0f, 0.0f, 10f
// FULL ZOOM OUT AND TOP LEFT: -25f, 25f, 40f
// move position
gl2.glTranslatef( -cameraX, -cameraY, -cameraZ );
我怀疑glTranslatef z-coord可能是个嫌疑人。因为我正在绘制远离原点的方形40f(例如)
映射顶点信息
// here are the coordinates/dimensions of my textured square ( my map )
float[] vertexArray = {
-25f, 25f,
25f, 25f,
25f, -25f,
25f, -25f,
};
鼠标点击位置计算
“借来的”来自java-tips 1628-how-to-use-gluunproject-in-jogl.html
int x = mouse.getX(), y = mouse.getY();
int viewport[] = new int[4];
double mvmatrix[] = new double[16];
double projmatrix[] = new double[16];
int realy = 0;
double wcoord[] = new double[4];
gl2.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
gl2.glGetDoublev(GL2.GL_MODELVIEW_MATRIX, mvmatrix, 0);
gl2.glGetDoublev(GL2.GL_PROJECTION_MATRIX, projmatrix, 0);
realy = viewport[3] - (int) y - 1;
glu.gluUnProject(
(double) x,
(double) realy,
0.0, // I have experimented with having this as 1.0 also
mvmatrix, 0,
projmatrix, 0,
viewport, 0,
wcoord, 0
);
尝试使用near / far位(gluUnProject的第3个参数)似乎产生了更好的效果,但似乎没有最佳位置(我发现的最佳点是0.945)
我非常希望mCX,mCY相对于渲染的地图坐标(-25f - 25f)而不管Z位置
mCX = (float)wcoord[0];
mCY = (float)wcoord[1];
在平移坐标处绘制一个矩形
gl2.glColor3f(1.f, 0.f, 0.f);
gl2.glBegin(GL2.GL_QUADS);
gl2.glVertex2f( mCX-0.1f, mCY+0.1f );
gl2.glVertex2f( mCX+0.1f, mCY+0.1f );
gl2.glVertex2f( mCX+0.1f, mCY-0.1f );
gl2.glVertex2f( mCX-0.1f, mCY-0.1f );
gl2.glEnd();
目前,坐标与x&如果我单击屏幕的正中心,它将在正确的位置绘制一个框,而不管我的glTranslatef运动。如果我点击屏幕中心,我会看到一个指数偏移。
演示指数偏移
当我点击屏幕的非常死点时,它会在鼠标点周围绘制这个紫红色的正方形,但运动最小时会产生以下效果:
Fully zoomed in, click a couple of pixels right of centre
更新和工作......现在
在为我的地图生成纹理时,我还生成了一个替代纹理,它将每个“图块”表示为不同的颜色。在我的初始和当前尝试中,此图块的颜色是其X和Y坐标的函数(地图由100个图块组成,100个图块向下,因此x + y坐标范围为0 - 99)
我最终得到的纹理看起来像是从绿色到红色的渐变。下面的代码将在鼠标单击时快速渲染此纹理(用户无法察觉)并读取鼠标下的rgb值。然后我们将rgb值转换为世界坐标和BOOM ...我的地图的相对坐标被实现。
float pX, pY;
// render a colourised version of the scene for the purposes of "picking"
// https://www.opengl.org/archives/resources/faq/technical/selection.htm
public void pick ( GL2 gl2 ) {
// DRAW PICKING SCENE
gl2.glClearBufferfv(GL2.GL_COLOR, 0, clearColor);
gl2.glClearBufferfv(GL2.GL_DEPTH, 0, clearDepth);
gl2.glTranslatef( -cameraX, -cameraY, -cameraZ );
// draw my map but use the colour gradient texture
for ( Entity e : this.entities ) {
e.drawPick( gl2 );
}
// not sure what this does #cargo-cult
gl2.glFlush();
gl2.glFinish();
gl2.glPixelStorei(GL2.GL_UNPACK_ALIGNMENT, 1);
// After rendering ask OpenGL to read the colour of the screen at the given window coordinates!
FloatBuffer buffer = FloatBuffer.allocate(4);
int realy = 0;
int viewport[] = new int[4];
gl2.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
realy = viewport[3] - (int) mouse.getY() - 1;
gl2.glReadPixels( mouse.getX(), realy, 1, 1, GL2.GL_RGBA, GL2.GL_FLOAT, buffer);
float[] pixels = new float[3];
pixels = buffer.array();
// pixels holds rgb values respectively
// convert the red + green values back into x + y values
pX = (pixels[0] * 255) - 25f;
pY = -((pixels[1] * 255) - 25f);
// draw the proper texture
for ( Entity e : this.entities ) {
e.draw( gl2 );
}
}
答案 0 :(得分:0)
你差不多了。但是,在unproject函数中,你需要一个很好的Z值。
您要做的是获取光标的位置并乘以矩阵以在“3d空间”中给出一个点。你的矩阵可能是4x4或4x3,所以你需要一个4分量向量。 (X,Y,Z,W)
绘制地图时,现有点乘以1个或多个矩阵,包括投影矩阵。 (例如-25.0f,25.0f,0.0f,1.0f
- 实际上是3d点)。当它与所有矩阵相乘时,GPU基本上返回该顶点的归一化设备坐标(NDC)(所有轴中的-1和1之间)的值。
要做相反的事情并且取消项目,你需要为Z设置一个有效/良好的值。原因是在NDC中所有绘制的内容都在-1,1所有轴上,以便将所有内容都放入(更远的地方)事情被压扁了一点)。如果你有一个巨大的>这就是你如何变得闪烁和怪异。例如,100000 zFar距离,它仍然必须适合-1,1。
执行此操作的最佳方法是使用深度缓冲区,通过捕获深度值,它将为您提供NDC中z坐标的良好近似值,您可以将其传递给unproject调用。
0.945是甜蜜点的原因可能取决于相机与地图的距离,反之亦然。通常情况下,深度缓冲区距离近平面更远的细节远远超过远 - 它不是线性的。
http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/在页面底部附近具有良好的视觉效果,并且是一般介绍矩阵的良好资源:
您可以看到移动到NDC造成的失真。从perspactive视点查看时需要这样做,但是当你向后变换时也需要考虑它。
如上所述的颜色选择对于采摘也是可行的,但仍需要一些工作。因为您有一个对象,所以您必须使用不同的颜色渲染图像的每个纹素,将其输出到单独的颜色缓冲区,检查缓冲区上的颜色,并以某种方式将其与空间中的某个点相关联。它可能会完成,但我会说颜色选择更适合多个对象。
根据我的阅读 - 深度缓冲区可能更适合您,因为它是一个对象,深度缓冲区将为您点击的每个点提供Z坐标。它仍然可以在你的飞机上,但它仍会给你一个价值。
或者,如@elect所建议的那样使用正交投影。