【问题标题】:Resize only a part of texture, OpenGL仅调整纹理的一部分,OpenGL
【发布时间】:2012-12-13 14:23:59
【问题描述】:

我正在开发 OpenGL 中的 GUI。我正在使用此图像来纹理我的按钮:

你看不太清楚,但它周围有一个浅色边框(2 像素宽)。

我想要实现的是拥有可以很好地调整大小的按钮,使其边框保持不变。根据这里给我的提示,在 StackOverflow 上我决定使用 9 单元格模式,所以我将我的四边形分成 9 个部分,如下所示:

我真的很喜欢我在边界附近实现的效果,但问题在于中心(第 9 个)的四边形:

我想像我一样重复或包裹纹理,但忽略边框。

所以我的问题是 - 有没有办法只用我现在使用的一种纹理来做到这一点?或者我应该创建第二个纹理,它会减少一个边框宽度并用这个纹理在中间渲染这个四边形?

我也不知道是否有必要,但我在这里放了我的代码片段:

这是我用于平铺/包装纹理的代码:

switch(m_bTiling)
{
case true:
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
                     GL_REPEAT );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
                     GL_REPEAT );
    break;
case false:
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,
                     GL_CLAMP );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
                     GL_CLAMP );
    break;
}

这是绘制四边形的代码:

// Top left quad [1]
glBegin(GL_QUADS);
    // Bottom left
    glTexCoord2f(0.0f, 1.0-maxTexCoordBorderY);                     
    glVertex2i(pos.x, pos.y + m_borderWidth);

    // Top left
    glTexCoord2f(0.0f, 1.0);    
    glVertex2i(pos.x, pos.y);

    // Top right
    glTexCoord2f(maxTexCoordBorderX, 1.0);  
    glVertex2i(pos.x + m_borderWidth, pos.y);

    // Bottom right
    glTexCoord2f(maxTexCoordBorderX, 1.0-maxTexCoordBorderY);
    glVertex2i(pos.x + m_borderWidth, pos.y + m_borderWidth);
glEnd();

// Top middle quad [2]
glBegin(GL_QUADS);
    // Bottom left
    glTexCoord2f(maxTexCoordBorderX, 1.0 - maxTexCoordBorderY);             
    glVertex2i(pos.x + m_borderWidth, pos.y + m_borderWidth);

    // Top left
    glTexCoord2f(maxTexCoordBorderX, 1.0);
    glVertex2i(pos.x + m_borderWidth, pos.y);

    // Top right
    glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, 1.0);   
    glVertex2i(pos.x + width - m_borderWidth, pos.y);

    // Bottom right
    glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, 1.0 - maxTexCoordBorderY);
    glVertex2i(pos.x + width - m_borderWidth, pos.y + m_borderWidth);
glEnd();

// Top right quad [3]
glBegin(GL_QUADS);
    // Bottom left
    glTexCoord2f(1.0 - maxTexCoordBorderX, 1.0 - maxTexCoordBorderY);                   
    glVertex2i(pos.x + width - m_borderWidth, pos.y + m_borderWidth);

    // Top left
    glTexCoord2f(1.0 - maxTexCoordBorderX, 1.0);
    glVertex2i(pos.x + width - m_borderWidth, pos.y);

    // Top right
    glTexCoord2f(1.0, 1.0); 
    glVertex2i(pos.x + width, pos.y);

    // Bottom right
    glTexCoord2f(1.0, 1.0 - maxTexCoordBorderY);    
    glVertex2i(pos.x + width, pos.y + m_borderWidth);
glEnd();

// Middle left quad [4]
glBegin(GL_QUADS);
    // Bottom left
    glTexCoord2f(0.0, maxTexCoordBorderY);              
    glVertex2i(pos.x, pos.y + height - m_borderWidth);

    // Top left
    glTexCoord2f(0.0, maxTexCoordHeight - maxTexCoordBorderY);
    glVertex2i(pos.x, pos.y + m_borderWidth);

    // Top right
    glTexCoord2f(maxTexCoordBorderX, maxTexCoordHeight - maxTexCoordBorderY);           
    glVertex2i(pos.x + m_borderWidth, pos.y + m_borderWidth);

    // Bottom right
    glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);
    glVertex2i(pos.x + m_borderWidth, pos.y + height - m_borderWidth);
