处理 8 位位图中的 Alpha 通道的好方法? - OpenGL - C++

发布于 2024-11-16 16:44:48 字数 185 浏览 4 评论 0原文

我正在使用 OpenGL 加载位图来纹理化 3D 网格。其中一些位图的某些像素具有 alpha 通道(透明度),我需要找出

  1. 获取每个像素的透明度值

  1. 使用应用的透明度渲染它们的

最佳方法有人有这方面的好例子吗? OpenGL 支持这个吗?

I am loading bitmaps with OpenGL to texture a 3d mesh. Some of these bitmaps have alpha channels (transparency) for some of the pixels and I need to figure out the best way to

  1. obtain the values of transparency for each pixel

and

  1. render them with the transparency applied

Does anyone have a good example of this? Does OpenGL support this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

祁梦 2024-11-23 16:44:48

首先,通常最好将位图数据转换为 32 位,以便每个通道(R、G、B、A)获得 8 位。上传纹理时,指定 32 位格式。

然后在渲染时,您需要glEnable(GL_BLEND);并设置混合函数,例如:glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);。这告诉 OpenGL 使用纹理的 Alpha 将纹理的 RGB 与背景的 RGB 混合。

如果您对 3D 对象执行此操作,您可能还需要关闭背面剔除(以便您通过正面看到对象的背面)并从后到前对三角形进行排序(以便发生混合以正确的顺序)。

如果您的源位图是 8 位(即:使用将一种颜色指定为透明蒙版的调色板),那么将其转换为 RGBA 可能是最简单的方法,当颜色与您的透明蒙版匹配时将 alpha 值设置为 0。

一些让事情(也许)看起来更好的提示:

  • 你的 Alpha 通道将是一个要么全有要么全无的事情(0x00 或 0xff),所以应用一些模糊算法来获得更柔和的边缘,如果这就是你所追求的。
  • 对于 alpha 为零(完全透明)的纹素(纹理像素),将 RGB 颜色替换为最接近的非透明纹素。当纹理坐标被插值时,它们不会与 BMP 中的原始透明度颜色混合。

First of all, it's generally best to convert your bitmap data to 32-bit so that each channel (R,G,B,A) gets 8 bits. When you upload your texture, specify a 32bit format.

Then when rendering, you'll need to glEnable(GL_BLEND); and set the blend function, eg: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);. This tells OpenGL to mix the RGB of the texture with that of the background, using the alpha of your texture.

If you're doing this to 3D objects, you might also want to turn off back-face culling (so that you see the back of the object through the front) and sort your triangles back-to-front (so that the blends happen in the correct order).

If your source bitmap is 8-bit (ie: using a palette with one colour specified as the transparency mask), then it's probably easiest to convert that to RGBA, setting the alpha value to 0 when the colour matches your transparency mask.

Some hints to make things (maybe) look better:

  • Your alpha channel is going to be an all-or-nothing affair (either 0x00 or 0xff), so apply some blur algorithm to get softer edges, if that's what you're after.
  • For texels (texture-pixels) with an alpha of zero (fully transparent), replace the RGB colour with the closest non-transparent texel. When texture coordinates are being interpolated, they wont be blended towards the original transparency colour from your BMP.
执手闯天涯 2024-11-23 16:44:48

如果您的像素图是 8 位单通道,它们要么是灰度图,要么使用调色板。您首先需要做的是将像素图数据转换为 RGBA 格式。为此,您分配一个足够大的缓冲区来容纳原始文件尺寸的 4 通道像素图。然后,对于像素图的每个像素,使用该像素的值作为调色板(查找表)的索引,并将该颜色值放入 RGBA 缓冲区中的相应像素中。完成后,使用glTexImage2D上传到OpenGL。

如果您的 GPU 支持片段着色器(很可能),您可以在着色器中执行 LUT 转换:将 8 位像素上传为 GL_RED 或 GL_LUMINANCE 2D 纹理。并将调色板作为 1D GL_RGBA 纹理上传。然后在片段着色器中:

uniform sampler2D texture;
uniform sampler1D palette_lut;

void main()
{
    float palette_index = texture2D(texture,gl_TexCoord[0].st).r;
    vec4 color = texture1D(palette_lut, palette_index);
    gl_FragColor = color;
}

混合渲染与 Z 缓冲区算法冲突,因此您必须从后到前对几何体进行排序,以使事物看起来正确。只要这会影响整个对象,这就相当简单,但如果您需要对每一帧渲染的网格物体的面进行排序,就会变得乏味。避免这种情况的方法是将网格分解为凸子网格(当然,已经是凸的网格不能进一步分解)。然后使用以下方法:

  • 启用面剔除
  • 在sorted(meshes, far to close)中为凸面子网格 :
    • 将面部剔除设置为正面(即渲染背面)
    • 渲染凸面子网格
    • 将面剔除设置为背面(即渲染正面)
    • 再次渲染凸面子网格

If your pixmap are 8-bit single channel they are either grayscale or use a palette. What you first need to do is converting the pixmap data into RGBA format. For this you allocate a buffer large enough to hold a 4-channel pixmap of the dimensions of the original file. Then for each pixel of the pixmap use that pixel's value as index into the palette (look up table) and put that color value into the corresponding pixel in the RGBA buffer. Once finished, upload to OpenGL using glTexImage2D.

If your GPU supports fragment shaders (very likely) you can do that LUT transformation in the shader: Upload the 8-bit pixmal as a GL_RED or GL_LUMINANCE 2D texture. And upload the palette as a 1D GL_RGBA texture. Then in the fragment shader:

uniform sampler2D texture;
uniform sampler1D palette_lut;

void main()
{
    float palette_index = texture2D(texture,gl_TexCoord[0].st).r;
    vec4 color = texture1D(palette_lut, palette_index);
    gl_FragColor = color;
}

Blended rendering conflicts with the Z buffer algorithm, so you must sort your geometry back-to-front for things to look properly. As long as this affects objects at a whole this is rather simple, but it becomes tedious if you need to sort the faces of a mesh rendering each and every frame. A method to avoid this is breaking down meshes into convex submeshes (of course a mesh that's convex already can not be broken down further). Then use the following method:

  • Enable face culling
  • for convex_submesh in sorted(meshes, far to near):
    • set face culling to front faces (i.e. the backside gets rendered)
    • render convex_submesh
    • set face culling to back faces (i.e. the fronside gets rendered)
    • render convex_submesh again
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文