2009-02-19 32 views
3

我已创建了OpenGL中的regular dodecahedron。我想让脸部变得透明(如维基百科上的图片),但这并不总是奏效。在OpenGL文档中进行了一些挖掘之后,看起来我“需要sort the transparent faces from back to front”。嗯。我怎么做?一些面是透明的,其它是不透明

我的意思是我请glRotatef()来旋转坐标系,但面的基准坐标保持不变;旋转效果应用于我的代码“外部”。

如果我申请改造的坐标,那么一切将停止移动。

我怎么能在这种情况下,面排序?

[编辑]我知道为什么发生这种情况。我不知道解决方案可能是什么样子。有人可以指示我去正确的OpenGL调用或一段示例代码吗?我知道什么时候坐标变换完成,并且我有人脸顶点的坐标。我知道如何计算面的中心坐标。我知道我需要用Z值对它们进行排序。如何通过当前视图矩阵(或者称为旋转我的坐标系的任何东西)来转换Vector3f?

代码以旋转视图:

glRotatef(xrot, 1.0f, 0.0f, 0.0f); 
    glRotatef(yrot, 0.0f, 1.0f, 0.0f); 
+0

您的代码是否适用于不透明的面部?我问,因为我遇到了同样的问题,但面对不透明 - 即使我正确设置法线,脸部不能正确渲染。 – diciu 2009-02-19 14:19:29

回答

3

当OpenGL文档说“排序透明面”时,它的意思是“改变顺序你画他们“。您不会自己变换人脸的几何图形,而是确保按照正确的顺序绘制人脸:距离相机最远的位置,距离相机最近的位置,以便在帧缓冲区中正确混合颜色。

这样做的一种方法是为每个透明面计算距摄像机的代表距离(例如,其中心距摄像机中心的距离),然后对该代表的透明面列表进行排序距离。

您需要这样做,因为OpenGL使用Z-buffering技术。 (我应该补充一点,“根据脸部中心距离排序”的技术有点幼稚,并且在脸部很大或靠近相机的情况下会导致错误的结果,但这很简单并让你开始,就会有足够的时间后担心更复杂的方法,以Z分类)


更新:阿龙,你澄清后,表明你理解了上面的,但不知道如何计算每个脸部的合适Z值。是对的吗?我通常会通过测量从相机到相关脸部的距离来做到这一点。所以我想这意味着你不知道相机在哪里?

如果这是你所遇到的问题的一个正确的说法,看OpenGL FAQ 8.010

至于OpenGL的来讲,有没有摄像头。更具体地说,相机总是位于眼睛空间坐标(0.,0,0,0)处。

更新:也许问题是,你不知道如何通过模型视图矩阵来转换点?如果即:OpenGL FAQ 9.130

将点乘以ModelView矩阵,将点转换为眼坐标空间。然后简单地计算它与原点的距离。

使用glGetFloatv(GL_MODELVIEW_MATRIX, dst)可以将模型视图矩阵作为16个浮点的列表。我认为你必须自己完成乘法运算:据我所知,OpenGL并没有为此提供API。

0

你试过只绘制每个面,相对于普通的世界,从后到前的坐标?通常看起来,某些OpenGL文档中的措辞很奇怪。我认为如果您以正确的顺序得到绘图而不用担心旋转,那么当您添加旋转时它可能会自动工作。旋转矩阵时,OpenGL可能会处理面的重新排序。

或者,您可以在绘制时抓取当前矩阵(glGetMatrix()),并根据哪些面将旋转后/前重新排列绘图算法。

+0

按世界坐标排序:不起作用。 – 2009-02-19 14:47:42

+0

lwjgl中没有调用glGetMatrix();是GL_MODELVIEW_MATRIX还是GL_PROJECTION_MATRIX? – 2009-02-19 15:00:05

0

这句话说明了一切 - 你需要排序面部。

当绘制这样一个简单的对象可以只使后端面的第一和正面向着第二使用Z缓冲器(通过用不同的z缓冲器比较函数渲染两次)。

但通常,你只是要变换的对象,然后面排序。您只需在内存中转换对象的表示形式,然后通过排序确定绘图顺序,然后使用原始坐标按顺序绘制,并根据需要使用转换(需要与已完成的排序一致)。在一个真正的应用程序中,你可能会隐式地进行转换,例如。通过将场景存储为BSP或四维或R或任意树并从各个方向简单地遍历树。

请注意,排序部分可能会很棘手,因为函数“is-obsucred-by”是您想要比较脸部的函数(因为您需要首先绘制遮挡的脸部)不是排序,例如。可以有周期(面A遮掩B)。在这种情况下,您可能会拆分其中一个面来打破循环。

