Package com.ardor3d.extension.effect.bloom

Source Code of com.ardor3d.extension.effect.bloom.BloomRenderPass

/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.extension.effect.bloom;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.ardor3d.framework.DisplaySettings;
import com.ardor3d.image.Texture;
import com.ardor3d.image.Texture2D;
import com.ardor3d.math.ColorRGBA;
import com.ardor3d.renderer.Camera;
import com.ardor3d.renderer.ContextCapabilities;
import com.ardor3d.renderer.ContextManager;
import com.ardor3d.renderer.Renderer;
import com.ardor3d.renderer.TextureRenderer;
import com.ardor3d.renderer.TextureRendererFactory;
import com.ardor3d.renderer.pass.Pass;
import com.ardor3d.renderer.queue.RenderBucketType;
import com.ardor3d.renderer.state.BlendState;
import com.ardor3d.renderer.state.GLSLShaderObjectsState;
import com.ardor3d.renderer.state.RenderState;
import com.ardor3d.renderer.state.TextureState;
import com.ardor3d.scenegraph.Renderable;
import com.ardor3d.scenegraph.hint.CullHint;
import com.ardor3d.scenegraph.hint.LightCombineMode;
import com.ardor3d.scenegraph.hint.TextureCombineMode;
import com.ardor3d.scenegraph.shape.Quad;
import com.ardor3d.util.resource.ResourceLocatorTool;

/**
* GLSL bloom effect pass. - Render supplied source to a texture - Extract intensity - Blur intensity - Blend with first
* pass
*/
public class BloomRenderPass extends Pass {
    /** The Constant logger. */
    private static final Logger logger = Logger.getLogger(BloomRenderPass.class.getName());

    private static final long serialVersionUID = 1L;

    private double throttle = 0;
    private double sinceLast = 1;

    private TextureRenderer tRenderer = null;
    private TextureRenderer fullTRenderer = null;
    private Texture2D mainTexture = null;
    private Texture2D secondTexture = null;
    private Texture2D screenTexture = null;

    private Quad fullScreenQuad = null;

    private GLSLShaderObjectsState extractionShader = null;
    private GLSLShaderObjectsState blurShader = null;
    private GLSLShaderObjectsState blurShaderHorizontal = null;
    private GLSLShaderObjectsState blurShaderVertical = null;
    private GLSLShaderObjectsState finalShader = null;

    private final Camera cam;
    private final int renderScale;

    private int nrBlurPasses;
    private float blurSize;
    private float blurIntensityMultiplier;
    private float exposurePow;
    private float exposureCutoff;
    private boolean supported = true;
    private boolean useCurrentScene = false;

    private boolean useSeparateConvolution = false;

    public static String shaderDirectory = "com/ardor3d/extension/effect/bloom/";

    private boolean initialized = false;

    /**
     * Reset bloom parameters to default
     */
    public void resetParameters() {
        nrBlurPasses = 2;
        blurSize = 0.02f;
        blurIntensityMultiplier = 1.3f;
        exposurePow = 3.0f;
        exposureCutoff = 0.0f;
    }

    /**
     * Release pbuffers in TextureRenderer's. Preferably called from user cleanup method.
     */
    @Override
    public void cleanUp() {
        super.cleanUp();
        if (tRenderer != null) {
            tRenderer.cleanup();
        }
        if (fullTRenderer != null) {
            fullTRenderer.cleanup();
        }
    }

    public boolean isSupported() {
        return supported;
    }

    /**
     * Creates a new bloom renderpass
     *
     * @param cam
     *            Camera used for rendering the bloomsource
     * @param renderScale
     *            Scale of bloom texture
     */
    public BloomRenderPass(final Camera cam, final int renderScale) {
        this.cam = cam;
        this.renderScale = renderScale;
        resetParameters();
    }

    @Override
    protected void doUpdate(final double tpf) {
        super.doUpdate(tpf);
        sinceLast += tpf;
    }

