我在Iphone OpenGL中加载了一个wavefront对象。
它可以围绕x / y轴旋转,平移,放大/缩小。
我的任务是 - 当点击对象时,在屏幕上突出显示它的2d中心坐标,例如:(想象一下+位于可见对象的中心。)
加载OpenGL对象时,我存储它:
当用户点击屏幕时,我可以区分哪个对象被点击。但是 - 因为用户可以点击对象上的任何位置 - 点击点不是中心。
当用户触摸某个物体时,我希望能够找到相应的物体可见近似中心坐标。
我该怎么做?
我能找到的google中的大多数代码都意味着 - 将3d坐标转换为2d但没有旋转。
代码中的一些变量:
Vertex3D centerPosition;
Vertex3D currentPosition;
Rotation3D currentRotation;
//centerPosition.x, centerPosition.y, centerPosition.z
//currentPosition.x, currentPosition.y, currentPosition.z
//currentRotation.x, currentRotation.y, currentRotation.z
提前谢谢你。
(找出我点击的对象 - 以不同颜色重新着色每个对象,因此我知道用户点击了什么颜色。)
对象drawSelf函数:
// Save the current transformation by pushing it on the stack
glPushMatrix();
// Load the identity matrix to restore to origin
glLoadIdentity();
// Translate to the current position
glTranslatef(currentPosition.x, currentPosition.y, currentPosition.z);
// Rotate to the current rotation
glRotatef(currentRotation.x, 1.0, 0.0, 0.0);
glRotatef(currentRotation.y, 0.0, 1.0, 0.0);
glRotatef(currentRotation.z, 0.0, 0.0, 1.0);
// Enable and load the vertex array
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glNormalPointer(GL_FLOAT, 0, vertexNormals);
// Loop through each group
if (textureCoords != NULL)
{
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(valuesPerCoord, GL_FLOAT, 0, textureCoords);
}
for (OpenGLWaveFrontGroup *group in groups)
{
if (textureCoords != NULL && group.material.texture != nil)
[group.material.texture bind];
// Set color and materials based on group's material
Color3D ambient = group.material.ambient;
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, (const GLfloat *)&ambient);
Color3D diffuse = group.material.diffuse;
glColor4f(diffuse.red, diffuse.green, diffuse.blue, diffuse.alpha);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, (const GLfloat *)&diffuse);
Color3D specular = group.material.specular;
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, (const GLfloat *)&specular);
glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, group.material.shininess);
glDrawElements(GL_TRIANGLES, 3*group.numberOfFaces, GL_UNSIGNED_SHORT, &(group.faces[0]));
}
if (textureCoords != NULL)
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
// Restore the current transformation by popping it off
glPopMatrix();
答案 0 :(得分:1)
好吧,正如我所说,你需要将相同的变换应用到对象中心,这些变换由图形管道应用于对象的顶点;只有这一次,图形管道不会帮助你 - 你必须自己做。它涉及一些矩阵计算,所以我建议得到一个像the OpenGL Maths library这样的好的数学库,它具有功能名称等与OpenGL极其相似的优点。
步骤1:将中心形状对象坐标转换为模型视图坐标
在您的代码中,您可以像下面这样设置4x4模型视图矩阵:
// Load the identity matrix to restore to origin
glLoadIdentity();
// Translate to the current position
glTranslatef(currentPosition.x, currentPosition.y, currentPosition.z);
// Rotate to the current rotation
glRotatef(currentRotation.x, 1.0, 0.0, 0.0);
glRotatef(currentRotation.y, 0.0, 1.0, 0.0);
glRotatef(currentRotation.z, 0.0, 0.0, 1.0);
你需要将该矩阵与对象中心相乘,而OpenGL对此没有帮助,因为它本身不是数学库。如果你使用glm,有一些函数,如rotate(),translate()等功能类似于glRotatef()& glTranslatef(),您可以使用它们来构建模型视图矩阵。此外,由于矩阵是4x4,你必须将1.f作为第四个组件附加到对象中心(称为“w-component”),否则你不能将它与4x4矩阵相乘。
或者,您可以直接从OpenGl查询模型视图矩阵的当前值:
GLfloat matrix[16];
glGetFloatv (GL_MODELVIEW_MATRIX, matrix);
但是你必须为乘法编写自己的代码...
第2步:从modelview坐标转到剪辑坐标
从您发布的内容来看,我无法判断您是否更改了投影矩阵(某处是否存在glMatrixMode(GL_PROJECTION)?) - 如果您从未触摸投影矩阵,则可以省略此步骤;否则你现在需要将变换后的物体中心与投影矩阵相乘。第3步:透视划分
将对象中心的所有4个分量除以第4个 - 然后扔掉第4个分量,只保留xyz。 如果省略了第2步,则也可以省略除法。
第4步:将对象中心坐标映射到窗口坐标
现在,对象中心在标准化设备坐标中定义,x& y分量在[-1.f,1.f]范围内。最后一步是将它们映射到视口,即映射到像素位置。无论如何,z分量并不重要,所以让我们忽略z并调用x& y分别是obj_x和obj_y。
应使用glViewport( viewport_x, viewport_y, width, height )
在代码中的某处设置视口尺寸。从函数参数中,您可以像这样计算中心的像素位置:
pixel_x = width/2 * obj_x + viewport_x + width/2;
pixel_y = height/2 * obj_y + viewport_y + height/2;
基本上就是这样。