编辑:

你得到一个顶点通过采取传递给glVertex3f()坐标通过追加1 z坐标,使其4D(齐次坐标),与模型视图矩阵变换,然后用改造它投影矩阵,然后做透视分割。详细信息请参阅第2章中的OpenGL规范,坐标转换部分。

但是,没有任何API可以实际进行转换。 OpenGL允许你做的唯一事情就是绘制原语,并告诉渲染器如何绘制它们(例如,如何转换它们)。它不会让您轻松转换坐标或其他任何东西(尽管IIUC是告诉OpenGL将转换后的坐标写入缓冲区的方法,但这并不容易)。如果你想要一些库来帮助你操纵实际的物体,坐标等,可以考虑使用某种场景图库(OpenInventor或其他)

+0

如何获取脸部的Z坐标? – 2009-02-19 15:07:52

1

作为参考,这里是代码(使用lwjgl 2.0.1)。我通过使用浮动数组的数组为坐标定义我模型:

 float one = 1f * scale; 

     // Cube of size 2*scale 
     float[][] coords = new float[][] { 
      { one, one, one }, // 0 
      { -one, one, one }, 
      { one, -one, one }, 
      { -one, -one, one }, 
      { one, one, -one }, 
      { -one, one, -one }, 
      { one, -one, -one }, 
      { -one, -one, -one }, // 7 
     }; 

面在INT数组的数组定义。内阵列中的项目是顶点的索引:

 int[][] faces = new int[][] { 
      { 0, 2, 3, 1, }, 
      { 0, 4, 6, 2, }, 
      { 0, 1, 5, 4, }, 
      { 4, 5, 7, 6, }, 
      { 5, 1, 3, 7, }, 
      { 4, 5, 1, 0, }, 
     }; 

这些行加载模型/视图矩阵:

 Matrix4f matrix = new Matrix4f(); 
     FloatBuffer params = FloatBuffer.allocate (16); 
     GL11.glGetFloat (GL11.GL_MODELVIEW_MATRIX, params); 
     matrix.load (params); 

我存储每个面的一些信息存储在面部类:

public static class Face 
{ 
    public int id; 
    public Vector3f center; 

    @Override 
    public String toString() 
    { 
     return String.format ("%d %.2f", id, center.z); 
    } 
} 

然后使用该比较器按Z深度对面部进行分类:

public static final Comparator<Face> FACE_DEPTH_COMPARATOR = new Comparator<Face>() 
{ 
    @Override 
    public int compare (Face o1, Face o2) 
    { 
     float d = o1.center.z - o2.center.z; 
     return d < 0f ? -1 : (d == 0 ? 0 : 1); 
    } 

}; 

getCenter()返回一个面的中心:

public static Vector3f getCenter (float[][] coords, int[] face) 
    { 
     Vector3f center = new Vector3f(); 
     for (int vertice = 0; vertice < face.length; vertice ++) 
     { 
      float[] c = coords[face[vertice]]; 
      center.x += c[0]; 
      center.y += c[1]; 
      center.z += c[2]; 
     } 
     float N = face.length; 
     center.x /= N; 
     center.y /= N; 
     center.z /= N; 
     return center; 
    } 

现在我需要设置的面阵列:

 Face[] faceArray = new Face[faces.length]; 
     Vector4f v = new Vector4f(); 
     for (int f = 0; f < faces.length; f ++) 
     { 
      Face face = faceArray[f] = new Face(); 
      face.id = f; 
      face.center = getCenter (coords, faces[f]); 
      v.x = face.center.x; 
      v.y = face.center.y; 
      v.z = face.center.z; 
      v.w = 0f; 
      Matrix4f.transform (matrix, v, v); 
      face.center.x = v.x; 
      face.center.y = v.y; 
      face.center.z = v.z; 
     } 

这个循环后,我有转化的中心向量在faceArray和我可以通过Z值进行排序:

 Arrays.sort (faceArray, FACE_DEPTH_COMPARATOR); 
     //System.out.println (Arrays.toString (faceArray)); 

渲染发生在另一个嵌套循环:

 float[] faceColor = new float[] { .3f, .7f, .9f, .3f }; 
     for (Face f: faceArray) 
     { 
      int[] face = faces[f.id]; 
      glColor4fv(faceColor); 

      GL11.glBegin(GL11.GL_TRIANGLE_FAN); 
      for (int vertice = 0; vertice < face.length; vertice ++) 
      { 
       glVertex3fv (coords[face[vertice]]); 
      } 
      GL11.glEnd(); 
     }