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


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
抱歉,我是一个语言模型AI,无法直接进行编程。但是,我可以为你提供一些编程思路和参考资料。 基于DEM数据的3D地形绘制是一个比较复杂的任务,需要用到计算机图形学、地理信息系统和数学等多个领域的知识。其CSGL是一个比较常用的计算机图形学库,可以方便地实现3D绘制和渲染。 下面是一个简单的基于CSGL的绘制3D地形的示例代码: ```c++ #include <GL/glut.h> #include <iostream> #include <fstream> #include <vector> using namespace std; const int WINDOW_WIDTH = 800; const int WINDOW_HEIGHT = 600; int rows, cols; vector<vector<float>> data; void init() { glClearColor(1.0, 1.0, 1.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (GLfloat)WINDOW_WIDTH / (GLfloat)WINDOW_HEIGHT, 0.1, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glColor3f(0.0, 0.0, 0.0); for (int i = 0; i < rows - 1; i++) { glBegin(GL_TRIANGLE_STRIP); for (int j = 0; j < cols; j++) { glVertex3f(j, i, data[i][j]); glVertex3f(j, i + 1, data[i + 1][j]); } glEnd(); } glPopMatrix(); glutSwapBuffers(); } void reshape(int w, int h) { glViewport(0, 0, (GLsizei)w, (GLsizei)h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, (GLfloat)w / (GLfloat)h, 0.1, 100.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.0, 0.0, 10.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0); } void readDEMData(const char* filename) { ifstream file(filename); file >> rows >> cols; data.resize(rows); for (int i = 0; i < rows; i++) { data[i].resize(cols); for (int j = 0; j < cols; j++) { file >> data[i][j]; } } file.close(); } int main(int argc, char** argv) { if (argc < 2) { cout << "Usage: " << argv[0] << " filename" << endl; return 1; } readDEMData(argv[1]); glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMainLoop(); return 0; } ``` 这个程序可以读取一个DEM数据文件,然后绘制出3D地形。其,读取DEM数据的函数readDEMData()需要根据自己的数据格式进行修改。绘制地形的部分使用了GL_TRIANGLE_STRIP来绘制三角形网格,可以根据需要自行修改。 参考资料: 1. OpenGL Programming Guide: https://www.glprogramming.com/red/ 2. CSGL: https://github.com/csgl/csgl 3. DEM数据格式: https://en.wikipedia.org/wiki/Digital_elevation_model
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ls9512

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值