glEnd();

// Middle right quad [5] 
glBegin(GL_QUADS);
    // Bottom left
    glTexCoord2f(1.0 - maxTexCoordBorderX, maxTexCoordBorderY);                     
    glVertex2i(pos.x + width - m_borderWidth, pos.y + height - m_borderWidth);

    // Top left
    glTexCoord2f(1.0 - maxTexCoordBorderX, maxTexCoordHeight - maxTexCoordBorderY);
    glVertex2i(pos.x + width - m_borderWidth, pos.y + m_borderWidth);

    // Top right
    glTexCoord2f(1.0, maxTexCoordHeight - maxTexCoordBorderY);  
    glVertex2i(pos.x + width, pos.y + m_borderWidth);

    // Bottom right 
    glTexCoord2f(1.0, maxTexCoordBorderY);  
    glVertex2i(pos.x + width, pos.y + height - m_borderWidth);
glEnd();

// Bottom left quad [6]
glBegin(GL_QUADS);
    // Bottom left
    glTexCoord2f(0.0, 0.0);                     
    glVertex2i(pos.x, pos.y + height);

    // Top left
    glTexCoord2f(0.0, maxTexCoordBorderY);  
    glVertex2i(pos.x, pos.y + height - m_borderWidth);

    // Top right
    glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);   
    glVertex2i(pos.x + m_borderWidth, pos.y + height - m_borderWidth);

    // Bottom right
    glTexCoord2f(maxTexCoordBorderX, 0.0);  
    glVertex2i(pos.x + m_borderWidth, pos.y + height);
glEnd();

// Bottom middle quad [7]
glBegin(GL_QUADS);
    // Bottom left
    glTexCoord2f(maxTexCoordBorderX, 0.0);                          
    glVertex2i(pos.x + m_borderWidth, pos.y + height);

    // Top left
    glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);
    glVertex2i(pos.x + m_borderWidth, pos.y + height - m_borderWidth);

    // Top right
    glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, maxTexCoordBorderY);    
    glVertex2i(pos.x + width - m_borderWidth, pos.y + height - m_borderWidth);

    // Bottom right
    glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, 0.0);   
    glVertex2i(pos.x + width - m_borderWidth, pos.y + height);
glEnd();

// Bottom right quad [8]
glBegin(GL_QUADS);
    // Bottom left
    glTexCoord2f(1.0 - maxTexCoordBorderX, 0.0);                        
    glVertex2i(pos.x + width - m_borderWidth, pos.y + height);

    // Top left
    glTexCoord2f(1.0 - maxTexCoordBorderX, maxTexCoordBorderY);
    glVertex2i(pos.x + width - m_borderWidth, pos.y + height - m_borderWidth);

    // Top right
    glTexCoord2f(1.0, maxTexCoordBorderY);  
    glVertex2i(pos.x + width, pos.y + height - m_borderWidth);

    // Bottom right 
    glTexCoord2f(1.0, 0.0);
    glVertex2i(pos.x + width, pos.y + height);
glEnd();

// Middle middle quad [9]
glBegin(GL_QUADS);
    // Bottom left
    glTexCoord2f(maxTexCoordBorderX, maxTexCoordBorderY);                   
    glVertex2i(pos.x + m_borderWidth, pos.y + height - m_borderWidth);

    // Top left
    glTexCoord2f(maxTexCoordBorderX, maxTexCoordHeight - maxTexCoordBorderY);   
    glVertex2i(pos.x + m_borderWidth, pos.y + m_borderWidth);

    // Top right
    glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, maxTexCoordHeight - maxTexCoordBorderY);        
    glVertex2i(pos.x + width - m_borderWidth, pos.y + m_borderWidth);

    // Bottom right 
    glTexCoord2f(maxTexCoordWidth - maxTexCoordBorderX, maxTexCoordBorderY);
    glVertex2i(pos.x + width - m_borderWidth, pos.y + height - m_borderWidth);
glEnd();

【问题讨论】:

  • 请注意,由于内部的颜色渐变,您的纹理不容易平铺。您可以尝试从近似 (x=2,y=20,w=18,h=18) 中取一个四边形并将其平铺以获得更好的结果

