OpenGL透视投影裁剪多边形,顶点在视锥外=错误的纹理映射?
我看到一个问题,如果所有顶点都保留在透视投影中的屏幕上,我可以正确绘制带纹理的多边形,但是如果我将四边形缩放到足够大,使得再有一个顶点落在查看体积太远"之后,那么生成的 OpenGL 绘图不正确(参见屏幕截图).纹理映射变得倾斜,并且看起来好像屏幕外的顶点移动"并变得扭曲.我在符合 GLES 3.0 的驱动程序上使用 GLES 2.0 代码(详细信息在底部).我现在将更详细地解释我的测试--
I see an issue where I can correctly draw a textured polygon if all vertices remain onscreen within a perspective projection, BUT if I scale the quad large enough such that one more more vertices fall 'too far behind' the viewing volume, then the resulting OpenGL drawing is incorrect (see screenshots). The texture mapping becomes skewed, and it appears as though the offscreen vertex 'moved' and becomes distorted. I am using GLES 2.0 code on a GLES 3.0 compliant driver (details at bottom). I will now explain my test in more detail --
我正在绘制一个由两个简单多边形组成的 GL_TRIANGLE_STRIP正方形",并在四边形上应用简单的纹理贴图(纹理只完美地映射到四边形上一次,没有重复.UV 坐标 0->1 映射如您所愿期待.
I am drawing a GL_TRIANGLE_STRIP 'square' made of two simple polygons, and applying simplistic texture map on the quad (the texture maps perfectly onto the quad once only, with no repeats. UV coordinates 0->1 mapped as you would expect.
另外,我使用 GLM 函数为矩阵转换提供帮助,随后使用 glm::PerspectiveFov() 设置查看体积(截锥体).结果是相机略微向下看四边形,创建了一个类似地面"的表面,上面带有棋盘格纹理.
Seperately, I am using GLM functions to give me helpers for matrix transformations, and subsequently using glm::PerspectiveFov() to set up the viewing volume (frustum). The result is a camera looking slightly downward onto the quad, creating a 'ground' like surface with a checker patterned texture on it.
四屏截图的正确绘制视图
从这里开始,如果我进一步增加四边形上的比例变换因子,或者旋转相机以使屏幕外角顶点位于距离查看区域更远"的位置,我会突然看到极端奇怪的行为,就好像纹理映射发生变化,或者多边形的一个顶点移动不正确.见这里:
From here, if I increase the scale transformation factor on the quad any further, or rotate the camera such that the offscreen corner vertices lie 'further back' from the viewing area, I see suddenly extreme weird behavior, as though the texture mapping changes, or if one vertex of the polygon is shifting incorrectly. See here:
多边形纹理映射出错
对于相机旋转,我使用 glm::lookAt() - 实际上我移动了眼睛"位置,同时将目标保持在场景中的 0,0(多边形中心).
For the camera rotation I am using glm::lookAt() -- effectively I move the 'eye' position while keeping the target at 0,0 in the scene (center of the polygon).
还要注意,当我越过这个阈值时,我看到我绘制的连接所有顶点的红色调试线突然改变了它应该在的位置.
Also note that when I cross this threshold, I see the red debug line I draw connecting all the vertices suddenly shift its orientation from where it should be.
有人知道这个问题是怎么产生的吗?有没有办法解决它,这样我就可以绘制一个巨大的四边形并且在没有这些问题/伪影的情况下在屏幕外有顶点?谢谢!!!
Does anyone know how this problem originates? Is there a way to solve it so I can draw a big huge quad and have vertices offscreen without these problems/artifacts? Thanks!!!
GPU 信息:
GL 供应商:Vivante Corporation
GL Vendor: Vivante Corporation
GL 渲染器:Vivante GC2000
GL Renderer: Vivante GC2000
GL 版本:OpenGL ES 3.0 V5.0.11.p8.41671
GL Version: OpenGL ES 3.0 V5.0.11.p8.41671
GLSL 版本:OpenGL ES GLSL ES 3.00
GLSL Version: OpenGL ES GLSL ES 3.00
推荐答案
对我最初的问题的一些研究和评论使我相信观察到的效果是 Vivante GPU GC2000 上的 OpenGL 驱动程序实现中的错误的结果.显然,此类错误在嵌入式 GPU 硬件驱动程序中很常见 - 由于此类 ES 实现的源代码永远不可用,这一问题更加严重.
Some research and comments on my original question have led me to believe that the observed effect is the result of a bug in the OpenGL driver implementation on the Vivante GPU GC2000. Apparently such bugs are common on embedded GPU hardware drivers - a problem exacerbated by the fact that the source code for such ES implementations is never available.
为了通过一种变通方法解决这个问题,我能够获取原始正方形的尺寸,而是创建一个纹理正方形的网格阵列,这样所有多边形最终都足够小,可以适合"到足够靠近查看区域(或者完全剪裁,避免错误行为).C++ 代码:
To solve this one via a workaround, I was able to take the dimensions of my original square and instead create a grid array of textured squares so that all polygons end up being small enough to 'fit' close enough to the viewing area (or alternatively be completely clipped, avoiding the bug behavior). Code in 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;
}
相关文章