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