/** * Copyright (c) 2003-2009, Xith3D Project Group all rights reserved. * * Portions based on the Java3D interface, Copyright by Sun Microsystems. * Many thanks to the developers of Java3D and Sun Microsystems for their * innovation and design. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * Neither the name of the 'Xith3D Project Group' nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE */ package org.xith3d.effects.bloom; import java.io.IOException; import java.net.URL; import java.util.List; import org.jagatoo.opengl.enums.FaceCullMode; import org.jagatoo.opengl.enums.TextureFormat; import org.openmali.types.twodee.Sized2iRO; import org.openmali.vecmath2.Colorf; import org.xith3d.base.Xith3DEnvironment; import org.xith3d.loaders.shaders.impl.glsl.GLSLShaderLoader; import org.xith3d.loaders.texture.TextureCreator; import org.xith3d.render.ForegroundRenderPass; import org.xith3d.render.RenderPass; import org.xith3d.render.TextureRenderTarget; import org.xith3d.scenegraph.Appearance; import org.xith3d.scenegraph.GLSLFragmentShader; import org.xith3d.scenegraph.GLSLContext; import org.xith3d.scenegraph.GLSLShaderProgram; import org.xith3d.scenegraph.GLSLVertexShader; import org.xith3d.scenegraph.GroupNode; import org.xith3d.scenegraph.PolygonAttributes; import org.xith3d.scenegraph.StaticTransform; import org.xith3d.scenegraph.Texture; import org.xith3d.scenegraph.Texture2D; import org.xith3d.scenegraph.Transform3D; import org.xith3d.scenegraph.primitives.Rectangle; /** * The GLSLBloomFactory is an implementation of Bloom effect using GLSL shaders.<br> * <br> * I requires more render passes but all pixels computations (brightness, gaussian, and blending) * are done by the GPU.<br> * <br> * * @author Yoann Meste (aka Mancer) */ public class GLSLBloomFactory extends BloomFactory { private static final int TEXTURE_SIZE = 128; private GLSLContext brightpassFilter = null; private GLSLContext verticalGaussianFilter = null; private GLSLContext horizontalGaussianFilter = null; private GLSLContext blendFilter = null; private Texture2D inTex, brightTex, gaussianTex, outTex; private final Colorf bgColor = new Colorf( 0f, 0f, 0f, 1.0f ); private static URL getResource( String resName ) throws IOException { URL url = GLSLBloomFactory.class.getClassLoader().getResource( resName ); if ( url == null ) { throw new IOException( "Could not find resource \"" + resName + "\"." ); } return ( url ); } private void loadShaders() throws IOException { GLSLVertexShader vertexShader; GLSLFragmentShader fragmentShader; vertexShader = GLSLShaderLoader.getInstance().loadVertexShader( getResource( "resources/org/xith3d/shaders/bloom/bloom.glslvert" ) ); fragmentShader = GLSLShaderLoader.getInstance().loadFragmentShader( getResource( "resources/org/xith3d/shaders/bloom/brightness_filter.glslfrag" ) ); GLSLShaderProgram program = new GLSLShaderProgram(); program.addShader( vertexShader ); program.addShader( fragmentShader ); brightpassFilter = new GLSLContext( program ); brightpassFilter.getUniformParameters().setUniformVar( "tex", 0 ); fragmentShader = GLSLShaderLoader.getInstance().loadFragmentShader( getResource( "resources/org/xith3d/shaders/bloom/gaussian_v.glslfrag" ) ); program = new GLSLShaderProgram(); program.addShader( vertexShader ); program.addShader( fragmentShader ); verticalGaussianFilter = new GLSLContext( program ); verticalGaussianFilter.getUniformParameters().setUniformVar( "inTexture", 0 ); fragmentShader = GLSLShaderLoader.getInstance().loadFragmentShader( getResource( "resources/org/xith3d/shaders/bloom/gaussian_h.glslfrag" ) ); program = new GLSLShaderProgram(); program.addShader( vertexShader ); program.addShader( fragmentShader ); horizontalGaussianFilter = new GLSLContext( program ); horizontalGaussianFilter.getUniformParameters().setUniformVar( "inTexture", 0 ); fragmentShader = GLSLShaderLoader.getInstance().loadFragmentShader( getResource( "resources/org/xith3d/shaders/bloom/bloom.glslfrag" ) ); program = new GLSLShaderProgram(); program.addShader( vertexShader ); program.addShader( fragmentShader ); blendFilter = new GLSLContext( program ); } private void initTextures( Sized2iRO resolution ) { inTex = TextureCreator.createTexture( TextureFormat.RGBA, resolution.getWidth(), resolution.getHeight(), bgColor ); inTex.enableAutoFreeLocalData(); brightTex = TextureCreator.createTexture( TextureFormat.RGBA, TEXTURE_SIZE, TEXTURE_SIZE, bgColor ); brightTex.enableAutoFreeLocalData(); gaussianTex = TextureCreator.createTexture( TextureFormat.RGBA, TEXTURE_SIZE, TEXTURE_SIZE, bgColor ); gaussianTex.enableAutoFreeLocalData(); outTex = TextureCreator.createTexture( TextureFormat.RGBA, TEXTURE_SIZE, TEXTURE_SIZE, bgColor ); outTex.enableAutoFreeLocalData(); } private void createFilter( Xith3DEnvironment env, Sized2iRO res, GLSLContext program, Texture in, Texture out ) { // TODO: Check, in what way this texture could be cached! Texture2D empty = TextureCreator.createTexture( TextureFormat.RGBA, 1024, 1024, new Colorf( 0f, 0f, 0f, 1f ) ); Rectangle finalTarget = new Rectangle( 2f, 2f / res.getWidth() * res.getHeight(), empty ); Appearance appearance = finalTarget.getAppearance( true ); appearance.setTexture( 0, in ); appearance.setShaderProgramContext( program ); RenderPass finalPass = ForegroundRenderPass.createParallel(); finalPass.getConfig().setViewTransform( Transform3D.IDENTITY ); finalPass.getBranchGroup().addChild( finalTarget ); TextureRenderTarget renderTarget = new TextureRenderTarget( finalPass.getBranchGroup(), out, bgColor ); finalPass.setRenderTarget( renderTarget ); env.addRenderPass( finalPass ); } @Override public void prepareForBloom( Xith3DEnvironment env, Sized2iRO resolution, GroupNode group ) throws IOException { loadShaders(); initTextures( resolution ); List< RenderPass > passes = env.getRenderer().getRenderPasses( group.getRoot() ); TextureRenderTarget renderTarget1 = new TextureRenderTarget( group, inTex, bgColor ); passes.get( 0 ).setRenderTarget( renderTarget1 ); createFilter( env, resolution, brightpassFilter, inTex, brightTex ); createFilter( env, resolution, horizontalGaussianFilter, brightTex, gaussianTex ); createFilter( env, resolution, verticalGaussianFilter, gaussianTex, outTex ); // TODO: Check, in what way this texture could be cached! Texture2D empty = TextureCreator.createTexture( TextureFormat.RGBA, 1024, 1024, new Colorf( 0f, 0f, 0f, 1f ) ); Rectangle finalTarget = new Rectangle( 2f, 2f / resolution.getWidth() * resolution.getHeight(), empty ); Appearance appearance = finalTarget.getAppearance( true ); appearance.setTexture( 0, inTex ); appearance.setTexture( 1, outTex ); blendFilter.getUniformParameters().setUniformVar( "originalWeight", getSceneWeight() ); blendFilter.getUniformParameters().setUniformVar( "bloomWeight", getBloomWeight() ); blendFilter.getUniformParameters().setUniformVar( "originalTex", 0 ); blendFilter.getUniformParameters().setUniformVar( "filteredTex", 1 ); appearance.setShaderProgramContext( blendFilter ); appearance.setPolygonAttributes( new PolygonAttributes( FaceCullMode.BACK ) ); //RenderPass finalPass = env.addParallelBranch(); RenderPass finalPass = ForegroundRenderPass.createParallel(); env.addRenderPass( finalPass ); finalPass.getConfig().setViewTransform( Transform3D.IDENTITY ); StaticTransform.translate( finalTarget, 0, 0, -1f ); finalPass.getBranchGroup().addChild( finalTarget ); //TODO the skybox is still not visible ... why ??? //TODO When the bloom is applied on BSPLoader testcase, the polygons aren't displayed correctly } @Override protected void updateBloomSettings() { if ( blendFilter != null ) { blendFilter.getUniformParameters().setUniformVar( "originalWeight", getSceneWeight() ); blendFilter.getUniformParameters().setUniformVar( "bloomWeight", getBloomWeight() ); } } public GLSLBloomFactory() { } }