【问题标题】:how to remove a color (make it transparent) taking the color from a pixel in OpenGL如何从OpenGL中的像素中删除颜色(使其透明)
【发布时间】:2013-09-19 20:16:15
【问题描述】:

我想做的是这个,想象我有一个小瓷砖(32x32),里面有太阳,那是一个黑色背景的黄色圆圈。

我想画出天空中的太阳(浅蓝色)。显然黑色边框会破坏我的构图。我必须让 OpenGL 删除那个黑色。

在 Photoshop 中,我会使用魔术工具选择所有黑色像素,然后将它们删除,保存带有 Alpha 通道的新文件。

但是,如果您有数百万张图片,这可能会太长。我必须在运行时处理这个问题。

我一直在寻找 glStencilMask 方法,但如果您确实有纹理可用作遮罩,则该方法会起作用。

我找到了一个 C# 示例,它讨论了将 24 位图像转换为带有 alpha 通道的 32 位,这对我来说听起来不错,但可能在耗时和资源消耗过多的问题上,特别是如果瓷砖的数量是高(60fps 时大约 30x20 块)

问题是这很难达到,达到这个目标的人不会告诉任何人......

实际上绘制图块的代码是这样的,它将剪切、平移、旋转和所有需要的东西。

GL11.glPushMatrix();

    // bind to the appropriate texture for this sprite
    this.texture.bind();

    // translate to the right location and prepare to draw
    GL11.glColor3f(1, 1, 1);
    GL11.glTranslated(x + ((32 - this.texture.getImageWidth()) / 2) + (this.texture.getImageWidth() / 2), y + ((32 - this.texture.getImageHeight()) / 2)
            + (this.texture.getImageHeight() / 2), 0);
    //      System.out.println(this.angle);
    GL11.glRotated(this.angle, 0, 0, 1);
    GL11.glTranslated(-this.texture.getImageWidth() / 2, -this.texture.getImageHeight() / 2, 0);
    // draw a quad textured to match the sprite
    GL11.glBegin(GL11.GL_QUADS);
    {
        GL11.glTexCoord2f(0, 0);
        GL11.glVertex2f(0, 0);
        GL11.glTexCoord2f(0, this.texture.getHeight());
        GL11.glVertex2f(0, this.texture.getImageHeight());
        GL11.glTexCoord2f(this.texture.getWidth(), this.texture.getHeight());
        GL11.glVertex2f(this.texture.getImageWidth(), this.texture.getImageHeight());
        GL11.glTexCoord2f(this.texture.getWidth(), 0);
        GL11.glVertex2f(this.texture.getImageWidth(), 0);
    }
    GL11.glEnd();

    // restore the model view matrix to prevent contamination
    GL11.glPopMatrix();

texture.bind 是这样的:

public void bind() {
    GL11.glBindTexture(this.target, this.textureID);
}

使用包含透明层的图像一切都是完美的。

一旦我知道如何移除特定颜色,我希望根据左上角的像素移除颜色,这将通过glReadPixels() 完成

这里是加载器:

public Texture getTexture(String resourceName, int target, int dstPixelFormat, int minFilter, int magFilter) throws IOException {
    int srcPixelFormat = 0;

    // create the texture ID for this texture
    int textureID = this.createTextureID();
    Texture texture = new Texture(target, textureID);

    // bind this texture
    GL11.glBindTexture(target, textureID);

    BufferedImage bufferedImage = this.loadImage(resourceName);
    texture.setWidth(bufferedImage.getWidth());
    texture.setHeight(bufferedImage.getHeight());

    if (bufferedImage.getColorModel().hasAlpha()) {
        srcPixelFormat = GL11.GL_RGBA;
    } else {
        srcPixelFormat = GL11.GL_RGB;
    }

    // convert that image into a byte buffer of texture data
    ByteBuffer textureBuffer = this.convertImageData(bufferedImage, texture);

    if (target == GL11.GL_TEXTURE_2D) {
        GL11.glTexParameteri(target, GL11.GL_TEXTURE_MIN_FILTER, minFilter);
        GL11.glTexParameteri(target, GL11.GL_TEXTURE_MAG_FILTER, magFilter);
    }

    // produce a texture from the byte buffer
    GL11.glTexImage2D(target, 0, dstPixelFormat, this.get2Fold(bufferedImage.getWidth()), this.get2Fold(bufferedImage.getHeight()), 0, srcPixelFormat,
            GL11.GL_UNSIGNED_BYTE, textureBuffer);

    return texture;
}

【问题讨论】:

  • 为什么不在将纹理发送到 OGL 之前根据要求自动更改纹理(添加适当的 alpha)?这只需在纹理加载时执行一次。
  • 有什么方法可以做到吗?无论如何,你是个好主意,我会用纹理的代码加载器更新我的代码
  • 从“C# 示例中讨论获取 24 位图像并使用 alpha 通道转换为 32 位”开始?这可能包含所有需要的信息。
  • 不,对每个图块都完成了,这对于非核计算机来说太多了
  • 在加载时预处理您的纹理并从透明蒙版颜色插入 Alpha 通道。自古以来就是这样做的。如果我的旧 P2 233 可以处理这个,那么无论这台“非核”计算机是什么,都可以处理它。

标签: java opengl lwjgl alpha


【解决方案1】:

实际上我已经为这个问题创建了一个解决方案,所以我创建了一个方法,我将在这里发布关于 SO 的知识,以供未来的人们使用。

/**
 * Sets the specified colour, or the color taken from the top-left pixel, to transparent
 * 
 * @param image
 *            The image to process (<code>BufferedImage</code>)
 * @param cornerTransparency
 *            If true the method will take the top-left pixel's colour and make it transparent in the image
 * @param transCol
 *            If <code>cornerTransparency</code> is false, this is the color that will be set to transparent.
 * @return The loaded buffered image
 * @throws IOException
 *             Indicates a failure to find a resource
 */
private BufferedImage loadImage(BufferedImage image, boolean cornerTransparency, int transCol) throws IOException {

    if(image == null){
                throw new IllegalArgumentException();
            }

    int firstPixel = bufferedImage.getRGB(0, 0);
        BufferedImage bff = new BufferedImage(bufferedImage.getWidth(), bufferedImage.getHeight(), BufferedImage.TYPE_INT_ARGB);
        for (int y = 0; y < bufferedImage.getHeight(); ++y) {
            for (int x = 0; x < bufferedImage.getWidth(); ++x) {
                int argb = bufferedImage.getRGB(x, y);
                if (cornerTransparency) {
                    if (argb == firstPixel) {//we are certain that they are of the same type (RGB,ARGB etc)
                        bff.setRGB(x, y, 0); //black with alpha = 0
                    } else {
                        bff.setRGB(x, y, argb);
                    }
                } else {
                    if ((argb & 0xFF000000) == (transCol & 0xFF000000)) {//not sure if are of the same type, I remove the alpha data.
                        bff.setRGB(x, y, 0); //black with alpha = 0
                    } else {
                        bff.setRGB(x, y, argb);
                    }
                }
            }
        }
        return bff;
    } else {
        return bufferedImage;
    }

【讨论】:

    猜你喜欢
    • 2014-02-07
    • 1970-01-01
    • 2011-12-23
    • 2011-04-02
    • 2011-12-06
    • 1970-01-01
    • 2017-02-27
    • 1970-01-01
    • 2016-06-24
    相关资源
    最近更新 更多