简体   繁体   English

如何从OpenGL中的像素中去除颜色(使其透明)

[英]how to remove a color (make it transparent) taking the color from a pixel in OpenGL

What I want to do is this, imagine I have a little tile (32x32) with the Sun inside, that is a yellow circle with black background. 我想做的是,假设我有一个小瓷砖(32x32),里面有太阳,那是一个黑色背景的黄色圆圈。

I want to draw that Sun in the sky (light blue). 我想在天空中绘制太阳(浅蓝色)。 Obviously the black border will ruin my composition. 显然,黑色边框会破坏我的构图。 I have to make OpenGL delete that black color. 我必须使OpenGL删除该黑色。

In photoshop I would select with the magic tool all the black pixels and then remove them saving the new file with alpha channel. 在photoshop中,我将使用魔术工具选择所有黑色像素,然后将其删除,并使用alpha通道保存新文件。

But this can be too long to do if you have millions of images. 但是,如果您有数百万个图像,那么这样做可能会太长。 I have to handle this issue at runtime. 我必须在运行时处理此问题。

I was looking for the glStencilMask method, but that will work if you actually have a texture to use as mask. 我一直在寻找glStencilMask方法,但是如果您确实有要用作遮罩的纹理,那么该方法将起作用。

I found an example for C# that talks about taking the 24bit image and transform to 32bit with alpha channel, this sound to me good, but maybe in matter of time consuming and resource spending is too much especially if the number of tile is high (about 30x20 tiles at 60fps) 我找到了一个C#的示例,该示例涉及拍摄24位图像并通过alpha通道转换为32位,这对我来说听起来不错,但可能会很耗时,而且资源消耗过多,尤其是当分片的数量很高时(大约30x20格(60fps)

The thing is that this is difficult to reach, and the one who reach this goal is not going to tell anybody... 事实是,这很难实现,实现这一目标的人不会告诉任何人...

Actually the code to draw the tile is this, that will cut, translate, rotate and all the stuff that are needed. 实际上,绘制图块的代码就是这个,它将剪切,平移,旋转以及所有需要的东西。

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 is this: texture.bind是这样的:

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

With image that contain a transparent layer all is perfect. 对于包含透明层的图像,一切都是完美的。

Once I have find out how to remove that specific color I wish to remove the color according to the upper-left pixel and that will be done with glReadPixels() 一旦找到如何删除特定颜色,我希望根据左上像素删除颜色,这将使用glReadPixels()

here is the loader: 这是装载机:

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

Actually I've created a solution to the problem, so I've created a method that I am going to post here on SO to knowledge for future people. 实际上,我已经为该问题创建了解决方案,因此我创建了一种方法,该方法将在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;
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM