Andengine-图像post处理-场景模糊

Andengine - image post processing - scene blurring

AndEngine是否可以对整个场景进行模糊处理?我想模糊整个场景而不是模糊儿童场景。你有什么建议吗?

public class MyScene extends Scene {
    private Sprite backgroundSprite;
    private Sprite playerSprite;
    private Sprite enemySprite;

    public void create() {
        attachChild(backgroundSprite);
        attachChild(playerSprite);
        attachChild(enemySprite);
    }

    public void openChildScene() {
        // PERFORM BLURRING of a scene

        CameraScene childScene = new CameraScene(camera);

        // attach children
        .
        .
        .

        childScene.setBackgroundEnabled(false);

        setChildScene(childScene);
    }
}

这绝对有可能。查看 AndEngineExamples 项目中的 Shader 示例。您基本上必须将场景渲染为(空)纹理,然后在其上使用着色器。

径向模糊示例:

package org.andengine.examples;

import org.andengine.engine.Engine;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.scene.IOnSceneTouchListener;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.sprite.UncoloredSprite;
import org.andengine.entity.util.FPSLogger;
import org.andengine.input.touch.TouchEvent;
import org.andengine.input.touch.detector.ClickDetector;
import org.andengine.input.touch.detector.ClickDetector.IClickDetectorListener;
import org.andengine.opengl.shader.PositionTextureCoordinatesShaderProgram;
import org.andengine.opengl.shader.ShaderProgram;
import org.andengine.opengl.shader.constants.ShaderProgramConstants;
import org.andengine.opengl.shader.exception.ShaderProgramException;
import org.andengine.opengl.shader.exception.ShaderProgramLinkException;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.TextureRegionFactory;
import org.andengine.opengl.texture.render.RenderTexture;
import org.andengine.opengl.util.GLState;
import org.andengine.opengl.vbo.attribute.VertexBufferObjectAttributes;
import org.andengine.ui.activity.SimpleBaseGameActivity;

import android.opengl.GLES20;

/**
 * (c) Zynga 2011
 *
 * @author Nicolas Gramlich <ngramlich@zynga.com>
 * @since 16:55:18 - 06.11.2011
 */
public class RadialBlurExample extends SimpleBaseGameActivity implements IOnSceneTouchListener, IClickDetectorListener {
    // ===========================================================
    // Constants
    // ===========================================================

    private static final int CAMERA_WIDTH = 720;
    private static final int CAMERA_HEIGHT = 480;

    // ===========================================================
    // Fields
    // ===========================================================

    private Camera mCamera;
    private BitmapTextureAtlas mBitmapTextureAtlas;
    private ITextureRegion mFaceTextureRegion;

    private boolean mRadialBlurring = true;
    private float mRadialBlurCenterX = 0.5f;
    private float mRadialBlurCenterY = 0.5f;
    private ClickDetector mClickDetector;

    // ===========================================================
    // Constructors
    // ===========================================================

    // ===========================================================
    // Getter & Setter
    // ===========================================================

    // ===========================================================
    // Methods for/from SuperClass/Interfaces
    // ===========================================================

