【C# / OpenGL】CSGL中2D紋理加載PNG等透明圖片顯示的黑邊問題

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);
        }


發佈了35 篇原創文章 · 獲贊 41 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章