首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将自透明纹理呈现给帧缓冲区时出现奇怪的混合

将自透明纹理呈现给帧缓冲区时出现奇怪的混合
EN

Stack Overflow用户
提问于 2015-06-30 17:04:09
回答 1查看 524关注 0票数 0

我试图将自透明的纹理呈现给框架缓冲区,但我得到的不是我所猜到的:以前在框架缓冲区上呈现的所有内容都被忽略了,这个纹理与我清理过的主画布上的颜色混在一起。

这就是我想要得到的,但不使用框架缓冲区:

代码语言:javascript
复制
package test;

import com.badlogic.gdx.*;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;

public class GdxTest extends ApplicationAdapter {
    SpriteBatch batch;
    Texture img;


    @Override
    public void create () {
        batch = new SpriteBatch();
        Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
        pixmap.setColor(1, 1, 1, 1);
        pixmap.fillRectangle(0, 0, 1, 1);
        // Generating a simple 1x1 white texture
        img = new Texture(pixmap);
        pixmap.dispose();
    }

    @Override
    public void render () {
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        batch.begin();
        batch.setColor(1, 1, 1, 1);
        batch.draw(img, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        batch.setColor(0, 0, 0, 0.5f);
        batch.draw(img, 0, 0, 300, 300);
        batch.end();
    }
}

它的工作原理非常完美:

http://i.stack.imgur.com/wpFNg.png

这就是我使用framebuffer (我不明白为什么第二个呈现的纹理不与前一个纹理混合,就像它没有framebuffer那样):

代码语言:javascript
复制
package test;

import com.badlogic.gdx.*;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.*;
import com.badlogic.gdx.graphics.glutils.*;

public class GdxTest extends ApplicationAdapter {
    SpriteBatch batch;
    Texture img;

    FrameBuffer buffer;
    TextureRegion region;

    @Override
    public void create () {
        batch = new SpriteBatch();
        Pixmap pixmap = new Pixmap(1, 1, Pixmap.Format.RGBA8888);
        pixmap.setColor(1, 1, 1, 1);
        pixmap.fillRectangle(0, 0, 1, 1);
        // Generating a simple 1x1 white texture
        img = new Texture(pixmap);
        pixmap.dispose();
        // Generating a framebuffer
        buffer = new FrameBuffer(Pixmap.Format.RGBA8888, Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
        region = new TextureRegion(buffer.getColorBufferTexture());
        region.flip(false, true);
    }

    @Override
    public void render () {
        // Filling with red shows the problem
        Gdx.gl.glClearColor(1, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        buffer.begin();
        batch.begin();
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.setColor(1, 1, 1, 1);
        batch.draw(img, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        batch.setColor(0, 0, 0, 0.5f);
        batch.draw(img, 0, 0, 300, 300);
        batch.end();
        buffer.end();

        batch.begin();
        batch.setColor(1, 1, 1, 1);
        batch.draw(region, 0, 0);
        batch.end();
    }
}

一个不可预测的结果:

http://i.stack.imgur.com/UdDKD.png

那么,我如何使框架缓冲版本像第一个版本那样工作呢?)

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-06-30 19:08:44

简单的答案是在呈现到屏幕时禁用混合。

但我认为,如果你想要使用FBO,了解为什么会发生这种情况是很好的。让我们来看看到底发生了什么。

首先,确保了解纹理的颜色和批处理的颜色(顶点颜色):它们是成倍的。因此,当将批处理颜色设置为0,0,0,0.5,并且纹理像素( 1,1,1,1 )为1,1,1,1时,这将导致1*0,1*0,1*0,1*0.5 = 0,0,0,0.5的值。

接下来,确保了解共混是如何工作的。默认情况下,混合是启用的,并将使用SRC_ALPHAONE_MINUS_SRC_ALPHA函数。这意味着源值( texel)乘以源alpha,目标值(屏幕像素)乘以1减去源alpha。因此,如果屏幕像素的值为1,1,1,1,而纹理的值为0,0,0,0.5,则屏幕像素将设置为:(0.5*0, 0.5*0, 0.5*0, 0.5*0.5) + ((1-0.5)*1, (1-0.5)*1, (1-0.5)*1, (1-0.5)*1),即(0,0,0,0.25) + (0.5, 0.5, 0.5, 0.5) = (0.5, 0.5, 0.5, 0.75)

因此,让我们在第一段代码中看看它是如何工作的:

  1. 您可以使用1, 0, 0, 1清除屏幕,换句话说:屏幕上的每个像素都包含值1, 0, 0, 1
  2. 然后,您将呈现一个完整的矩形,每个文本值都是1,1,1,1,屏幕上的每个像素现在都包含值1, 1, 1, 1
  3. 然后,您将呈现一个较小的矩形,每个文本值0,0,0,0.5,屏幕该部分上的每个像素现在都包含值0.5, 0.5, 0.5, 0.75

已经对这件事有感觉了吗?让我们看看在第二段代码中发生了什么:

  1. 使用1, 0, 0, 1清除屏幕:屏幕的每个像素都包含值1, 0, 0, 1
  2. 绑定FBO并使用1, 1, 1, 1清除它: FBO的每个像素都包含值1, 1, 1, 1
  3. 您可以向FBO呈现一个完整的矩形,每个文本值都是1,1,1,1:FBO的每个像素现在都包含值1,1,1,1
  4. 您呈现一个较小的矩形,每个贴图值0,0,0,0.5,FBO的该部分上的每个像素现在都包含值0.5, 0.5, 0.5, 0.75
  5. 然后再将屏幕绑定为呈现目标,每个像素仍然包含值1, 0, 0, 1
  6. 最后,将FBO纹理作为完整的矩形呈现到屏幕上,从而使这些纹理与屏幕像素混合。对于较小的矩形,这意味着混合0.5, 0.5, 0.5, 0.75乘以0.75,1, 0, 0, 1乘以1-0.75=0.25,这将导致0.375, 0.375, 0.375, 0.56250.25, 0, 0, 0.25。所以最后的颜色是0.625, 0.375, 0.375, 0,8125

一定要理解这个过程,否则会引起一些令人沮丧的奇怪问题。如果您发现很难跟上,那么您可以拿笔和纸,并手动计算每一步的价值。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31144207

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档