- remove desktop-fx package and move effects to core, remove HDRRenderer swing UI
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8849 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
85ed03bb92
commit
c16e880888
@ -67,12 +67,11 @@
|
|||||||
<echo>Compile Desktop</echo>
|
<echo>Compile Desktop</echo>
|
||||||
<j2seproject3:javac
|
<j2seproject3:javac
|
||||||
destdir="${build.dir}/desktop"
|
destdir="${build.dir}/desktop"
|
||||||
srcdir="${src.desktop.dir}:${src.desktop-fx.dir}"
|
srcdir="${src.desktop.dir}"
|
||||||
classpath="${javac.classpath}:${build.dir}/core"
|
classpath="${javac.classpath}:${build.dir}/core"
|
||||||
gensrcdir="${build.generated.sources.dir}"/>
|
gensrcdir="${build.generated.sources.dir}"/>
|
||||||
<copy todir="${build.dir}/desktop">
|
<copy todir="${build.dir}/desktop">
|
||||||
<fileset dir="${src.desktop.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
<fileset dir="${src.desktop.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
||||||
<fileset dir="${src.desktop-fx.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
|
||||||
</copy>
|
</copy>
|
||||||
|
|
||||||
<echo>Compile Blender Loader</echo>
|
<echo>Compile Blender Loader</echo>
|
||||||
@ -330,7 +329,6 @@
|
|||||||
<zipfileset dir="${src.core-data.dir}"/>
|
<zipfileset dir="${src.core-data.dir}"/>
|
||||||
<zipfileset dir="${src.core-plugins.dir}"/>
|
<zipfileset dir="${src.core-plugins.dir}"/>
|
||||||
<zipfileset dir="${src.desktop.dir}"/>
|
<zipfileset dir="${src.desktop.dir}"/>
|
||||||
<zipfileset dir="${src.desktop-fx.dir}"/>
|
|
||||||
<zipfileset dir="${src.jbullet.dir}"/>
|
<zipfileset dir="${src.jbullet.dir}"/>
|
||||||
<zipfileset dir="${src.niftygui.dir}"/>
|
<zipfileset dir="${src.niftygui.dir}"/>
|
||||||
<zipfileset dir="${src.jogg.dir}"/>
|
<zipfileset dir="${src.jogg.dir}"/>
|
||||||
@ -388,7 +386,6 @@
|
|||||||
<zipfileset dir="${src.core-data.dir}" prefix="source"/>
|
<zipfileset dir="${src.core-data.dir}" prefix="source"/>
|
||||||
<zipfileset dir="${src.core-plugins.dir}" prefix="source"/>
|
<zipfileset dir="${src.core-plugins.dir}" prefix="source"/>
|
||||||
<zipfileset dir="${src.desktop.dir}" prefix="source"/>
|
<zipfileset dir="${src.desktop.dir}" prefix="source"/>
|
||||||
<zipfileset dir="${src.desktop-fx.dir}" prefix="source"/>
|
|
||||||
<zipfileset dir="${src.jbullet.dir}" prefix="source"/>
|
<zipfileset dir="${src.jbullet.dir}" prefix="source"/>
|
||||||
<zipfileset dir="${src.niftygui.dir}" prefix="source"/>
|
<zipfileset dir="${src.niftygui.dir}" prefix="source"/>
|
||||||
<zipfileset dir="${src.jogg.dir}" prefix="source"/>
|
<zipfileset dir="${src.jogg.dir}" prefix="source"/>
|
||||||
|
@ -170,7 +170,6 @@ is divided into following sections:
|
|||||||
<available file="${src.core-data.dir}"/>
|
<available file="${src.core-data.dir}"/>
|
||||||
<available file="${src.core-plugins.dir}"/>
|
<available file="${src.core-plugins.dir}"/>
|
||||||
<available file="${src.desktop.dir}"/>
|
<available file="${src.desktop.dir}"/>
|
||||||
<available file="${src.desktop-fx.dir}"/>
|
|
||||||
<available file="${src.terrain.dir}"/>
|
<available file="${src.terrain.dir}"/>
|
||||||
<available file="${src.jbullet.dir}"/>
|
<available file="${src.jbullet.dir}"/>
|
||||||
<available file="${src.bullet.dir}"/>
|
<available file="${src.bullet.dir}"/>
|
||||||
@ -253,7 +252,6 @@ is divided into following sections:
|
|||||||
<fail unless="src.core-data.dir">Must set src.core-data.dir</fail>
|
<fail unless="src.core-data.dir">Must set src.core-data.dir</fail>
|
||||||
<fail unless="src.core-plugins.dir">Must set src.core-plugins.dir</fail>
|
<fail unless="src.core-plugins.dir">Must set src.core-plugins.dir</fail>
|
||||||
<fail unless="src.desktop.dir">Must set src.desktop.dir</fail>
|
<fail unless="src.desktop.dir">Must set src.desktop.dir</fail>
|
||||||
<fail unless="src.desktop-fx.dir">Must set src.desktop-fx.dir</fail>
|
|
||||||
<fail unless="src.terrain.dir">Must set src.terrain.dir</fail>
|
<fail unless="src.terrain.dir">Must set src.terrain.dir</fail>
|
||||||
<fail unless="src.jbullet.dir">Must set src.jbullet.dir</fail>
|
<fail unless="src.jbullet.dir">Must set src.jbullet.dir</fail>
|
||||||
<fail unless="src.bullet.dir">Must set src.bullet.dir</fail>
|
<fail unless="src.bullet.dir">Must set src.bullet.dir</fail>
|
||||||
@ -289,7 +287,7 @@ is divided into following sections:
|
|||||||
</target>
|
</target>
|
||||||
<target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
|
<target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
|
||||||
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
|
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||||
<attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.desktop-fx.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
|
<attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
|
||||||
<attribute default="${build.classes.dir}" name="destdir"/>
|
<attribute default="${build.classes.dir}" name="destdir"/>
|
||||||
<attribute default="${javac.classpath}" name="classpath"/>
|
<attribute default="${javac.classpath}" name="classpath"/>
|
||||||
<attribute default="${javac.processorpath}" name="processorpath"/>
|
<attribute default="${javac.processorpath}" name="processorpath"/>
|
||||||
@ -329,7 +327,7 @@ is divided into following sections:
|
|||||||
</target>
|
</target>
|
||||||
<target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
|
<target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
|
||||||
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
|
<macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||||
<attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.desktop-fx.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
|
<attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
|
||||||
<attribute default="${build.classes.dir}" name="destdir"/>
|
<attribute default="${build.classes.dir}" name="destdir"/>
|
||||||
<attribute default="${javac.classpath}" name="classpath"/>
|
<attribute default="${javac.classpath}" name="classpath"/>
|
||||||
<attribute default="${javac.processorpath}" name="processorpath"/>
|
<attribute default="${javac.processorpath}" name="processorpath"/>
|
||||||
@ -361,7 +359,7 @@ is divided into following sections:
|
|||||||
</target>
|
</target>
|
||||||
<target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
|
<target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
|
||||||
<macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
|
<macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
|
||||||
<attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.desktop-fx.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
|
<attribute default="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}" name="srcdir"/>
|
||||||
<attribute default="${build.classes.dir}" name="destdir"/>
|
<attribute default="${build.classes.dir}" name="destdir"/>
|
||||||
<attribute default="${javac.classpath}" name="classpath"/>
|
<attribute default="${javac.classpath}" name="classpath"/>
|
||||||
<sequential>
|
<sequential>
|
||||||
@ -659,7 +657,7 @@ is divided into following sections:
|
|||||||
<include name="*"/>
|
<include name="*"/>
|
||||||
</dirset>
|
</dirset>
|
||||||
</pathconvert>
|
</pathconvert>
|
||||||
<j2seproject3:depend srcdir="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.desktop-fx.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}:${build.generated.subdirs}"/>
|
<j2seproject3:depend srcdir="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}:${build.generated.subdirs}"/>
|
||||||
</target>
|
</target>
|
||||||
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
|
<target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
|
||||||
<j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
|
<j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
|
||||||
@ -668,7 +666,6 @@ is divided into following sections:
|
|||||||
<fileset dir="${src.core-data.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
<fileset dir="${src.core-data.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
||||||
<fileset dir="${src.core-plugins.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
<fileset dir="${src.core-plugins.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
||||||
<fileset dir="${src.desktop.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
<fileset dir="${src.desktop.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
||||||
<fileset dir="${src.desktop-fx.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
|
||||||
<fileset dir="${src.terrain.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
<fileset dir="${src.terrain.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
||||||
<fileset dir="${src.jbullet.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
<fileset dir="${src.jbullet.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
||||||
<fileset dir="${src.bullet.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
<fileset dir="${src.bullet.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
|
||||||
@ -703,7 +700,7 @@ is divided into following sections:
|
|||||||
<target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
|
<target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
|
||||||
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
|
<fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
|
||||||
<j2seproject3:force-recompile/>
|
<j2seproject3:force-recompile/>
|
||||||
<j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.desktop-fx.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}"/>
|
<j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.core.dir}:${src.core-data.dir}:${src.core-plugins.dir}:${src.desktop.dir}:${src.terrain.dir}:${src.jbullet.dir}:${src.bullet.dir}:${src.bullet-common.dir}:${src.networking.dir}:${src.niftygui.dir}:${src.jogg.dir}:${src.ogre.dir}:${src.blender.dir}:${src.xml.dir}:${src.tools.dir}:${src.test.dir}:${src.lwjgl.dir}:${src.android.dir}"/>
|
||||||
</target>
|
</target>
|
||||||
<target name="-post-compile-single">
|
<target name="-post-compile-single">
|
||||||
<!-- Empty placeholder for easier customization. -->
|
<!-- Empty placeholder for easier customization. -->
|
||||||
@ -935,9 +932,6 @@ is divided into following sections:
|
|||||||
<fileset dir="${src.desktop.dir}" excludes="*.java,${excludes}" includes="${includes}">
|
<fileset dir="${src.desktop.dir}" excludes="*.java,${excludes}" includes="${includes}">
|
||||||
<filename name="**/*.java"/>
|
<filename name="**/*.java"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
<fileset dir="${src.desktop-fx.dir}" excludes="*.java,${excludes}" includes="${includes}">
|
|
||||||
<filename name="**/*.java"/>
|
|
||||||
</fileset>
|
|
||||||
<fileset dir="${src.terrain.dir}" excludes="*.java,${excludes}" includes="${includes}">
|
<fileset dir="${src.terrain.dir}" excludes="*.java,${excludes}" includes="${includes}">
|
||||||
<filename name="**/*.java"/>
|
<filename name="**/*.java"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
@ -998,9 +992,6 @@ is divided into following sections:
|
|||||||
<fileset dir="${src.desktop.dir}" excludes="${excludes}" includes="${includes}">
|
<fileset dir="${src.desktop.dir}" excludes="${excludes}" includes="${includes}">
|
||||||
<filename name="**/doc-files/**"/>
|
<filename name="**/doc-files/**"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
<fileset dir="${src.desktop-fx.dir}" excludes="${excludes}" includes="${includes}">
|
|
||||||
<filename name="**/doc-files/**"/>
|
|
||||||
</fileset>
|
|
||||||
<fileset dir="${src.terrain.dir}" excludes="${excludes}" includes="${includes}">
|
<fileset dir="${src.terrain.dir}" excludes="${excludes}" includes="${includes}">
|
||||||
<filename name="**/doc-files/**"/>
|
<filename name="**/doc-files/**"/>
|
||||||
</fileset>
|
</fileset>
|
||||||
|
@ -3,8 +3,8 @@ build.xml.script.CRC32=34d4c2f2
|
|||||||
build.xml.stylesheet.CRC32=958a1d3e
|
build.xml.stylesheet.CRC32=958a1d3e
|
||||||
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
|
# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
|
||||||
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
|
# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
|
||||||
nbproject/build-impl.xml.data.CRC32=3272ce3a
|
nbproject/build-impl.xml.data.CRC32=11158891
|
||||||
nbproject/build-impl.xml.script.CRC32=d1b33dd7
|
nbproject/build-impl.xml.script.CRC32=283800d6
|
||||||
nbproject/build-impl.xml.stylesheet.CRC32=0ae3a408@1.44.1.45
|
nbproject/build-impl.xml.stylesheet.CRC32=0ae3a408@1.44.1.45
|
||||||
nbproject/profiler-build-impl.xml.data.CRC32=aff514c1
|
nbproject/profiler-build-impl.xml.data.CRC32=aff514c1
|
||||||
nbproject/profiler-build-impl.xml.script.CRC32=abda56ed
|
nbproject/profiler-build-impl.xml.script.CRC32=abda56ed
|
||||||
|
@ -109,7 +109,6 @@ src.bullet.dir=src/bullet
|
|||||||
src.core-data.dir=src/core-data
|
src.core-data.dir=src/core-data
|
||||||
src.core-plugins.dir=src/core-plugins
|
src.core-plugins.dir=src/core-plugins
|
||||||
src.core.dir=src/core
|
src.core.dir=src/core
|
||||||
src.desktop-fx.dir=src/desktop-fx
|
|
||||||
src.desktop.dir=src/desktop
|
src.desktop.dir=src/desktop
|
||||||
src.jbullet.dir=src/jbullet
|
src.jbullet.dir=src/jbullet
|
||||||
src.jogg.dir=src/jogg
|
src.jogg.dir=src/jogg
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
<root id="src.core-data.dir" name="Core-Data"/>
|
<root id="src.core-data.dir" name="Core-Data"/>
|
||||||
<root id="src.core-plugins.dir" name="Core-Plugins"/>
|
<root id="src.core-plugins.dir" name="Core-Plugins"/>
|
||||||
<root id="src.desktop.dir" name="Desktop"/>
|
<root id="src.desktop.dir" name="Desktop"/>
|
||||||
<root id="src.desktop-fx.dir" name="Desktop-FX"/>
|
|
||||||
<root id="src.terrain.dir" name="Terrain"/>
|
<root id="src.terrain.dir" name="Terrain"/>
|
||||||
<root id="src.jbullet.dir" name="Java Bullet"/>
|
<root id="src.jbullet.dir" name="Java Bullet"/>
|
||||||
<root id="src.bullet.dir" name="Native Bullet"/>
|
<root id="src.bullet.dir" name="Native Bullet"/>
|
||||||
|
419
engine/src/core/com/jme3/post/HDRRenderer.java
Normal file
419
engine/src/core/com/jme3/post/HDRRenderer.java
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.jme3.post;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.Vector2f;
|
||||||
|
import com.jme3.renderer.*;
|
||||||
|
import com.jme3.renderer.queue.RenderQueue;
|
||||||
|
import com.jme3.texture.FrameBuffer;
|
||||||
|
import com.jme3.texture.Image;
|
||||||
|
import com.jme3.texture.Image.Format;
|
||||||
|
import com.jme3.texture.Texture;
|
||||||
|
import com.jme3.texture.Texture.MagFilter;
|
||||||
|
import com.jme3.texture.Texture.MinFilter;
|
||||||
|
import com.jme3.texture.Texture2D;
|
||||||
|
import com.jme3.ui.Picture;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class HDRRenderer implements SceneProcessor {
|
||||||
|
|
||||||
|
private static final int LUMMODE_NONE = 0x1,
|
||||||
|
LUMMODE_ENCODE_LUM = 0x2,
|
||||||
|
LUMMODE_DECODE_LUM = 0x3;
|
||||||
|
|
||||||
|
private Renderer renderer;
|
||||||
|
private RenderManager renderManager;
|
||||||
|
private ViewPort viewPort;
|
||||||
|
private static final Logger logger = Logger.getLogger(HDRRenderer.class.getName());
|
||||||
|
|
||||||
|
private Camera fbCam = new Camera(1, 1);
|
||||||
|
|
||||||
|
private FrameBuffer msFB;
|
||||||
|
|
||||||
|
private FrameBuffer mainSceneFB;
|
||||||
|
private Texture2D mainScene;
|
||||||
|
private FrameBuffer scene64FB;
|
||||||
|
private Texture2D scene64;
|
||||||
|
private FrameBuffer scene8FB;
|
||||||
|
private Texture2D scene8;
|
||||||
|
private FrameBuffer scene1FB[] = new FrameBuffer[2];
|
||||||
|
private Texture2D scene1[] = new Texture2D[2];
|
||||||
|
|
||||||
|
private Material hdr64;
|
||||||
|
private Material hdr8;
|
||||||
|
private Material hdr1;
|
||||||
|
private Material tone;
|
||||||
|
|
||||||
|
private Picture fsQuad;
|
||||||
|
private float time = 0;
|
||||||
|
private int curSrc = -1;
|
||||||
|
private int oppSrc = -1;
|
||||||
|
private float blendFactor = 0;
|
||||||
|
|
||||||
|
private int numSamples = 0;
|
||||||
|
private float exposure = 0.18f;
|
||||||
|
private float whiteLevel = 100f;
|
||||||
|
private float throttle = -1;
|
||||||
|
private int maxIterations = -1;
|
||||||
|
private Image.Format bufFormat = Format.RGB16F;
|
||||||
|
|
||||||
|
private MinFilter fbMinFilter = MinFilter.BilinearNoMipMaps;
|
||||||
|
private MagFilter fbMagFilter = MagFilter.Bilinear;
|
||||||
|
private AssetManager manager;
|
||||||
|
|
||||||
|
private boolean enabled = true;
|
||||||
|
|
||||||
|
public HDRRenderer(AssetManager manager, Renderer renderer){
|
||||||
|
this.manager = manager;
|
||||||
|
this.renderer = renderer;
|
||||||
|
|
||||||
|
Collection<Caps> caps = renderer.getCaps();
|
||||||
|
if (caps.contains(Caps.PackedFloatColorBuffer))
|
||||||
|
bufFormat = Format.RGB111110F;
|
||||||
|
else if (caps.contains(Caps.FloatColorBuffer))
|
||||||
|
bufFormat = Format.RGB16F;
|
||||||
|
else{
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSamples(int samples){
|
||||||
|
this.numSamples = samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExposure(float exp){
|
||||||
|
this.exposure = exp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWhiteLevel(float whiteLevel){
|
||||||
|
this.whiteLevel = whiteLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxIterations(int maxIterations){
|
||||||
|
this.maxIterations = maxIterations;
|
||||||
|
|
||||||
|
// regenerate shaders if needed
|
||||||
|
if (hdr64 != null)
|
||||||
|
createLumShaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setThrottle(float throttle){
|
||||||
|
this.throttle = throttle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUseFastFilter(boolean fastFilter){
|
||||||
|
if (fastFilter){
|
||||||
|
fbMagFilter = MagFilter.Nearest;
|
||||||
|
fbMinFilter = MinFilter.NearestNoMipMaps;
|
||||||
|
}else{
|
||||||
|
fbMagFilter = MagFilter.Bilinear;
|
||||||
|
fbMinFilter = MinFilter.BilinearNoMipMaps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Picture createDisplayQuad(/*int mode, Texture tex*/){
|
||||||
|
if (scene64 == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Material mat = new Material(manager, "Common/MatDefs/Hdr/LogLum.j3md");
|
||||||
|
// if (mode == LUMMODE_ENCODE_LUM)
|
||||||
|
// mat.setBoolean("EncodeLum", true);
|
||||||
|
// else if (mode == LUMMODE_DECODE_LUM)
|
||||||
|
mat.setBoolean("DecodeLum", true);
|
||||||
|
mat.setTexture("Texture", scene64);
|
||||||
|
// mat.setTexture("Texture", tex);
|
||||||
|
|
||||||
|
Picture dispQuad = new Picture("Luminance Display");
|
||||||
|
dispQuad.setMaterial(mat);
|
||||||
|
return dispQuad;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Material createLumShader(int srcW, int srcH, int bufW, int bufH, int mode,
|
||||||
|
int iters, Texture tex){
|
||||||
|
Material mat = new Material(manager, "Common/MatDefs/Hdr/LogLum.j3md");
|
||||||
|
|
||||||
|
Vector2f blockSize = new Vector2f(1f / bufW, 1f / bufH);
|
||||||
|
Vector2f pixelSize = new Vector2f(1f / srcW, 1f / srcH);
|
||||||
|
Vector2f blocks = new Vector2f();
|
||||||
|
float numPixels = Float.POSITIVE_INFINITY;
|
||||||
|
if (iters != -1){
|
||||||
|
do {
|
||||||
|
pixelSize.multLocal(2);
|
||||||
|
blocks.set(blockSize.x / pixelSize.x,
|
||||||
|
blockSize.y / pixelSize.y);
|
||||||
|
numPixels = blocks.x * blocks.y;
|
||||||
|
} while (numPixels > iters);
|
||||||
|
}else{
|
||||||
|
blocks.set(blockSize.x / pixelSize.x,
|
||||||
|
blockSize.y / pixelSize.y);
|
||||||
|
numPixels = blocks.x * blocks.y;
|
||||||
|
}
|
||||||
|
System.out.println(numPixels);
|
||||||
|
|
||||||
|
mat.setBoolean("Blocks", true);
|
||||||
|
if (mode == LUMMODE_ENCODE_LUM)
|
||||||
|
mat.setBoolean("EncodeLum", true);
|
||||||
|
else if (mode == LUMMODE_DECODE_LUM)
|
||||||
|
mat.setBoolean("DecodeLum", true);
|
||||||
|
|
||||||
|
mat.setTexture("Texture", tex);
|
||||||
|
mat.setVector2("BlockSize", blockSize);
|
||||||
|
mat.setVector2("PixelSize", pixelSize);
|
||||||
|
mat.setFloat("NumPixels", numPixels);
|
||||||
|
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createLumShaders(){
|
||||||
|
int w = mainSceneFB.getWidth();
|
||||||
|
int h = mainSceneFB.getHeight();
|
||||||
|
hdr64 = createLumShader(w, h, 64, 64, LUMMODE_ENCODE_LUM, maxIterations, mainScene);
|
||||||
|
hdr8 = createLumShader(64, 64, 8, 8, LUMMODE_NONE, maxIterations, scene64);
|
||||||
|
hdr1 = createLumShader(8, 8, 1, 1, LUMMODE_NONE, maxIterations, scene8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int opposite(int i){
|
||||||
|
return i == 1 ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderProcessing(Renderer r, FrameBuffer dst, Material mat){
|
||||||
|
if (dst == null){
|
||||||
|
fsQuad.setWidth(mainSceneFB.getWidth());
|
||||||
|
fsQuad.setHeight(mainSceneFB.getHeight());
|
||||||
|
fbCam.resize(mainSceneFB.getWidth(), mainSceneFB.getHeight(), true);
|
||||||
|
}else{
|
||||||
|
fsQuad.setWidth(dst.getWidth());
|
||||||
|
fsQuad.setHeight(dst.getHeight());
|
||||||
|
fbCam.resize(dst.getWidth(), dst.getHeight(), true);
|
||||||
|
}
|
||||||
|
fsQuad.setMaterial(mat);
|
||||||
|
fsQuad.updateGeometricState();
|
||||||
|
renderManager.setCamera(fbCam, true);
|
||||||
|
|
||||||
|
r.setFrameBuffer(dst);
|
||||||
|
r.clearBuffers(true, true, true);
|
||||||
|
renderManager.renderGeometry(fsQuad);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderToneMap(Renderer r, FrameBuffer out){
|
||||||
|
tone.setFloat("A", exposure);
|
||||||
|
tone.setFloat("White", whiteLevel);
|
||||||
|
tone.setTexture("Lum", scene1[oppSrc]);
|
||||||
|
tone.setTexture("Lum2", scene1[curSrc]);
|
||||||
|
tone.setFloat("BlendFactor", blendFactor);
|
||||||
|
renderProcessing(r, out, tone);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAverageLuminance(Renderer r){
|
||||||
|
renderProcessing(r, scene64FB, hdr64);
|
||||||
|
renderProcessing(r, scene8FB, hdr8);
|
||||||
|
renderProcessing(r, scene1FB[curSrc], hdr1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInitialized(){
|
||||||
|
return viewPort != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reshape(ViewPort vp, int w, int h){
|
||||||
|
if (mainSceneFB != null){
|
||||||
|
renderer.deleteFrameBuffer(mainSceneFB);
|
||||||
|
}
|
||||||
|
|
||||||
|
mainSceneFB = new FrameBuffer(w, h, 1);
|
||||||
|
mainScene = new Texture2D(w, h, bufFormat);
|
||||||
|
mainSceneFB.setDepthBuffer(Format.Depth);
|
||||||
|
mainSceneFB.setColorTexture(mainScene);
|
||||||
|
mainScene.setMagFilter(fbMagFilter);
|
||||||
|
mainScene.setMinFilter(fbMinFilter);
|
||||||
|
|
||||||
|
if (msFB != null){
|
||||||
|
renderer.deleteFrameBuffer(msFB);
|
||||||
|
}
|
||||||
|
|
||||||
|
tone.setTexture("Texture", mainScene);
|
||||||
|
|
||||||
|
Collection<Caps> caps = renderer.getCaps();
|
||||||
|
if (numSamples > 1 && caps.contains(Caps.FrameBufferMultisample)){
|
||||||
|
msFB = new FrameBuffer(w, h, numSamples);
|
||||||
|
msFB.setDepthBuffer(Format.Depth);
|
||||||
|
msFB.setColorBuffer(bufFormat);
|
||||||
|
vp.setOutputFrameBuffer(msFB);
|
||||||
|
}else{
|
||||||
|
if (numSamples > 1)
|
||||||
|
logger.warning("FBO multisampling not supported on this GPU, request ignored.");
|
||||||
|
|
||||||
|
vp.setOutputFrameBuffer(mainSceneFB);
|
||||||
|
}
|
||||||
|
|
||||||
|
createLumShaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(RenderManager rm, ViewPort vp){
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
renderer = rm.getRenderer();
|
||||||
|
renderManager = rm;
|
||||||
|
viewPort = vp;
|
||||||
|
|
||||||
|
// loadInitial()
|
||||||
|
fsQuad = new Picture("HDR Fullscreen Quad");
|
||||||
|
|
||||||
|
Format lumFmt = Format.RGB8;
|
||||||
|
scene64FB = new FrameBuffer(64, 64, 1);
|
||||||
|
scene64 = new Texture2D(64, 64, lumFmt);
|
||||||
|
scene64FB.setColorTexture(scene64);
|
||||||
|
scene64.setMagFilter(fbMagFilter);
|
||||||
|
scene64.setMinFilter(fbMinFilter);
|
||||||
|
|
||||||
|
scene8FB = new FrameBuffer(8, 8, 1);
|
||||||
|
scene8 = new Texture2D(8, 8, lumFmt);
|
||||||
|
scene8FB.setColorTexture(scene8);
|
||||||
|
scene8.setMagFilter(fbMagFilter);
|
||||||
|
scene8.setMinFilter(fbMinFilter);
|
||||||
|
|
||||||
|
scene1FB[0] = new FrameBuffer(1, 1, 1);
|
||||||
|
scene1[0] = new Texture2D(1, 1, lumFmt);
|
||||||
|
scene1FB[0].setColorTexture(scene1[0]);
|
||||||
|
|
||||||
|
scene1FB[1] = new FrameBuffer(1, 1, 1);
|
||||||
|
scene1[1] = new Texture2D(1, 1, lumFmt);
|
||||||
|
scene1FB[1].setColorTexture(scene1[1]);
|
||||||
|
|
||||||
|
// prepare tonemap shader
|
||||||
|
tone = new Material(manager, "Common/MatDefs/Hdr/ToneMap.j3md");
|
||||||
|
tone.setFloat("A", 0.18f);
|
||||||
|
tone.setFloat("White", 100);
|
||||||
|
|
||||||
|
// load();
|
||||||
|
int w = vp.getCamera().getWidth();
|
||||||
|
int h = vp.getCamera().getHeight();
|
||||||
|
reshape(vp, w, h);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void preFrame(float tpf) {
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
time += tpf;
|
||||||
|
blendFactor = (time / throttle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postQueue(RenderQueue rq) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postFrame(FrameBuffer out) {
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (msFB != null){
|
||||||
|
// first render to multisampled FB
|
||||||
|
// renderer.setFrameBuffer(msFB);
|
||||||
|
// renderer.clearBuffers(true,true,true);
|
||||||
|
//
|
||||||
|
// renderManager.renderViewPortRaw(viewPort);
|
||||||
|
|
||||||
|
// render back to non-multisampled FB
|
||||||
|
renderer.copyFrameBuffer(msFB, mainSceneFB);
|
||||||
|
}else{
|
||||||
|
// renderer.setFrameBuffer(mainSceneFB);
|
||||||
|
// renderer.clearBuffers(true,true,false);
|
||||||
|
//
|
||||||
|
// renderManager.renderViewPortRaw(viewPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
// should we update avg lum?
|
||||||
|
if (throttle == -1){
|
||||||
|
// update every frame
|
||||||
|
curSrc = 0;
|
||||||
|
oppSrc = 0;
|
||||||
|
blendFactor = 0;
|
||||||
|
time = 0;
|
||||||
|
updateAverageLuminance(renderer);
|
||||||
|
}else{
|
||||||
|
if (curSrc == -1){
|
||||||
|
curSrc = 0;
|
||||||
|
oppSrc = 0;
|
||||||
|
|
||||||
|
// initial update
|
||||||
|
updateAverageLuminance(renderer);
|
||||||
|
|
||||||
|
blendFactor = 0;
|
||||||
|
time = 0;
|
||||||
|
}else if (time > throttle){
|
||||||
|
|
||||||
|
// time to switch
|
||||||
|
oppSrc = curSrc;
|
||||||
|
curSrc = opposite(curSrc);
|
||||||
|
|
||||||
|
updateAverageLuminance(renderer);
|
||||||
|
|
||||||
|
blendFactor = 0;
|
||||||
|
time = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// since out == mainSceneFB, tonemap into the main screen instead
|
||||||
|
//renderToneMap(renderer, out);
|
||||||
|
renderToneMap(renderer, null);
|
||||||
|
|
||||||
|
renderManager.setCamera(viewPort.getCamera(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (msFB != null)
|
||||||
|
renderer.deleteFrameBuffer(msFB);
|
||||||
|
if (mainSceneFB != null)
|
||||||
|
renderer.deleteFrameBuffer(mainSceneFB);
|
||||||
|
if (scene64FB != null){
|
||||||
|
renderer.deleteFrameBuffer(scene64FB);
|
||||||
|
renderer.deleteFrameBuffer(scene8FB);
|
||||||
|
renderer.deleteFrameBuffer(scene1FB[0]);
|
||||||
|
renderer.deleteFrameBuffer(scene1FB[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
309
engine/src/core/com/jme3/post/filters/BloomFilter.java
Normal file
309
engine/src/core/com/jme3/post/filters/BloomFilter.java
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.export.InputCapsule;
|
||||||
|
import com.jme3.export.JmeExporter;
|
||||||
|
import com.jme3.export.JmeImporter;
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.texture.Image.Format;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BloomFilter is used to make objects in the scene have a glow effect.<br>
|
||||||
|
* There are 2 mode : Scene and Objects.<br>
|
||||||
|
* Scene mode extracts the bright parts of the scene to make them glow<br>
|
||||||
|
* Object mode make objects glow according to their material's glowMap or their GlowColor<br>
|
||||||
|
* @see <a href="http://jmonkeyengine.org/wiki/doku.php/jme3:advanced:bloom_and_glow">advanced:bloom_and_glow</a> for more details
|
||||||
|
*
|
||||||
|
* @author Rémy Bouquet aka Nehon
|
||||||
|
*/
|
||||||
|
public class BloomFilter extends Filter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GlowMode specifies if the glow will be applied to the whole scene,or to objects that have aglow color or a glow map
|
||||||
|
*/
|
||||||
|
public enum GlowMode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply bloom filter to bright areas in the scene.
|
||||||
|
*/
|
||||||
|
Scene,
|
||||||
|
/**
|
||||||
|
* Apply bloom only to objects that have a glow map or a glow color.
|
||||||
|
*/
|
||||||
|
Objects,
|
||||||
|
/**
|
||||||
|
* Apply bloom to both bright parts of the scene and objects with glow map.
|
||||||
|
*/
|
||||||
|
SceneAndObjects;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GlowMode glowMode = GlowMode.Scene;
|
||||||
|
//Bloom parameters
|
||||||
|
private float blurScale = 1.5f;
|
||||||
|
private float exposurePower = 5.0f;
|
||||||
|
private float exposureCutOff = 0.0f;
|
||||||
|
private float bloomIntensity = 2.0f;
|
||||||
|
private float downSamplingFactor = 1;
|
||||||
|
private Pass preGlowPass;
|
||||||
|
private Pass extractPass;
|
||||||
|
private Pass horizontalBlur = new Pass();
|
||||||
|
private Pass verticalalBlur = new Pass();
|
||||||
|
private Material extractMat;
|
||||||
|
private Material vBlurMat;
|
||||||
|
private Material hBlurMat;
|
||||||
|
private int screenWidth;
|
||||||
|
private int screenHeight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a Bloom filter
|
||||||
|
*/
|
||||||
|
public BloomFilter() {
|
||||||
|
super("BloomFilter");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the bloom filter with the specific glow mode
|
||||||
|
* @param glowMode
|
||||||
|
*/
|
||||||
|
public BloomFilter(GlowMode glowMode) {
|
||||||
|
this();
|
||||||
|
this.glowMode = glowMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
screenWidth = (int) Math.max(1, (w / downSamplingFactor));
|
||||||
|
screenHeight = (int) Math.max(1, (h / downSamplingFactor));
|
||||||
|
// System.out.println(screenWidth + " " + screenHeight);
|
||||||
|
if (glowMode != GlowMode.Scene) {
|
||||||
|
preGlowPass = new Pass();
|
||||||
|
preGlowPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
postRenderPasses = new ArrayList<Pass>();
|
||||||
|
//configuring extractPass
|
||||||
|
extractMat = new Material(manager, "Common/MatDefs/Post/BloomExtract.j3md");
|
||||||
|
extractPass = new Pass() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresSceneAsTexture() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeRender() {
|
||||||
|
extractMat.setFloat("ExposurePow", exposurePower);
|
||||||
|
extractMat.setFloat("ExposureCutoff", exposureCutOff);
|
||||||
|
if (glowMode != GlowMode.Scene) {
|
||||||
|
extractMat.setTexture("GlowMap", preGlowPass.getRenderedTexture());
|
||||||
|
}
|
||||||
|
extractMat.setBoolean("Extract", glowMode != GlowMode.Objects);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extractPass.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, extractMat);
|
||||||
|
postRenderPasses.add(extractPass);
|
||||||
|
|
||||||
|
//configuring horizontal blur pass
|
||||||
|
hBlurMat = new Material(manager, "Common/MatDefs/Blur/HGaussianBlur.j3md");
|
||||||
|
horizontalBlur = new Pass() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeRender() {
|
||||||
|
hBlurMat.setTexture("Texture", extractPass.getRenderedTexture());
|
||||||
|
hBlurMat.setFloat("Size", screenWidth);
|
||||||
|
hBlurMat.setFloat("Scale", blurScale);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
horizontalBlur.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, hBlurMat);
|
||||||
|
postRenderPasses.add(horizontalBlur);
|
||||||
|
|
||||||
|
//configuring vertical blur pass
|
||||||
|
vBlurMat = new Material(manager, "Common/MatDefs/Blur/VGaussianBlur.j3md");
|
||||||
|
verticalalBlur = new Pass() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeRender() {
|
||||||
|
vBlurMat.setTexture("Texture", horizontalBlur.getRenderedTexture());
|
||||||
|
vBlurMat.setFloat("Size", screenHeight);
|
||||||
|
vBlurMat.setFloat("Scale", blurScale);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
verticalalBlur.init(renderManager.getRenderer(), screenWidth, screenHeight, Format.RGBA8, Format.Depth, 1, vBlurMat);
|
||||||
|
postRenderPasses.add(verticalalBlur);
|
||||||
|
|
||||||
|
|
||||||
|
//final material
|
||||||
|
material = new Material(manager, "Common/MatDefs/Post/BloomFinal.j3md");
|
||||||
|
material.setTexture("BloomTex", verticalalBlur.getRenderedTexture());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
material.setFloat("BloomIntensity", bloomIntensity);
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
|
||||||
|
if (glowMode != GlowMode.Scene) {
|
||||||
|
renderManager.getRenderer().setBackgroundColor(ColorRGBA.BlackNoAlpha);
|
||||||
|
renderManager.getRenderer().setFrameBuffer(preGlowPass.getRenderFrameBuffer());
|
||||||
|
renderManager.getRenderer().clearBuffers(true, true, true);
|
||||||
|
renderManager.setForcedTechnique("Glow");
|
||||||
|
renderManager.renderViewPortQueues(viewPort, false);
|
||||||
|
renderManager.setForcedTechnique(null);
|
||||||
|
renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the bloom intensity
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getBloomIntensity() {
|
||||||
|
return bloomIntensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* intensity of the bloom effect default is 2.0
|
||||||
|
* @param bloomIntensity
|
||||||
|
*/
|
||||||
|
public void setBloomIntensity(float bloomIntensity) {
|
||||||
|
this.bloomIntensity = bloomIntensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the blur scale
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getBlurScale() {
|
||||||
|
return blurScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets The spread of the bloom default is 1.5f
|
||||||
|
* @param blurScale
|
||||||
|
*/
|
||||||
|
public void setBlurScale(float blurScale) {
|
||||||
|
this.blurScale = blurScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the exposure cutoff<br>
|
||||||
|
* for more details see {@link setExposureCutOff(float exposureCutOff)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getExposureCutOff() {
|
||||||
|
return exposureCutOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define the color threshold on which the bloom will be applied (0.0 to 1.0)
|
||||||
|
* @param exposureCutOff
|
||||||
|
*/
|
||||||
|
public void setExposureCutOff(float exposureCutOff) {
|
||||||
|
this.exposureCutOff = exposureCutOff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the exposure power<br>
|
||||||
|
* form more details see {@link setExposurePower(float exposurePower)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getExposurePower() {
|
||||||
|
return exposurePower;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* defines how many time the bloom extracted color will be multiplied by itself. default id 5.0<br>
|
||||||
|
* a high value will reduce rough edges in the bloom and somhow the range of the bloom area *
|
||||||
|
* @param exposurePower
|
||||||
|
*/
|
||||||
|
public void setExposurePower(float exposurePower) {
|
||||||
|
this.exposurePower = exposurePower;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the downSampling factor<br>
|
||||||
|
* form more details see {@link setDownSamplingFactor(float downSamplingFactor)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getDownSamplingFactor() {
|
||||||
|
return downSamplingFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the downSampling factor : the size of the computed texture will be divided by this factor. default is 1 for no downsampling
|
||||||
|
* A 2 value is a good way of widening the blur
|
||||||
|
* @param downSamplingFactor
|
||||||
|
*/
|
||||||
|
public void setDownSamplingFactor(float downSamplingFactor) {
|
||||||
|
this.downSamplingFactor = downSamplingFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
super.write(ex);
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.write(glowMode, "glowMode", GlowMode.Scene);
|
||||||
|
oc.write(blurScale, "blurScale", 1.5f);
|
||||||
|
oc.write(exposurePower, "exposurePower", 5.0f);
|
||||||
|
oc.write(exposureCutOff, "exposureCutOff", 0.0f);
|
||||||
|
oc.write(bloomIntensity, "bloomIntensity", 2.0f);
|
||||||
|
oc.write(downSamplingFactor, "downSamplingFactor", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
super.read(im);
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
glowMode = ic.readEnum("glowMode", GlowMode.class, GlowMode.Scene);
|
||||||
|
blurScale = ic.readFloat("blurScale", 1.5f);
|
||||||
|
exposurePower = ic.readFloat("exposurePower", 5.0f);
|
||||||
|
exposureCutOff = ic.readFloat("exposureCutOff", 0.0f);
|
||||||
|
bloomIntensity = ic.readFloat("bloomIntensity", 2.0f);
|
||||||
|
downSamplingFactor = ic.readFloat("downSamplingFactor", 1);
|
||||||
|
}
|
||||||
|
}
|
245
engine/src/core/com/jme3/post/filters/CartoonEdgeFilter.java
Normal file
245
engine/src/core/com/jme3/post/filters/CartoonEdgeFilter.java
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.post.Filter.Pass;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.Renderer;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.texture.Image.Format;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a cartoon-style edge detection filter to all objects in the scene.
|
||||||
|
*
|
||||||
|
* @author Kirill Vainer
|
||||||
|
*/
|
||||||
|
public class CartoonEdgeFilter extends Filter {
|
||||||
|
|
||||||
|
private Pass normalPass;
|
||||||
|
private float edgeWidth = 1.0f;
|
||||||
|
private float edgeIntensity = 1.0f;
|
||||||
|
private float normalThreshold = 0.5f;
|
||||||
|
private float depthThreshold = 0.1f;
|
||||||
|
private float normalSensitivity = 1.0f;
|
||||||
|
private float depthSensitivity = 10.0f;
|
||||||
|
private ColorRGBA edgeColor = new ColorRGBA(0, 0, 0, 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a CartoonEdgeFilter
|
||||||
|
*/
|
||||||
|
public CartoonEdgeFilter() {
|
||||||
|
super("CartoonEdgeFilter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRequiresDepthTexture() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
|
||||||
|
Renderer r = renderManager.getRenderer();
|
||||||
|
r.setFrameBuffer(normalPass.getRenderFrameBuffer());
|
||||||
|
renderManager.getRenderer().clearBuffers(true, true, true);
|
||||||
|
renderManager.setForcedTechnique("PreNormalPass");
|
||||||
|
renderManager.renderViewPortQueues(viewPort, false);
|
||||||
|
renderManager.setForcedTechnique(null);
|
||||||
|
renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
material.setTexture("NormalsTexture", normalPass.getRenderedTexture());
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
normalPass = new Pass();
|
||||||
|
normalPass.init(renderManager.getRenderer(), w, h, Format.RGBA8, Format.Depth);
|
||||||
|
material = new Material(manager, "Common/MatDefs/Post/CartoonEdge.j3md");
|
||||||
|
material.setFloat("EdgeWidth", edgeWidth);
|
||||||
|
material.setFloat("EdgeIntensity", edgeIntensity);
|
||||||
|
material.setFloat("NormalThreshold", normalThreshold);
|
||||||
|
material.setFloat("DepthThreshold", depthThreshold);
|
||||||
|
material.setFloat("NormalSensitivity", normalSensitivity);
|
||||||
|
material.setFloat("DepthSensitivity", depthSensitivity);
|
||||||
|
material.setColor("EdgeColor", edgeColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the depth sensitivity<br>
|
||||||
|
* for more details see {@link setDepthSensitivity(float depthSensitivity)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getDepthSensitivity() {
|
||||||
|
return depthSensitivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the depth sensitivity<br>
|
||||||
|
* defines how much depth will influence edges, default is 10
|
||||||
|
* @param depthSensitivity
|
||||||
|
*/
|
||||||
|
public void setDepthSensitivity(float depthSensitivity) {
|
||||||
|
this.depthSensitivity = depthSensitivity;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("DepthSensitivity", depthSensitivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the depth threshold<br>
|
||||||
|
* for more details see {@link setDepthThreshold(float depthThreshold)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getDepthThreshold() {
|
||||||
|
return depthThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the depth threshold<br>
|
||||||
|
* Defines at what threshold of difference of depth an edge is outlined default is 0.1f
|
||||||
|
* @param depthThreshold
|
||||||
|
*/
|
||||||
|
public void setDepthThreshold(float depthThreshold) {
|
||||||
|
this.depthThreshold = depthThreshold;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("DepthThreshold", depthThreshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the edge intensity<br>
|
||||||
|
* for more details see {@link setEdgeIntensity(float edgeIntensity) }
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getEdgeIntensity() {
|
||||||
|
return edgeIntensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the edge intensity<br>
|
||||||
|
* Defineshow visilble will be the outlined edges
|
||||||
|
* @param edgeIntensity
|
||||||
|
*/
|
||||||
|
public void setEdgeIntensity(float edgeIntensity) {
|
||||||
|
this.edgeIntensity = edgeIntensity;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("EdgeIntensity", edgeIntensity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the width of the edges
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getEdgeWidth() {
|
||||||
|
return edgeWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the witdh of the edge in pixels default is 1
|
||||||
|
* @param edgeWidth
|
||||||
|
*/
|
||||||
|
public void setEdgeWidth(float edgeWidth) {
|
||||||
|
this.edgeWidth = edgeWidth;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("EdgeWidth", edgeWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the normals sensitivity<br>
|
||||||
|
* form more details see {@link setNormalSensitivity(float normalSensitivity)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getNormalSensitivity() {
|
||||||
|
return normalSensitivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the normals sensitivity default is 1
|
||||||
|
* @param normalSensitivity
|
||||||
|
*/
|
||||||
|
public void setNormalSensitivity(float normalSensitivity) {
|
||||||
|
this.normalSensitivity = normalSensitivity;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("NormalSensitivity", normalSensitivity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the normal threshold<br>
|
||||||
|
* for more details see {@link setNormalThreshold(float normalThreshold)}
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getNormalThreshold() {
|
||||||
|
return normalThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the normal threshold default is 0.5
|
||||||
|
* @param normalThreshold
|
||||||
|
*/
|
||||||
|
public void setNormalThreshold(float normalThreshold) {
|
||||||
|
this.normalThreshold = normalThreshold;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("NormalThreshold", normalThreshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the edge color
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ColorRGBA getEdgeColor() {
|
||||||
|
return edgeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the edge color, default is black
|
||||||
|
* @param edgeColor
|
||||||
|
*/
|
||||||
|
public void setEdgeColor(ColorRGBA edgeColor) {
|
||||||
|
this.edgeColor = edgeColor;
|
||||||
|
if (material != null) {
|
||||||
|
material.setColor("EdgeColor", edgeColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
111
engine/src/core/com/jme3/post/filters/ColorOverlayFilter.java
Normal file
111
engine/src/core/com/jme3/post/filters/ColorOverlayFilter.java
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.export.InputCapsule;
|
||||||
|
import com.jme3.export.JmeExporter;
|
||||||
|
import com.jme3.export.JmeImporter;
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This filter simply multiply the whole scene by a color
|
||||||
|
* @author Rémy Bouquet aka Nehon
|
||||||
|
*/
|
||||||
|
public class ColorOverlayFilter extends Filter {
|
||||||
|
|
||||||
|
private ColorRGBA color = ColorRGBA.White;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a colorOverlayFilter with a white coor (transparent)
|
||||||
|
*/
|
||||||
|
public ColorOverlayFilter() {
|
||||||
|
super("Color Overlay");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a colorOverlayFilter with the given color
|
||||||
|
* @param color
|
||||||
|
*/
|
||||||
|
public ColorOverlayFilter(ColorRGBA color) {
|
||||||
|
this();
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
|
||||||
|
material.setColor("Color", color);
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the color
|
||||||
|
* @return color
|
||||||
|
*/
|
||||||
|
public ColorRGBA getColor() {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the color
|
||||||
|
* @param color
|
||||||
|
*/
|
||||||
|
public void setColor(ColorRGBA color) {
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
super.write(ex);
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.write(color, "color", ColorRGBA.White);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
super.read(im);
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
color = (ColorRGBA) ic.readSavable("color", ColorRGBA.White);
|
||||||
|
}
|
||||||
|
}
|
305
engine/src/core/com/jme3/post/filters/CrossHatchFilter.java
Normal file
305
engine/src/core/com/jme3/post/filters/CrossHatchFilter.java
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Post Processing filter that makes the screen look like it was drawn as
|
||||||
|
* diagonal lines with a pen.
|
||||||
|
* Try combining this with a cartoon edge filter to obtain manga style visuals.
|
||||||
|
*
|
||||||
|
* Based on an article from Geeks3D:
|
||||||
|
* <a href="http://www.geeks3d.com/20110219/shader-library-crosshatching-glsl-filter/" rel="nofollow">http://www.geeks3d.com/20110219/shader-library-crosshatching-glsl-filter/</a>
|
||||||
|
*
|
||||||
|
* @author: Roy Straver a.k.a. Baal Garnaal
|
||||||
|
*/
|
||||||
|
public class CrossHatchFilter extends Filter {
|
||||||
|
|
||||||
|
private ColorRGBA lineColor = ColorRGBA.Black.clone();
|
||||||
|
private ColorRGBA paperColor = ColorRGBA.White.clone();
|
||||||
|
private float colorInfluenceLine = 0.8f;
|
||||||
|
private float colorInfluencePaper = 0.1f;
|
||||||
|
private float fillValue = 0.9f;
|
||||||
|
private float luminance1 = 0.9f;
|
||||||
|
private float luminance2 = 0.7f;
|
||||||
|
private float luminance3 = 0.5f;
|
||||||
|
private float luminance4 = 0.3f;
|
||||||
|
private float luminance5 = 0.0f;
|
||||||
|
private float lineThickness = 1.0f;
|
||||||
|
private float lineDistance = 4.0f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a crossHatch filter
|
||||||
|
*/
|
||||||
|
public CrossHatchFilter() {
|
||||||
|
super("CrossHatchFilter");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a crossHatch filter
|
||||||
|
* @param lineColor the colors of the lines
|
||||||
|
* @param paperColor the paper color
|
||||||
|
*/
|
||||||
|
public CrossHatchFilter(ColorRGBA lineColor, ColorRGBA paperColor) {
|
||||||
|
this();
|
||||||
|
this.lineColor = lineColor;
|
||||||
|
this.paperColor = paperColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRequiresDepthTexture() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
material = new Material(manager, "Common/MatDefs/Post/CrossHatch.j3md");
|
||||||
|
material.setColor("LineColor", lineColor);
|
||||||
|
material.setColor("PaperColor", paperColor);
|
||||||
|
|
||||||
|
material.setFloat("ColorInfluenceLine", colorInfluenceLine);
|
||||||
|
material.setFloat("ColorInfluencePaper", colorInfluencePaper);
|
||||||
|
|
||||||
|
material.setFloat("FillValue", fillValue);
|
||||||
|
|
||||||
|
material.setFloat("Luminance1", luminance1);
|
||||||
|
material.setFloat("Luminance2", luminance2);
|
||||||
|
material.setFloat("Luminance3", luminance3);
|
||||||
|
material.setFloat("Luminance4", luminance4);
|
||||||
|
material.setFloat("Luminance5", luminance5);
|
||||||
|
|
||||||
|
material.setFloat("LineThickness", lineThickness);
|
||||||
|
material.setFloat("LineDistance", lineDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets color used to draw lines
|
||||||
|
* @param lineColor
|
||||||
|
*/
|
||||||
|
public void setLineColor(ColorRGBA lineColor) {
|
||||||
|
this.lineColor = lineColor;
|
||||||
|
if (material != null) {
|
||||||
|
material.setColor("LineColor", lineColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets color used as background
|
||||||
|
* @param paperColor
|
||||||
|
*/
|
||||||
|
public void setPaperColor(ColorRGBA paperColor) {
|
||||||
|
this.paperColor = paperColor;
|
||||||
|
if (material != null) {
|
||||||
|
material.setColor("PaperColor", paperColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets color influence of original image on lines drawn
|
||||||
|
* @param colorInfluenceLine
|
||||||
|
*/
|
||||||
|
public void setColorInfluenceLine(float colorInfluenceLine) {
|
||||||
|
this.colorInfluenceLine = colorInfluenceLine;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("ColorInfluenceLine", colorInfluenceLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets color influence of original image on non-line areas
|
||||||
|
* @param colorInfluencePaper
|
||||||
|
*/
|
||||||
|
public void setColorInfluencePaper(float colorInfluencePaper) {
|
||||||
|
this.colorInfluencePaper = colorInfluencePaper;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("ColorInfluencePaper", colorInfluencePaper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets line/paper color ratio for areas with values < luminance5,
|
||||||
|
* really dark areas get no lines but a filled blob instead
|
||||||
|
* @param fillValue
|
||||||
|
*/
|
||||||
|
public void setFillValue(float fillValue) {
|
||||||
|
this.fillValue = fillValue;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("FillValue", fillValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Sets minimum luminance levels for lines drawn
|
||||||
|
* @param luminance1 Top-left to down right 1
|
||||||
|
* @param luminance2 Top-right to bottom left 1
|
||||||
|
* @param luminance3 Top-left to down right 2
|
||||||
|
* @param luminance4 Top-right to bottom left 2
|
||||||
|
* @param luminance5 Blobs
|
||||||
|
*/
|
||||||
|
public void setLuminanceLevels(float luminance1, float luminance2, float luminance3, float luminance4, float luminance5) {
|
||||||
|
this.luminance1 = luminance1;
|
||||||
|
this.luminance2 = luminance2;
|
||||||
|
this.luminance3 = luminance3;
|
||||||
|
this.luminance4 = luminance4;
|
||||||
|
this.luminance5 = luminance5;
|
||||||
|
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("Luminance1", luminance1);
|
||||||
|
material.setFloat("Luminance2", luminance2);
|
||||||
|
material.setFloat("Luminance3", luminance3);
|
||||||
|
material.setFloat("Luminance4", luminance4);
|
||||||
|
material.setFloat("Luminance5", luminance5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the thickness of lines drawn
|
||||||
|
* @param lineThickness
|
||||||
|
*/
|
||||||
|
public void setLineThickness(float lineThickness) {
|
||||||
|
this.lineThickness = lineThickness;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("LineThickness", lineThickness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets minimum distance between lines drawn
|
||||||
|
* Primary lines are drawn at 2*lineDistance
|
||||||
|
* Secondary lines are drawn at lineDistance
|
||||||
|
* @param lineDistance
|
||||||
|
*/
|
||||||
|
public void setLineDistance(float lineDistance) {
|
||||||
|
this.lineDistance = lineDistance;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("LineDistance", lineDistance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns line color
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ColorRGBA getLineColor() {
|
||||||
|
return lineColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns paper background color
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ColorRGBA getPaperColor() {
|
||||||
|
return paperColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current influence of image colors on lines
|
||||||
|
*/
|
||||||
|
public float getColorInfluenceLine() {
|
||||||
|
return colorInfluenceLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current influence of image colors on paper background
|
||||||
|
*/
|
||||||
|
public float getColorInfluencePaper() {
|
||||||
|
return colorInfluencePaper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns line/paper color ratio for blobs
|
||||||
|
*/
|
||||||
|
public float getFillValue() {
|
||||||
|
return fillValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the thickness of the lines drawn
|
||||||
|
*/
|
||||||
|
public float getLineThickness() {
|
||||||
|
return lineThickness;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns minimum distance between lines
|
||||||
|
*/
|
||||||
|
public float getLineDistance() {
|
||||||
|
return lineDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns treshold for lines 1
|
||||||
|
*/
|
||||||
|
public float getLuminance1() {
|
||||||
|
return luminance1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns treshold for lines 2
|
||||||
|
*/
|
||||||
|
public float getLuminance2() {
|
||||||
|
return luminance2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns treshold for lines 3
|
||||||
|
*/
|
||||||
|
public float getLuminance3() {
|
||||||
|
return luminance3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns treshold for lines 4
|
||||||
|
*/
|
||||||
|
public float getLuminance4() {
|
||||||
|
return luminance4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns treshold for blobs
|
||||||
|
*/
|
||||||
|
public float getLuminance5() {
|
||||||
|
return luminance5;
|
||||||
|
}
|
||||||
|
}
|
158
engine/src/core/com/jme3/post/filters/DepthOfFieldFilter.java
Normal file
158
engine/src/core/com/jme3/post/filters/DepthOfFieldFilter.java
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A post-processing filter that performs a depth range
|
||||||
|
* blur using a scaled convolution filter.
|
||||||
|
*
|
||||||
|
* @version $Revision: 779 $
|
||||||
|
* @author Paul Speed
|
||||||
|
*/
|
||||||
|
public class DepthOfFieldFilter extends Filter {
|
||||||
|
|
||||||
|
private float focusDistance = 50f;
|
||||||
|
private float focusRange = 10f;
|
||||||
|
private float blurScale = 1f;
|
||||||
|
// These values are set internally based on the
|
||||||
|
// viewport size.
|
||||||
|
private float xScale;
|
||||||
|
private float yScale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a DepthOfField filter
|
||||||
|
*/
|
||||||
|
public DepthOfFieldFilter() {
|
||||||
|
super("Depth Of Field");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRequiresDepthTexture() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager assets, RenderManager renderManager,
|
||||||
|
ViewPort vp, int w, int h) {
|
||||||
|
material = new Material(assets, "Common/MatDefs/Post/DepthOfField.j3md");
|
||||||
|
material.setFloat("FocusDistance", focusDistance);
|
||||||
|
material.setFloat("FocusRange", focusRange);
|
||||||
|
|
||||||
|
|
||||||
|
xScale = 1.0f / w;
|
||||||
|
yScale = 1.0f / h;
|
||||||
|
|
||||||
|
material.setFloat("XScale", blurScale * xScale);
|
||||||
|
material.setFloat("YScale", blurScale * yScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the distance at which objects are purely in focus.
|
||||||
|
*/
|
||||||
|
public void setFocusDistance(float f) {
|
||||||
|
|
||||||
|
this.focusDistance = f;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("FocusDistance", focusDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the focus distance
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getFocusDistance() {
|
||||||
|
return focusDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the range to either side of focusDistance where the
|
||||||
|
* objects go gradually out of focus. Less than focusDistance - focusRange
|
||||||
|
* and greater than focusDistance + focusRange, objects are maximally "blurred".
|
||||||
|
*/
|
||||||
|
public void setFocusRange(float f) {
|
||||||
|
this.focusRange = f;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("FocusRange", focusRange);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the focus range
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getFocusRange() {
|
||||||
|
return focusRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the blur amount by scaling the convolution filter up or
|
||||||
|
* down. A value of 1 (the default) performs a sparse 5x5 evenly
|
||||||
|
* distribubted convolution at pixel level accuracy. Higher values skip
|
||||||
|
* more pixels, and so on until you are no longer blurring the image
|
||||||
|
* but simply hashing it.
|
||||||
|
*
|
||||||
|
* The sparse convolution is as follows:
|
||||||
|
*%MINIFYHTMLc3d0cd9fab65de6875a381fd3f83e1b338%*
|
||||||
|
* Where 'x' is the texel being modified. Setting blur scale higher
|
||||||
|
* than 1 spaces the samples out.
|
||||||
|
*/
|
||||||
|
public void setBlurScale(float f) {
|
||||||
|
this.blurScale = f;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("XScale", blurScale * xScale);
|
||||||
|
material.setFloat("YScale", blurScale * yScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the blur scale
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getBlurScale() {
|
||||||
|
return blurScale;
|
||||||
|
}
|
||||||
|
}
|
95
engine/src/core/com/jme3/post/filters/FXAAFilter.java
Normal file
95
engine/src/core/com/jme3/post/filters/FXAAFilter.java
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <a href="http://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-opengl-test-radeon-geforce/3/" rel="nofollow">http://www.geeks3d.com/20110405/fxaa-fast-approximate-anti-aliasing-demo-glsl-<span class="domtooltips" title="OpenGL (Open Graphics Library) is a standard specification defining a cross-language, cross-platform API for writing applications that produce 2D and 3D computer graphics." id="domtooltipsspan11">opengl</span>-test-radeon-geforce/3/</a>
|
||||||
|
* <a href="http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf" rel="nofollow">http://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf</a>
|
||||||
|
*
|
||||||
|
* @author Phate666 (adapted to jme3)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FXAAFilter extends Filter {
|
||||||
|
|
||||||
|
private float subPixelShift = 1.0f / 4.0f;
|
||||||
|
private float vxOffset = 0.0f;
|
||||||
|
private float spanMax = 8.0f;
|
||||||
|
private float reduceMul = 1.0f / 8.0f;
|
||||||
|
|
||||||
|
public FXAAFilter() {
|
||||||
|
super("FXAAFilter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager,
|
||||||
|
RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
material = new Material(manager, "Common/MatDefs/Post/FXAA.j3md");
|
||||||
|
material.setFloat("SubPixelShift", subPixelShift);
|
||||||
|
material.setFloat("VxOffset", vxOffset);
|
||||||
|
material.setFloat("SpanMax", spanMax);
|
||||||
|
material.setFloat("ReduceMul", reduceMul);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSpanMax(float spanMax) {
|
||||||
|
this.spanMax = spanMax;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("SpanMax", this.spanMax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set to 0.0f for higher quality
|
||||||
|
*
|
||||||
|
* @param subPixelShift
|
||||||
|
*/
|
||||||
|
public void setSubPixelShift(float subPixelShift) {
|
||||||
|
this.subPixelShift = subPixelShift;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("SubPixelShif", this.subPixelShift);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set to 0.0f for higher quality
|
||||||
|
*
|
||||||
|
* @param reduceMul
|
||||||
|
*/
|
||||||
|
public void setReduceMul(float reduceMul) {
|
||||||
|
this.reduceMul = reduceMul;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("ReduceMul", this.reduceMul);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVxOffset(float vxOffset) {
|
||||||
|
this.vxOffset = vxOffset;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("VxOffset", this.vxOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getReduceMul() {
|
||||||
|
return reduceMul;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSpanMax() {
|
||||||
|
return spanMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getSubPixelShift() {
|
||||||
|
return subPixelShift;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getVxOffset() {
|
||||||
|
return vxOffset;
|
||||||
|
}
|
||||||
|
}
|
170
engine/src/core/com/jme3/post/filters/FadeFilter.java
Normal file
170
engine/src/core/com/jme3/post/filters/FadeFilter.java
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.export.InputCapsule;
|
||||||
|
import com.jme3.export.JmeExporter;
|
||||||
|
import com.jme3.export.JmeImporter;
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Fade Filter allows you to make an animated fade effect on a scene.
|
||||||
|
* @author Rémy Bouquet aka Nehon
|
||||||
|
* implemented from boxjar implementation
|
||||||
|
* @see <a href="http://jmonkeyengine.org/groups/graphics/forum/topic/newbie-question-general-fade-inout-effect/#post-105559">http://jmonkeyengine.org/groups/graphics/forum/topic/newbie-question-general-fade-inout-effect/#post-105559</a>
|
||||||
|
*/
|
||||||
|
public class FadeFilter extends Filter {
|
||||||
|
|
||||||
|
private float value = 1;
|
||||||
|
private boolean playing = false;
|
||||||
|
private float direction = 1;
|
||||||
|
private float duration = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a FadeFilter
|
||||||
|
*/
|
||||||
|
public FadeFilter() {
|
||||||
|
super("Fade In/Out");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a FadeFilter with the given duration
|
||||||
|
* @param duration
|
||||||
|
*/
|
||||||
|
public FadeFilter(float duration) {
|
||||||
|
this();
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
material.setFloat("Value", value);
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
material = new Material(manager, "Common/MatDefs/Post/Fade.j3md");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void preFrame(float tpf) {
|
||||||
|
if (playing) {
|
||||||
|
value += tpf * direction / duration;
|
||||||
|
|
||||||
|
if (direction > 0 && value > 1) {
|
||||||
|
value = 1;
|
||||||
|
playing = false;
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
if (direction < 0 && value < 0) {
|
||||||
|
value = 0;
|
||||||
|
playing = false;
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the duration of the effect
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getDuration() {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the duration of the filter default is 1 second
|
||||||
|
* @param duration
|
||||||
|
*/
|
||||||
|
public void setDuration(float duration) {
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fades the scene in (black to scene)
|
||||||
|
*/
|
||||||
|
public void fadeIn() {
|
||||||
|
setEnabled(true);
|
||||||
|
direction = 1;
|
||||||
|
playing = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fades the scene out (scene to black)
|
||||||
|
*/
|
||||||
|
public void fadeOut() {
|
||||||
|
setEnabled(true);
|
||||||
|
direction = -1;
|
||||||
|
playing = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
super.write(ex);
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.write(duration, "duration", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
super.read(im);
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
duration = ic.readFloat("duration", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the current value of the fading
|
||||||
|
* can be used to chack if fade is complete (eg value=1)
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the fade value
|
||||||
|
* can be used to force complete black or compete scene
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
public void setValue(float value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
172
engine/src/core/com/jme3/post/filters/FogFilter.java
Normal file
172
engine/src/core/com/jme3/post/filters/FogFilter.java
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.export.InputCapsule;
|
||||||
|
import com.jme3.export.JmeExporter;
|
||||||
|
import com.jme3.export.JmeImporter;
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filter to render a fog effect
|
||||||
|
* @author Rémy Bouquet aka Nehon
|
||||||
|
*/
|
||||||
|
public class FogFilter extends Filter {
|
||||||
|
|
||||||
|
private ColorRGBA fogColor = ColorRGBA.White.clone();
|
||||||
|
private float fogDensity = 0.7f;
|
||||||
|
private float fogDistance = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a FogFilter
|
||||||
|
*/
|
||||||
|
public FogFilter() {
|
||||||
|
super("FogFilter");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a fog filter
|
||||||
|
* @param fogColor the color of the fog (default is white)
|
||||||
|
* @param fogDensity the density of the fog (default is 0.7)
|
||||||
|
* @param fogDistance the distance of the fog (default is 1000)
|
||||||
|
*/
|
||||||
|
public FogFilter(ColorRGBA fogColor, float fogDensity, float fogDistance) {
|
||||||
|
this();
|
||||||
|
this.fogColor = fogColor;
|
||||||
|
this.fogDensity = fogDensity;
|
||||||
|
this.fogDistance = fogDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRequiresDepthTexture() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
material = new Material(manager, "Common/MatDefs/Post/Fog.j3md");
|
||||||
|
material.setColor("FogColor", fogColor);
|
||||||
|
material.setFloat("FogDensity", fogDensity);
|
||||||
|
material.setFloat("FogDistance", fogDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the fog color
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public ColorRGBA getFogColor() {
|
||||||
|
return fogColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the color of the fog
|
||||||
|
* @param fogColor
|
||||||
|
*/
|
||||||
|
public void setFogColor(ColorRGBA fogColor) {
|
||||||
|
if (material != null) {
|
||||||
|
material.setColor("FogColor", fogColor);
|
||||||
|
}
|
||||||
|
this.fogColor = fogColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the fog density
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getFogDensity() {
|
||||||
|
return fogDensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the density of the fog, a high value gives a thick fog
|
||||||
|
* @param fogColor
|
||||||
|
*/
|
||||||
|
public void setFogDensity(float fogDensity) {
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("FogDensity", fogDensity);
|
||||||
|
}
|
||||||
|
this.fogDensity = fogDensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the fog distance
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getFogDistance() {
|
||||||
|
return fogDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the distance of the fog. the higer the value the distant the fog looks
|
||||||
|
* @param fogDistance
|
||||||
|
*/
|
||||||
|
public void setFogDistance(float fogDistance) {
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("FogDistance", fogDistance);
|
||||||
|
}
|
||||||
|
this.fogDistance = fogDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
super.write(ex);
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.write(fogColor, "fogColor", ColorRGBA.White.clone());
|
||||||
|
oc.write(fogDensity, "fogDensity", 0.7f);
|
||||||
|
oc.write(fogDistance, "fogDistance", 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
super.read(im);
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
fogColor = (ColorRGBA) ic.readSavable("fogColor", ColorRGBA.White.clone());
|
||||||
|
fogDensity = ic.readFloat("fogDensity", 0.7f);
|
||||||
|
fogDistance = ic.readFloat("fogDistance", 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Phate666
|
||||||
|
* @version 1.0 initial version
|
||||||
|
* @version 1.1 added luma
|
||||||
|
*/
|
||||||
|
public class GammaCorrectionFilter extends Filter
|
||||||
|
{
|
||||||
|
private float gamma = 2.0f;
|
||||||
|
private boolean computeLuma = false;
|
||||||
|
|
||||||
|
public GammaCorrectionFilter()
|
||||||
|
{
|
||||||
|
super("GammaCorrectionFilter");
|
||||||
|
}
|
||||||
|
|
||||||
|
public GammaCorrectionFilter(float gamma)
|
||||||
|
{
|
||||||
|
this();
|
||||||
|
this.setGamma(gamma);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial()
|
||||||
|
{
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager,
|
||||||
|
RenderManager renderManager, ViewPort vp, int w, int h)
|
||||||
|
{
|
||||||
|
material = new Material(manager,
|
||||||
|
"Common/MatDefs/Post/GammaCorrection.j3md");
|
||||||
|
material.setFloat("gamma", gamma);
|
||||||
|
material.setBoolean("computeLuma", computeLuma);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getGamma()
|
||||||
|
{
|
||||||
|
return gamma;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set to 0.0 to disable gamma correction
|
||||||
|
* @param gamma
|
||||||
|
*/
|
||||||
|
public void setGamma(float gamma)
|
||||||
|
{
|
||||||
|
if (material != null)
|
||||||
|
{
|
||||||
|
material.setFloat("gamma", gamma);
|
||||||
|
}
|
||||||
|
this.gamma = gamma;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isComputeLuma()
|
||||||
|
{
|
||||||
|
return computeLuma;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setComputeLuma(boolean computeLuma)
|
||||||
|
{
|
||||||
|
if (material != null)
|
||||||
|
{
|
||||||
|
material.setBoolean("computeLuma", computeLuma);
|
||||||
|
}
|
||||||
|
this.computeLuma = computeLuma;
|
||||||
|
}
|
||||||
|
}
|
243
engine/src/core/com/jme3/post/filters/LightScatteringFilter.java
Normal file
243
engine/src/core/com/jme3/post/filters/LightScatteringFilter.java
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.export.InputCapsule;
|
||||||
|
import com.jme3.export.JmeExporter;
|
||||||
|
import com.jme3.export.JmeImporter;
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.Camera;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LightScattering filters creates rays comming from a light sources
|
||||||
|
* This is often reffered as god rays.
|
||||||
|
*
|
||||||
|
* @author Rémy Bouquet aka Nehon
|
||||||
|
*/
|
||||||
|
public class LightScatteringFilter extends Filter {
|
||||||
|
|
||||||
|
private Vector3f lightPosition;
|
||||||
|
private Vector3f screenLightPos = new Vector3f();
|
||||||
|
private int nbSamples = 50;
|
||||||
|
private float blurStart = 0.02f;
|
||||||
|
private float blurWidth = 0.9f;
|
||||||
|
private float lightDensity = 1.4f;
|
||||||
|
private boolean adaptative = true;
|
||||||
|
Vector3f viewLightPos = new Vector3f();
|
||||||
|
private boolean display = true;
|
||||||
|
private float innerLightDensity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a lightScaterring filter
|
||||||
|
*/
|
||||||
|
public LightScatteringFilter() {
|
||||||
|
super("Light Scattering");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a lightScatteringFilter
|
||||||
|
* @param lightPosition
|
||||||
|
*/
|
||||||
|
public LightScatteringFilter(Vector3f lightPosition) {
|
||||||
|
this();
|
||||||
|
this.lightPosition = lightPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRequiresDepthTexture() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
material.setVector3("LightPosition", screenLightPos);
|
||||||
|
material.setInt("NbSamples", nbSamples);
|
||||||
|
material.setFloat("BlurStart", blurStart);
|
||||||
|
material.setFloat("BlurWidth", blurWidth);
|
||||||
|
material.setFloat("LightDensity", innerLightDensity);
|
||||||
|
material.setBoolean("Display", display);
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
|
||||||
|
getClipCoordinates(lightPosition, screenLightPos, viewPort.getCamera());
|
||||||
|
// screenLightPos.x = screenLightPos.x / viewPort.getCamera().getWidth();
|
||||||
|
// screenLightPos.y = screenLightPos.y / viewPort.getCamera().getHeight();
|
||||||
|
|
||||||
|
viewPort.getCamera().getViewMatrix().mult(lightPosition, viewLightPos);
|
||||||
|
//System.err.println("viewLightPos "+viewLightPos);
|
||||||
|
display = screenLightPos.x < 1.6f && screenLightPos.x > -0.6f && screenLightPos.y < 1.6f && screenLightPos.y > -0.6f && viewLightPos.z < 0;
|
||||||
|
//System.err.println("camdir "+viewPort.getCamera().getDirection());
|
||||||
|
//System.err.println("lightPos "+lightPosition);
|
||||||
|
//System.err.println("screenLightPos "+screenLightPos);
|
||||||
|
if (adaptative) {
|
||||||
|
innerLightDensity = Math.max(lightDensity - Math.max(screenLightPos.x, screenLightPos.y), 0.0f);
|
||||||
|
} else {
|
||||||
|
innerLightDensity = lightDensity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3f getClipCoordinates(Vector3f worldPosition, Vector3f store, Camera cam) {
|
||||||
|
|
||||||
|
float w = cam.getViewProjectionMatrix().multProj(worldPosition, store);
|
||||||
|
store.divideLocal(w);
|
||||||
|
|
||||||
|
store.x = ((store.x + 1f) * (cam.getViewPortRight() - cam.getViewPortLeft()) / 2f + cam.getViewPortLeft());
|
||||||
|
store.y = ((store.y + 1f) * (cam.getViewPortTop() - cam.getViewPortBottom()) / 2f + cam.getViewPortBottom());
|
||||||
|
store.z = (store.z + 1f) / 2f;
|
||||||
|
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
material = new Material(manager, "Common/MatDefs/Post/LightScattering.j3md");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the blur start of the scattering
|
||||||
|
* see {@link setBlurStart(float blurStart)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getBlurStart() {
|
||||||
|
return blurStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the blur start<br>
|
||||||
|
* at which distance from the light source the effect starts default is 0.02
|
||||||
|
* @param blurStart
|
||||||
|
*/
|
||||||
|
public void setBlurStart(float blurStart) {
|
||||||
|
this.blurStart = blurStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the blur width<br>
|
||||||
|
* see {@link setBlurWidth(float blurWidth)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getBlurWidth() {
|
||||||
|
return blurWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the blur width default is 0.9
|
||||||
|
* @param blurWidth
|
||||||
|
*/
|
||||||
|
public void setBlurWidth(float blurWidth) {
|
||||||
|
this.blurWidth = blurWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retiurns the light density<br>
|
||||||
|
* see {@link setLightDensity(float lightDensity)}
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getLightDensity() {
|
||||||
|
return lightDensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets how much the effect is visible over the rendered scene default is 1.4
|
||||||
|
* @param lightDensity
|
||||||
|
*/
|
||||||
|
public void setLightDensity(float lightDensity) {
|
||||||
|
this.lightDensity = lightDensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the light position
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Vector3f getLightPosition() {
|
||||||
|
return lightPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the light position
|
||||||
|
* @param lightPosition
|
||||||
|
*/
|
||||||
|
public void setLightPosition(Vector3f lightPosition) {
|
||||||
|
this.lightPosition = lightPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the nmber of samples for the radial blur
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getNbSamples() {
|
||||||
|
return nbSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the number of samples for the radial blur default is 50
|
||||||
|
* the higher the value the higher the quality, but the slower the performances.
|
||||||
|
* @param nbSamples
|
||||||
|
*/
|
||||||
|
public void setNbSamples(int nbSamples) {
|
||||||
|
this.nbSamples = nbSamples;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
super.write(ex);
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.write(lightPosition, "lightPosition", Vector3f.ZERO);
|
||||||
|
oc.write(nbSamples, "nbSamples", 50);
|
||||||
|
oc.write(blurStart, "blurStart", 0.02f);
|
||||||
|
oc.write(blurWidth, "blurWidth", 0.9f);
|
||||||
|
oc.write(lightDensity, "lightDensity", 1.4f);
|
||||||
|
oc.write(adaptative, "adaptative", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
super.read(im);
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
lightPosition = (Vector3f) ic.readSavable("lightPosition", Vector3f.ZERO);
|
||||||
|
nbSamples = ic.readInt("nbSamples", 50);
|
||||||
|
blurStart = ic.readFloat("blurStart", 0.02f);
|
||||||
|
blurWidth = ic.readFloat("blurWidth", 0.9f);
|
||||||
|
lightDensity = ic.readFloat("lightDensity", 1.4f);
|
||||||
|
adaptative = ic.readBoolean("adaptative", true);
|
||||||
|
}
|
||||||
|
}
|
147
engine/src/core/com/jme3/post/filters/PosterizationFilter.java
Normal file
147
engine/src/core/com/jme3/post/filters/PosterizationFilter.java
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Post Processing filter to change colors appear with sharp edges as if the
|
||||||
|
* available amount of colors available was not enough to draw the true image.
|
||||||
|
* Possibly useful in cartoon styled games. Use the strength variable to lessen
|
||||||
|
* influence of this filter on the total result. Values from 0.2 to 0.7 appear
|
||||||
|
* to give nice results.
|
||||||
|
*
|
||||||
|
* Based on an article from Geeks3D:
|
||||||
|
* <a href="http://www.geeks3d.com/20091027/shader-library-posterization-post-processing-effect-glsl/" rel="nofollow">http://www.geeks3d.com/20091027/shader-library-posterization-post-processing-effect-glsl/</a>
|
||||||
|
*
|
||||||
|
* @author: Roy Straver a.k.a. Baal Garnaal
|
||||||
|
*/
|
||||||
|
public class PosterizationFilter extends Filter {
|
||||||
|
|
||||||
|
private int numColors = 8;
|
||||||
|
private float gamma = 0.6f;
|
||||||
|
private float strength = 1.0f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a posterization Filter
|
||||||
|
*/
|
||||||
|
public PosterizationFilter() {
|
||||||
|
super("PosterizationFilter");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a posterization Filter with the given number of colors
|
||||||
|
* @param numColors
|
||||||
|
*/
|
||||||
|
public PosterizationFilter(int numColors) {
|
||||||
|
this();
|
||||||
|
this.numColors = numColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a posterization Filter with the given number of colors and gamma
|
||||||
|
* @param numColors
|
||||||
|
* @param gamma
|
||||||
|
*/
|
||||||
|
public PosterizationFilter(int numColors, float gamma) {
|
||||||
|
this(numColors);
|
||||||
|
this.gamma = gamma;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
material = new Material(manager, "Common/MatDefs/Post/Posterization.j3md");
|
||||||
|
material.setInt("NumColors", numColors);
|
||||||
|
material.setFloat("Gamma", gamma);
|
||||||
|
material.setFloat("Strength", strength);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets number of color levels used to draw the screen
|
||||||
|
*/
|
||||||
|
public void setNumColors(int numColors) {
|
||||||
|
this.numColors = numColors;
|
||||||
|
if (material != null) {
|
||||||
|
material.setInt("NumColors", numColors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets gamma level used to enhange visual quality
|
||||||
|
*/
|
||||||
|
public void setGamma(float gamma) {
|
||||||
|
this.gamma = gamma;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("Gamma", gamma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets urrent strength value, i.e. influence on final image
|
||||||
|
*/
|
||||||
|
public void setStrength(float strength) {
|
||||||
|
this.strength = strength;
|
||||||
|
if (material != null) {
|
||||||
|
material.setFloat("Strength", strength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns number of color levels used
|
||||||
|
*/
|
||||||
|
public int getNumColors() {
|
||||||
|
return numColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current gamma value
|
||||||
|
*/
|
||||||
|
public float getGamma() {
|
||||||
|
return gamma;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current strength value, i.e. influence on final image
|
||||||
|
*/
|
||||||
|
public float getStrength() {
|
||||||
|
return strength;
|
||||||
|
}
|
||||||
|
}
|
156
engine/src/core/com/jme3/post/filters/RadialBlurFilter.java
Normal file
156
engine/src/core/com/jme3/post/filters/RadialBlurFilter.java
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.export.InputCapsule;
|
||||||
|
import com.jme3.export.JmeExporter;
|
||||||
|
import com.jme3.export.JmeImporter;
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.shader.VarType;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Radially blurs the scene from the center of it
|
||||||
|
* @author Rémy Bouquet aka Nehon
|
||||||
|
*/
|
||||||
|
public class RadialBlurFilter extends Filter {
|
||||||
|
|
||||||
|
private float sampleDist = 1.0f;
|
||||||
|
private float sampleStrength = 2.2f;
|
||||||
|
private float[] samples = {-0.08f, -0.05f, -0.03f, -0.02f, -0.01f, 0.01f, 0.02f, 0.03f, 0.05f, 0.08f};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a RadialBlurFilter
|
||||||
|
*/
|
||||||
|
public RadialBlurFilter() {
|
||||||
|
super("Radial blur");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a RadialBlurFilter
|
||||||
|
* @param sampleDist the distance between samples
|
||||||
|
* @param sampleStrength the strenght of each sample
|
||||||
|
*/
|
||||||
|
public RadialBlurFilter(float sampleDist, float sampleStrength) {
|
||||||
|
this();
|
||||||
|
this.sampleDist = sampleDist;
|
||||||
|
this.sampleStrength = sampleStrength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
|
||||||
|
material.setFloat("SampleDist", sampleDist);
|
||||||
|
material.setFloat("SampleStrength", sampleStrength);
|
||||||
|
material.setParam("Samples", VarType.FloatArray, samples);
|
||||||
|
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the sample distance
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getSampleDistance() {
|
||||||
|
return sampleDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the samples distances default is 1
|
||||||
|
* @param sampleDist
|
||||||
|
*/
|
||||||
|
public void setSampleDistance(float sampleDist) {
|
||||||
|
this.sampleDist = sampleDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* @deprecated use {@link getSampleDistance()}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public float getSampleDist() {
|
||||||
|
return sampleDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param sampleDist
|
||||||
|
* @deprecated use {@link setSampleDistance(float sampleDist)}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
public void setSampleDist(float sampleDist) {
|
||||||
|
this.sampleDist = sampleDist;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the sample Strength
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getSampleStrength() {
|
||||||
|
return sampleStrength;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the sample streanght default is 2.2
|
||||||
|
* @param sampleStrength
|
||||||
|
*/
|
||||||
|
public void setSampleStrength(float sampleStrength) {
|
||||||
|
this.sampleStrength = sampleStrength;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
material = new Material(manager, "Common/MatDefs/Blur/RadialBlur.j3md");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
super.write(ex);
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.write(sampleDist, "sampleDist", 1.0f);
|
||||||
|
oc.write(sampleStrength, "sampleStrength", 2.2f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
super.read(im);
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
sampleDist = ic.readFloat("sampleDist", 1.0f);
|
||||||
|
sampleStrength = ic.readFloat("sampleStrength", 2.2f);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.filters;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.Renderer;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.renderer.queue.RenderQueue;
|
||||||
|
import com.jme3.texture.FrameBuffer;
|
||||||
|
import com.jme3.texture.Texture2D;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A filter to handle translucent objects when rendering a scene with filters that uses depth like WaterFilter and SSAOFilter
|
||||||
|
* just create a TranslucentBucketFilter and add it to the Filter list of a FilterPostPorcessor
|
||||||
|
* @author Nehon
|
||||||
|
*/
|
||||||
|
public final class TranslucentBucketFilter extends Filter {
|
||||||
|
|
||||||
|
private RenderManager renderManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager rm, ViewPort vp, int w, int h) {
|
||||||
|
this.renderManager = rm;
|
||||||
|
material = new Material(manager, "Common/MatDefs/Post/Overlay.j3md");
|
||||||
|
material.setColor("Color", ColorRGBA.White);
|
||||||
|
Texture2D tex = processor.getFilterTexture();
|
||||||
|
material.setTexture("Texture", tex);
|
||||||
|
if (tex.getImage().getMultiSamples() > 1) {
|
||||||
|
material.setInt("NumSamples", tex.getImage().getMultiSamples());
|
||||||
|
} else {
|
||||||
|
material.clearParam("NumSamples");
|
||||||
|
}
|
||||||
|
renderManager.setHandleTranslucentBucket(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override this method and return false if your Filter does not need the scene texture
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected boolean isRequiresSceneTexture() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void postFrame(RenderManager renderManager, ViewPort viewPort, FrameBuffer prevFilterBuffer, FrameBuffer sceneBuffer) {
|
||||||
|
renderManager.setCamera(viewPort.getCamera(), false);
|
||||||
|
if (prevFilterBuffer != sceneBuffer) {
|
||||||
|
renderManager.getRenderer().copyFrameBuffer(prevFilterBuffer, sceneBuffer, false);
|
||||||
|
}
|
||||||
|
renderManager.getRenderer().setFrameBuffer(sceneBuffer);
|
||||||
|
viewPort.getQueue().renderQueue(RenderQueue.Bucket.Translucent, renderManager, viewPort.getCamera());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanUpFilter(Renderer r) {
|
||||||
|
if (renderManager != null) {
|
||||||
|
renderManager.setHandleTranslucentBucket(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
super.setEnabled(enabled);
|
||||||
|
if (renderManager != null) {
|
||||||
|
renderManager.setHandleTranslucentBucket(!enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
326
engine/src/core/com/jme3/post/ssao/SSAOFilter.java
Normal file
326
engine/src/core/com/jme3/post/ssao/SSAOFilter.java
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.post.ssao;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.export.InputCapsule;
|
||||||
|
import com.jme3.export.JmeExporter;
|
||||||
|
import com.jme3.export.JmeImporter;
|
||||||
|
import com.jme3.export.OutputCapsule;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.Vector2f;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.post.Filter;
|
||||||
|
import com.jme3.post.Filter.Pass;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.Renderer;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.shader.VarType;
|
||||||
|
import com.jme3.texture.Image.Format;
|
||||||
|
import com.jme3.texture.Texture;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SSAO stands for screen space ambient occlusion
|
||||||
|
* It's a technique that fake ambient lighting by computing shadows that near by objects would casts on each others
|
||||||
|
* under the effect of an ambient light
|
||||||
|
* more info on this in this blog post <a href="http://jmonkeyengine.org/2010/08/16/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/">http://jmonkeyengine.org/2010/08/16/screen-space-ambient-occlusion-for-jmonkeyengine-3-0/</a>
|
||||||
|
*
|
||||||
|
* @author Rémy Bouquet aka Nehon
|
||||||
|
*/
|
||||||
|
public class SSAOFilter extends Filter {
|
||||||
|
|
||||||
|
private Pass normalPass;
|
||||||
|
private Vector3f frustumCorner;
|
||||||
|
private Vector2f frustumNearFar;
|
||||||
|
private Vector2f[] samples = {new Vector2f(1.0f, 0.0f), new Vector2f(-1.0f, 0.0f), new Vector2f(0.0f, 1.0f), new Vector2f(0.0f, -1.0f)};
|
||||||
|
private float sampleRadius = 5.1f;
|
||||||
|
private float intensity = 1.5f;
|
||||||
|
private float scale = 0.2f;
|
||||||
|
private float bias = 0.1f;
|
||||||
|
private boolean useOnlyAo = false;
|
||||||
|
private boolean useAo = true;
|
||||||
|
private Material ssaoMat;
|
||||||
|
private Pass ssaoPass;
|
||||||
|
// private Material downSampleMat;
|
||||||
|
// private Pass downSamplePass;
|
||||||
|
private float downSampleFactor = 1f;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Screen Space Ambient Occlusion Filter
|
||||||
|
*/
|
||||||
|
public SSAOFilter() {
|
||||||
|
super("SSAOFilter");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Screen Space Ambient Occlusion Filter
|
||||||
|
* @param sampleRadius The radius of the area where random samples will be picked. default 5.1f
|
||||||
|
* @param intensity intensity of the resulting AO. default 1.2f
|
||||||
|
* @param scale distance between occluders and occludee. default 0.2f
|
||||||
|
* @param bias the width of the occlusion cone considered by the occludee. default 0.1f
|
||||||
|
*/
|
||||||
|
public SSAOFilter(float sampleRadius, float intensity, float scale, float bias) {
|
||||||
|
this();
|
||||||
|
this.sampleRadius = sampleRadius;
|
||||||
|
this.intensity = intensity;
|
||||||
|
this.scale = scale;
|
||||||
|
this.bias = bias;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isRequiresDepthTexture() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void postQueue(RenderManager renderManager, ViewPort viewPort) {
|
||||||
|
Renderer r = renderManager.getRenderer();
|
||||||
|
r.setFrameBuffer(normalPass.getRenderFrameBuffer());
|
||||||
|
renderManager.getRenderer().clearBuffers(true, true, true);
|
||||||
|
renderManager.setForcedTechnique("PreNormalPass");
|
||||||
|
renderManager.renderViewPortQueues(viewPort, false);
|
||||||
|
renderManager.setForcedTechnique(null);
|
||||||
|
renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Material getMaterial() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initFilter(AssetManager manager, RenderManager renderManager, ViewPort vp, int w, int h) {
|
||||||
|
int screenWidth = w;
|
||||||
|
int screenHeight = h;
|
||||||
|
postRenderPasses = new ArrayList<Pass>();
|
||||||
|
|
||||||
|
normalPass = new Pass();
|
||||||
|
normalPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth);
|
||||||
|
|
||||||
|
|
||||||
|
frustumNearFar = new Vector2f();
|
||||||
|
|
||||||
|
float farY = (vp.getCamera().getFrustumTop() / vp.getCamera().getFrustumNear()) * vp.getCamera().getFrustumFar();
|
||||||
|
float farX = farY * ((float) screenWidth / (float) screenHeight);
|
||||||
|
frustumCorner = new Vector3f(farX, farY, vp.getCamera().getFrustumFar());
|
||||||
|
frustumNearFar.x = vp.getCamera().getFrustumNear();
|
||||||
|
frustumNearFar.y = vp.getCamera().getFrustumFar();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//ssao Pass
|
||||||
|
ssaoMat = new Material(manager, "Common/MatDefs/SSAO/ssao.j3md");
|
||||||
|
ssaoMat.setTexture("Normals", normalPass.getRenderedTexture());
|
||||||
|
Texture random = manager.loadTexture("Common/MatDefs/SSAO/Textures/random.png");
|
||||||
|
random.setWrap(Texture.WrapMode.Repeat);
|
||||||
|
ssaoMat.setTexture("RandomMap", random);
|
||||||
|
|
||||||
|
ssaoPass = new Pass() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean requiresDepthAsTexture() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ssaoPass.init(renderManager.getRenderer(), (int) (screenWidth / downSampleFactor), (int) (screenHeight / downSampleFactor), Format.RGBA8, Format.Depth, 1, ssaoMat);
|
||||||
|
ssaoPass.getRenderedTexture().setMinFilter(Texture.MinFilter.Trilinear);
|
||||||
|
ssaoPass.getRenderedTexture().setMagFilter(Texture.MagFilter.Bilinear);
|
||||||
|
postRenderPasses.add(ssaoPass);
|
||||||
|
material = new Material(manager, "Common/MatDefs/SSAO/ssaoBlur.j3md");
|
||||||
|
material.setTexture("SSAOMap", ssaoPass.getRenderedTexture());
|
||||||
|
|
||||||
|
ssaoMat.setVector3("FrustumCorner", frustumCorner);
|
||||||
|
ssaoMat.setFloat("SampleRadius", sampleRadius);
|
||||||
|
ssaoMat.setFloat("Intensity", intensity);
|
||||||
|
ssaoMat.setFloat("Scale", scale);
|
||||||
|
ssaoMat.setFloat("Bias", bias);
|
||||||
|
material.setBoolean("UseAo", useAo);
|
||||||
|
material.setBoolean("UseOnlyAo", useOnlyAo);
|
||||||
|
ssaoMat.setVector2("FrustumNearFar", frustumNearFar);
|
||||||
|
material.setVector2("FrustumNearFar", frustumNearFar);
|
||||||
|
ssaoMat.setParam("Samples", VarType.Vector2Array, samples);
|
||||||
|
|
||||||
|
float xScale = 1.0f / w;
|
||||||
|
float yScale = 1.0f / h;
|
||||||
|
|
||||||
|
float blurScale = 2f;
|
||||||
|
material.setFloat("XScale", blurScale * xScale);
|
||||||
|
material.setFloat("YScale", blurScale * yScale);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the bias<br>
|
||||||
|
* see {@link setBias(float bias)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getBias() {
|
||||||
|
return bias;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the the width of the occlusion cone considered by the occludee default is 0.1f
|
||||||
|
* @param bias
|
||||||
|
*/
|
||||||
|
public void setBias(float bias) {
|
||||||
|
this.bias = bias;
|
||||||
|
if (ssaoMat != null) {
|
||||||
|
ssaoMat.setFloat("Bias", bias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the ambient occlusion intensity
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getIntensity() {
|
||||||
|
return intensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the Ambient occlusion intensity default is 1.2f
|
||||||
|
* @param intensity
|
||||||
|
*/
|
||||||
|
public void setIntensity(float intensity) {
|
||||||
|
this.intensity = intensity;
|
||||||
|
if (ssaoMat != null) {
|
||||||
|
ssaoMat.setFloat("Intensity", intensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the sample radius<br>
|
||||||
|
* see {link setSampleRadius(float sampleRadius)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getSampleRadius() {
|
||||||
|
return sampleRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the radius of the area where random samples will be picked dafault 5.1f
|
||||||
|
* @param sampleRadius
|
||||||
|
*/
|
||||||
|
public void setSampleRadius(float sampleRadius) {
|
||||||
|
this.sampleRadius = sampleRadius;
|
||||||
|
if (ssaoMat != null) {
|
||||||
|
ssaoMat.setFloat("SampleRadius", sampleRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the scale<br>
|
||||||
|
* see {@link setScale(float scale)}
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getScale() {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Returns the distance between occluders and occludee. default 0.2f
|
||||||
|
* @param scale
|
||||||
|
*/
|
||||||
|
public void setScale(float scale) {
|
||||||
|
this.scale = scale;
|
||||||
|
if (ssaoMat != null) {
|
||||||
|
ssaoMat.setFloat("Scale", scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debugging only , will be removed
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isUseAo() {
|
||||||
|
return useAo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debugging only , will be removed
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public void setUseAo(boolean useAo) {
|
||||||
|
this.useAo = useAo;
|
||||||
|
if (material != null) {
|
||||||
|
material.setBoolean("UseAo", useAo);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debugging only , will be removed
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isUseOnlyAo() {
|
||||||
|
return useOnlyAo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debugging only , will be removed
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public void setUseOnlyAo(boolean useOnlyAo) {
|
||||||
|
this.useOnlyAo = useOnlyAo;
|
||||||
|
if (material != null) {
|
||||||
|
material.setBoolean("UseOnlyAo", useOnlyAo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JmeExporter ex) throws IOException {
|
||||||
|
super.write(ex);
|
||||||
|
OutputCapsule oc = ex.getCapsule(this);
|
||||||
|
oc.write(sampleRadius, "sampleRadius", 5.1f);
|
||||||
|
oc.write(intensity, "intensity", 1.5f);
|
||||||
|
oc.write(scale, "scale", 0.2f);
|
||||||
|
oc.write(bias, "bias", 0.1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(JmeImporter im) throws IOException {
|
||||||
|
super.read(im);
|
||||||
|
InputCapsule ic = im.getCapsule(this);
|
||||||
|
sampleRadius = ic.readFloat("sampleRadius", 5.1f);
|
||||||
|
intensity = ic.readFloat("intensity", 1.5f);
|
||||||
|
scale = ic.readFloat("scale", 0.2f);
|
||||||
|
bias = ic.readFloat("bias", 0.1f);
|
||||||
|
}
|
||||||
|
}
|
216
engine/src/core/com/jme3/shadow/BasicShadowRenderer.java
Normal file
216
engine/src/core/com/jme3/shadow/BasicShadowRenderer.java
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.shadow;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.post.SceneProcessor;
|
||||||
|
import com.jme3.renderer.Camera;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.Renderer;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.renderer.queue.GeometryList;
|
||||||
|
import com.jme3.renderer.queue.RenderQueue;
|
||||||
|
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||||
|
import com.jme3.texture.FrameBuffer;
|
||||||
|
import com.jme3.texture.Image.Format;
|
||||||
|
import com.jme3.texture.Texture2D;
|
||||||
|
import com.jme3.ui.Picture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BasicShadowRenderer uses standard shadow mapping with one map
|
||||||
|
* it's useful to render shadows in a small scene, but edges might look a bit jagged.
|
||||||
|
*
|
||||||
|
* @author Kirill Vainer
|
||||||
|
*/
|
||||||
|
public class BasicShadowRenderer implements SceneProcessor {
|
||||||
|
|
||||||
|
private RenderManager renderManager;
|
||||||
|
private ViewPort viewPort;
|
||||||
|
private FrameBuffer shadowFB;
|
||||||
|
private Texture2D shadowMap;
|
||||||
|
private Camera shadowCam;
|
||||||
|
private Material preshadowMat;
|
||||||
|
private Material postshadowMat;
|
||||||
|
private Picture dispPic = new Picture("Picture");
|
||||||
|
private boolean noOccluders = false;
|
||||||
|
private Vector3f[] points = new Vector3f[8];
|
||||||
|
private Vector3f direction = new Vector3f();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a BasicShadowRenderer
|
||||||
|
* @param manager the asset manager
|
||||||
|
* @param size the size of the shadow map (the map is square)
|
||||||
|
*/
|
||||||
|
public BasicShadowRenderer(AssetManager manager, int size) {
|
||||||
|
shadowFB = new FrameBuffer(size, size, 1);
|
||||||
|
shadowMap = new Texture2D(size, size, Format.Depth);
|
||||||
|
shadowFB.setDepthTexture(shadowMap);
|
||||||
|
shadowCam = new Camera(size, size);
|
||||||
|
|
||||||
|
preshadowMat = new Material(manager, "Common/MatDefs/Shadow/PreShadow.j3md");
|
||||||
|
postshadowMat = new Material(manager, "Common/MatDefs/Shadow/PostShadow.j3md");
|
||||||
|
postshadowMat.setTexture("ShadowMap", shadowMap);
|
||||||
|
|
||||||
|
dispPic.setTexture(manager, shadowMap, false);
|
||||||
|
|
||||||
|
for (int i = 0; i < points.length; i++) {
|
||||||
|
points[i] = new Vector3f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(RenderManager rm, ViewPort vp) {
|
||||||
|
renderManager = rm;
|
||||||
|
viewPort = vp;
|
||||||
|
|
||||||
|
reshape(vp, vp.getCamera().getWidth(), vp.getCamera().getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInitialized() {
|
||||||
|
return viewPort != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the light direction used for this processor
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Vector3f getDirection() {
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the light direction to use to computs shadows
|
||||||
|
* @param direction
|
||||||
|
*/
|
||||||
|
public void setDirection(Vector3f direction) {
|
||||||
|
this.direction.set(direction).normalizeLocal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debug only
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Vector3f[] getPoints() {
|
||||||
|
return points;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debug only
|
||||||
|
* returns the shadow camera
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Camera getShadowCamera() {
|
||||||
|
return shadowCam;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postQueue(RenderQueue rq) {
|
||||||
|
GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);
|
||||||
|
if (occluders.size() == 0) {
|
||||||
|
noOccluders = true;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
noOccluders = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive);
|
||||||
|
|
||||||
|
// update frustum points based on current camera
|
||||||
|
Camera viewCam = viewPort.getCamera();
|
||||||
|
ShadowUtil.updateFrustumPoints(viewCam,
|
||||||
|
viewCam.getFrustumNear(),
|
||||||
|
viewCam.getFrustumFar(),
|
||||||
|
1.0f,
|
||||||
|
points);
|
||||||
|
|
||||||
|
Vector3f frustaCenter = new Vector3f();
|
||||||
|
for (Vector3f point : points) {
|
||||||
|
frustaCenter.addLocal(point);
|
||||||
|
}
|
||||||
|
frustaCenter.multLocal(1f / 8f);
|
||||||
|
|
||||||
|
// update light direction
|
||||||
|
shadowCam.setProjectionMatrix(null);
|
||||||
|
shadowCam.setParallelProjection(true);
|
||||||
|
// shadowCam.setFrustumPerspective(45, 1, 1, 20);
|
||||||
|
|
||||||
|
shadowCam.lookAtDirection(direction, Vector3f.UNIT_Y);
|
||||||
|
shadowCam.update();
|
||||||
|
shadowCam.setLocation(frustaCenter);
|
||||||
|
shadowCam.update();
|
||||||
|
shadowCam.updateViewProjection();
|
||||||
|
|
||||||
|
// render shadow casters to shadow map
|
||||||
|
ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points);
|
||||||
|
|
||||||
|
Renderer r = renderManager.getRenderer();
|
||||||
|
renderManager.setCamera(shadowCam, false);
|
||||||
|
renderManager.setForcedMaterial(preshadowMat);
|
||||||
|
|
||||||
|
r.setFrameBuffer(shadowFB);
|
||||||
|
r.clearBuffers(false, true, false);
|
||||||
|
viewPort.getQueue().renderShadowQueue(ShadowMode.Cast, renderManager, shadowCam, true);
|
||||||
|
r.setFrameBuffer(viewPort.getOutputFrameBuffer());
|
||||||
|
|
||||||
|
renderManager.setForcedMaterial(null);
|
||||||
|
renderManager.setCamera(viewCam, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debug only
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Picture getDisplayPicture() {
|
||||||
|
return dispPic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postFrame(FrameBuffer out) {
|
||||||
|
if (!noOccluders) {
|
||||||
|
postshadowMat.setMatrix4("LightViewProjectionMatrix", shadowCam.getViewProjectionMatrix());
|
||||||
|
renderManager.setForcedMaterial(postshadowMat);
|
||||||
|
viewPort.getQueue().renderShadowQueue(ShadowMode.Receive, renderManager, viewPort.getCamera(), true);
|
||||||
|
renderManager.setForcedMaterial(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void preFrame(float tpf) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reshape(ViewPort vp, int w, int h) {
|
||||||
|
dispPic.setPosition(w / 20f, h / 20f);
|
||||||
|
dispPic.setWidth(w / 5f);
|
||||||
|
dispPic.setHeight(h / 5f);
|
||||||
|
}
|
||||||
|
}
|
539
engine/src/core/com/jme3/shadow/PssmShadowRenderer.java
Normal file
539
engine/src/core/com/jme3/shadow/PssmShadowRenderer.java
Normal file
@ -0,0 +1,539 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine All rights reserved.
|
||||||
|
* <p/>
|
||||||
|
* 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.
|
||||||
|
* <p/>
|
||||||
|
* * 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.
|
||||||
|
* <p/>
|
||||||
|
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
* <p/>
|
||||||
|
* 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)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.shadow;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.ColorRGBA;
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.post.SceneProcessor;
|
||||||
|
import com.jme3.renderer.Camera;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.Renderer;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.renderer.queue.GeometryList;
|
||||||
|
import com.jme3.renderer.queue.OpaqueComparator;
|
||||||
|
import com.jme3.renderer.queue.RenderQueue;
|
||||||
|
import com.jme3.renderer.queue.RenderQueue.ShadowMode;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.scene.debug.WireFrustum;
|
||||||
|
import com.jme3.texture.FrameBuffer;
|
||||||
|
import com.jme3.texture.Image.Format;
|
||||||
|
import com.jme3.texture.Texture.MagFilter;
|
||||||
|
import com.jme3.texture.Texture.MinFilter;
|
||||||
|
import com.jme3.texture.Texture.ShadowCompareMode;
|
||||||
|
import com.jme3.texture.Texture2D;
|
||||||
|
import com.jme3.ui.Picture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PssmShadow renderer use Parrallel Split Shadow Mapping technique (pssm)<br>
|
||||||
|
* It splits the view frustum in several parts and compute a shadow map for each
|
||||||
|
* one.<br> splits are distributed so that the closer they are from the camera,
|
||||||
|
* the smaller they are to maximize the resolution used of the shadow map.<br>
|
||||||
|
* This result in a better quality shadow than standard shadow mapping.<br> for
|
||||||
|
* more informations on this read this
|
||||||
|
* <a href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a><br>
|
||||||
|
* <p/>
|
||||||
|
* @author Rémy Bouquet aka Nehon
|
||||||
|
*/
|
||||||
|
public class PssmShadowRenderer implements SceneProcessor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>FilterMode</code> specifies how shadows are filtered
|
||||||
|
*/
|
||||||
|
public enum FilterMode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shadows are not filtered. Nearest sample is used, causing in blocky
|
||||||
|
* shadows.
|
||||||
|
*/
|
||||||
|
Nearest,
|
||||||
|
/**
|
||||||
|
* Bilinear filtering is used. Has the potential of being hardware
|
||||||
|
* accelerated on some GPUs
|
||||||
|
*/
|
||||||
|
Bilinear,
|
||||||
|
/**
|
||||||
|
* Dither-based sampling is used, very cheap but can look bad
|
||||||
|
* at low resolutions.
|
||||||
|
*/
|
||||||
|
Dither,
|
||||||
|
/**
|
||||||
|
* 4x4 percentage-closer filtering is used. Shadows will be smoother
|
||||||
|
* at the cost of performance
|
||||||
|
*/
|
||||||
|
PCF4,
|
||||||
|
/**
|
||||||
|
* 8x8 percentage-closer filtering is used. Shadows will be smoother
|
||||||
|
* at the cost of performance
|
||||||
|
*/
|
||||||
|
PCF8
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the shadow comparison mode
|
||||||
|
*/
|
||||||
|
public enum CompareMode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shadow depth comparisons are done by using shader code
|
||||||
|
*/
|
||||||
|
Software,
|
||||||
|
/**
|
||||||
|
* Shadow depth comparisons are done by using the GPU's dedicated
|
||||||
|
* shadowing pipeline.
|
||||||
|
*/
|
||||||
|
Hardware;
|
||||||
|
}
|
||||||
|
private int nbSplits = 3;
|
||||||
|
private float lambda = 0.65f;
|
||||||
|
private float shadowIntensity = 0.7f;
|
||||||
|
private float zFarOverride = 0;
|
||||||
|
private RenderManager renderManager;
|
||||||
|
private ViewPort viewPort;
|
||||||
|
private FrameBuffer[] shadowFB;
|
||||||
|
private Texture2D[] shadowMaps;
|
||||||
|
private Texture2D dummyTex;
|
||||||
|
private Camera shadowCam;
|
||||||
|
private Material preshadowMat;
|
||||||
|
private Material postshadowMat;
|
||||||
|
private GeometryList splitOccluders = new GeometryList(new OpaqueComparator());
|
||||||
|
private Matrix4f[] lightViewProjectionsMatrices;
|
||||||
|
private ColorRGBA splits;
|
||||||
|
private float[] splitsArray;
|
||||||
|
private boolean noOccluders = false;
|
||||||
|
private Vector3f direction = new Vector3f();
|
||||||
|
private AssetManager assetManager;
|
||||||
|
private boolean debug = false;
|
||||||
|
private float edgesThickness = 1.0f;
|
||||||
|
private FilterMode filterMode;
|
||||||
|
private CompareMode compareMode;
|
||||||
|
private Picture[] dispPic;
|
||||||
|
private Vector3f[] points = new Vector3f[8];
|
||||||
|
private boolean flushQueues = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a PSSM Shadow Renderer
|
||||||
|
* More info on the technique at <a href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a>
|
||||||
|
* @param manager the application asset manager
|
||||||
|
* @param size the size of the rendered shadowmaps (512,1024,2048, etc...)
|
||||||
|
* @param nbSplits the number of shadow maps rendered (the more shadow maps the more quality, the less fps).
|
||||||
|
*/
|
||||||
|
public PssmShadowRenderer(AssetManager manager, int size, int nbSplits) {
|
||||||
|
assetManager = manager;
|
||||||
|
nbSplits = Math.max(Math.min(nbSplits, 4), 1);
|
||||||
|
this.nbSplits = nbSplits;
|
||||||
|
|
||||||
|
shadowFB = new FrameBuffer[nbSplits];
|
||||||
|
shadowMaps = new Texture2D[nbSplits];
|
||||||
|
dispPic = new Picture[nbSplits];
|
||||||
|
lightViewProjectionsMatrices = new Matrix4f[nbSplits];
|
||||||
|
splits = new ColorRGBA();
|
||||||
|
splitsArray = new float[nbSplits + 1];
|
||||||
|
|
||||||
|
//DO NOT COMMENT THIS (it prevent the OSX incomplete read buffer crash)
|
||||||
|
dummyTex = new Texture2D(size, size, Format.RGBA8);
|
||||||
|
|
||||||
|
preshadowMat = new Material(manager, "Common/MatDefs/Shadow/PreShadow.j3md");
|
||||||
|
postshadowMat = new Material(manager, "Common/MatDefs/Shadow/PostShadowPSSM.j3md");
|
||||||
|
|
||||||
|
for (int i = 0; i < nbSplits; i++) {
|
||||||
|
lightViewProjectionsMatrices[i] = new Matrix4f();
|
||||||
|
shadowFB[i] = new FrameBuffer(size, size, 1);
|
||||||
|
shadowMaps[i] = new Texture2D(size, size, Format.Depth);
|
||||||
|
|
||||||
|
shadowFB[i].setDepthTexture(shadowMaps[i]);
|
||||||
|
|
||||||
|
//DO NOT COMMENT THIS (it prevent the OSX incomplete read buffer crash)
|
||||||
|
shadowFB[i].setColorTexture(dummyTex);
|
||||||
|
|
||||||
|
postshadowMat.setTexture("ShadowMap" + i, shadowMaps[i]);
|
||||||
|
|
||||||
|
//quads for debuging purpose
|
||||||
|
dispPic[i] = new Picture("Picture" + i);
|
||||||
|
dispPic[i].setTexture(manager, shadowMaps[i], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
setCompareMode(CompareMode.Hardware);
|
||||||
|
setFilterMode(FilterMode.Bilinear);
|
||||||
|
setShadowIntensity(0.7f);
|
||||||
|
|
||||||
|
shadowCam = new Camera(size, size);
|
||||||
|
shadowCam.setParallelProjection(true);
|
||||||
|
|
||||||
|
for (int i = 0; i < points.length; i++) {
|
||||||
|
points[i] = new Vector3f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the filtering mode for shadow edges see {@link FilterMode} for more info
|
||||||
|
* @param filterMode
|
||||||
|
*/
|
||||||
|
public void setFilterMode(FilterMode filterMode) {
|
||||||
|
if (filterMode == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.filterMode == filterMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.filterMode = filterMode;
|
||||||
|
postshadowMat.setInt("FilterMode", filterMode.ordinal());
|
||||||
|
postshadowMat.setFloat("PCFEdge", edgesThickness);
|
||||||
|
if (compareMode == CompareMode.Hardware) {
|
||||||
|
for (Texture2D shadowMap : shadowMaps) {
|
||||||
|
if (filterMode == FilterMode.Bilinear) {
|
||||||
|
shadowMap.setMagFilter(MagFilter.Bilinear);
|
||||||
|
shadowMap.setMinFilter(MinFilter.BilinearNoMipMaps);
|
||||||
|
} else {
|
||||||
|
shadowMap.setMagFilter(MagFilter.Nearest);
|
||||||
|
shadowMap.setMinFilter(MinFilter.NearestNoMipMaps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the shadow compare mode see {@link CompareMode} for more info
|
||||||
|
* @param compareMode
|
||||||
|
*/
|
||||||
|
public void setCompareMode(CompareMode compareMode) {
|
||||||
|
if (compareMode == null) {
|
||||||
|
throw new NullPointerException();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.compareMode == compareMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.compareMode = compareMode;
|
||||||
|
for (Texture2D shadowMap : shadowMaps) {
|
||||||
|
if (compareMode == CompareMode.Hardware) {
|
||||||
|
shadowMap.setShadowCompareMode(ShadowCompareMode.LessOrEqual);
|
||||||
|
if (filterMode == FilterMode.Bilinear) {
|
||||||
|
shadowMap.setMagFilter(MagFilter.Bilinear);
|
||||||
|
shadowMap.setMinFilter(MinFilter.BilinearNoMipMaps);
|
||||||
|
} else {
|
||||||
|
shadowMap.setMagFilter(MagFilter.Nearest);
|
||||||
|
shadowMap.setMinFilter(MinFilter.NearestNoMipMaps);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
shadowMap.setShadowCompareMode(ShadowCompareMode.Off);
|
||||||
|
shadowMap.setMagFilter(MagFilter.Nearest);
|
||||||
|
shadowMap.setMinFilter(MinFilter.NearestNoMipMaps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
postshadowMat.setBoolean("HardwareShadows", compareMode == CompareMode.Hardware);
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug function that create a displayable frustrum
|
||||||
|
private Geometry createFrustum(Vector3f[] pts, int i) {
|
||||||
|
WireFrustum frustum = new WireFrustum(pts);
|
||||||
|
Geometry frustumMdl = new Geometry("f", frustum);
|
||||||
|
frustumMdl.setCullHint(Spatial.CullHint.Never);
|
||||||
|
frustumMdl.setShadowMode(ShadowMode.Off);
|
||||||
|
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||||
|
mat.getAdditionalRenderState().setWireframe(true);
|
||||||
|
frustumMdl.setMaterial(mat);
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
frustumMdl.getMaterial().setColor("Color", ColorRGBA.Pink);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
frustumMdl.getMaterial().setColor("Color", ColorRGBA.Red);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
frustumMdl.getMaterial().setColor("Color", ColorRGBA.Green);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
frustumMdl.getMaterial().setColor("Color", ColorRGBA.Blue);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
frustumMdl.getMaterial().setColor("Color", ColorRGBA.White);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
frustumMdl.updateGeometricState();
|
||||||
|
return frustumMdl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(RenderManager rm, ViewPort vp) {
|
||||||
|
renderManager = rm;
|
||||||
|
viewPort = vp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInitialized() {
|
||||||
|
return viewPort != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the light direction used by the processor
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Vector3f getDirection() {
|
||||||
|
return direction;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the light direction to use to compute shadows
|
||||||
|
* @param direction
|
||||||
|
*/
|
||||||
|
public void setDirection(Vector3f direction) {
|
||||||
|
this.direction.set(direction).normalizeLocal();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("fallthrough")
|
||||||
|
public void postQueue(RenderQueue rq) {
|
||||||
|
GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);
|
||||||
|
if (occluders.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive);
|
||||||
|
if (receivers.size() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Camera viewCam = viewPort.getCamera();
|
||||||
|
|
||||||
|
float zFar = zFarOverride;
|
||||||
|
if (zFar == 0) {
|
||||||
|
zFar = viewCam.getFrustumFar();
|
||||||
|
}
|
||||||
|
|
||||||
|
//We prevent computing the frustum points and splits with zeroed or negative near clip value
|
||||||
|
float frustumNear = Math.max(viewCam.getFrustumNear(), 0.001f);
|
||||||
|
ShadowUtil.updateFrustumPoints(viewCam, frustumNear, zFar, 1.0f, points);
|
||||||
|
|
||||||
|
//shadowCam.setDirection(direction);
|
||||||
|
shadowCam.getRotation().lookAt(direction, shadowCam.getUp());
|
||||||
|
shadowCam.update();
|
||||||
|
shadowCam.updateViewProjection();
|
||||||
|
|
||||||
|
PssmShadowUtil.updateFrustumSplits(splitsArray, frustumNear, zFar, lambda);
|
||||||
|
|
||||||
|
|
||||||
|
switch (splitsArray.length) {
|
||||||
|
case 5:
|
||||||
|
splits.a = splitsArray[4];
|
||||||
|
case 4:
|
||||||
|
splits.b = splitsArray[3];
|
||||||
|
case 3:
|
||||||
|
splits.g = splitsArray[2];
|
||||||
|
case 2:
|
||||||
|
case 1:
|
||||||
|
splits.r = splitsArray[1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer r = renderManager.getRenderer();
|
||||||
|
renderManager.setForcedMaterial(preshadowMat);
|
||||||
|
renderManager.setForcedTechnique("PreShadow");
|
||||||
|
|
||||||
|
for (int i = 0; i < nbSplits; i++) {
|
||||||
|
|
||||||
|
// update frustum points based on current camera and split
|
||||||
|
ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], 1.0f, points);
|
||||||
|
|
||||||
|
//Updating shadow cam with curent split frustra
|
||||||
|
ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points, splitOccluders);
|
||||||
|
|
||||||
|
//saving light view projection matrix for this split
|
||||||
|
lightViewProjectionsMatrices[i] = shadowCam.getViewProjectionMatrix().clone();
|
||||||
|
renderManager.setCamera(shadowCam, false);
|
||||||
|
|
||||||
|
r.setFrameBuffer(shadowFB[i]);
|
||||||
|
r.clearBuffers(false, true, false);
|
||||||
|
|
||||||
|
// render shadow casters to shadow map
|
||||||
|
viewPort.getQueue().renderShadowQueue(splitOccluders, renderManager, shadowCam, true);
|
||||||
|
}
|
||||||
|
if (flushQueues) {
|
||||||
|
occluders.clear();
|
||||||
|
}
|
||||||
|
//restore setting for future rendering
|
||||||
|
r.setFrameBuffer(viewPort.getOutputFrameBuffer());
|
||||||
|
renderManager.setForcedMaterial(null);
|
||||||
|
renderManager.setForcedTechnique(null);
|
||||||
|
renderManager.setCamera(viewCam, false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug only : displays depth shadow maps
|
||||||
|
private void displayShadowMap(Renderer r) {
|
||||||
|
Camera cam = viewPort.getCamera();
|
||||||
|
renderManager.setCamera(cam, true);
|
||||||
|
int h = cam.getHeight();
|
||||||
|
for (int i = 0; i < dispPic.length; i++) {
|
||||||
|
dispPic[i].setPosition(64 * (i + 1) + 128 * i, h / 20f);
|
||||||
|
dispPic[i].setWidth(128);
|
||||||
|
dispPic[i].setHeight(128);
|
||||||
|
dispPic[i].updateGeometricState();
|
||||||
|
renderManager.renderGeometry(dispPic[i]);
|
||||||
|
}
|
||||||
|
renderManager.setCamera(cam, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**For dubuging purpose
|
||||||
|
* Allow to "snapshot" the current frustrum to the scene
|
||||||
|
*/
|
||||||
|
public void displayDebug() {
|
||||||
|
debug = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postFrame(FrameBuffer out) {
|
||||||
|
Camera cam = viewPort.getCamera();
|
||||||
|
if (!noOccluders) {
|
||||||
|
postshadowMat.setColor("Splits", splits);
|
||||||
|
for (int i = 0; i < nbSplits; i++) {
|
||||||
|
postshadowMat.setMatrix4("LightViewProjectionMatrix" + i, lightViewProjectionsMatrices[i]);
|
||||||
|
}
|
||||||
|
renderManager.setForcedMaterial(postshadowMat);
|
||||||
|
|
||||||
|
viewPort.getQueue().renderShadowQueue(ShadowMode.Receive, renderManager, cam, flushQueues);
|
||||||
|
|
||||||
|
renderManager.setForcedMaterial(null);
|
||||||
|
renderManager.setCamera(cam, false);
|
||||||
|
|
||||||
|
}
|
||||||
|
if (debug) {
|
||||||
|
displayShadowMap(renderManager.getRenderer());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void preFrame(float tpf) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reshape(ViewPort vp, int w, int h) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the labda parameter<br>
|
||||||
|
* see {@link setLambda(float lambda)}
|
||||||
|
* @return lambda
|
||||||
|
*/
|
||||||
|
public float getLambda() {
|
||||||
|
return lambda;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adjust the repartition of the different shadow maps in the shadow extend
|
||||||
|
* usualy goes from 0.0 to 1.0
|
||||||
|
* a low value give a more linear repartition resulting in a constant quality in the shadow over the extends, but near shadows could look very jagged
|
||||||
|
* a high value give a more logarithmic repartition resulting in a high quality for near shadows, but the quality quickly decrease over the extend.
|
||||||
|
* the default value is set to 0.65f (theoric optimal value).
|
||||||
|
* @param lambda the lambda value.
|
||||||
|
*/
|
||||||
|
public void setLambda(float lambda) {
|
||||||
|
this.lambda = lambda;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How far the shadows are rendered in the view
|
||||||
|
* see {@link setShadowZExtend(float zFar)}
|
||||||
|
* @return shadowZExtend
|
||||||
|
*/
|
||||||
|
public float getShadowZExtend() {
|
||||||
|
return zFarOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the distance from the eye where the shadows will be rendered
|
||||||
|
* default value is dynamicaly computed to the shadow casters/receivers union bound zFar, capped to view frustum far value.
|
||||||
|
* @param zFar the zFar values that override the computed one
|
||||||
|
*/
|
||||||
|
public void setShadowZExtend(float zFar) {
|
||||||
|
this.zFarOverride = zFar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the shdaow intensity<br>
|
||||||
|
* see {@link setShadowIntensity(float shadowIntensity)}
|
||||||
|
* @return shadowIntensity
|
||||||
|
*/
|
||||||
|
public float getShadowIntensity() {
|
||||||
|
return shadowIntensity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the shadowIntensity, the value should be between 0 and 1,
|
||||||
|
* a 0 value gives a bright and invisilble shadow,
|
||||||
|
* a 1 value gives a pitch black shadow,
|
||||||
|
* default is 0.7
|
||||||
|
* @param shadowIntensity the darkness of the shadow
|
||||||
|
*/
|
||||||
|
public void setShadowIntensity(float shadowIntensity) {
|
||||||
|
this.shadowIntensity = shadowIntensity;
|
||||||
|
postshadowMat.setFloat("ShadowIntensity", shadowIntensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the edges thickness <br>
|
||||||
|
* see {@link setEdgesThickness(int edgesThickness)}
|
||||||
|
* @return edgesThickness
|
||||||
|
*/
|
||||||
|
public int getEdgesThickness() {
|
||||||
|
return (int) (edgesThickness * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the shadow edges thickness. default is 1, setting it to lower values can help to reduce the jagged effect of the shadow edges
|
||||||
|
* @param edgesThickness
|
||||||
|
*/
|
||||||
|
public void setEdgesThickness(int edgesThickness) {
|
||||||
|
this.edgesThickness = Math.max(1, Math.min(edgesThickness, 10));
|
||||||
|
this.edgesThickness *= 0.1f;
|
||||||
|
postshadowMat.setFloat("PCFEdge", edgesThickness);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns true if the PssmRenderer flushed the shadow queues
|
||||||
|
* @return flushQueues
|
||||||
|
*/
|
||||||
|
public boolean isFlushQueues() {
|
||||||
|
return flushQueues;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set this to false if you want to use several PssmRederers to have multiple shadows cast by multiple light sources.
|
||||||
|
* Make sure the last PssmRenderer in the stack DO flush the queues, but not the others
|
||||||
|
* @param flushQueues
|
||||||
|
*/
|
||||||
|
public void setFlushQueues(boolean flushQueues) {
|
||||||
|
this.flushQueues = flushQueues;
|
||||||
|
}
|
||||||
|
}
|
81
engine/src/core/com/jme3/shadow/PssmShadowUtil.java
Normal file
81
engine/src/core/com/jme3/shadow/PssmShadowUtil.java
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.shadow;
|
||||||
|
|
||||||
|
import com.jme3.bounding.BoundingBox;
|
||||||
|
import com.jme3.math.FastMath;
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
|
import com.jme3.renderer.Camera;
|
||||||
|
import com.jme3.renderer.queue.GeometryList;
|
||||||
|
import static java.lang.Math.max;
|
||||||
|
import static java.lang.Math.min;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Includes various useful shadow mapping functions.
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <ul>
|
||||||
|
* <li><a href="http://appsrv.cse.cuhk.edu.hk/~fzhang/pssm_vrcia/">http://appsrv.cse.cuhk.edu.hk/~fzhang/pssm_vrcia/</a></li>
|
||||||
|
* <li><a href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a></li>
|
||||||
|
* </ul>
|
||||||
|
* for more info.
|
||||||
|
*/
|
||||||
|
public final class PssmShadowUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the frustum splits stores in <code>splits</code> using PSSM.
|
||||||
|
*/
|
||||||
|
public static void updateFrustumSplits(float[] splits, float near, float far, float lambda) {
|
||||||
|
for (int i = 0; i < splits.length; i++) {
|
||||||
|
float IDM = i / (float) splits.length;
|
||||||
|
float log = near * FastMath.pow((far / near), IDM);
|
||||||
|
float uniform = near + (far - near) * IDM;
|
||||||
|
splits[i] = log * lambda + uniform * (1.0f - lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is used to improve the correctness of the calculations. Our main near- and farplane
|
||||||
|
// of the camera always stay the same, no matter what happens.
|
||||||
|
splits[0] = near;
|
||||||
|
splits[splits.length - 1] = far;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the Zfar in the model vieuw to adjust the Zfar distance for the splits calculation
|
||||||
|
*/
|
||||||
|
public static float computeZFar(GeometryList occ, GeometryList recv, Camera cam) {
|
||||||
|
Matrix4f mat = cam.getViewMatrix();
|
||||||
|
BoundingBox bbOcc = ShadowUtil.computeUnionBound(occ, mat);
|
||||||
|
BoundingBox bbRecv = ShadowUtil.computeUnionBound(recv, mat);
|
||||||
|
|
||||||
|
return min(max(bbOcc.getZExtent() - bbOcc.getCenter().z, bbRecv.getZExtent() - bbRecv.getCenter().z), cam.getFrustumFar());
|
||||||
|
}
|
||||||
|
}
|
75
engine/src/core/com/jme3/shadow/ShadowCamera.java
Normal file
75
engine/src/core/com/jme3/shadow/ShadowCamera.java
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.shadow;
|
||||||
|
|
||||||
|
import com.jme3.light.DirectionalLight;
|
||||||
|
import com.jme3.light.Light;
|
||||||
|
import com.jme3.light.PointLight;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.renderer.Camera;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a camera according to a light
|
||||||
|
* Handy to compute projection matrix of a light
|
||||||
|
* @author Kirill Vainer
|
||||||
|
*/
|
||||||
|
public class ShadowCamera {
|
||||||
|
|
||||||
|
private Vector3f[] points = new Vector3f[8];
|
||||||
|
private Light target;
|
||||||
|
|
||||||
|
public ShadowCamera(Light target) {
|
||||||
|
this.target = target;
|
||||||
|
for (int i = 0; i < points.length; i++) {
|
||||||
|
points[i] = new Vector3f();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the camera view direction and position based on the light
|
||||||
|
*/
|
||||||
|
public void updateLightCamera(Camera lightCam) {
|
||||||
|
if (target.getType() == Light.Type.Directional) {
|
||||||
|
DirectionalLight dl = (DirectionalLight) target;
|
||||||
|
lightCam.setParallelProjection(true);
|
||||||
|
lightCam.setLocation(Vector3f.ZERO);
|
||||||
|
lightCam.lookAtDirection(dl.getDirection(), Vector3f.UNIT_Y);
|
||||||
|
lightCam.setFrustum(-1, 1, -1, 1, 1, -1);
|
||||||
|
} else {
|
||||||
|
PointLight pl = (PointLight) target;
|
||||||
|
lightCam.setParallelProjection(false);
|
||||||
|
lightCam.setLocation(pl.getPosition());
|
||||||
|
// direction will have to be calculated automatically
|
||||||
|
lightCam.setFrustumPerspective(45, 1, 1, 300);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
486
engine/src/core/com/jme3/shadow/ShadowUtil.java
Normal file
486
engine/src/core/com/jme3/shadow/ShadowUtil.java
Normal file
@ -0,0 +1,486 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.shadow;
|
||||||
|
|
||||||
|
import com.jme3.bounding.BoundingBox;
|
||||||
|
import com.jme3.bounding.BoundingVolume;
|
||||||
|
import com.jme3.math.Matrix4f;
|
||||||
|
import com.jme3.math.Transform;
|
||||||
|
import com.jme3.math.Vector2f;
|
||||||
|
import com.jme3.math.Vector3f;
|
||||||
|
import com.jme3.renderer.Camera;
|
||||||
|
import com.jme3.renderer.queue.GeometryList;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
|
import static java.lang.Math.max;
|
||||||
|
import static java.lang.Math.min;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Includes various useful shadow mapping functions.
|
||||||
|
*
|
||||||
|
* @see
|
||||||
|
* <ul>
|
||||||
|
* <li><a href="http://appsrv.cse.cuhk.edu.hk/~fzhang/pssm_vrcia/">http://appsrv.cse.cuhk.edu.hk/~fzhang/pssm_vrcia/</a></li>
|
||||||
|
* <li><a href="http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html">http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html</a></li>
|
||||||
|
* </ul>
|
||||||
|
* for more info.
|
||||||
|
*/
|
||||||
|
public class ShadowUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a points arrays with the frustum corners of the provided camera.
|
||||||
|
* @param viewCam
|
||||||
|
* @param points
|
||||||
|
*/
|
||||||
|
public static void updateFrustumPoints2(Camera viewCam, Vector3f[] points) {
|
||||||
|
int w = viewCam.getWidth();
|
||||||
|
int h = viewCam.getHeight();
|
||||||
|
float n = viewCam.getFrustumNear();
|
||||||
|
float f = viewCam.getFrustumFar();
|
||||||
|
|
||||||
|
points[0].set(viewCam.getWorldCoordinates(new Vector2f(0, 0), n));
|
||||||
|
points[1].set(viewCam.getWorldCoordinates(new Vector2f(0, h), n));
|
||||||
|
points[2].set(viewCam.getWorldCoordinates(new Vector2f(w, h), n));
|
||||||
|
points[3].set(viewCam.getWorldCoordinates(new Vector2f(w, 0), n));
|
||||||
|
|
||||||
|
points[4].set(viewCam.getWorldCoordinates(new Vector2f(0, 0), f));
|
||||||
|
points[5].set(viewCam.getWorldCoordinates(new Vector2f(0, h), f));
|
||||||
|
points[6].set(viewCam.getWorldCoordinates(new Vector2f(w, h), f));
|
||||||
|
points[7].set(viewCam.getWorldCoordinates(new Vector2f(w, 0), f));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the points array to contain the frustum corners of the given
|
||||||
|
* camera. The nearOverride and farOverride variables can be used
|
||||||
|
* to override the camera's near/far values with own values.
|
||||||
|
*
|
||||||
|
* TODO: Reduce creation of new vectors
|
||||||
|
*
|
||||||
|
* @param viewCam
|
||||||
|
* @param nearOverride
|
||||||
|
* @param farOverride
|
||||||
|
*/
|
||||||
|
public static void updateFrustumPoints(Camera viewCam,
|
||||||
|
float nearOverride,
|
||||||
|
float farOverride,
|
||||||
|
float scale,
|
||||||
|
Vector3f[] points) {
|
||||||
|
|
||||||
|
Vector3f pos = viewCam.getLocation();
|
||||||
|
Vector3f dir = viewCam.getDirection();
|
||||||
|
Vector3f up = viewCam.getUp();
|
||||||
|
|
||||||
|
float depthHeightRatio = viewCam.getFrustumTop() / viewCam.getFrustumNear();
|
||||||
|
float near = nearOverride;
|
||||||
|
float far = farOverride;
|
||||||
|
float ftop = viewCam.getFrustumTop();
|
||||||
|
float fright = viewCam.getFrustumRight();
|
||||||
|
float ratio = fright / ftop;
|
||||||
|
|
||||||
|
float near_height;
|
||||||
|
float near_width;
|
||||||
|
float far_height;
|
||||||
|
float far_width;
|
||||||
|
|
||||||
|
if (viewCam.isParallelProjection()) {
|
||||||
|
near_height = ftop;
|
||||||
|
near_width = near_height * ratio;
|
||||||
|
far_height = ftop;
|
||||||
|
far_width = far_height * ratio;
|
||||||
|
} else {
|
||||||
|
near_height = depthHeightRatio * near;
|
||||||
|
near_width = near_height * ratio;
|
||||||
|
far_height = depthHeightRatio * far;
|
||||||
|
far_width = far_height * ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f right = dir.cross(up).normalizeLocal();
|
||||||
|
|
||||||
|
Vector3f temp = new Vector3f();
|
||||||
|
temp.set(dir).multLocal(far).addLocal(pos);
|
||||||
|
Vector3f farCenter = temp.clone();
|
||||||
|
temp.set(dir).multLocal(near).addLocal(pos);
|
||||||
|
Vector3f nearCenter = temp.clone();
|
||||||
|
|
||||||
|
Vector3f nearUp = temp.set(up).multLocal(near_height).clone();
|
||||||
|
Vector3f farUp = temp.set(up).multLocal(far_height).clone();
|
||||||
|
Vector3f nearRight = temp.set(right).multLocal(near_width).clone();
|
||||||
|
Vector3f farRight = temp.set(right).multLocal(far_width).clone();
|
||||||
|
|
||||||
|
points[0].set(nearCenter).subtractLocal(nearUp).subtractLocal(nearRight);
|
||||||
|
points[1].set(nearCenter).addLocal(nearUp).subtractLocal(nearRight);
|
||||||
|
points[2].set(nearCenter).addLocal(nearUp).addLocal(nearRight);
|
||||||
|
points[3].set(nearCenter).subtractLocal(nearUp).addLocal(nearRight);
|
||||||
|
|
||||||
|
points[4].set(farCenter).subtractLocal(farUp).subtractLocal(farRight);
|
||||||
|
points[5].set(farCenter).addLocal(farUp).subtractLocal(farRight);
|
||||||
|
points[6].set(farCenter).addLocal(farUp).addLocal(farRight);
|
||||||
|
points[7].set(farCenter).subtractLocal(farUp).addLocal(farRight);
|
||||||
|
|
||||||
|
if (scale != 1.0f) {
|
||||||
|
// find center of frustum
|
||||||
|
Vector3f center = new Vector3f();
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
center.addLocal(points[i]);
|
||||||
|
}
|
||||||
|
center.divideLocal(8f);
|
||||||
|
|
||||||
|
Vector3f cDir = new Vector3f();
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
cDir.set(points[i]).subtractLocal(center);
|
||||||
|
cDir.multLocal(scale - 1.0f);
|
||||||
|
points[i].addLocal(cDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute bounds of a geomList
|
||||||
|
* @param list
|
||||||
|
* @param transform
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static BoundingBox computeUnionBound(GeometryList list, Transform transform) {
|
||||||
|
BoundingBox bbox = new BoundingBox();
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
BoundingVolume vol = list.get(i).getWorldBound();
|
||||||
|
BoundingVolume newVol = vol.transform(transform);
|
||||||
|
//Nehon : prevent NaN and infinity values to screw the final bounding box
|
||||||
|
if (!Float.isNaN(newVol.getCenter().x) && !Float.isInfinite(newVol.getCenter().x)) {
|
||||||
|
bbox.mergeLocal(newVol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute bounds of a geomList
|
||||||
|
* @param list
|
||||||
|
* @param mat
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static BoundingBox computeUnionBound(GeometryList list, Matrix4f mat) {
|
||||||
|
BoundingBox bbox = new BoundingBox();
|
||||||
|
BoundingVolume store = null;
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
BoundingVolume vol = list.get(i).getWorldBound();
|
||||||
|
store = vol.clone().transform(mat, null);
|
||||||
|
//Nehon : prevent NaN and infinity values to screw the final bounding box
|
||||||
|
if (!Float.isNaN(store.getCenter().x) && !Float.isInfinite(store.getCenter().x)) {
|
||||||
|
bbox.mergeLocal(store);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes the bounds of multiple bounding volumes
|
||||||
|
* @param bv
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static BoundingBox computeUnionBound(List<BoundingVolume> bv) {
|
||||||
|
BoundingBox bbox = new BoundingBox();
|
||||||
|
for (int i = 0; i < bv.size(); i++) {
|
||||||
|
BoundingVolume vol = bv.get(i);
|
||||||
|
bbox.mergeLocal(vol);
|
||||||
|
}
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute bounds from an array of points
|
||||||
|
* @param pts
|
||||||
|
* @param transform
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static BoundingBox computeBoundForPoints(Vector3f[] pts, Transform transform) {
|
||||||
|
Vector3f min = new Vector3f(Vector3f.POSITIVE_INFINITY);
|
||||||
|
Vector3f max = new Vector3f(Vector3f.NEGATIVE_INFINITY);
|
||||||
|
Vector3f temp = new Vector3f();
|
||||||
|
for (int i = 0; i < pts.length; i++) {
|
||||||
|
transform.transformVector(pts[i], temp);
|
||||||
|
|
||||||
|
min.minLocal(temp);
|
||||||
|
max.maxLocal(temp);
|
||||||
|
}
|
||||||
|
Vector3f center = min.add(max).multLocal(0.5f);
|
||||||
|
Vector3f extent = max.subtract(min).multLocal(0.5f);
|
||||||
|
return new BoundingBox(center, extent.x, extent.y, extent.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute bounds from an array of points
|
||||||
|
* @param pts
|
||||||
|
* @param mat
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static BoundingBox computeBoundForPoints(Vector3f[] pts, Matrix4f mat) {
|
||||||
|
Vector3f min = new Vector3f(Vector3f.POSITIVE_INFINITY);
|
||||||
|
Vector3f max = new Vector3f(Vector3f.NEGATIVE_INFINITY);
|
||||||
|
Vector3f temp = new Vector3f();
|
||||||
|
|
||||||
|
for (int i = 0; i < pts.length; i++) {
|
||||||
|
float w = mat.multProj(pts[i], temp);
|
||||||
|
|
||||||
|
temp.x /= w;
|
||||||
|
temp.y /= w;
|
||||||
|
// Why was this commented out?
|
||||||
|
temp.z /= w;
|
||||||
|
|
||||||
|
min.minLocal(temp);
|
||||||
|
max.maxLocal(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f center = min.add(max).multLocal(0.5f);
|
||||||
|
Vector3f extent = max.subtract(min).multLocal(0.5f);
|
||||||
|
//Nehon 08/18/2010 : Added an offset to the extend to avoid banding artifacts when the frustum are aligned
|
||||||
|
return new BoundingBox(center, extent.x + 2.0f, extent.y + 2.0f, extent.z + 2.5f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the shadow camera to properly contain the given
|
||||||
|
* points (which contain the eye camera frustum corners)
|
||||||
|
*
|
||||||
|
* @param occluders
|
||||||
|
* @param lightCam
|
||||||
|
* @param points
|
||||||
|
*/
|
||||||
|
public static void updateShadowCamera(Camera shadowCam, Vector3f[] points) {
|
||||||
|
boolean ortho = shadowCam.isParallelProjection();
|
||||||
|
shadowCam.setProjectionMatrix(null);
|
||||||
|
|
||||||
|
if (ortho) {
|
||||||
|
shadowCam.setFrustum(-1, 1, -1, 1, 1, -1);
|
||||||
|
} else {
|
||||||
|
shadowCam.setFrustumPerspective(45, 1, 1, 150);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4f viewProjMatrix = shadowCam.getViewProjectionMatrix();
|
||||||
|
Matrix4f projMatrix = shadowCam.getProjectionMatrix();
|
||||||
|
|
||||||
|
BoundingBox splitBB = computeBoundForPoints(points, viewProjMatrix);
|
||||||
|
|
||||||
|
Vector3f splitMin = splitBB.getMin(null);
|
||||||
|
Vector3f splitMax = splitBB.getMax(null);
|
||||||
|
|
||||||
|
// splitMin.z = 0;
|
||||||
|
|
||||||
|
// Create the crop matrix.
|
||||||
|
float scaleX, scaleY, scaleZ;
|
||||||
|
float offsetX, offsetY, offsetZ;
|
||||||
|
|
||||||
|
scaleX = 2.0f / (splitMax.x - splitMin.x);
|
||||||
|
scaleY = 2.0f / (splitMax.y - splitMin.y);
|
||||||
|
offsetX = -0.5f * (splitMax.x + splitMin.x) * scaleX;
|
||||||
|
offsetY = -0.5f * (splitMax.y + splitMin.y) * scaleY;
|
||||||
|
scaleZ = 1.0f / (splitMax.z - splitMin.z);
|
||||||
|
offsetZ = -splitMin.z * scaleZ;
|
||||||
|
|
||||||
|
Matrix4f cropMatrix = new Matrix4f(scaleX, 0f, 0f, offsetX,
|
||||||
|
0f, scaleY, 0f, offsetY,
|
||||||
|
0f, 0f, scaleZ, offsetZ,
|
||||||
|
0f, 0f, 0f, 1f);
|
||||||
|
|
||||||
|
|
||||||
|
Matrix4f result = new Matrix4f();
|
||||||
|
result.set(cropMatrix);
|
||||||
|
result.multLocal(projMatrix);
|
||||||
|
|
||||||
|
shadowCam.setProjectionMatrix(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the shadow camera to properly contain the given
|
||||||
|
* points (which contain the eye camera frustum corners) and the
|
||||||
|
* shadow occluder objects.
|
||||||
|
*
|
||||||
|
* @param occluders
|
||||||
|
* @param lightCam
|
||||||
|
* @param points
|
||||||
|
*/
|
||||||
|
public static void updateShadowCamera(GeometryList occluders,
|
||||||
|
GeometryList receivers,
|
||||||
|
Camera shadowCam,
|
||||||
|
Vector3f[] points) {
|
||||||
|
updateShadowCamera(occluders, receivers, shadowCam, points, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the shadow camera to properly contain the given
|
||||||
|
* points (which contain the eye camera frustum corners) and the
|
||||||
|
* shadow occluder objects.
|
||||||
|
*
|
||||||
|
* @param occluders
|
||||||
|
* @param lightCam
|
||||||
|
* @param points
|
||||||
|
*/
|
||||||
|
public static void updateShadowCamera(GeometryList occluders,
|
||||||
|
GeometryList receivers,
|
||||||
|
Camera shadowCam,
|
||||||
|
Vector3f[] points,
|
||||||
|
GeometryList splitOccluders) {
|
||||||
|
|
||||||
|
boolean ortho = shadowCam.isParallelProjection();
|
||||||
|
|
||||||
|
shadowCam.setProjectionMatrix(null);
|
||||||
|
|
||||||
|
if (ortho) {
|
||||||
|
shadowCam.setFrustum(-1, 1, -1, 1, 1, -1);
|
||||||
|
} else {
|
||||||
|
shadowCam.setFrustumPerspective(45, 1, 1, 150);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create transform to rotate points to viewspace
|
||||||
|
Matrix4f viewProjMatrix = shadowCam.getViewProjectionMatrix();
|
||||||
|
|
||||||
|
BoundingBox splitBB = computeBoundForPoints(points, viewProjMatrix);
|
||||||
|
|
||||||
|
ArrayList<BoundingVolume> visRecvList = new ArrayList<BoundingVolume>();
|
||||||
|
for (int i = 0; i < receivers.size(); i++) {
|
||||||
|
// convert bounding box to light's viewproj space
|
||||||
|
Geometry receiver = receivers.get(i);
|
||||||
|
BoundingVolume bv = receiver.getWorldBound();
|
||||||
|
BoundingVolume recvBox = bv.transform(viewProjMatrix, null);
|
||||||
|
|
||||||
|
if (splitBB.intersects(recvBox)) {
|
||||||
|
visRecvList.add(recvBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<BoundingVolume> visOccList = new ArrayList<BoundingVolume>();
|
||||||
|
for (int i = 0; i < occluders.size(); i++) {
|
||||||
|
// convert bounding box to light's viewproj space
|
||||||
|
Geometry occluder = occluders.get(i);
|
||||||
|
BoundingVolume bv = occluder.getWorldBound();
|
||||||
|
BoundingVolume occBox = bv.transform(viewProjMatrix, null);
|
||||||
|
|
||||||
|
boolean intersects = splitBB.intersects(occBox);
|
||||||
|
if (!intersects && occBox instanceof BoundingBox) {
|
||||||
|
BoundingBox occBB = (BoundingBox) occBox;
|
||||||
|
//Kirill 01/10/2011
|
||||||
|
// Extend the occluder further into the frustum
|
||||||
|
// This fixes shadow dissapearing issues when
|
||||||
|
// the caster itself is not in the view camera
|
||||||
|
// but its shadow is in the camera
|
||||||
|
// The number is in world units
|
||||||
|
occBB.setZExtent(occBB.getZExtent() + 50);
|
||||||
|
occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25));
|
||||||
|
if (splitBB.intersects(occBB)) {
|
||||||
|
// To prevent extending the depth range too much
|
||||||
|
// We return the bound to its former shape
|
||||||
|
// Before adding it
|
||||||
|
occBB.setZExtent(occBB.getZExtent() - 50);
|
||||||
|
occBB.setCenter(occBB.getCenter().subtractLocal(0, 0, 25));
|
||||||
|
visOccList.add(occBox);
|
||||||
|
if (splitOccluders != null) {
|
||||||
|
splitOccluders.add(occluder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (intersects) {
|
||||||
|
visOccList.add(occBox);
|
||||||
|
if (splitOccluders != null) {
|
||||||
|
splitOccluders.add(occluder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundingBox casterBB = computeUnionBound(visOccList);
|
||||||
|
BoundingBox receiverBB = computeUnionBound(visRecvList);
|
||||||
|
|
||||||
|
//Nehon 08/18/2010 this is to avoid shadow bleeding when the ground is set to only receive shadows
|
||||||
|
if (visOccList.size() != visRecvList.size()) {
|
||||||
|
casterBB.setXExtent(casterBB.getXExtent() + 2.0f);
|
||||||
|
casterBB.setYExtent(casterBB.getYExtent() + 2.0f);
|
||||||
|
casterBB.setZExtent(casterBB.getZExtent() + 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector3f casterMin = casterBB.getMin(null);
|
||||||
|
Vector3f casterMax = casterBB.getMax(null);
|
||||||
|
|
||||||
|
Vector3f receiverMin = receiverBB.getMin(null);
|
||||||
|
Vector3f receiverMax = receiverBB.getMax(null);
|
||||||
|
|
||||||
|
Vector3f splitMin = splitBB.getMin(null);
|
||||||
|
Vector3f splitMax = splitBB.getMax(null);
|
||||||
|
|
||||||
|
splitMin.z = 0;
|
||||||
|
|
||||||
|
if (!ortho) {
|
||||||
|
shadowCam.setFrustumPerspective(45, 1, 1, splitMax.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
Matrix4f projMatrix = shadowCam.getProjectionMatrix();
|
||||||
|
|
||||||
|
Vector3f cropMin = new Vector3f();
|
||||||
|
Vector3f cropMax = new Vector3f();
|
||||||
|
|
||||||
|
// IMPORTANT: Special handling for Z values
|
||||||
|
cropMin.x = max(max(casterMin.x, receiverMin.x), splitMin.x);
|
||||||
|
cropMax.x = min(min(casterMax.x, receiverMax.x), splitMax.x);
|
||||||
|
|
||||||
|
cropMin.y = max(max(casterMin.y, receiverMin.y), splitMin.y);
|
||||||
|
cropMax.y = min(min(casterMax.y, receiverMax.y), splitMax.y);
|
||||||
|
|
||||||
|
cropMin.z = min(casterMin.z, splitMin.z);
|
||||||
|
cropMax.z = min(receiverMax.z, splitMax.z);
|
||||||
|
|
||||||
|
|
||||||
|
// Create the crop matrix.
|
||||||
|
float scaleX, scaleY, scaleZ;
|
||||||
|
float offsetX, offsetY, offsetZ;
|
||||||
|
|
||||||
|
scaleX = (2.0f) / (cropMax.x - cropMin.x);
|
||||||
|
scaleY = (2.0f) / (cropMax.y - cropMin.y);
|
||||||
|
|
||||||
|
offsetX = -0.5f * (cropMax.x + cropMin.x) * scaleX;
|
||||||
|
offsetY = -0.5f * (cropMax.y + cropMin.y) * scaleY;
|
||||||
|
|
||||||
|
scaleZ = 1.0f / (cropMax.z - cropMin.z);
|
||||||
|
offsetZ = -cropMin.z * scaleZ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Matrix4f cropMatrix = new Matrix4f(scaleX, 0f, 0f, offsetX,
|
||||||
|
0f, scaleY, 0f, offsetY,
|
||||||
|
0f, 0f, scaleZ, offsetZ,
|
||||||
|
0f, 0f, 0f, 1f);
|
||||||
|
|
||||||
|
|
||||||
|
Matrix4f result = new Matrix4f();
|
||||||
|
result.set(cropMatrix);
|
||||||
|
result.multLocal(projMatrix);
|
||||||
|
|
||||||
|
shadowCam.setProjectionMatrix(result);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
125
engine/src/core/com/jme3/water/ReflectionProcessor.java
Normal file
125
engine/src/core/com/jme3/water/ReflectionProcessor.java
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/*
|
||||||
|
* To change this template, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.jme3.water;
|
||||||
|
|
||||||
|
import com.jme3.math.Plane;
|
||||||
|
import com.jme3.post.SceneProcessor;
|
||||||
|
import com.jme3.renderer.Camera;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.renderer.queue.RenderQueue;
|
||||||
|
import com.jme3.texture.FrameBuffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reflection Processor
|
||||||
|
* Used to render the reflected scene in an off view port
|
||||||
|
*/
|
||||||
|
public class ReflectionProcessor implements SceneProcessor {
|
||||||
|
|
||||||
|
private RenderManager rm;
|
||||||
|
private ViewPort vp;
|
||||||
|
private Camera reflectionCam;
|
||||||
|
private FrameBuffer reflectionBuffer;
|
||||||
|
private Plane reflectionClipPlane;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ReflectionProcessor
|
||||||
|
* @param reflectionCam the cam to use for reflection
|
||||||
|
* @param reflectionBuffer the FrameBuffer to render to
|
||||||
|
* @param reflectionClipPlane the clipping plane
|
||||||
|
*/
|
||||||
|
public ReflectionProcessor(Camera reflectionCam, FrameBuffer reflectionBuffer, Plane reflectionClipPlane) {
|
||||||
|
this.reflectionCam = reflectionCam;
|
||||||
|
this.reflectionBuffer = reflectionBuffer;
|
||||||
|
this.reflectionClipPlane = reflectionClipPlane;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(RenderManager rm, ViewPort vp) {
|
||||||
|
this.rm = rm;
|
||||||
|
this.vp = vp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reshape(ViewPort vp, int w, int h) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInitialized() {
|
||||||
|
return rm != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void preFrame(float tpf) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postQueue(RenderQueue rq) {
|
||||||
|
//we need special treatement for the sky because it must not be clipped
|
||||||
|
rm.getRenderer().setFrameBuffer(reflectionBuffer);
|
||||||
|
reflectionCam.setProjectionMatrix(null);
|
||||||
|
rm.setCamera(reflectionCam, false);
|
||||||
|
rm.getRenderer().clearBuffers(true, true, true);
|
||||||
|
//Rendering the sky whithout clipping
|
||||||
|
rm.getRenderer().setDepthRange(1, 1);
|
||||||
|
vp.getQueue().renderQueue(RenderQueue.Bucket.Sky, rm, reflectionCam, true);
|
||||||
|
rm.getRenderer().setDepthRange(0, 1);
|
||||||
|
//setting the clip plane to the cam
|
||||||
|
reflectionCam.setClipPlane(reflectionClipPlane, Plane.Side.Positive);//,1
|
||||||
|
rm.setCamera(reflectionCam, false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postFrame(FrameBuffer out) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal use only<br>
|
||||||
|
* returns the frame buffer
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public FrameBuffer getReflectionBuffer() {
|
||||||
|
return reflectionBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal use only<br>
|
||||||
|
* sets the frame buffer
|
||||||
|
* @param reflectionBuffer
|
||||||
|
*/
|
||||||
|
public void setReflectionBuffer(FrameBuffer reflectionBuffer) {
|
||||||
|
this.reflectionBuffer = reflectionBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the reflection cam
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Camera getReflectionCam() {
|
||||||
|
return reflectionCam;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the reflection cam
|
||||||
|
* @param reflectionCam
|
||||||
|
*/
|
||||||
|
public void setReflectionCam(Camera reflectionCam) {
|
||||||
|
this.reflectionCam = reflectionCam;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the reflection clip plane
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Plane getReflectionClipPlane() {
|
||||||
|
return reflectionClipPlane;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reflection clip plane
|
||||||
|
* @param reflectionClipPlane
|
||||||
|
*/
|
||||||
|
public void setReflectionClipPlane(Plane reflectionClipPlane) {
|
||||||
|
this.reflectionClipPlane = reflectionClipPlane;
|
||||||
|
}
|
||||||
|
}
|
589
engine/src/core/com/jme3/water/SimpleWaterProcessor.java
Normal file
589
engine/src/core/com/jme3/water/SimpleWaterProcessor.java
Normal file
@ -0,0 +1,589 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2010 jMonkeyEngine
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* 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 'jMonkeyEngine' 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) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package com.jme3.water;
|
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager;
|
||||||
|
import com.jme3.material.Material;
|
||||||
|
import com.jme3.math.*;
|
||||||
|
import com.jme3.post.SceneProcessor;
|
||||||
|
import com.jme3.renderer.Camera;
|
||||||
|
import com.jme3.renderer.RenderManager;
|
||||||
|
import com.jme3.renderer.Renderer;
|
||||||
|
import com.jme3.renderer.ViewPort;
|
||||||
|
import com.jme3.renderer.queue.RenderQueue;
|
||||||
|
import com.jme3.scene.Geometry;
|
||||||
|
import com.jme3.scene.Spatial;
|
||||||
|
import com.jme3.scene.shape.Quad;
|
||||||
|
import com.jme3.texture.FrameBuffer;
|
||||||
|
import com.jme3.texture.Image.Format;
|
||||||
|
import com.jme3.texture.Texture.WrapMode;
|
||||||
|
import com.jme3.texture.Texture2D;
|
||||||
|
import com.jme3.ui.Picture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Simple Water renders a simple plane that use reflection and refraction to look like water.
|
||||||
|
* It's pretty basic, but much faster than the WaterFilter
|
||||||
|
* It's useful if you aim low specs hardware and still want a good looking water.
|
||||||
|
* Usage is :
|
||||||
|
* <code>
|
||||||
|
* SimpleWaterProcessor waterProcessor = new SimpleWaterProcessor(assetManager);
|
||||||
|
* //setting the scene to use for reflection
|
||||||
|
* waterProcessor.setReflectionScene(mainScene);
|
||||||
|
* //setting the light position
|
||||||
|
* waterProcessor.setLightPosition(lightPos);
|
||||||
|
*
|
||||||
|
* //setting the water plane
|
||||||
|
* Vector3f waterLocation=new Vector3f(0,-20,0);
|
||||||
|
* waterProcessor.setPlane(new Plane(Vector3f.UNIT_Y, waterLocation.dot(Vector3f.UNIT_Y)));
|
||||||
|
* //setting the water color
|
||||||
|
* waterProcessor.setWaterColor(ColorRGBA.Brown);
|
||||||
|
*
|
||||||
|
* //creating a quad to render water to
|
||||||
|
* Quad quad = new Quad(400,400);
|
||||||
|
*
|
||||||
|
* //the texture coordinates define the general size of the waves
|
||||||
|
* quad.scaleTextureCoordinates(new Vector2f(6f,6f));
|
||||||
|
*
|
||||||
|
* //creating a geom to attach the water material
|
||||||
|
* Geometry water=new Geometry("water", quad);
|
||||||
|
* water.setLocalTranslation(-200, -20, 250);
|
||||||
|
* water.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
|
||||||
|
* //finally setting the material
|
||||||
|
* water.setMaterial(waterProcessor.getMaterial());
|
||||||
|
*
|
||||||
|
* //attaching the water to the root node
|
||||||
|
* rootNode.attachChild(water);
|
||||||
|
* </code>
|
||||||
|
* @author Normen Hansen & Rémy Bouquet
|
||||||
|
*/
|
||||||
|
public class SimpleWaterProcessor implements SceneProcessor {
|
||||||
|
|
||||||
|
protected RenderManager rm;
|
||||||
|
protected ViewPort vp;
|
||||||
|
protected Spatial reflectionScene;
|
||||||
|
protected ViewPort reflectionView;
|
||||||
|
protected ViewPort refractionView;
|
||||||
|
protected FrameBuffer reflectionBuffer;
|
||||||
|
protected FrameBuffer refractionBuffer;
|
||||||
|
protected Camera reflectionCam;
|
||||||
|
protected Camera refractionCam;
|
||||||
|
protected Texture2D reflectionTexture;
|
||||||
|
protected Texture2D refractionTexture;
|
||||||
|
protected Texture2D depthTexture;
|
||||||
|
protected Texture2D normalTexture;
|
||||||
|
protected Texture2D dudvTexture;
|
||||||
|
protected int renderWidth = 512;
|
||||||
|
protected int renderHeight = 512;
|
||||||
|
protected Plane plane = new Plane(Vector3f.UNIT_Y, Vector3f.ZERO.dot(Vector3f.UNIT_Y));
|
||||||
|
protected float speed = 0.05f;
|
||||||
|
protected Ray ray = new Ray();
|
||||||
|
protected Vector3f targetLocation = new Vector3f();
|
||||||
|
protected AssetManager manager;
|
||||||
|
protected Material material;
|
||||||
|
protected float waterDepth = 1;
|
||||||
|
protected float waterTransparency = 0.4f;
|
||||||
|
protected boolean debug = false;
|
||||||
|
private Picture dispRefraction;
|
||||||
|
private Picture dispReflection;
|
||||||
|
private Picture dispDepth;
|
||||||
|
private Plane reflectionClipPlane;
|
||||||
|
private Plane refractionClipPlane;
|
||||||
|
private float refractionClippingOffset = 0.3f;
|
||||||
|
private float reflectionClippingOffset = -5f;
|
||||||
|
private Vector3f vect1 = new Vector3f();
|
||||||
|
private Vector3f vect2 = new Vector3f();
|
||||||
|
private Vector3f vect3 = new Vector3f();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a SimpleWaterProcessor
|
||||||
|
* @param manager the asset manager
|
||||||
|
*/
|
||||||
|
public SimpleWaterProcessor(AssetManager manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
material = new Material(manager, "Common/MatDefs/Water/SimpleWater.j3md");
|
||||||
|
material.setFloat("waterDepth", waterDepth);
|
||||||
|
material.setFloat("waterTransparency", waterTransparency / 10);
|
||||||
|
material.setColor("waterColor", ColorRGBA.White);
|
||||||
|
material.setVector3("lightPos", new Vector3f(1, -1, 1));
|
||||||
|
|
||||||
|
material.setColor("distortionScale", new ColorRGBA(0.2f, 0.2f, 0.2f, 0.2f));
|
||||||
|
material.setColor("distortionMix", new ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f));
|
||||||
|
material.setColor("texScale", new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
|
||||||
|
updateClipPlanes();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize(RenderManager rm, ViewPort vp) {
|
||||||
|
this.rm = rm;
|
||||||
|
this.vp = vp;
|
||||||
|
|
||||||
|
loadTextures(manager);
|
||||||
|
createTextures();
|
||||||
|
applyTextures(material);
|
||||||
|
|
||||||
|
createPreViews();
|
||||||
|
|
||||||
|
material.setVector2("FrustumNearFar", new Vector2f(vp.getCamera().getFrustumNear(), vp.getCamera().getFrustumFar()));
|
||||||
|
|
||||||
|
if (debug) {
|
||||||
|
dispRefraction = new Picture("dispRefraction");
|
||||||
|
dispRefraction.setTexture(manager, refractionTexture, false);
|
||||||
|
dispReflection = new Picture("dispRefraction");
|
||||||
|
dispReflection.setTexture(manager, reflectionTexture, false);
|
||||||
|
dispDepth = new Picture("depthTexture");
|
||||||
|
dispDepth.setTexture(manager, depthTexture, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reshape(ViewPort vp, int w, int h) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInitialized() {
|
||||||
|
return rm != null;
|
||||||
|
}
|
||||||
|
float time = 0;
|
||||||
|
float savedTpf = 0;
|
||||||
|
|
||||||
|
public void preFrame(float tpf) {
|
||||||
|
time = time + (tpf * speed);
|
||||||
|
if (time > 1f) {
|
||||||
|
time = 0;
|
||||||
|
}
|
||||||
|
material.setFloat("time", time);
|
||||||
|
savedTpf = tpf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postQueue(RenderQueue rq) {
|
||||||
|
Camera sceneCam = rm.getCurrentCamera();
|
||||||
|
|
||||||
|
//update ray
|
||||||
|
ray.setOrigin(sceneCam.getLocation());
|
||||||
|
ray.setDirection(sceneCam.getDirection());
|
||||||
|
|
||||||
|
//update refraction cam
|
||||||
|
refractionCam.setLocation(sceneCam.getLocation());
|
||||||
|
refractionCam.setRotation(sceneCam.getRotation());
|
||||||
|
refractionCam.setFrustum(sceneCam.getFrustumNear(),
|
||||||
|
sceneCam.getFrustumFar(),
|
||||||
|
sceneCam.getFrustumLeft(),
|
||||||
|
sceneCam.getFrustumRight(),
|
||||||
|
sceneCam.getFrustumTop(),
|
||||||
|
sceneCam.getFrustumBottom());
|
||||||
|
|
||||||
|
//update reflection cam
|
||||||
|
boolean inv = false;
|
||||||
|
if (!ray.intersectsWherePlane(plane, targetLocation)) {
|
||||||
|
ray.setDirection(ray.getDirection().negateLocal());
|
||||||
|
ray.intersectsWherePlane(plane, targetLocation);
|
||||||
|
inv = true;
|
||||||
|
}
|
||||||
|
Vector3f loc = plane.reflect(sceneCam.getLocation(), new Vector3f());
|
||||||
|
reflectionCam.setLocation(loc);
|
||||||
|
reflectionCam.setFrustum(sceneCam.getFrustumNear(),
|
||||||
|
sceneCam.getFrustumFar(),
|
||||||
|
sceneCam.getFrustumLeft(),
|
||||||
|
sceneCam.getFrustumRight(),
|
||||||
|
sceneCam.getFrustumTop(),
|
||||||
|
sceneCam.getFrustumBottom());
|
||||||
|
// tempVec and calcVect are just temporary vector3f objects
|
||||||
|
vect1.set(sceneCam.getLocation()).addLocal(sceneCam.getUp());
|
||||||
|
float planeDistance = plane.pseudoDistance(vect1);
|
||||||
|
vect2.set(plane.getNormal()).multLocal(planeDistance * 2.0f);
|
||||||
|
vect3.set(vect1.subtractLocal(vect2)).subtractLocal(loc).normalizeLocal().negateLocal();
|
||||||
|
// now set the up vector
|
||||||
|
reflectionCam.lookAt(targetLocation, vect3);
|
||||||
|
if (inv) {
|
||||||
|
reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Rendering reflection and refraction
|
||||||
|
rm.renderViewPort(reflectionView, savedTpf);
|
||||||
|
rm.renderViewPort(refractionView, savedTpf);
|
||||||
|
rm.getRenderer().setFrameBuffer(vp.getOutputFrameBuffer());
|
||||||
|
rm.setCamera(sceneCam, false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postFrame(FrameBuffer out) {
|
||||||
|
if (debug) {
|
||||||
|
displayMap(rm.getRenderer(), dispRefraction, 64);
|
||||||
|
displayMap(rm.getRenderer(), dispReflection, 256);
|
||||||
|
displayMap(rm.getRenderer(), dispDepth, 448);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//debug only : displays maps
|
||||||
|
protected void displayMap(Renderer r, Picture pic, int left) {
|
||||||
|
Camera cam = vp.getCamera();
|
||||||
|
rm.setCamera(cam, true);
|
||||||
|
int h = cam.getHeight();
|
||||||
|
|
||||||
|
pic.setPosition(left, h / 20f);
|
||||||
|
|
||||||
|
pic.setWidth(128);
|
||||||
|
pic.setHeight(128);
|
||||||
|
pic.updateGeometricState();
|
||||||
|
rm.renderGeometry(pic);
|
||||||
|
rm.setCamera(cam, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void loadTextures(AssetManager manager) {
|
||||||
|
normalTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/water_normalmap.dds");
|
||||||
|
dudvTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/dudv_map.jpg");
|
||||||
|
normalTexture.setWrap(WrapMode.Repeat);
|
||||||
|
dudvTexture.setWrap(WrapMode.Repeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createTextures() {
|
||||||
|
reflectionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
|
||||||
|
refractionTexture = new Texture2D(renderWidth, renderHeight, Format.RGBA8);
|
||||||
|
depthTexture = new Texture2D(renderWidth, renderHeight, Format.Depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void applyTextures(Material mat) {
|
||||||
|
mat.setTexture("water_reflection", reflectionTexture);
|
||||||
|
mat.setTexture("water_refraction", refractionTexture);
|
||||||
|
mat.setTexture("water_depthmap", depthTexture);
|
||||||
|
mat.setTexture("water_normalmap", normalTexture);
|
||||||
|
mat.setTexture("water_dudvmap", dudvTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createPreViews() {
|
||||||
|
reflectionCam = new Camera(renderWidth, renderHeight);
|
||||||
|
refractionCam = new Camera(renderWidth, renderHeight);
|
||||||
|
|
||||||
|
// create a pre-view. a view that is rendered before the main view
|
||||||
|
reflectionView = new ViewPort("Reflection View", reflectionCam);
|
||||||
|
reflectionView.setClearFlags(true, true, true);
|
||||||
|
reflectionView.setBackgroundColor(ColorRGBA.Black);
|
||||||
|
// create offscreen framebuffer
|
||||||
|
reflectionBuffer = new FrameBuffer(renderWidth, renderHeight, 1);
|
||||||
|
//setup framebuffer to use texture
|
||||||
|
reflectionBuffer.setDepthBuffer(Format.Depth);
|
||||||
|
reflectionBuffer.setColorTexture(reflectionTexture);
|
||||||
|
|
||||||
|
//set viewport to render to offscreen framebuffer
|
||||||
|
reflectionView.setOutputFrameBuffer(reflectionBuffer);
|
||||||
|
reflectionView.addProcessor(new ReflectionProcessor(reflectionCam, reflectionBuffer, reflectionClipPlane));
|
||||||
|
// attach the scene to the viewport to be rendered
|
||||||
|
reflectionView.attachScene(reflectionScene);
|
||||||
|
|
||||||
|
// create a pre-view. a view that is rendered before the main view
|
||||||
|
refractionView = new ViewPort("Refraction View", refractionCam);
|
||||||
|
refractionView.setClearFlags(true, true, true);
|
||||||
|
refractionView.setBackgroundColor(ColorRGBA.Black);
|
||||||
|
// create offscreen framebuffer
|
||||||
|
refractionBuffer = new FrameBuffer(renderWidth, renderHeight, 1);
|
||||||
|
//setup framebuffer to use texture
|
||||||
|
refractionBuffer.setDepthBuffer(Format.Depth);
|
||||||
|
refractionBuffer.setColorTexture(refractionTexture);
|
||||||
|
refractionBuffer.setDepthTexture(depthTexture);
|
||||||
|
//set viewport to render to offscreen framebuffer
|
||||||
|
refractionView.setOutputFrameBuffer(refractionBuffer);
|
||||||
|
refractionView.addProcessor(new RefractionProcessor());
|
||||||
|
// attach the scene to the viewport to be rendered
|
||||||
|
refractionView.attachScene(reflectionScene);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void destroyViews() {
|
||||||
|
// rm.removePreView(reflectionView);
|
||||||
|
rm.removePreView(refractionView);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the water material from this processor, apply this to your water quad.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Material getMaterial() {
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the reflected scene, should not include the water quad!
|
||||||
|
* Set before adding processor.
|
||||||
|
* @param spat
|
||||||
|
*/
|
||||||
|
public void setReflectionScene(Spatial spat) {
|
||||||
|
reflectionScene = spat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the width of the reflection and refraction textures
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getRenderWidth() {
|
||||||
|
return renderWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the height of the reflection and refraction textures
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int getRenderHeight() {
|
||||||
|
return renderHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the reflection Texture render size,
|
||||||
|
* set before adding the processor!
|
||||||
|
* @param with
|
||||||
|
* @param height
|
||||||
|
*/
|
||||||
|
public void setRenderSize(int width, int height) {
|
||||||
|
renderWidth = width;
|
||||||
|
renderHeight = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the water plane
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Plane getPlane() {
|
||||||
|
return plane;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the water plane for this processor.
|
||||||
|
* @param plane
|
||||||
|
*/
|
||||||
|
public void setPlane(Plane plane) {
|
||||||
|
this.plane.setConstant(plane.getConstant());
|
||||||
|
this.plane.setNormal(plane.getNormal());
|
||||||
|
updateClipPlanes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the water plane using an origin (location) and a normal (reflection direction).
|
||||||
|
* @param origin Set to 0,-6,0 if your water quad is at that location for correct reflection
|
||||||
|
* @param normal Set to 0,1,0 (Vector3f.UNIT_Y) for normal planar water
|
||||||
|
*/
|
||||||
|
public void setPlane(Vector3f origin, Vector3f normal) {
|
||||||
|
this.plane.setOriginNormal(origin, normal);
|
||||||
|
updateClipPlanes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateClipPlanes() {
|
||||||
|
reflectionClipPlane = plane.clone();
|
||||||
|
reflectionClipPlane.setConstant(reflectionClipPlane.getConstant() + reflectionClippingOffset);
|
||||||
|
refractionClipPlane = plane.clone();
|
||||||
|
refractionClipPlane.setConstant(refractionClipPlane.getConstant() + refractionClippingOffset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the light Position for the processor
|
||||||
|
* @param position
|
||||||
|
*/
|
||||||
|
//TODO maybe we should provide a convenient method to compute position from direction
|
||||||
|
public void setLightPosition(Vector3f position) {
|
||||||
|
material.setVector3("lightPos", position);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the color that will be added to the refraction texture.
|
||||||
|
* @param color
|
||||||
|
*/
|
||||||
|
public void setWaterColor(ColorRGBA color) {
|
||||||
|
material.setColor("waterColor", color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Higher values make the refraction texture shine through earlier.
|
||||||
|
* Default is 4
|
||||||
|
* @param depth
|
||||||
|
*/
|
||||||
|
public void setWaterDepth(float depth) {
|
||||||
|
waterDepth = depth;
|
||||||
|
material.setFloat("waterDepth", depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the water depth
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getWaterDepth() {
|
||||||
|
return waterDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns water transparency
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getWaterTransparency() {
|
||||||
|
return waterTransparency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the water transparency default os 0.1f
|
||||||
|
* @param waterTransparency
|
||||||
|
*/
|
||||||
|
public void setWaterTransparency(float waterTransparency) {
|
||||||
|
this.waterTransparency = Math.max(0, waterTransparency);
|
||||||
|
material.setFloat("waterTransparency", waterTransparency / 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the speed of the wave animation, default = 0.05f.
|
||||||
|
* @param speed
|
||||||
|
*/
|
||||||
|
public void setWaveSpeed(float speed) {
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scale of distortion by the normal map, default = 0.2
|
||||||
|
*/
|
||||||
|
public void setDistortionScale(float value) {
|
||||||
|
material.setColor("distortionScale", new ColorRGBA(value, value, value, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets how the normal and dudv map are mixed to create the wave effect, default = 0.5
|
||||||
|
*/
|
||||||
|
public void setDistortionMix(float value) {
|
||||||
|
material.setColor("distortionMix", new ColorRGBA(value, value, value, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the scale of the normal/dudv texture, default = 1.
|
||||||
|
* Note that the waves should be scaled by the texture coordinates of the quad to avoid animation artifacts,
|
||||||
|
* use mesh.scaleTextureCoordinates(Vector2f) for that.
|
||||||
|
*/
|
||||||
|
public void setTexScale(float value) {
|
||||||
|
material.setColor("texScale", new ColorRGBA(value, value, value, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* retruns true if the waterprocessor is in debug mode
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isDebug() {
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set to true to display reflection and refraction textures in the GUI for debug purpose
|
||||||
|
* @param debug
|
||||||
|
*/
|
||||||
|
public void setDebug(boolean debug) {
|
||||||
|
this.debug = debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a quad with the water material applied to it.
|
||||||
|
* @param width
|
||||||
|
* @param height
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Geometry createWaterGeometry(float width, float height) {
|
||||||
|
Quad quad = new Quad(width, height);
|
||||||
|
Geometry geom = new Geometry("WaterGeometry", quad);
|
||||||
|
geom.setLocalRotation(new Quaternion().fromAngleAxis(-FastMath.HALF_PI, Vector3f.UNIT_X));
|
||||||
|
geom.setMaterial(material);
|
||||||
|
return geom;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the reflection clipping plane offset
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getReflectionClippingOffset() {
|
||||||
|
return reflectionClippingOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the reflection clipping plane offset
|
||||||
|
* set a nagetive value to lower the clipping plane for relection texture rendering.
|
||||||
|
* @param reflectionClippingOffset
|
||||||
|
*/
|
||||||
|
public void setReflectionClippingOffset(float reflectionClippingOffset) {
|
||||||
|
this.reflectionClippingOffset = reflectionClippingOffset;
|
||||||
|
updateClipPlanes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the refraction clipping plane offset
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public float getRefractionClippingOffset() {
|
||||||
|
return refractionClippingOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the refraction clipping plane offset
|
||||||
|
* set a positive value to raise the clipping plane for refraction texture rendering
|
||||||
|
* @param refractionClippingOffset
|
||||||
|
*/
|
||||||
|
public void setRefractionClippingOffset(float refractionClippingOffset) {
|
||||||
|
this.refractionClippingOffset = refractionClippingOffset;
|
||||||
|
updateClipPlanes();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refraction Processor
|
||||||
|
*/
|
||||||
|
public class RefractionProcessor implements SceneProcessor {
|
||||||
|
|
||||||
|
RenderManager rm;
|
||||||
|
ViewPort vp;
|
||||||
|
|
||||||
|
public void initialize(RenderManager rm, ViewPort vp) {
|
||||||
|
this.rm = rm;
|
||||||
|
this.vp = vp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reshape(ViewPort vp, int w, int h) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInitialized() {
|
||||||
|
return rm != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void preFrame(float tpf) {
|
||||||
|
refractionCam.setClipPlane(refractionClipPlane, Plane.Side.Negative);//,-1
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postQueue(RenderQueue rq) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void postFrame(FrameBuffer out) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1050
engine/src/core/com/jme3/water/WaterFilter.java
Normal file
1050
engine/src/core/com/jme3/water/WaterFilter.java
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user