experimental
parent
97ff9c2949
commit
3838216207
@ -0,0 +1,125 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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.RenderManager; |
||||
import com.jme3.renderer.ViewPort; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* Tone-mapping filter that uses filmic curve. |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public class ToneMapFilter extends Filter { |
||||
|
||||
private static final Vector3f DEFAULT_WHITEPOINT = new Vector3f(11.2f, 11.2f, 11.2f); |
||||
|
||||
private Vector3f whitePoint = DEFAULT_WHITEPOINT.clone(); |
||||
|
||||
/** |
||||
* Creates a tone-mapping filter with the default white-point of 11.2. |
||||
*/ |
||||
public ToneMapFilter() { |
||||
super("ToneMapFilter"); |
||||
} |
||||
|
||||
/** |
||||
* Creates a tone-mapping filter with the specified white-point. |
||||
* |
||||
* @param whitePoint The intensity of the brightest part of the scene. |
||||
*/ |
||||
public ToneMapFilter(Vector3f whitePoint) { |
||||
this(); |
||||
this.whitePoint = whitePoint.clone(); |
||||
} |
||||
|
||||
@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/ToneMap.j3md"); |
||||
material.setVector3("WhitePoint", whitePoint); |
||||
} |
||||
|
||||
@Override |
||||
protected Material getMaterial() { |
||||
return material; |
||||
} |
||||
|
||||
/** |
||||
* Set the scene white point. |
||||
* |
||||
* @param whitePoint The intensity of the brightest part of the scene. |
||||
*/ |
||||
public void setWhitePoint(Vector3f whitePoint) { |
||||
if (material != null) { |
||||
material.setVector3("WhitePoint", whitePoint); |
||||
} |
||||
this.whitePoint = whitePoint; |
||||
} |
||||
|
||||
/** |
||||
* Get the scene white point. |
||||
* |
||||
* @return The intensity of the brightest part of the scene. |
||||
*/ |
||||
public Vector3f getWhitePoint() { |
||||
return whitePoint; |
||||
} |
||||
|
||||
@Override |
||||
public void write(JmeExporter ex) throws IOException { |
||||
super.write(ex); |
||||
OutputCapsule oc = ex.getCapsule(this); |
||||
oc.write(whitePoint, "whitePoint", DEFAULT_WHITEPOINT.clone()); |
||||
} |
||||
|
||||
@Override |
||||
public void read(JmeImporter im) throws IOException { |
||||
super.read(im); |
||||
InputCapsule ic = im.getCapsule(this); |
||||
whitePoint = (Vector3f) ic.readSavable("whitePoint", DEFAULT_WHITEPOINT.clone()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,38 @@ |
||||
#import "Common/ShaderLib/MultiSample.glsllib" |
||||
|
||||
uniform COLORTEXTURE m_Texture; |
||||
uniform vec3 m_WhitePoint; |
||||
|
||||
#if __VERSION__ >= 150 |
||||
in vec2 texCoord; |
||||
#else |
||||
varying vec2 texCoord; |
||||
#endif |
||||
|
||||
vec3 FilmicCurve(in vec3 x) |
||||
{ |
||||
const float A = 0.22; |
||||
const float B = 0.30; |
||||
const float C = 0.10; |
||||
const float D = 0.20; |
||||
const float E = 0.01; |
||||
const float F = 0.30; |
||||
|
||||
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F; |
||||
} |
||||
|
||||
// whitePoint should be 11.2 |
||||
|
||||
vec3 ToneMap_Filmic(vec3 color, vec3 whitePoint) |
||||
{ |
||||
return FilmicCurve(color) / FilmicCurve(whitePoint); |
||||
} |
||||
|
||||
void main() { |
||||
// TODO: This is incorrect if multi-sampling is used. |
||||
// The tone-mapping should be performed for each sample independently. |
||||
|
||||
vec4 texVal = getColor(m_Texture, texCoord); |
||||
vec3 toneMapped = ToneMap_Filmic(texVal.rgb, m_WhitePoint); |
||||
gl_FragColor = vec4(toneMapped, texVal.a); |
||||
} |
@ -0,0 +1,31 @@ |
||||
MaterialDef Default GUI { |
||||
|
||||
MaterialParameters { |
||||
Int NumSamples |
||||
Int NumSamplesDepth |
||||
Texture2D Texture |
||||
Vector3 WhitePoint |
||||
} |
||||
|
||||
Technique { |
||||
VertexShader GLSL150: Common/MatDefs/Post/Post15.vert |
||||
FragmentShader GLSL150: Common/MatDefs/Post/ToneMap.frag |
||||
|
||||
WorldParameters { |
||||
} |
||||
|
||||
Defines { |
||||
RESOLVE_MS : NumSamples |
||||
} |
||||
|
||||
} |
||||
|
||||
Technique { |
||||
VertexShader GLSL100: Common/MatDefs/Post/Post.vert |
||||
FragmentShader GLSL100: Common/MatDefs/Post/ToneMap.frag |
||||
|
||||
WorldParameters { |
||||
} |
||||
|
||||
} |
||||
} |
@ -0,0 +1,141 @@ |
||||
/* |
||||
* Copyright (c) 2009-2012 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 jme3test.post; |
||||
|
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.controls.ActionListener; |
||||
import com.jme3.input.controls.AnalogListener; |
||||
import com.jme3.input.controls.KeyTrigger; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.post.FilterPostProcessor; |
||||
import com.jme3.post.HDRRenderer; |
||||
import com.jme3.post.filters.ColorOverlayFilter; |
||||
import com.jme3.post.filters.RadialBlurFilter; |
||||
import com.jme3.post.filters.ToneMapFilter; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.shape.Box; |
||||
import com.jme3.system.AppSettings; |
||||
import com.jme3.ui.Picture; |
||||
|
||||
public class TestToneMapFilter extends SimpleApplication { |
||||
|
||||
private boolean enabled = true; |
||||
private FilterPostProcessor fpp; |
||||
private ToneMapFilter toneMapFilter; |
||||
|
||||
public static void main(String[] args){ |
||||
TestToneMapFilter app = new TestToneMapFilter(); |
||||
AppSettings settings = new AppSettings(true); |
||||
|
||||
// Must turn on gamma correction, as otherwise it looks too dark.
|
||||
settings.setGammaCorrection(true); |
||||
|
||||
app.setSettings(settings); |
||||
app.start(); |
||||
} |
||||
|
||||
public Geometry createHDRBox(){ |
||||
Box boxMesh = new Box(1, 1, 1); |
||||
Geometry box = new Geometry("Box", boxMesh); |
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.setTexture("ColorMap", assetManager.loadTexture("Textures/HdrTest/Memorial.hdr")); |
||||
box.setMaterial(mat); |
||||
return box; |
||||
} |
||||
|
||||
@Override |
||||
public void simpleInitApp() { |
||||
fpp = new FilterPostProcessor(assetManager); |
||||
toneMapFilter = new ToneMapFilter(); |
||||
fpp.addFilter(toneMapFilter); |
||||
viewPort.addProcessor(fpp); |
||||
|
||||
rootNode.attachChild(createHDRBox()); |
||||
|
||||
cam.setLocation(new Vector3f(0f,0f,3f)); |
||||
|
||||
initInputs(); |
||||
} |
||||
|
||||
private void initInputs() { |
||||
inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); |
||||
inputManager.addMapping("WhitePointUp", new KeyTrigger(KeyInput.KEY_Y)); |
||||
inputManager.addMapping("WhitePointDown", new KeyTrigger(KeyInput.KEY_H)); |
||||
|
||||
ActionListener acl = new ActionListener() { |
||||
|
||||
public void onAction(String name, boolean keyPressed, float tpf) { |
||||
if (name.equals("toggle") && keyPressed) { |
||||
if (enabled) { |
||||
enabled = false; |
||||
viewPort.removeProcessor(fpp); |
||||
} else { |
||||
enabled = true; |
||||
viewPort.addProcessor(fpp); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
AnalogListener anl = new AnalogListener() { |
||||
|
||||
public void onAnalog(String name, float isPressed, float tpf) { |
||||
float wp = toneMapFilter.getWhitePoint().x; |
||||
|
||||
if (name.equals("WhitePointUp")) { |
||||
wp += tpf * 1.0; |
||||
if (wp > 12f) { |
||||
wp = 12f; |
||||
} |
||||
toneMapFilter.setWhitePoint(new Vector3f(wp, wp, wp)); |
||||
System.out.println("White point: " + wp); |
||||
} |
||||
|
||||
if (name.equals("WhitePointDown")) { |
||||
wp -= tpf * 1.0; |
||||
if (wp < 0.01f) { |
||||
wp = 0.01f; |
||||
} |
||||
toneMapFilter.setWhitePoint(new Vector3f(wp, wp, wp)); |
||||
System.out.println("White point: " + wp); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
inputManager.addListener(acl, "toggle"); |
||||
inputManager.addListener(anl, "WhitePointUp", "WhitePointDown"); |
||||
} |
||||
} |
Loading…
Reference in new issue