    @Override
    public void doRender(final Renderer r) {
        if (!initialized) {
            doInit(r);
        }

        if (!isSupported() || !useCurrentScene && _spatials.size() == 0) {
            return;
        }

        final BlendState blend = (BlendState) fullScreenQuad.getWorldRenderState(RenderState.StateType.Blend);

        if (sinceLast > throttle) {
            sinceLast = 0;

            tRenderer.getCamera().setLocation(cam.getLocation());
            tRenderer.getCamera().setDirection(cam.getDirection());
            tRenderer.getCamera().setUp(cam.getUp());
            tRenderer.getCamera().setLeft(cam.getLeft());

            blend.setEnabled(false);
            final TextureState ts = (TextureState) fullScreenQuad.getWorldRenderState(RenderState.StateType.Texture);

            // see if we should use the current scene to bloom, or only things added to the pass.
            if (useCurrentScene) {
                // grab backbuffer to texture
                if (screenTexture == null) {
                    final DisplaySettings settings = new DisplaySettings(cam.getWidth(), cam.getHeight(), 24, 0, 0, 8,
                            0, 0, false, false);
                    fullTRenderer = TextureRendererFactory.INSTANCE.createTextureRenderer(settings, false, r,
                            ContextManager.getCurrentContext().getCapabilities());
                    screenTexture = new Texture2D();
                    screenTexture.setWrap(Texture.WrapMode.Clamp);
                    screenTexture.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
                    fullTRenderer.setupTexture(screenTexture);
                }
                fullTRenderer.copyToTexture(screenTexture, 0, 0, cam.getWidth(), cam.getHeight(), 0, 0);
                ts.setTexture(screenTexture, 0);
            } else {
                // Render scene to texture
                tRenderer.render(_spatials, mainTexture, Renderer.BUFFER_COLOR_AND_DEPTH);
                ts.setTexture(mainTexture, 0);
            }

            // Extract intensity
            extractionShader.setUniform("exposurePow", getExposurePow());
            extractionShader.setUniform("exposureCutoff", getExposureCutoff());

            fullScreenQuad.setRenderState(extractionShader);
            fullScreenQuad.updateWorldRenderStates(false);
            // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = extractionShader;
            tRenderer.render(fullScreenQuad, secondTexture, Renderer.BUFFER_NONE);

            if (!useSeparateConvolution) {
                blurShader.setUniform("sampleDist", getBlurSize());
                blurShader.setUniform("blurIntensityMultiplier", getBlurIntensityMultiplier());

                ts.setTexture(secondTexture, 0);
                fullScreenQuad.setRenderState(blurShader);
                fullScreenQuad.updateWorldRenderStates(false);
                // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = blurShader;
                tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);

                // Extra blur passes
                for (int i = 1; i < getNrBlurPasses(); i++) {
                    blurShader.setUniform("sampleDist", getBlurSize() - i * getBlurSize() / getNrBlurPasses());
                    if (i % 2 == 1) {
                        ts.setTexture(mainTexture, 0);
                        tRenderer.render(fullScreenQuad, secondTexture, Renderer.BUFFER_NONE);
                    } else {
                        ts.setTexture(secondTexture, 0);
                        tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
                    }
                }
                if (getNrBlurPasses() % 2 == 1) {
                    ts.setTexture(mainTexture, 0);
                } else {
                    ts.setTexture(secondTexture, 0);
                    tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
                    ts.setTexture(mainTexture, 0);
                }
            } else {
                blurShaderVertical.setUniform("blurIntensityMultiplier", getBlurIntensityMultiplier());

                for (int i = 0; i < getNrBlurPasses(); i++) {
                    blurShaderHorizontal
                            .setUniform("sampleDist", getBlurSize() - i * getBlurSize() / getNrBlurPasses());
                    blurShaderVertical.setUniform("sampleDist", getBlurSize() - i * getBlurSize() / getNrBlurPasses());

                    ts.setTexture(secondTexture, 0);
                    fullScreenQuad.setRenderState(blurShaderHorizontal);
                    fullScreenQuad.updateWorldRenderStates(false);
                    // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = blurShaderHorizontal;
                    tRenderer.render(fullScreenQuad, mainTexture, Renderer.BUFFER_NONE);
                    ts.setTexture(mainTexture, 0);
                    fullScreenQuad.setRenderState(blurShaderVertical);
                    fullScreenQuad.updateWorldRenderStates(false);
                    // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = blurShaderVertical;
                    tRenderer.render(fullScreenQuad, secondTexture, Renderer.BUFFER_NONE);
                }
                ts.setTexture(secondTexture, 0);
            }
        }

