CSGL加載PNG格式圖片作爲紋理映射顯示後是有黑邊的,使用的是CSGL封裝的OpenGLTexture2D類。
後來查了很多OpenGL透明紋理的資料,網上找了各種其他語言的透明紋理實現,在CSGL庫上均不起效,最後懷疑是CSGL底層封裝時對像素的處理有問題。
反正是開源庫,那就打開源碼看看,最後自己實現了一個加載紋理的函數,和一個繪製紋理到二維座標系的函數。
有效解決了黑邊的問題,但是還有如下小問題沒有解決:
1.只能區分透明和不透明(0或255 Alpha),中間的其他半透明效果均無法正確融合顯示
2.圖片縮放後會有空白像素點,可能是線性過濾導致的,但不開啓過濾也無法正常顯示紋理。
/// <summary>
/// 從文件創建2D紋理
/// </summary>
/// <param name="fileName">文件名(路徑)</param>
/// <returns>紋理ID</returns>
public static uint[] CreateTexture2D(string fileName)
{
// 用GDI將原始圖像轉換爲32位png格式圖像
Bitmap bmp_orign = new Bitmap(fileName);
Bitmap bmp_new = new Bitmap(bmp_orign.Width, bmp_orign.Height, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bmp_new);
g.DrawImage(bmp_orign, new Rectangle(0, 0, bmp_orign.Width, bmp_orign.Height));
// 鎖定內存
BitmapData tex = bmp_new.LockBits(new Rectangle(0, 0, bmp_new.Width, bmp_new.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
// 像素處理
IntPtr ptr = tex.Scan0;
int bytesLength = tex.Stride * tex.Height;
byte[] rgbValues = new byte[bytesLength];
Marshal.Copy(ptr, rgbValues, 0, bytesLength);
for (int i = 0; i < rgbValues.Length; i += 4)
{
//rgbValues[i] = 255; // B
//rgbValues[i + 1] = 255; // G
//rgbValues[i + 2] = 255; // R
//rgbValues[i + 3] = 255; // A
if (rgbValues[i + 3] == 0) rgbValues[i + 3] = 150;
}
Marshal.Copy(rgbValues, 0, ptr, bytesLength);
// 創建紋理
uint[] texture = new uint[1];
GL.glGenTextures(texture.Length, texture);
GL.glBindTexture(GL.GL_TEXTURE_2D, texture[0]);
// 設置像素對齊
GL.glPixelStoref(GL.GL_PACK_ALIGNMENT, 1);
// 設置環境融合方式和線性過濾參數
GL.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, (int)GL.GL_MODULATE);
GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);
GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP);
GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP);
// 創建紋理
bool IsBorder = true;
bool IsMipmaped = true;
if (IsMipmaped)
{
GL.gluBuild2DMipmaps(GL.GL_TEXTURE_2D, (int)GL.GL_BGRA, bmp_new.Width, bmp_new.Height, GL.GL_BGRA, GL.GL_UNSIGNED_BYTE, tex.Scan0);
}
else
{
GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, (int)GL.GL_BGRA, bmp_new.Width, bmp_new.Height, IsBorder ? 1 : 0, GL.GL_BGRA, GL.GL_UNSIGNED_BYTE, tex.Scan0);
}
// 解鎖內存
bmp_new.UnlockBits(tex);
// 返回紋理ID
return texture;
}
/// <summary>
/// 繪製紋理
/// </summary>
/// <param name="texture">紋理ID</param>
/// <param name="x">起點x</param>
/// <param name="y">起點y</param>
/// <param name="width">寬度</param>
/// <param name="height">高度</param>
public static void DrawImage(uint[] texture, int x, int y, int width, int height)
{
// 允許使用紋理
GL.glEnable(GL.GL_TEXTURE_2D);
// 啓用顏色混合
GL.glEnable(GL.GL_BLEND);
GL.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_DST_ALPHA);
// 綁定紋理
GL.glBindTexture(GL.GL_TEXTURE_2D, texture[0]);
// 座標轉換
y = General.Win_Rect.Height - y - height;
GL.glBegin(GL.GL_QUADS);
{
// 紋理座標映射
GL.glTexCoord2f(0.0f, 1.0f); GL.glVertex2f(x, y);
GL.glTexCoord2f(1.0f, 1.0f); GL.glVertex2f(x + width, y);
GL.glTexCoord2f(1.0f, 0.0f); GL.glVertex2f(x + width, y + height);
GL.glTexCoord2f(0.0f, 0.0f); GL.glVertex2f(x, y + height);
}
GL.glEnd();
// 禁用混合
GL.glDisable(GL.GL_BLEND);
}