OpenTK/OOpenGL混合半透明纹理问题
本文关键字:纹理 问题 半透明 混合 OOpenGL OpenTK | 更新日期: 2023-09-27 18:19:30
我正在使用C#中的OpenTK为一个游戏开发2D菜单。目前,菜单分为3个不同的纹理四边形或"层",看起来像这样。
第1层:按钮的基本外观。
第2层:当鼠标悬停在"继续"按钮上时,它的外观。
第三层:一个"齿轮",用来固定按钮以及它们的文本/名称。
这些层中的每一层都由绑定到Quad的半透明(32-bit.png)纹理组成。当仅绘制层1&3,纹理似乎工作正常,但当我想显示第2层时,第3层从我的屏幕上消失了,如图所示。在这张图中,只绘制了我的基本按钮(第1层)和高亮显示的"继续"按钮(第2层)。
我相信这是我的混合函数的问题,事实上我画了两个以上的精灵。我对OpenTK/OOpenGL还比较陌生,我希望这里有人能帮我解决这个问题。我将在下面添加一些代码:
当游戏开始时,我设置了一些GL属性:
GL.Enable(EnableCap.DepthTest);
GL.Enable(EnableCap.CullFace);
GL.Enable(EnableCap.Texture2D);
GL.Enable(EnableCap.Blend); //I migh t be missing something here, like textEnv?
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
这部分代码绘制了我的二维元素。我从一个关于OpenTK的教程中获得了它。
public void DrawHUD()
{
// Clear only the depth buffer, so that everything
// we draw for the HUD will appear in front of the
// world objects.
GL.Clear(ClearBufferMask.DepthBufferBit);
// Reset the ModelView matrix so the following
// objects are not affected by the camera position
GL.LoadIdentity();
////draw 3d hud elements (weapon in the main game)
// Disable lighting for the HUD graphics
// GL.Disable(EnableCap.Lighting);
// Save the current perspective projection
GL.MatrixMode(MatrixMode.Projection);
GL.PushMatrix();
// Switch to orthogonal view
GL.LoadIdentity();
GL.Ortho(0, Width, 0, Height, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
// Go back to working with the ModelView
GL.MatrixMode(MatrixMode.Modelview);
//// Draw the HUD elements
GameEngine.Draw2D();
// Switch back to perspective view
GL.MatrixMode(MatrixMode.Projection);
GL.PopMatrix();
GL.MatrixMode(MatrixMode.Modelview);
// Turn lighting back on
// GL.Enable(EnableCap.Lighting);
}
我将菜单"图层"添加到数组列表中,然后使用Graphic绘制,Graphic是一个保存我的"图层"的位置/纹理信息的类
public virtual void Draw2D()
{
Vector2 pos;
int Z = 0; //to fight z-fighting? this fixed an issue where drawing a 2nd sprite would also make the 1st one dissapear partially
foreach (Graphic G in _2DList)
{
if (G.visible())
{
pos = G.position();
Renderer.DrawHUDSprite(pos.X, pos.Y, Z, G.W(), G.H(), G.Texture());
Z++;
}
}
}
最后,我为hudsprites绘制的函数如下:
public static void DrawHUDSprite(float x, float y, float z, float width, float height, int textID)
{
// Save the ModelView matrix
GL.PushMatrix();
// Move to the correct location on screen
GL.Translate(x, y, z);
GL.BindTexture(TextureTarget.Texture2D, textID);
// Setup for drawing the texture
GL.Color3(Color.White);
// Draw a flat rectangle
GL.Begin(PrimitiveType.Quads);
GL.TexCoord2(0.0f, 1.0f); GL.Vertex3(0, 0, 0);
GL.TexCoord2(1.0f, 1.0f); GL.Vertex3(width, 0, 0);
GL.TexCoord2(1.0f, 0.0f); GL.Vertex3(width, height, 0);
GL.TexCoord2(0.0f, 0.0f); GL.Vertex3(0, height, 0);
GL.End();
// Restore the ModelView matrix
GL.BindTexture(TextureTarget.Texture2D, 0);
GL.PopMatrix();
}
如果这与我加载纹理的方式有关,我也会为此添加代码。
我自己解决了问题:问题出在draw2D()函数上,我使用Z坐标来防止剪切问题。在2D中绘制时,Z坐标只能在[0..1]的范围内。
我以前的解决方案将Z增加1(Z++),这将导致2个以上纹理/图形出现问题(Z>1,意味着不显示四边形)。固定版本如下:
public virtual void Draw2D()
{
if (_2DList.Count > 0) { //pervents dividing by 0, and skips memory allocation if we have no Graphics
Vector2 pos;
float Z = 0; //to fight z-fighting, the sprites ar drawn in the order they were added.
float step = 1.0f / _2DList.Count; //limiting the Z between [0..1]
foreach (Graphic G in _2DList)
{
if (G.visible())
{
pos = G.position();
Renderer.DrawHUDSprite(pos.X, pos.Y, Z, G.W(), G.H(), G.Texture());
Z += step; //with z starting at 0, it will never be 1.
}
}
}
}