顶点在 Frustum 外的 OpenGL 透视投影裁剪多边形 = 错误的纹理映射?
OpenGL Perspective Projection Clipping Polygon with Vertex Outside Frustum = Wrong texture mapping?
我看到一个问题,如果所有顶点都保留在透视投影内的屏幕上,我可以正确绘制带纹理的多边形,但是如果我将四边形缩放到足够大,使得更多顶点落在 'too far behind' 查看体积,则生成的 OpenGL 绘图不正确(请参见屏幕截图)。纹理贴图变得倾斜,看起来就像是屏幕外的顶点 'moved' 并且变得扭曲了。我在 GLES 3.0 兼容驱动程序上使用 GLES 2.0 代码(底部有详细信息)。我现在将更详细地解释我的测试 --
我正在绘制一个由两个简单的多边形组成的 GL_TRIANGLE_STRIP 'square',并在四边形上应用简单的纹理贴图(纹理只在四边形上完美贴图一次,没有重复。UV 坐标0->1 映射如您所料。
另外,我使用 GLM 函数为矩阵转换提供帮助,随后使用 glm::PerspectiveFov() 设置观察体积(截锥体)。结果是一个相机稍微向下看四边形,创建一个 'ground' 像上面有方格图案纹理的表面。
correctly drawn view of quad screenshot
从这里开始,如果我进一步增加四边形的比例变换因子,或者旋转相机,使屏幕外的角顶点位于 'further back' 从观察区域,我会突然看到极端奇怪的行为,因为尽管纹理映射发生变化,或者多边形的一个顶点移动不正确。看这里:
polygon texture mapping becomes wrong
对于相机旋转,我使用 glm::lookAt() - 我有效地移动了 'eye' 位置,同时将场景中的目标保持在 0,0(多边形的中心)。
另请注意,当我超过此阈值时,我看到我绘制的连接所有顶点的红色调试线突然改变了其应有的方向。
有谁知道这个问题是怎么来的?有没有办法解决这个问题,这样我就可以绘制一个巨大的四边形并在没有这些 problems/artifacts 的情况下让顶点离开屏幕?谢谢!!!
GPU 信息:
GL 供应商:Vivante Corporation
GL 渲染器:Vivante GC2000
GL版本:OpenGL ES 3.0 V5.0.11.p8.41671
GLSL 版本:OpenGL ES GLSL ES 3.00
对我最初的问题的一些研究和评论使我相信观察到的效果是 Vivante GPU GC2000 上 OpenGL 驱动程序实现中的错误的结果。显然,此类错误在嵌入式 GPU 硬件驱动程序中很常见 - 此类 ES 实现的源代码永远不可用这一事实加剧了这一问题。
为了通过变通方法解决这个问题,我能够获取原始正方形的尺寸,而不是创建一个带纹理正方形的网格阵列,这样所有多边形最终都足够小 'fit' 足够接近到查看区域(或者完全剪裁,避免错误行为)。 C++ 代码:
// measurements we will add as we move along the grid
float tile_size = 1.0 / num_grid_subdivisions; // square width 1
float tile_uv_dist = 1.0 / num_grid_subdivisions; // assume 0->1 texture mapping
XY curr_bl = XY(-0.5, -0.5); // quad from -0.5 to 0.5 in x and y (1x1)
float cu = 0; //current texture coordinates in x dimension
float cv = 0; //current texture coordinates in y dimension
for (int row = 0; row < num_grid_subdivisions; ++row)
{
for (int row_item = 0; row_item < num_grid_subdivisions; ++row_item)
{
// GL_TRIANGLES to keep simple, but could use STRIP later
VertXYUV bl(curr_bl, cu, cv); // bottomleft
// if we know bottomleft, we know the rest of the points of the square
VertXYUV tl(XY(curr_bl.x, curr_bl.y + tile_size), cu, cv + tile_uv_dist);
VertXYUV br(XY(curr_bl.x + tile_size, curr_bl.y), cu+ tile_uv_dist, cv );
VertXYUV tr(XY(curr_bl.x + tile_size, curr_bl.y + tile_size),
cu + tile_uv_dist, cv + tile_uv_dist);
// our square tile is two triangle polygons
AddVert(bl); AddVert(tl); AddVert(br); // triangle 1
AddVert(br); AddVert(tl); AddVert(tr); // triangle 2
// current info should always be tracking 'bl' of current tile
// increment row item, moving across to the right (+x)
cu += tile_uv_dist;
curr_bl.x += tile_size;
}
// current info should always be tracking 'bl' of current tile
// incrementing row, moving up (+y)
cv += tile_uv_dist;
cu = 0; // reset x space texture coordinate back to left side (0)
curr_bl.y += tile_size;
curr_bl.x = grid_bl.x;
}
我看到一个问题,如果所有顶点都保留在透视投影内的屏幕上,我可以正确绘制带纹理的多边形,但是如果我将四边形缩放到足够大,使得更多顶点落在 'too far behind' 查看体积,则生成的 OpenGL 绘图不正确(请参见屏幕截图)。纹理贴图变得倾斜,看起来就像是屏幕外的顶点 'moved' 并且变得扭曲了。我在 GLES 3.0 兼容驱动程序上使用 GLES 2.0 代码(底部有详细信息)。我现在将更详细地解释我的测试 --
我正在绘制一个由两个简单的多边形组成的 GL_TRIANGLE_STRIP 'square',并在四边形上应用简单的纹理贴图(纹理只在四边形上完美贴图一次,没有重复。UV 坐标0->1 映射如您所料。
另外,我使用 GLM 函数为矩阵转换提供帮助,随后使用 glm::PerspectiveFov() 设置观察体积(截锥体)。结果是一个相机稍微向下看四边形,创建一个 'ground' 像上面有方格图案纹理的表面。
correctly drawn view of quad screenshot
从这里开始,如果我进一步增加四边形的比例变换因子,或者旋转相机,使屏幕外的角顶点位于 'further back' 从观察区域,我会突然看到极端奇怪的行为,因为尽管纹理映射发生变化,或者多边形的一个顶点移动不正确。看这里:
polygon texture mapping becomes wrong
对于相机旋转,我使用 glm::lookAt() - 我有效地移动了 'eye' 位置,同时将场景中的目标保持在 0,0(多边形的中心)。
另请注意,当我超过此阈值时,我看到我绘制的连接所有顶点的红色调试线突然改变了其应有的方向。
有谁知道这个问题是怎么来的?有没有办法解决这个问题,这样我就可以绘制一个巨大的四边形并在没有这些 problems/artifacts 的情况下让顶点离开屏幕?谢谢!!!
GPU 信息:
GL 供应商:Vivante Corporation
GL 渲染器:Vivante GC2000
GL版本:OpenGL ES 3.0 V5.0.11.p8.41671
GLSL 版本:OpenGL ES GLSL ES 3.00
对我最初的问题的一些研究和评论使我相信观察到的效果是 Vivante GPU GC2000 上 OpenGL 驱动程序实现中的错误的结果。显然,此类错误在嵌入式 GPU 硬件驱动程序中很常见 - 此类 ES 实现的源代码永远不可用这一事实加剧了这一问题。
为了通过变通方法解决这个问题,我能够获取原始正方形的尺寸,而不是创建一个带纹理正方形的网格阵列,这样所有多边形最终都足够小 'fit' 足够接近到查看区域(或者完全剪裁,避免错误行为)。 C++ 代码:
// measurements we will add as we move along the grid
float tile_size = 1.0 / num_grid_subdivisions; // square width 1
float tile_uv_dist = 1.0 / num_grid_subdivisions; // assume 0->1 texture mapping
XY curr_bl = XY(-0.5, -0.5); // quad from -0.5 to 0.5 in x and y (1x1)
float cu = 0; //current texture coordinates in x dimension
float cv = 0; //current texture coordinates in y dimension
for (int row = 0; row < num_grid_subdivisions; ++row)
{
for (int row_item = 0; row_item < num_grid_subdivisions; ++row_item)
{
// GL_TRIANGLES to keep simple, but could use STRIP later
VertXYUV bl(curr_bl, cu, cv); // bottomleft
// if we know bottomleft, we know the rest of the points of the square
VertXYUV tl(XY(curr_bl.x, curr_bl.y + tile_size), cu, cv + tile_uv_dist);
VertXYUV br(XY(curr_bl.x + tile_size, curr_bl.y), cu+ tile_uv_dist, cv );
VertXYUV tr(XY(curr_bl.x + tile_size, curr_bl.y + tile_size),
cu + tile_uv_dist, cv + tile_uv_dist);
// our square tile is two triangle polygons
AddVert(bl); AddVert(tl); AddVert(br); // triangle 1
AddVert(br); AddVert(tl); AddVert(tr); // triangle 2
// current info should always be tracking 'bl' of current tile
// increment row item, moving across to the right (+x)
cu += tile_uv_dist;
curr_bl.x += tile_size;
}
// current info should always be tracking 'bl' of current tile
// incrementing row, moving up (+y)
cv += tile_uv_dist;
cu = 0; // reset x space texture coordinate back to left side (0)
curr_bl.y += tile_size;
curr_bl.x = grid_bl.x;
}