    @Override
    public EngineOptions onCreateEngineOptions() {
        this.mCamera = new Camera(0, 0, RadialBlurExample.CAMERA_WIDTH, RadialBlurExample.CAMERA_HEIGHT);

        return new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(RadialBlurExample.CAMERA_WIDTH, RadialBlurExample.CAMERA_HEIGHT), this.mCamera);
    }

    @Override
    public Engine onCreateEngine(EngineOptions pEngineOptions) {
        return new Engine(pEngineOptions) {
            private boolean mRenderTextureInitialized;

            private RenderTexture mRenderTexture;
            private UncoloredSprite mRenderTextureSprite;

            @Override
            public void onDrawFrame(final GLState pGLState) throws InterruptedException {
                final boolean firstFrame = !this.mRenderTextureInitialized;

                if(firstFrame) {
                    this.initRenderTextures(pGLState);
                    this.mRenderTextureInitialized = true;
                }

                final int surfaceWidth = this.mCamera.getSurfaceWidth();
                final int surfaceHeight = this.mCamera.getSurfaceHeight();

                this.mRenderTexture.begin(pGLState);
                {
                    /* Draw current frame. */
                    super.onDrawFrame(pGLState);
                }
                this.mRenderTexture.end(pGLState);

                /* Draw rendered texture with custom shader. */
                {
                    pGLState.pushProjectionGLMatrix();
                    pGLState.orthoProjectionGLMatrixf(0, surfaceWidth, 0, surfaceHeight, -1, 1);
                    {
                        this.mRenderTextureSprite.onDraw(pGLState, this.mCamera);
                    }
                    pGLState.popProjectionGLMatrix();
                }
            }

            private void initRenderTextures(final GLState pGLState) {
                final int surfaceWidth = this.mCamera.getSurfaceWidth();
                final int surfaceHeight = this.mCamera.getSurfaceHeight();

                this.mRenderTexture = new RenderTexture(RadialBlurExample.this.getTextureManager(), surfaceWidth, surfaceHeight);
                this.mRenderTexture.init(pGLState);

                final ITextureRegion renderTextureTextureRegion = TextureRegionFactory.extractFromTexture(this.mRenderTexture);
                this.mRenderTextureSprite = new UncoloredSprite(0, 0, renderTextureTextureRegion, this.getVertexBufferObjectManager()) {
                    @Override
                    protected void preDraw(final GLState pGLState, final Camera pCamera) {
                        if(RadialBlurExample.this.mRadialBlurring) {
                            this.setShaderProgram(RadialBlurShaderProgram.getInstance());
                        } else {
                            this.setShaderProgram(PositionTextureCoordinatesShaderProgram.getInstance());
                        }
                        super.preDraw(pGLState, pCamera);

                        GLES20.glUniform2f(RadialBlurShaderProgram.sUniformRadialBlurCenterLocation, RadialBlurExample.this.mRadialBlurCenterX, 1 - RadialBlurExample.this.mRadialBlurCenterY);
                    }
                };
            }
        };
    }

    @Override
    public void onCreateResources() {
        BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");

        this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 512, 512);
        this.mFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBitmapTextureAtlas, this, "badge_large.png", 0, 0);
        this.mBitmapTextureAtlas.load();

        this.getShaderProgramManager().loadShaderProgram(RadialBlurShaderProgram.getInstance());
    }

    @Override
    public Scene onCreateScene() {
        this.mEngine.registerUpdateHandler(new FPSLogger());

        final Scene scene = new Scene();

        /* Calculate the coordinates for the face, so its centered on the camera. */
        final float centerX = (RadialBlurExample.CAMERA_WIDTH - this.mFaceTextureRegion.getWidth()) / 2;
        final float centerY = (RadialBlurExample.CAMERA_HEIGHT - this.mFaceTextureRegion.getHeight()) / 2;

        /* Create the face and add it to the scene. */
        final Sprite face = new Sprite(centerX, centerY, this.mFaceTextureRegion, this.getVertexBufferObjectManager());
//      face.setScale(3);
        scene.attachChild(face);

        /* TouchListener */
        this.mClickDetector = new ClickDetector(this);
        scene.setOnSceneTouchListener(this);

        return scene;
    }

    @Override
    public void onClick(final ClickDetector pClickDetector, final int pPointerID, final float pSceneX, final float pSceneY) {
        this.mRadialBlurring = !this.mRadialBlurring;
    }

    @Override
    public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
        this.mClickDetector.onSceneTouchEvent(pScene, pSceneTouchEvent);

        this.mRadialBlurCenterX = pSceneTouchEvent.getMotionEvent().getX() / this.mCamera.getSurfaceWidth();
        this.mRadialBlurCenterY = pSceneTouchEvent.getMotionEvent().getY() / this.mCamera.getSurfaceHeight();

        return true;
    }

    // ===========================================================
    // Methods
    // ===========================================================

    // ===========================================================
    // Inner and Anonymous Classes
    // ===========================================================

    public static class RadialBlurShaderProgram extends ShaderProgram {
        // ===========================================================
        // Constants
        // ===========================================================

        private static RadialBlurShaderProgram INSTANCE;

        public static final String VERTEXSHADER =
            "uniform mat4 " + ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX + ";\n" +
            "attribute vec4 " + ShaderProgramConstants.ATTRIBUTE_POSITION + ";\n" +
            "attribute vec2 " + ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES + ";\n" +
            "varying vec2 " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ";\n" +
            "void main() {\n" +
            "   " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " = " + ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES + ";\n" +
            "   gl_Position = " + ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX + " * " + ShaderProgramConstants.ATTRIBUTE_POSITION + ";\n" +
            "}";

        private static final String UNIFORM_RADIALBLUR_CENTER = "u_radialblur_center";

        public static final String FRAGMENTSHADER =
            "precision lowp float;\n" +

            "uniform sampler2D " + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ";\n" +
            "varying mediump vec2 " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ";\n" +

            "uniform vec2 " + RadialBlurShaderProgram.UNIFORM_RADIALBLUR_CENTER + ";\n" +

            "const float sampleShare = (1.0 / 11.0);\n" +
            "const float sampleDist = 1.0;\n" +
            "const float sampleStrength = 1.25;\n" +

            "void main() {\n" +
            /* The actual (unburred) sample. */
            "   vec4 color = texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ");\n" +

            /* Calculate direction towards center of the blur. */
            "   vec2 direction = " + RadialBlurShaderProgram.UNIFORM_RADIALBLUR_CENTER + " - " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + ";\n" +

            /* Calculate the distance to the center of the blur. */
            "   float distance = sqrt(direction.x * direction.x + direction.y * direction.y);\n" +

            /* Normalize the direction (reuse the distance). */
            "   direction = direction / distance;\n" +

            "   vec4 sum = color * sampleShare;\n" +
            /* Take 10 additional samples along the direction towards the center of the blur. */
            "   vec2 directionSampleDist = direction * sampleDist;\n" +
            "   sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " - 0.08 * directionSampleDist) * sampleShare;\n" +
            "   sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " - 0.05 * directionSampleDist) * sampleShare;\n" +
            "   sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " - 0.03 * directionSampleDist) * sampleShare;\n" +
            "   sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " - 0.02 * directionSampleDist) * sampleShare;\n" +
            "   sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " - 0.01 * directionSampleDist) * sampleShare;\n" +
            "   sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " + 0.01 * directionSampleDist) * sampleShare;\n" +
            "   sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " + 0.02 * directionSampleDist) * sampleShare;\n" +
            "   sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " + 0.03 * directionSampleDist) * sampleShare;\n" +
            "   sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " + 0.05 * directionSampleDist) * sampleShare;\n" +
            "   sum += texture2D(" + ShaderProgramConstants.UNIFORM_TEXTURE_0 + ", " + ShaderProgramConstants.VARYING_TEXTURECOORDINATES + " + 0.08 * directionSampleDist) * sampleShare;\n" +

            /* Weighten the blur effect with the distance to the center of the blur (further out is blurred more). */
            "   float t = sqrt(distance) * sampleStrength;\n" +
            "   t = clamp(t, 0.0, 1.0);\n" + // 0 <= t >= 1

            /* Blend the original color with the averaged pixels. */
            "   gl_FragColor = mix(color, sum, t);\n" +
            "}";

        // ===========================================================
        // Fields
        // ===========================================================

        public static int sUniformModelViewPositionMatrixLocation = ShaderProgramConstants.LOCATION_INVALID;
        public static int sUniformTexture0Location = ShaderProgramConstants.LOCATION_INVALID;
        public static int sUniformRadialBlurCenterLocation = ShaderProgramConstants.LOCATION_INVALID;

        // ===========================================================
        // Constructors
        // ===========================================================

        private RadialBlurShaderProgram() {
            super(RadialBlurShaderProgram.VERTEXSHADER, RadialBlurShaderProgram.FRAGMENTSHADER);
        }

        public static RadialBlurShaderProgram getInstance() {
            if(RadialBlurShaderProgram.INSTANCE == null) {
                RadialBlurShaderProgram.INSTANCE = new RadialBlurShaderProgram();
            }
            return RadialBlurShaderProgram.INSTANCE;
        }

        // ===========================================================
        // Getter & Setter
        // ===========================================================

        // ===========================================================
        // Methods for/from SuperClass/Interfaces
        // ===========================================================

        @Override
        protected void link(final GLState pGLState) throws ShaderProgramLinkException {
            GLES20.glBindAttribLocation(this.mProgramID, ShaderProgramConstants.ATTRIBUTE_POSITION_LOCATION, ShaderProgramConstants.ATTRIBUTE_POSITION);
            GLES20.glBindAttribLocation(this.mProgramID, ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES_LOCATION, ShaderProgramConstants.ATTRIBUTE_TEXTURECOORDINATES);

            super.link(pGLState);

            RadialBlurShaderProgram.sUniformModelViewPositionMatrixLocation = this.getUniformLocation(ShaderProgramConstants.UNIFORM_MODELVIEWPROJECTIONMATRIX);
            RadialBlurShaderProgram.sUniformTexture0Location = this.getUniformLocation(ShaderProgramConstants.UNIFORM_TEXTURE_0);

            RadialBlurShaderProgram.sUniformRadialBlurCenterLocation = this.getUniformLocation(RadialBlurShaderProgram.UNIFORM_RADIALBLUR_CENTER);
        }

        @Override
        public void bind(final GLState pGLState, final VertexBufferObjectAttributes pVertexBufferObjectAttributes) {
            GLES20.glDisableVertexAttribArray(ShaderProgramConstants.ATTRIBUTE_COLOR_LOCATION);

            super.bind(pGLState, pVertexBufferObjectAttributes);

            GLES20.glUniformMatrix4fv(RadialBlurShaderProgram.sUniformModelViewPositionMatrixLocation, 1, false, pGLState.getModelViewProjectionGLMatrix(), 0);
            GLES20.glUniform1i(RadialBlurShaderProgram.sUniformTexture0Location, 0);
        }

        @Override
        public void unbind(final GLState pGLState) throws ShaderProgramException {
            GLES20.glEnableVertexAttribArray(ShaderProgramConstants.ATTRIBUTE_COLOR_LOCATION);

            super.unbind(pGLState);
        }

        // ===========================================================
        // Methods
        // ===========================================================

        // ===========================================================
        // Inner and Anonymous Classes
        // ===========================================================
    }
}