Python openGL中不正确的遮挡、正面剔除
我正在使用自己的算法剔除不应该显示的被遮挡的正面。当我不剔除人脸时,我有一组完美的块。当我启用面部剔除时,我得到了意想不到的结果。我已经检查了我的剔除代码,我相信它正确地剔除了适当的面 为了简单起见,我已将输出减少到9个框的平面。作为一个例子,在飞机中部的箱子只需要一个顶面和一个底面。所有其他面都可以被丢弃,因为它们在任何地方都不会被看到 我检查了代码中的每个框,以确定它们是否剔除了正确的面,我相信它们确实如此。这让我觉得这是顶点、索引或法线的问题 我正在使用python的Pyglet,它自动创建和管理VAO和VBO OpenGL设置:Python openGL中不正确的遮挡、正面剔除,python,opengl,pyglet,culling,Python,Opengl,Pyglet,Culling,我正在使用自己的算法剔除不应该显示的被遮挡的正面。当我不剔除人脸时,我有一组完美的块。当我启用面部剔除时,我得到了意想不到的结果。我已经检查了我的剔除代码,我相信它正确地剔除了适当的面 为了简单起见,我已将输出减少到9个框的平面。作为一个例子,在飞机中部的箱子只需要一个顶面和一个底面。所有其他面都可以被丢弃,因为它们在任何地方都不会被看到 我检查了代码中的每个框,以确定它们是否剔除了正确的面,我相信它们确实如此。这让我觉得这是顶点、索引或法线的问题 我正在使用python的Pyglet,它自动创
glEnable(GL_DEPTH_TEST)
glEnable(GL_CULL_FACE)
OpenGL绘图:
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
顶点代码:
v0 = [1, 1, 1]
v1 = [-1, 1, 1]
v2 = [-1, -1, 1]
v3 = [1, -1, 1]
v4 = [1, -1, -1]
v5 = [1, 1, -1]
v6 = [-1, 1, -1]
v7 = [-1, -1, -1]
pt = self.point
s = getattr(self, 'scale', 0.5)
faces = ((k, v) for k, v in (
('front', [v * s + p for vert in [v0, v1, v2, v3]
for v, p in zip(vert, pt)]),
('right', [v * s + p for vert in [v0, v3, v4, v5]
for v, p in zip(vert, pt)]),
('top', [v * s + p for vert in [v0, v5, v6, v1]
for v, p in zip(vert, pt)]),
('left', [v * s + p for vert in [v1, v6, v7, v2]
for v, p in zip(vert, pt)]),
('bottom', [v * s + p for vert in [v7, v4, v3, v2]
for v, p in zip(vert, pt)]),
('back', [v * s + p for vert in [v4, v7, v6, v5]
for v, p in zip(vert, pt)]))
if getattr(self, k)
)
法线代码:
verts_per_face = 4
faces = ((k, v) for k, v in (
('front', [0, 0, 1] * verts_per_face),
('right', [1, 0, 0] * verts_per_face),
('top', [0, 1, 0] * verts_per_face),
('left', [-1, 0, 0] * verts_per_face),
('bottom', [0, -1, 0] * verts_per_face),
('back', [0, 0, -1] * verts_per_face))
if getattr(self, k)
)
索引代码:
t0 = [0, 1, 2]
t1 = [2, 3, 0]
t2 = [4, 5, 6]
t3 = [6, 7, 4]
t4 = [8, 9, 10]
t5 = [10, 11, 8]
t6 = [12, 13, 14]
t7 = [14, 15, 12]
t8 = [16, 17, 18]
t9 = [18, 19, 16]
t10 = [20, 21, 22]
t11 = [22, 23, 20]
triangles = ((k, v) for k, v in (
('front', [t for triangle in [t0, t1] for t in triangle]),
('right', [t for triangle in [t2, t3] for t in triangle]),
('top', [t for triangle in [t4, t5] for t in triangle]),
('left', [t for triangle in [t6, t7] for t in triangle]),
('bottom', [t for triangle in [t8, t9] for t in triangle]),
('back', [t for triangle in [t10, t11] for t in triangle]))
if getattr(self, k)
)
剔除代码:
for face, neighbor_point in block.neighbors():
# import pdb; pdb.set_trace()
if neighbor_point in pts:
neighbor = self.blocks.get(neighbor_point)
if neighbor:
setattr(block, face, False)
else:
setattr(block, face, True)
else:
setattr(block, face, True)
剔除其中一个长方体上的前表面和左表面后的输出示例:
<Voxel (1,0,1) # top right corner box in images /w center point = (1, 0, 1)
[f r t l o a] # front, right, top, left, bottom, back
[ |+|+| |+|+] # + = face available, ' ' = face culled
(1, 0, 0) (1, 0, 0) (1, 0, 0) (1, 0, 0) # right normals
(0, 1, 0) (0, 1, 0) (0, 1, 0) (0, 1, 0) # top normals
(0, -1, 0) (0, -1, 0) (0, -1, 0) (0, -1, 0) # bottom normals
(0, 0, -1) (0, 0, -1) (0, 0, -1) (0, 0, -1) # back normals
[ 1.50| 0.50| 1.50| # right verts
1.50|-0.50| 1.50|
1.50|-0.50| 0.50|
1.50| 0.50| 0.50|
1.50| 0.50| 1.50| # top verts
1.50| 0.50| 0.50|
0.50| 0.50| 0.50|
0.50| 0.50| 1.50|
0.50|-0.50| 0.50| # bottom verts
1.50|-0.50| 0.50|
1.50|-0.50| 1.50|
0.50|-0.50| 1.50|
1.50|-0.50| 0.50| # back verts
0.50|-0.50| 0.50|
0.50| 0.50| 0.50|
1.50| 0.50| 0.50]>
有关如何实现剔除算法,请参见。在筛选代码中,您正在做一些完全无关的事情。若要确定是否应剔除面,您只需检查其缠绕顺序(假设您提供了所有与其法线相关的按CW或CCW顺序排列的三角形)。如果您的三角形没有排序,那么为了确定剔除,您必须检查三角形顶点的z顺序,这是图形卡自动执行的。如果您决定自己实现这一点,您将有效地实现软件渲染(尽管渲染是三角形片段,而不是单个像素)。我没有正确计算索引。新方法应为:
t0 = [0, 1, 2]
t1 = [2, 3, 0]
t2 = [4, 5, 6]
t3 = [6, 7, 4]
t4 = [8, 9, 10]
t5 = [10, 11, 8]
t6 = [12, 13, 14]
t7 = [14, 15, 12]
t8 = [16, 17, 18]
t9 = [18, 19, 16]
t10 = [20, 21, 22]
t11 = [22, 23, 20]
triangles = ((k, v) for k, v in (
('front', [t for triangle in [t0, t1] for t in triangle]),
('right', [t for triangle in [t2, t3] for t in triangle]),
('top', [t for triangle in [t4, t5] for t in triangle]),
('left', [t for triangle in [t6, t7] for t in triangle]),
('bottom', [t for triangle in [t8, t9] for t in triangle]),
('back', [t for triangle in [t10, t11] for t in triangle]))
)
inds = []
faces = [f for f, v in self.faces if v]
for triangle, face in zip(triangles, faces):
f, tdata = triangle
inds.extend(tdata)
我有点太懒了,看不懂你所有的代码。但我认为你对什么是面部剔除有一个基本的误解。您在“剔除”下发布的代码没有任何意义。gl侧gl_CULL_面上的消隐是完全自动的。理解它的最简单方法是它是二维的。计算每个结果二维三角形的面积。如果是负数,则为后向。你可以很容易地画这个。3个顶点,绘制三角形0,1,2和2,1,0。形状相同,但该区域的标志不同。这与邻居或普通人无关!只是2d缠绕。整个3d效果都很好,因为在投影下缠绕不会改变。但它实际上是一个2d的东西。作为练习,了解如何计算由三个索引0、1、2定义的具有3个顶点的二维三角形的面积。然后对索引2,1,0执行同样的操作。我试图删除从未见过的前向三角形。作为一个简单的例子,中间的长方体只需要一个顶面和一个底面——所有其他面都被另一个长方体共享,并且永远看不到。您可以执行仅深度预传递来消除线框中的内部面。从技术上讲,它不会剔除任何东西,只是通过第二次深度测试失败来防止这些面被着色。因为这听起来更像是为了减少顶点处理负载,所以我不认为这是您真正想要的。但老实说,在这个简单的例子中,识别被遮挡的人脸没有任何好处,它需要的处理时间比它节省的要多。即使你将其放大到更多的三角形(在合理范围内),这也是正确的。你是针对特定的平台吗?因为您使用的是Python,所以我认为它不是移动类GPU,而移动类GPU部分具有非常不同的体系结构。大多数传统的GPU在片段着色器之前进行深度测试。如果可以前后渲染几何体(使用网格中的块可能相当容易),则隐藏面将在片段着色器之前消除。这可能是你能做的最好的了。我怀疑在CPU上应用逻辑,特别是在Python中,会比让GPU消除不可见的面更有效。事实上,当我以后有大约350000个额外的面时,这一点就变得很重要了。我不是要删除“后向”三角形。正如您所指出的,这已经是自动完成的。然而,我试图剔除那些永远看不到的正面三角形。我确实认为这可能是一个棘手的问题。但我不确定为什么我的前向三角形在所有人都在场的情况下都能正常工作,但在有些人不在场的情况下却显得不正确。@Brian,好吧,我想我现在更明白了。在这种情况下,我不知道有什么办法可以满足你的要求。