        // Final blend
        blend.setEnabled(true);

        fullScreenQuad.setRenderState(finalShader);
        fullScreenQuad.updateWorldRenderStates(false);
        // fullScreenQuad.states[RenderState.StateType.GLSLShaderObjects.ordinal()] = finalShader;
        r.draw((Renderable) fullScreenQuad);
    }

    private void doInit(final Renderer r) {
        initialized = true;

        cleanUp();

        // Test for glsl support
        final ContextCapabilities caps = ContextManager.getCurrentContext().getCapabilities();
        if (!caps.isGLSLSupported() || !(caps.isPbufferSupported() || caps.isFBOSupported())) {
            supported = false;
            return;
        }

        // Create texture renderers and rendertextures(alternating between two not to overwrite pbuffers)
        final DisplaySettings settings = new DisplaySettings(cam.getWidth() / renderScale, cam.getHeight()
                / renderScale, 24, 0, 0, 8, 0, 0, false, false);
        tRenderer = TextureRendererFactory.INSTANCE.createTextureRenderer(settings, false, r, ContextManager
                .getCurrentContext().getCapabilities());

        if (tRenderer == null) {
            supported = false;
            return;
        }
        tRenderer.setMultipleTargets(true);
        tRenderer.setBackgroundColor(new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f));
        tRenderer.getCamera().setFrustum(cam.getFrustumNear(), cam.getFrustumFar(), cam.getFrustumLeft(),
                cam.getFrustumRight(), cam.getFrustumTop(), cam.getFrustumBottom());

        mainTexture = new Texture2D();
        mainTexture.setWrap(Texture.WrapMode.Clamp);
        mainTexture.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
        tRenderer.setupTexture(mainTexture);

        secondTexture = new Texture2D();
        secondTexture.setWrap(Texture.WrapMode.Clamp);
        secondTexture.setMagnificationFilter(Texture.MagnificationFilter.Bilinear);
        tRenderer.setupTexture(secondTexture);

        extractionShader = new GLSLShaderObjectsState();
        try {
            extractionShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
                    shaderDirectory + "bloom_extract.vert"));
            extractionShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
                    shaderDirectory + "bloom_extract.frag"));
        } catch (final IOException ex) {
            logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
        }
        extractionShader.setUniform("RT", 0);

        // Create blur shader
        blurShader = new GLSLShaderObjectsState();
        try {
            blurShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
                    shaderDirectory + "bloom_blur.vert"));
            blurShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
                    shaderDirectory + "bloom_blur.frag"));
        } catch (final IOException ex) {
            logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
        }
        blurShader.setUniform("RT", 0);

        // Create blur shader horizontal
        blurShaderHorizontal = new GLSLShaderObjectsState();
        try {
            blurShaderHorizontal.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(
                    BloomRenderPass.class, shaderDirectory + "bloom_blur.vert"));
            blurShaderHorizontal.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
                    BloomRenderPass.class, shaderDirectory + "bloom_blur_horizontal7.frag"));
        } catch (final IOException ex) {
            logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
        }
        blurShaderHorizontal.setUniform("RT", 0);

        // Create blur shader vertical
        blurShaderVertical = new GLSLShaderObjectsState();
        try {
            blurShaderVertical.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
                    shaderDirectory + "bloom_blur.vert"));
            blurShaderVertical.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
                    BloomRenderPass.class, shaderDirectory + "bloom_blur_vertical7.frag"));
        } catch (final IOException ex) {
            logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
        }
        blurShaderVertical.setUniform("RT", 0);

        // Create final shader(basic texturing)
        finalShader = new GLSLShaderObjectsState();
        try {
            finalShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
                    shaderDirectory + "bloom_final.vert"));
            finalShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(BloomRenderPass.class,
                    shaderDirectory + "bloom_final.frag"));
        } catch (final IOException ex) {
            logger.logp(Level.SEVERE, getClass().getName(), "init(Renderer)", "Could not load shaders.", ex);
        }

        // Create fullscreen quad
        fullScreenQuad = new Quad("FullScreenQuad", cam.getWidth() / 4, cam.getHeight() / 4);
        fullScreenQuad.setTranslation(cam.getWidth() / 2, cam.getHeight() / 2, 0);
        fullScreenQuad.getSceneHints().setRenderBucketType(RenderBucketType.Ortho);

        fullScreenQuad.getSceneHints().setCullHint(CullHint.Never);
        fullScreenQuad.getSceneHints().setTextureCombineMode(TextureCombineMode.Replace);
        fullScreenQuad.getSceneHints().setLightCombineMode(LightCombineMode.Off);

        final TextureState ts = new TextureState();
        ts.setEnabled(true);
        fullScreenQuad.setRenderState(ts);

        final BlendState as = new BlendState();
        as.setBlendEnabled(true);
        as.setSourceFunction(BlendState.SourceFunction.One);
        as.setDestinationFunction(BlendState.DestinationFunction.One);
        as.setEnabled(true);
        fullScreenQuad.setRenderState(as);

        fullScreenQuad.updateGeometricState(0.0f, true);
    }

    /**
     * @return The throttle amount - or in other words, how much time in seconds must pass before the bloom effect is
     *         updated.
     */
    public double getThrottle() {
        return throttle;
    }

    /**
     * @param throttle
     *            The throttle amount - or in other words, how much time in seconds must pass before the bloom effect is
     *            updated.
     */
    public void setThrottle(final float throttle) {
        this.throttle = throttle;
    }

    public float getBlurSize() {
        return blurSize;
    }

    public void setBlurSize(final float blurSize) {
        this.blurSize = blurSize;
    }

    public float getExposurePow() {
        return exposurePow;
    }

    public void setExposurePow(final float exposurePow) {
        this.exposurePow = exposurePow;
    }

    public float getExposureCutoff() {
        return exposureCutoff;
    }

    public void setExposureCutoff(final float exposureCutoff) {
        this.exposureCutoff = exposureCutoff;
    }

    public float getBlurIntensityMultiplier() {
        return blurIntensityMultiplier;
    }

    public void setBlurIntensityMultiplier(final float blurIntensityMultiplier) {
        this.blurIntensityMultiplier = blurIntensityMultiplier;
    }

    public int getNrBlurPasses() {
        return nrBlurPasses;
    }

    public void setNrBlurPasses(final int nrBlurPasses) {
        this.nrBlurPasses = nrBlurPasses;
    }

    public boolean useCurrentScene() {
        return useCurrentScene;
    }

    public void setUseCurrentScene(final boolean useCurrentScene) {
        this.useCurrentScene = useCurrentScene;
    }

    public void setUseSeparateConvolution(final boolean useSeparateConvolution) {
        this.useSeparateConvolution = useSeparateConvolution;
    }

    public boolean isUseSeparateConvolution() {
        return useSeparateConvolution;
    }

    public void markNeedsRefresh() {
        initialized = false;
    }
}
TOP

Related Classes of com.ardor3d.extension.effect.bloom.BloomRenderPass

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.