标签: user-interface opengl graphics 2d textures


【解决方案1】:

嗯 - 我明白你的问题。您正在为“中间中间”四边形使用 maxTexCoordBorderX(和 Y)的常量值。您需要随着尺寸的变化重新计算中心四边形的 UV 坐标(例如:width / (currWidth - 2 * borderWidth)),然后您可以将该纹理设置为始终重复,但是由于您将纹理坐标修改为 ui 元素调整大小,中心部分将永远不会重复。

当然 - 如果您打算在未来某个时间点使用 VBO 或性能更高的东西,您可以简单地定义两个片段着色器(每个都有自己的 sampler2D 对象;一个重复,另一个拉伸)用于每个平铺模式,并使用“重复”着色器渲染所有角四边形和中间中间四边形,使用拉伸着色器渲染所有边缘四边形。这不需要重新计算并且应该非常快。

注意:您在此处绘制多个四边形,这不是一个好主意。我建议使用具有共享顶点的索引网格。这将最大限度地减少四边形边缘“撕裂”的可能性。

【讨论】:

  • 感谢 Ananthonline 的回答。不过我还有一个问题——我对这个现代 OpenGL 完全不了解,所以我必须阅读有关 VBO 和休息的信息,但是是否可以用“现代”代码替换这个绘制四边形的代码,或者我会必须更改所有设置等?也比这个旧版本难很多吗?
  • 你可以做一个简单的替换——而不是两个着色器,使用一个带有统一控制的着色器来控制要使用的采样器(重复或拉伸)并在绘制每个四边形之前适当地设置它。在即时模式绘图中使用两个着色器的问题在于,您将在绘制单个四边形时进行多次更改,并且更改状态通常不利于性能。理想情况下,您应该收集具有相同状态的所有状态并尽可能批量渲染它们(在设置该状态之后)。这里 (lighthouse3d.com/opengl/glsl) 是一个 GLSL 教程,可以帮助您入门。
【解决方案2】:

如果你拉伸边缘/中心,你会很好,但由于你是平铺的,你将不得不创建一个只有中心部分的第二个纹理。

请注意,如果您有边框的大小,这可以通过编程方式完成。您可以将中心的内容复制到一个新的二维数组中,然后将其上传到另一个纹理。

另一个解决方案(正如我在评论中所说)是将中间中间四边形的纹理坐标设置为与角的内部顶点相同的坐标。这样,中心四边形的纹理就被拉伸了。请注意,除非整个东西都包含在右上角的四边形中,否则这会在右上角的光亮上产生一些奇怪的拉伸。如果您想使用重复解决方案,您仍然会遇到此问题。

如果您仍想重复中心部分并且不介意将整个渲染管道移动到未弃用的 OpenGL,那么 ananthonline 的答案会更好。如果您不想/不能将渲染代码移动到更现代的 OpenGL,那么纹理副本几乎是唯一的解决方案。

【讨论】:

  • 感谢 Robert 的回答,但拉伸边缘/中心是什么意思?您的意思是使用 GL_CLAMP 而不是 GL_REPEAT?
  • 不具体,您只需将中心四边形的纹理坐标定义为角块内部的相同纹理坐标。这样纹理的中心就会延伸到中心四边形。
  • 您必须编写更多样板代码。在即时模式下,每个顶点有多种方法,在现代 OpenGL 中,您的顶点数据存储在一个大数组中并存储在 GPU 上,称为缓冲区对象。当您创建缓冲区对象时,您会获得它的句柄并使用它将该数组绑定为将要绘制的顶点数组。
  • 除此之外,您还有着色器。这些是一种叫做 GLSL 的类 C 语言的相对较小的部分,您编写它来告诉 GPU 如何将您的顶点转换为屏幕空间以及如何为三角形内的每个像素着色。另一个答案建议您应该编写其中一个着色器来计算您认为重复的偏移量,而不是 OpenGL 认为重复的偏移量。
  • 如果你确实想了解现代 OpenGL,我推荐这个教程:open.gl
猜你喜欢
  • 1970-01-01
  • 2013-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-23
  • 1970-01-01
  • 2014-08-10
  • 1970-01-01
相关资源
最近更新 更多