3

我在 Iphone OpenGL 中加载了一个波前对象。

在此处输入图像描述

它可以围绕 x/y 轴旋转、平移、放大/缩小。

我的任务是 - 当对象被点击时,在屏幕上突出显示它的 2d 中心坐标,例如:(想象 + 位于可见对象的中心。) 在此处输入图像描述

加载 OpenGL 对象时,我将其存储为:

  1. 世界中的对象中心位置,
  2. x,y,z 位置偏移,
  3. x,y,z 旋转,
  4. 缩放比例。

当用户点击屏幕时,我可以区分哪个对象被点击了。但是 - 由于用户可以点击对象上的任何位置 - 被点击的点不是中心。

当用户触摸一个物体时,我希望能够找出对应的物体可见近似中心坐标。

我怎样才能做到这一点?

我能找到的谷歌中的大多数代码都是为了 - 将 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();
4

1 回答 1

1

好的,正如我所说,您需要对对象中心应用相同的转换,这些转换通过图形管道应用于对象的顶点;只是这一次,图形管道对你没有帮助——你必须自己做。它涉及一些矩阵计算,所以我建议获得一个好的数学库,如OpenGL 数学库,它的优点是函数名称等与 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 作为第 4 个组件附加到对象中心(称为 'w-component' ),否则您不能将其与 4x​​4 矩阵相乘。

或者,您可以直接从 OpenGL 查询模型视图矩阵的当前值:

GLfloat matrix[16]; 
glGetFloatv (GL_MODELVIEW_MATRIX, matrix);

但是你必须为乘法编写自己的代码......

第 2 步:从模型视图坐标转到剪辑坐标

从您发布的内容来看,我无法判断您是否曾经更改过投影矩阵(某处是否有 glMatrixMode( GL_PROJECTION )?) - 如果您从未触摸过投影矩阵,则可以省略此步骤;否则,您现在还需要将变换后的对象中心与投影矩阵相乘。

第三步:透视分割

将对象中心的所有 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; 

基本上就是这样。

于 2013-05-15T21:52:03.827 回答