【发布时间】:2020-03-08 09:59:00
【问题描述】:
我正在为 GWEN (GUI Without Extravagant Nonsense) 编写 Vulkan 渲染器,但在获取纹理坐标以匹配时遇到问题。
中心显示的纹理是我们用于 GUI 的图像,我确保测试将其渲染为四边形以确保正确加载它。
GUI 的结构似乎是正确的,这让我相信 UV 坐标不正确。特别是 Y 坐标,因为据我所知,X 看起来不错。
void Vulkan::AddVert(int x, int y, float u, float v)
{
vertices.emplace_back();
vertices.back().pos.x = ((float)x / 400) - 1.f;
vertices.back().pos.y = ((float)y / 300) - 1.f;
// Our image is 512x512 px
vertices.back().texCoord.x = (u / 512.0f);
vertices.back().texCoord.y = 1.0f - (v / 512.0f);
}
void Vulkan::DrawTexturedRect(Gwen::Texture* pTexture, Gwen::Rect rect, float u1, float v1, float u2, float v2)
{
// ToDo: Implement textures through GWEN
// The GUI texture is hardcoded for now
// Once we're rendering properly i'll expand this function to handle textures
Translate(rect);
AddVert(rect.x, rect.y, u1, v1);
AddVert(rect.x + rect.w, rect.y, u2, v1);
AddVert(rect.x, rect.y + rect.h, u1, v2);
AddVert(rect.x + rect.w, rect.y, u2, v1);
AddVert(rect.x + rect.w, rect.y + rect.h, u2, v2);
AddVert(rect.x, rect.y + rect.h, u1, v2);
}
该库构建一个顶点向量,然后最终每帧渲染顶点缓冲区。
作为参考,这里是来自 OpenGL 示例渲染器的相同函数:
void OpenGL::AddVert( int x, int y, float u, float v )
{
m_Vertices[ m_iVertNum ].x = ( float ) x;
m_Vertices[ m_iVertNum ].y = ( float ) y;
m_Vertices[ m_iVertNum ].u = u;
m_Vertices[ m_iVertNum ].v = v;
m_Vertices[ m_iVertNum ].r = m_Color.r;
m_Vertices[ m_iVertNum ].g = m_Color.g;
m_Vertices[ m_iVertNum ].b = m_Color.b;
m_Vertices[ m_iVertNum ].a = m_Color.a;
m_iVertNum++;
}
void OpenGL::DrawTexturedRect(Gwen::Texture* pTexture, Gwen::Rect rect, float u1, float v1, float u2, float v2)
{
GLuint* tex = ( GLuint* ) pTexture->data;
// Missing image, not loaded properly?
if ( !tex )
{
return DrawMissingImage( rect );
}
Translate(rect);
GLuint boundtex;
GLboolean texturesOn;
glGetBooleanv( GL_TEXTURE_2D, &texturesOn );
glGetIntegerv( GL_TEXTURE_BINDING_2D, ( GLint* ) &boundtex );
if ( !texturesOn || *tex != boundtex )
{
Flush();
glBindTexture( GL_TEXTURE_2D, *tex );
glEnable( GL_TEXTURE_2D );
}
AddVert(rect.x, rect.y, u1, v1);
AddVert(rect.x + rect.w, rect.y, u2, v1);
AddVert(rect.x, rect.y + rect.h, u1, v2);
AddVert(rect.x + rect.w, rect.y, u2, v1);
AddVert(rect.x + rect.w, rect.y + rect.h, u2, v2);
AddVert(rect.x, rect.y + rect.h, u1, v2);
}
我知道 Vulkan 将纹理坐标从 0.0 带到 1.0,这就是为什么我将 u 和 v 除以纹理大小 512 x 512。我也知道 Vulkan 使用图像的左下角为0,0,这就是我翻转 Y 坐标的原因。可悲的是,我仍然得到不正确的输出。我已经为texCoord.x 和texCoord.y 尝试了许多组合,但我永远无法获得正确的输出。有谁知道我在这里可能做错了什么?
编辑 将纹理除以 128 而不是 512 会产生正确的结果。我不明白为什么这解决了我的问题。纹理大小确实是 512x512 单位,所以除以 512 应该给我一个 0.0-1.0 的范围?相反,我只除以纹理大小的 1/4 的 128 来得到我的 0.0-1.0 范围?
vertices.back().texCoord.x = (u / 128);
vertices.back().texCoord.y = (v / 128);
【问题讨论】:
-
C++ 代码中的顶点布局与您提供给 Vulkan 的顶点描述之间是否存在不匹配的可能性?即,也许
texCoord.x和texCoord.y是正确的,但在数据到达顶点着色器时正在使用其他值。 -
重新运行程序会产生完全相同的输出。更改用于生成
texCoord.x和texCoord.y值的公式将在视觉上改变输出,因此着色器肯定会接收我们为texCoord.x和texCoord.y设置的值。例如,除以256或128而不是512在视觉上扩大了应用于GUI 的纹理,UV 映射完全错误。 -
texCoord.x = (u / 512.0f)应该将坐标标准化为0.0 (left)->1.0 (right)和texCoord.y = 1.0f - (v / 512.0f)应该将坐标标准化为0.0 (bottom)->1.0 (top)。除非应用程序中有其他问题,在这个阶段给我不正确的 UV 坐标。难道u1u2v1和v2需要在Vulkan::DrawTexturedRect内部重新排序? -
texCoord.y应该从上到下。这就是在 Vulkan 中对纹理进行采样的方式。
标签: c++ opengl vulkan normalize uv-mapping