- Introduced a new Light type : LightProbes that are lights holding Image based Lighting information that are sent to the shader. For now, only the closest LightProbe from a geometry is sent to the shader. This will be enhanced later as it's obviously not the best way to handle this. - Added a LightProbeFactory for easy creation and rendering of LightPorbes and associated maps. The maps generation process can also be monitored through a Listener class. - Added various utility classses for debuging purpose. - Added a new test case for environment with multiple LightProbes. - Adapted the previous test case to the new system.define_list_fix
parent
7b7c6951ad
commit
a35b499ee7
@ -0,0 +1,246 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.environment; |
||||
|
||||
import com.jme3.light.LightProbe; |
||||
import com.jme3.environment.generation.JobProgressListener; |
||||
import com.jme3.environment.generation.PrefilteredEnvMapFaceGenerator; |
||||
import com.jme3.environment.generation.IrradianceMapGenerator; |
||||
import com.jme3.environment.util.EnvMapUtils; |
||||
import com.jme3.environment.generation.JobProgressAdapter; |
||||
import com.jme3.app.Application; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.Spatial; |
||||
import com.jme3.texture.TextureCubeMap; |
||||
import java.util.concurrent.ScheduledThreadPoolExecutor; |
||||
|
||||
/** |
||||
* This Factory allows to create LightProbes within a scene given an EnvironmentCamera. |
||||
* |
||||
* Since the process can be long, you can provide a JobProgressListener that |
||||
* will be notified of the ongoing generation process when calling the makeProbe method. |
||||
* |
||||
* The process is the folowing : |
||||
* 1. Create an EnvironmentCamera |
||||
* 2. give it a position in the scene |
||||
* 3. call {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)} |
||||
* 4. add the created LightProbe to a node with the {@link Node#addLight(com.jme3.light.Light) } method. |
||||
* |
||||
* Optionally for step 3 call {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node, com.jme3.environment.generation.JobProgressListener) } |
||||
* with a {@link JobProgressListener} to be notified of the progress of the generation process. |
||||
* |
||||
* The generation will be split in several threads for faster generation. |
||||
* |
||||
* This class is entirely thread safe and can be called from any thread. |
||||
* |
||||
* Note that in case you are using a {@link JobProgressListener} all the its |
||||
* method will be called inside and app.enqueu callable. |
||||
* This means that it's completely safe to modify the scenegraph within the |
||||
* Listener method, but also means that the even will be delayed until next update loop. |
||||
* |
||||
* @see EnvironmentCamera |
||||
* @author bouquet |
||||
*/ |
||||
public class LightProbeFactory { |
||||
|
||||
/** |
||||
* Creates a LightProbe with the giver EnvironmentCamera in the given scene. |
||||
* |
||||
* Note that this is an assynchronous process that will run on multiple threads. |
||||
* The process is thread safe. |
||||
* The created lightProbe will only be marked as ready when the rendering process is done. |
||||
* |
||||
* If you want to monitor the process use {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node, com.jme3.environment.generation.JobProgressListener) } |
||||
* |
||||
* |
||||
* |
||||
* @see LightProbe |
||||
* @see EnvironmentCamera |
||||
* @param envCam the EnvironmentCamera |
||||
* @param scene the Scene |
||||
* @return the created LightProbe |
||||
*/ |
||||
public static LightProbe makeProbe(final EnvironmentCamera envCam, Spatial scene) { |
||||
return makeProbe(envCam, scene, null); |
||||
} |
||||
|
||||
/** |
||||
* Creates a LightProbe with the giver EnvironmentCamera in the given scene. |
||||
* |
||||
* Note that this is an assynchronous process that will run on multiple threads. |
||||
* The process is thread safe. |
||||
* The created lightProbe will only be marked as ready when the rendering process is done. |
||||
* |
||||
* The JobProgressListener will be notified of the progress of the generation. |
||||
* Note that you can also use a {@link JobProgressAdapter}. |
||||
* |
||||
* @see LightProbe |
||||
* @see EnvironmentCamera |
||||
* @see JobProgressListener |
||||
|
||||
* @param envCam the EnvironmentCamera |
||||
* @param scene the Scene |
||||
* @param listener the listener of the genration progress. |
||||
* @return the created LightProbe |
||||
*/ |
||||
public static LightProbe makeProbe(final EnvironmentCamera envCam, Spatial scene, final JobProgressListener<LightProbe> listener) { |
||||
final LightProbe probe = new LightProbe(); |
||||
probe.setPosition(envCam.getPosition()); |
||||
probe.setIrradianceMap(EnvMapUtils.createIrradianceMap(envCam.getSize(), envCam.getImageFormat())); |
||||
probe.setPrefilteredMap(EnvMapUtils.createPrefilteredEnvMap(envCam.getSize(), envCam.getImageFormat())); |
||||
envCam.snapshot(scene, new JobProgressAdapter<TextureCubeMap>() { |
||||
|
||||
@Override |
||||
public void done(TextureCubeMap map) { |
||||
generatePbrMaps(map, probe, envCam.getApplication(), listener); |
||||
} |
||||
}); |
||||
return probe; |
||||
} |
||||
|
||||
/** |
||||
* Internally called to generate the maps. |
||||
* This method will spawn 7 thread (one for the IrradianceMap, and one for each face of the prefiltered env map). |
||||
* Those threads will be executed in a ScheduledThreadPoolExecutor that will be shutdown when the genration is done. |
||||
* |
||||
* @param envMap the raw env map rendered by the env camera |
||||
* @param probe the LigthProbe to generate maps for |
||||
* @param app the Application |
||||
* @param listener a progress listener. (can be null if no progress reporting is needed) |
||||
*/ |
||||
private static void generatePbrMaps(TextureCubeMap envMap, final LightProbe probe, Application app, final JobProgressListener<LightProbe> listener) { |
||||
IrradianceMapGenerator irrMapGenerator; |
||||
PrefilteredEnvMapFaceGenerator[] pemGenerators = new PrefilteredEnvMapFaceGenerator[6]; |
||||
|
||||
final JobState jobState = new JobState(new ScheduledThreadPoolExecutor(7)); |
||||
|
||||
irrMapGenerator = new IrradianceMapGenerator(app, new JobListener(listener, jobState, probe, 6)); |
||||
int size = envMap.getImage().getWidth(); |
||||
irrMapGenerator.setGenerationParam(EnvMapUtils.duplicateCubeMap(envMap), size, EnvMapUtils.FixSeamsMethod.Wrap, probe.getIrradianceMap()); |
||||
|
||||
jobState.executor.execute(irrMapGenerator); |
||||
|
||||
for (int i = 0; i < pemGenerators.length; i++) { |
||||
pemGenerators[i] = new PrefilteredEnvMapFaceGenerator(app, i, new JobListener(listener, jobState, probe, i)); |
||||
pemGenerators[i].setGenerationParam(EnvMapUtils.duplicateCubeMap(envMap), size, EnvMapUtils.FixSeamsMethod.Wrap, probe.getPrefilteredEnvMap()); |
||||
jobState.executor.execute(pemGenerators[i]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* An inner class to keep the state of a generation process |
||||
*/ |
||||
private static class JobState { |
||||
|
||||
double progress[] = new double[7]; |
||||
boolean done[] = new boolean[7]; |
||||
ScheduledThreadPoolExecutor executor; |
||||
boolean started = false; |
||||
|
||||
public JobState(ScheduledThreadPoolExecutor executor) { |
||||
this.executor = executor; |
||||
} |
||||
|
||||
boolean isDone() { |
||||
for (boolean d : done) { |
||||
if (d == false) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
float getProgress() { |
||||
float mean = 0; |
||||
for (double progres : progress) { |
||||
mean += progres; |
||||
} |
||||
return mean / 7f; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* An inner JobProgressListener to controll the genration process and properly clean up when it's done |
||||
*/ |
||||
private static class JobListener extends JobProgressAdapter<Integer> { |
||||
|
||||
JobProgressListener<LightProbe> globalListener; |
||||
JobState jobState; |
||||
LightProbe probe; |
||||
|
||||
int index; |
||||
|
||||
public JobListener(JobProgressListener<LightProbe> globalListener, JobState jobState, LightProbe probe, int index) { |
||||
this.globalListener = globalListener; |
||||
this.jobState = jobState; |
||||
this.probe = probe; |
||||
this.index = index; |
||||
} |
||||
|
||||
@Override |
||||
public void start() { |
||||
if (globalListener != null && !jobState.started) { |
||||
jobState.started = true; |
||||
globalListener.start(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void progress(double value) { |
||||
jobState.progress[index] = value; |
||||
if (globalListener != null) { |
||||
globalListener.progress(jobState.getProgress()); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void done(Integer result) { |
||||
if (globalListener != null) { |
||||
if (result < 6) { |
||||
globalListener.step("Prefiltered env map face " + result + " generated"); |
||||
} else { |
||||
globalListener.step("Irradiance map generated"); |
||||
|
||||
} |
||||
} |
||||
|
||||
jobState.done[index] = true; |
||||
if (jobState.isDone()) { |
||||
probe.setReady(true); |
||||
if (globalListener != null) { |
||||
globalListener.done(probe); |
||||
} |
||||
jobState.executor.shutdownNow(); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,59 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.environment.generation; |
||||
|
||||
/** |
||||
* Abstract Adapter class that implements optional methods of JobProgressListener. |
||||
* Extends this class instead of implementing a JobProgressListener if you need |
||||
* only a subset of method implemented. |
||||
* |
||||
* @author nehon |
||||
* @param <T> |
||||
*/ |
||||
public abstract class JobProgressAdapter<T> implements JobProgressListener<T>{ |
||||
|
||||
@Override |
||||
public void progress(double value) { |
||||
} |
||||
|
||||
@Override |
||||
public void start() { |
||||
} |
||||
|
||||
@Override |
||||
public void step(String message) { |
||||
} |
||||
|
||||
@Override |
||||
public abstract void done(T result); |
||||
|
||||
} |
@ -0,0 +1,67 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.environment.generation; |
||||
|
||||
/** |
||||
* An interface listener that will be notified of the progress of an asynchronous |
||||
* generation job. |
||||
* |
||||
* |
||||
* @author nehon |
||||
* @param <T> The type of object generated. |
||||
*/ |
||||
public interface JobProgressListener<T> { |
||||
|
||||
/** |
||||
* Called when the process starts. |
||||
*/ |
||||
public void start(); |
||||
|
||||
/** |
||||
* Can be called when a step of the process has been completed with a relevant message. |
||||
* @param message the message stating of the paricular step completion. |
||||
*/ |
||||
public void step(String message); |
||||
|
||||
/** |
||||
* Called when the process has made some progress. |
||||
* @param value a value from 0 to 1 representing the percentage of completion of the process. |
||||
*/ |
||||
public void progress(double value); |
||||
|
||||
/** |
||||
* Called when the process is done. |
||||
* @param result the object generated by the process. |
||||
*/ |
||||
public void done(T result); |
||||
|
||||
} |
@ -0,0 +1,177 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.environment.util; |
||||
|
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.FastMath; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Mesh; |
||||
import com.jme3.scene.VertexBuffer.Type; |
||||
import com.jme3.util.BufferUtils; |
||||
import java.nio.FloatBuffer; |
||||
import java.nio.ShortBuffer; |
||||
|
||||
/** |
||||
* |
||||
* A debuging shape for a BoundingSphere |
||||
* Consists of 3 axis aligned circles. |
||||
* |
||||
* @author nehon |
||||
*/ |
||||
public class BoundingSphereDebug extends Mesh { |
||||
|
||||
protected int vertCount; |
||||
protected int triCount; |
||||
protected int radialSamples = 32; |
||||
protected boolean useEvenSlices; |
||||
protected boolean interior; |
||||
/** |
||||
* the distance from the center point each point falls on |
||||
*/ |
||||
public float radius; |
||||
|
||||
public float getRadius() { |
||||
return radius; |
||||
} |
||||
|
||||
public BoundingSphereDebug() { |
||||
setGeometryData(); |
||||
setIndexData(); |
||||
} |
||||
|
||||
/** |
||||
* builds the vertices based on the radius |
||||
*/ |
||||
private void setGeometryData() { |
||||
setMode(Mode.Lines); |
||||
|
||||
FloatBuffer posBuf = BufferUtils.createVector3Buffer((radialSamples + 1) * 3); |
||||
FloatBuffer colBuf = BufferUtils.createVector3Buffer((radialSamples + 1) * 4); |
||||
|
||||
setBuffer(Type.Position, 3, posBuf); |
||||
setBuffer(Type.Color, 4, colBuf); |
||||
|
||||
// generate geometry
|
||||
float fInvRS = 1.0f / radialSamples; |
||||
|
||||
// Generate points on the unit circle to be used in computing the mesh
|
||||
// points on a sphere slice.
|
||||
float[] afSin = new float[(radialSamples + 1)]; |
||||
float[] afCos = new float[(radialSamples + 1)]; |
||||
for (int iR = 0; iR < radialSamples; iR++) { |
||||
float fAngle = FastMath.TWO_PI * fInvRS * iR; |
||||
afCos[iR] = FastMath.cos(fAngle); |
||||
afSin[iR] = FastMath.sin(fAngle); |
||||
} |
||||
afSin[radialSamples] = afSin[0]; |
||||
afCos[radialSamples] = afCos[0]; |
||||
|
||||
for (int iR = 0; iR <= radialSamples; iR++) { |
||||
posBuf.put(afCos[iR]) |
||||
.put(afSin[iR]) |
||||
.put(0); |
||||
colBuf.put(ColorRGBA.Blue.r) |
||||
.put(ColorRGBA.Blue.g) |
||||
.put(ColorRGBA.Blue.b) |
||||
.put(ColorRGBA.Blue.a); |
||||
|
||||
} |
||||
for (int iR = 0; iR <= radialSamples; iR++) { |
||||
posBuf.put(afCos[iR]) |
||||
.put(0) |
||||
.put(afSin[iR]); |
||||
colBuf.put(ColorRGBA.Green.r) |
||||
.put(ColorRGBA.Green.g) |
||||
.put(ColorRGBA.Green.b) |
||||
.put(ColorRGBA.Green.a); |
||||
} |
||||
for (int iR = 0; iR <= radialSamples; iR++) { |
||||
posBuf.put(0) |
||||
.put(afCos[iR]) |
||||
.put(afSin[iR]); |
||||
colBuf.put(ColorRGBA.Yellow.r) |
||||
.put(ColorRGBA.Yellow.g) |
||||
.put(ColorRGBA.Yellow.b) |
||||
.put(ColorRGBA.Yellow.a); |
||||
} |
||||
|
||||
updateBound(); |
||||
setStatic(); |
||||
} |
||||
|
||||
/** |
||||
* sets the indices for rendering the sphere. |
||||
*/ |
||||
private void setIndexData() { |
||||
|
||||
// allocate connectivity
|
||||
int nbSegments = (radialSamples) * 3; |
||||
|
||||
ShortBuffer idxBuf = BufferUtils.createShortBuffer(2 * nbSegments); |
||||
setBuffer(Type.Index, 2, idxBuf); |
||||
|
||||
int idx = 0; |
||||
int segDone = 0; |
||||
while (segDone < nbSegments) { |
||||
idxBuf.put((short) idx); |
||||
idxBuf.put((short) (idx + 1)); |
||||
idx++; |
||||
segDone++; |
||||
if (segDone == radialSamples || segDone == radialSamples * 2) { |
||||
idx++; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* Convenience factory method that creates a debuging bounding sphere geometry |
||||
* @param assetManager the assetManager |
||||
* @return the bounding sphere debug geometry. |
||||
*/ |
||||
public static Geometry createDebugSphere(AssetManager assetManager) { |
||||
BoundingSphereDebug b = new BoundingSphereDebug(); |
||||
Geometry geom = new Geometry("BoundingDebug", b); |
||||
|
||||
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
mat.setBoolean("VertexColor", true); |
||||
mat.getAdditionalRenderState().setWireframe(true); |
||||
|
||||
geom.setMaterial(mat); |
||||
return geom; |
||||
|
||||
} |
||||
} |
@ -0,0 +1,214 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.environment.util; |
||||
|
||||
import com.jme3.app.Application; |
||||
import com.jme3.app.state.BaseAppState; |
||||
import com.jme3.bounding.BoundingSphere; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.light.LightProbe; |
||||
import com.jme3.light.Light; |
||||
import com.jme3.renderer.RenderManager; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.Spatial; |
||||
import com.jme3.scene.shape.Sphere; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* A debug state that will display LIght gizmos on screen. |
||||
* Still a wip and for now it only displays light probes. |
||||
* |
||||
* @author nehon |
||||
*/ |
||||
public class LightsDebugState extends BaseAppState { |
||||
|
||||
private Node debugNode; |
||||
private final Map<LightProbe, Node> probeMapping = new HashMap<LightProbe, Node>(); |
||||
private final List<LightProbe> garbage = new ArrayList<LightProbe>(); |
||||
private Geometry debugGeom; |
||||
private Geometry debugBounds; |
||||
private Material debugMaterial; |
||||
private DebugMode debugMode = DebugMode.PrefilteredEnvMap; |
||||
private float probeScale = 1.0f; |
||||
private Spatial scene = null; |
||||
private final List<LightProbe> probes = new ArrayList<LightProbe>(); |
||||
|
||||
/** |
||||
* Debug mode for light probes |
||||
*/ |
||||
public enum DebugMode { |
||||
|
||||
/** |
||||
* Displays the prefiltered env maps on the debug sphere |
||||
*/ |
||||
PrefilteredEnvMap, |
||||
/** |
||||
* displays the Irradiance map on the debug sphere |
||||
*/ |
||||
IrradianceMap |
||||
} |
||||
|
||||
@Override |
||||
protected void initialize(Application app) { |
||||
debugNode = new Node("Environment debug Node"); |
||||
Sphere s = new Sphere(16, 16, 1); |
||||
debugGeom = new Geometry("debugEnvProbe", s); |
||||
debugMaterial = new Material(app.getAssetManager(), "Common/MatDefs/Misc/reflect.j3md"); |
||||
debugGeom.setMaterial(debugMaterial); |
||||
debugBounds = BoundingSphereDebug.createDebugSphere(app.getAssetManager()); |
||||
if (scene == null) { |
||||
scene = app.getViewPort().getScenes().get(0); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void update(float tpf) { |
||||
for (Light light : scene.getWorldLightList()) { |
||||
switch (light.getType()) { |
||||
|
||||
case Probe: |
||||
LightProbe probe = (LightProbe) light; |
||||
probes.add(probe); |
||||
Node n = probeMapping.get(probe); |
||||
if (n == null) { |
||||
n = new Node("DebugProbe"); |
||||
n.attachChild(debugGeom.clone(true)); |
||||
n.attachChild(debugBounds.clone(false)); |
||||
debugNode.attachChild(n); |
||||
probeMapping.put(probe, n); |
||||
} |
||||
Geometry probeGeom = ((Geometry) n.getChild(0)); |
||||
Material m = probeGeom.getMaterial(); |
||||
probeGeom.setLocalScale(probeScale); |
||||
if (probe.isReady()) { |
||||
if (debugMode == DebugMode.IrradianceMap) { |
||||
m.setTexture("CubeMap", probe.getIrradianceMap()); |
||||
} else { |
||||
m.setTexture("CubeMap", probe.getPrefilteredEnvMap()); |
||||
} |
||||
} |
||||
n.setLocalTranslation(probe.getPosition()); |
||||
n.getChild(1).setLocalScale(((BoundingSphere) probe.getBounds()).getRadius()); |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
debugNode.updateLogicalState(tpf); |
||||
debugNode.updateGeometricState(); |
||||
cleanProbes(); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Set the scenes for wich to render light gizmos. |
||||
* @param scene |
||||
*/ |
||||
public void setScene(Spatial scene) { |
||||
this.scene = scene; |
||||
} |
||||
|
||||
private void cleanProbes() { |
||||
if (probes.size() != probeMapping.size()) { |
||||
for (LightProbe probe : probeMapping.keySet()) { |
||||
if (!probes.contains(probe)) { |
||||
garbage.add(probe); |
||||
} |
||||
} |
||||
for (LightProbe probe : garbage) { |
||||
probeMapping.remove(probe); |
||||
} |
||||
garbage.clear(); |
||||
probes.clear(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void render(RenderManager rm) { |
||||
rm.renderScene(debugNode, getApplication().getViewPort()); |
||||
} |
||||
|
||||
/** |
||||
* |
||||
* @see DebugMode |
||||
* @return the debug mode |
||||
*/ |
||||
public DebugMode getDebugMode() { |
||||
return debugMode; |
||||
} |
||||
|
||||
/** |
||||
* sets the debug mode |
||||
* @see DebugMode |
||||
* @param debugMode the debug mode |
||||
*/ |
||||
public void setDebugMode(DebugMode debugMode) { |
||||
this.debugMode = debugMode; |
||||
|
||||
} |
||||
|
||||
/** |
||||
* returns the scale of the probe's debug sphere |
||||
* @return |
||||
*/ |
||||
public float getProbeScale() { |
||||
return probeScale; |
||||
} |
||||
|
||||
/** |
||||
* sets the scale of the probe's debug sphere |
||||
* @param probeScale |
||||
*/ |
||||
public void setProbeScale(float probeScale) { |
||||
this.probeScale = probeScale; |
||||
} |
||||
|
||||
@Override |
||||
protected void cleanup(Application app) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
protected void onEnable() { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
protected void onDisable() { |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,251 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.light; |
||||
|
||||
import com.jme3.asset.AssetManager; |
||||
import com.jme3.bounding.BoundingBox; |
||||
import com.jme3.bounding.BoundingSphere; |
||||
import com.jme3.bounding.BoundingVolume; |
||||
import com.jme3.environment.EnvironmentCamera; |
||||
import com.jme3.environment.LightProbeFactory; |
||||
import com.jme3.environment.util.EnvMapUtils; |
||||
import com.jme3.export.InputCapsule; |
||||
import com.jme3.export.JmeExporter; |
||||
import com.jme3.export.JmeImporter; |
||||
import com.jme3.export.OutputCapsule; |
||||
import com.jme3.export.Savable; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.renderer.Camera; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.scene.Spatial; |
||||
import com.jme3.texture.TextureCubeMap; |
||||
import com.jme3.util.TempVars; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* A LightProbe is not exactly a light. It holds environment map information used for Image Based Lighting. |
||||
* This is used for indirect lighting in the Physically Based Rendering pipeline. |
||||
* |
||||
* A light probe has a position in world space. This is the position from where the Environment Map are rendered. |
||||
* There are two environment maps held by the LightProbe : |
||||
* - The irradiance map (used for indirect diffuse lighting in the PBR pipeline). |
||||
* - The prefiltered environment map (used for indirect specular lighting and reflection in the PBE pipeline). |
||||
* Note that when instanciating the LightProbe, both those maps are null. |
||||
* To render them see {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)} |
||||
* and {@link EnvironmentCamera}. |
||||
* |
||||
* The light probe has an area of effect that is a bounding volume centered on its position. (for now only Bounding spheres are supported). |
||||
* |
||||
* A LightProbe will only be taken into account when it's marked as ready. |
||||
* A light probe is ready when it has valid environment map data set. |
||||
* Note that you should never call setReady yourself. |
||||
* |
||||
* @see LightProbeFactory |
||||
* @see EnvironmentCamera |
||||
* @author nehon |
||||
*/ |
||||
public class LightProbe extends Light implements Savable { |
||||
|
||||
private TextureCubeMap irradianceMap; |
||||
private TextureCubeMap prefilteredEnvMap; |
||||
private BoundingVolume bounds = new BoundingSphere(1.0f, Vector3f.ZERO); |
||||
private boolean ready = false; |
||||
private Vector3f position = new Vector3f(); |
||||
private Node debugNode; |
||||
|
||||
/** |
||||
* Empty constructor used for serialization. |
||||
* You should never call it, use {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)} instead |
||||
*/ |
||||
public LightProbe() { |
||||
} |
||||
|
||||
/** |
||||
* returns the irradiance map texture of this Light probe. |
||||
* Note that this Texture may not have image data yet if the LightProbe is not ready |
||||
* @return the irradiance map |
||||
*/ |
||||
public TextureCubeMap getIrradianceMap() { |
||||
return irradianceMap; |
||||
} |
||||
|
||||
/** |
||||
* Sets the irradiance map |
||||
* @param irradianceMap the irradiance map |
||||
*/ |
||||
public void setIrradianceMap(TextureCubeMap irradianceMap) { |
||||
this.irradianceMap = irradianceMap; |
||||
} |
||||
|
||||
/** |
||||
* returns the prefiltered environment map texture of this light probe |
||||
* Note that this Texture may not have image data yet if the LightProbe is not ready |
||||
* @return the prefiltered environment map |
||||
*/ |
||||
public TextureCubeMap getPrefilteredEnvMap() { |
||||
return prefilteredEnvMap; |
||||
} |
||||
|
||||
/** |
||||
* Sets the prefiltered environment map |
||||
* @param prefileteredEnvMap the prefiltered environment map |
||||
*/ |
||||
public void setPrefilteredMap(TextureCubeMap prefileteredEnvMap) { |
||||
this.prefilteredEnvMap = prefileteredEnvMap; |
||||
} |
||||
|
||||
@Override |
||||
public void write(JmeExporter ex) throws IOException { |
||||
super.write(ex); |
||||
OutputCapsule oc = ex.getCapsule(this); |
||||
oc.write(irradianceMap, "irradianceMap", null); |
||||
oc.write(prefilteredEnvMap, "prefilteredEnvMap", null); |
||||
oc.write(position, "position", null); |
||||
oc.write(bounds, "bounds", bounds); |
||||
} |
||||
|
||||
@Override |
||||
public void read(JmeImporter im) throws IOException { |
||||
super.read(im); |
||||
InputCapsule ic = im.getCapsule(this); |
||||
irradianceMap = (TextureCubeMap) ic.readSavable("irradianceMap", null); |
||||
prefilteredEnvMap = (TextureCubeMap) ic.readSavable("prefilteredEnvMap", null); |
||||
position = (Vector3f) ic.readSavable("position", this); |
||||
bounds = (BoundingVolume) ic.readSavable("bounds", bounds); |
||||
} |
||||
|
||||
/** |
||||
* returns the bounding volume of this LightProbe |
||||
* @return a bounding volume. |
||||
*/ |
||||
public BoundingVolume getBounds() { |
||||
return bounds; |
||||
} |
||||
|
||||
/** |
||||
* Sets the bounds of this LightProbe |
||||
* Note that for now only BoundingSphere is supported and this method will |
||||
* throw an UnsupportedOperationException with any other BoundingVolume type |
||||
* @param bounds the bounds of the LightProbe |
||||
*/ |
||||
public void setBounds(BoundingVolume bounds) { |
||||
if( bounds.getType()!= BoundingVolume.Type.Sphere){ |
||||
throw new UnsupportedOperationException("For not only BoundingSphere are suported for LightProbe"); |
||||
} |
||||
this.bounds = bounds; |
||||
} |
||||
|
||||
/** |
||||
* return true if the LightProbe is ready, meaning the Environment maps have |
||||
* been loaded or rnedered and are ready to be used by a material |
||||
* @return the LightProbe ready state |
||||
*/ |
||||
public boolean isReady() { |
||||
return ready; |
||||
} |
||||
|
||||
/** |
||||
* Don't call this method directly. |
||||
* It's meant to be called by additional systems that will load or render |
||||
* the Environment maps of the LightProbe |
||||
* @param ready the ready state of the LightProbe. |
||||
*/ |
||||
public void setReady(boolean ready) { |
||||
this.ready = ready; |
||||
} |
||||
|
||||
/** |
||||
* For debuging porpose only |
||||
* Will return a Node meant to be added to a GUI presenting the 2 cube maps in a cross pattern with all the mip maps. |
||||
* |
||||
* @param manager the asset manager |
||||
* @return a debug node |
||||
*/ |
||||
public Node getDebugGui(AssetManager manager) { |
||||
if (!ready) { |
||||
throw new UnsupportedOperationException("This EnvProbeis not ready yet, try to test isReady()"); |
||||
} |
||||
if (debugNode == null) { |
||||
debugNode = new Node("debug gui probe"); |
||||
Node debugPfemCm = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(getPrefilteredEnvMap(), manager); |
||||
Node debugIrrCm = EnvMapUtils.getCubeMapCrossDebugView(getIrradianceMap(), manager); |
||||
|
||||
debugNode.attachChild(debugIrrCm); |
||||
debugNode.attachChild(debugPfemCm); |
||||
debugPfemCm.setLocalTranslation(520, 0, 0); |
||||
} |
||||
|
||||
return debugNode; |
||||
} |
||||
|
||||
/** |
||||
* Returns the position of the LightProbe in world space |
||||
* @return the wolrd space position |
||||
*/ |
||||
public Vector3f getPosition() { |
||||
return position; |
||||
} |
||||
|
||||
/** |
||||
* Sets the position of the LightProbe in world space |
||||
* @param position the wolrd space position |
||||
*/ |
||||
public void setPosition(Vector3f position) { |
||||
this.position.set(position); |
||||
} |
||||
|
||||
@Override |
||||
public boolean intersectsBox(BoundingBox box, TempVars vars) { |
||||
return getBounds().intersectsBoundingBox(box); |
||||
} |
||||
|
||||
@Override |
||||
public boolean intersectsFrustum(Camera camera, TempVars vars) { |
||||
return camera.contains(bounds) != Camera.FrustumIntersect.Outside; |
||||
} |
||||
|
||||
@Override |
||||
protected void computeLastDistance(Spatial owner) { |
||||
if (owner.getWorldBound() != null) { |
||||
BoundingVolume bv = owner.getWorldBound(); |
||||
lastDistance = bv.distanceSquaredTo(position); |
||||
} else { |
||||
lastDistance = owner.getWorldTranslation().distanceSquared(position); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Type getType() { |
||||
return Type.Probe; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,45 @@ |
||||
MaterialDef Simple { |
||||
MaterialParameters { |
||||
TextureCubeMap CubeMap |
||||
} |
||||
Technique { |
||||
WorldParameters { |
||||
WorldViewProjectionMatrix |
||||
WorldMatrix |
||||
CameraPosition |
||||
} |
||||
VertexShaderNodes { |
||||
ShaderNode Reflect { |
||||
Definition : Reflect : Common/MatDefs/ShaderNodes/Environment/reflect.j3sn |
||||
InputMappings { |
||||
normal = Attr.inNormal |
||||
position = Global.position.xyz |
||||
worldMatrix = WorldParam.WorldMatrix |
||||
camPosition = WorldParam.CameraPosition |
||||
} |
||||
} |
||||
ShaderNode CommonVert { |
||||
Definition : CommonVert : Common/MatDefs/ShaderNodes/Common/CommonVert.j3sn |
||||
InputMappings { |
||||
worldViewProjectionMatrix = WorldParam.WorldViewProjectionMatrix |
||||
modelPosition = Global.position.xyz |
||||
} |
||||
OutputMappings { |
||||
Global.position = projPosition |
||||
} |
||||
} |
||||
} |
||||
FragmentShaderNodes { |
||||
ShaderNode EnvMapping { |
||||
Definition : EnvMapping : Common/MatDefs/ShaderNodes/Environment/envMapping.j3sn |
||||
InputMappings { |
||||
refVec = Reflect.refVec |
||||
cubeMap = MatParam.CubeMap |
||||
} |
||||
OutputMappings { |
||||
Global.color = color |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,22 @@ |
||||
ShaderNodeDefinitions{ |
||||
ShaderNodeDefinition EnvMapping { |
||||
Type: Fragment |
||||
|
||||
Shader GLSL100: Common/MatDefs/ShaderNodes/Environment/envMapping100.frag |
||||
Shader GLSL130: Common/MatDefs/ShaderNodes/Environment/envMapping130.frag |
||||
|
||||
Documentation{ |
||||
fetches a texel in a cube map |
||||
@input vec3 refVec the reflection vector |
||||
@input samplerCube cubeMap the cube map |
||||
@output vec4 color the output color |
||||
} |
||||
Input { |
||||
vec3 refVec |
||||
samplerCube cubeMap |
||||
} |
||||
Output { |
||||
vec4 color |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,8 @@ |
||||
|
||||
void main(){ |
||||
//@input vec3 refVec the reflection vector |
||||
//@input samplerCube cubeMap the cube map |
||||
//@output vec4 color the output color |
||||
|
||||
color = textureCube(cubeMap, refVec, 0.0); |
||||
} |
@ -0,0 +1,8 @@ |
||||
|
||||
void main(){ |
||||
//@input vec3 refVec the reflection vector |
||||
//@input samplerCube cubeMap the cube map |
||||
//@output vec4 color the output color |
||||
|
||||
color = texture(cubeMap, refVec, 0.0); |
||||
} |
@ -0,0 +1,25 @@ |
||||
ShaderNodeDefinitions{ |
||||
ShaderNodeDefinition Reflect { |
||||
Type: Vertex |
||||
|
||||
Shader GLSL100: Common/MatDefs/ShaderNodes/Environment/reflect100.vert |
||||
|
||||
Documentation{ |
||||
Computes the relfection vector necessary to do some environment mapping |
||||
@input vec3 position position in model space |
||||
@input vec3 normal the normal of the vertex |
||||
@input vec3 camPosition camera position in world space |
||||
@input mat4 worldMatrix the world matrix |
||||
@output vec3 refVec the reflection vector |
||||
} |
||||
Input { |
||||
vec3 position |
||||
vec3 normal |
||||
vec3 camPosition |
||||
mat4 worldMatrix |
||||
} |
||||
Output { |
||||
vec3 refVec |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,14 @@ |
||||
|
||||
void main(){ |
||||
//@input vec3 position position in model space |
||||
//@input vec3 normal the normal of the vertex |
||||
//@input vec3 camPosition camera position in world space |
||||
//@input mat4 worldMatrix the world view matrix |
||||
//@output vec3 refVec the reflection vector |
||||
|
||||
vec3 worldPos = (worldMatrix * vec4(position, 1.0)).xyz; |
||||
vec3 N = normalize((worldMatrix * vec4(normal, 0.0)).xyz); |
||||
vec3 I = normalize( camPosition - worldPos ).xyz; |
||||
refVec.xyz = reflect(-I, N); |
||||
|
||||
} |
@ -0,0 +1,90 @@ |
||||
package jme3test.light; |
||||
|
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.input.ChaseCamera; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.controls.AnalogListener; |
||||
import com.jme3.light.DirectionalLight; |
||||
import com.jme3.input.controls.KeyTrigger; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.FastMath; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.post.FilterPostProcessor; |
||||
import com.jme3.renderer.queue.RenderQueue; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.shape.Box; |
||||
import com.jme3.shadow.DirectionalLightShadowFilter; |
||||
import com.jme3.shadow.DirectionalLightShadowRenderer; |
||||
|
||||
public class TestColorApp extends SimpleApplication { |
||||
public static void main(String[] args) { |
||||
TestColorApp app = new TestColorApp(); |
||||
app.start(); |
||||
} |
||||
|
||||
@Override |
||||
public void simpleInitApp() { |
||||
// Lights
|
||||
DirectionalLight sun = new DirectionalLight(); |
||||
Vector3f sunPosition = new Vector3f(1, -1, 1); |
||||
sun.setDirection(sunPosition); |
||||
sun.setColor(new ColorRGBA(1f,1f,1f,1f)); |
||||
rootNode.addLight(sun); |
||||
|
||||
//DirectionalLightShadowFilter sun_renderer = new DirectionalLightShadowFilter(assetManager, 2048, 4);
|
||||
DirectionalLightShadowRenderer sun_renderer = new DirectionalLightShadowRenderer(assetManager, 2048, 1); |
||||
sun_renderer.setLight(sun); |
||||
viewPort.addProcessor(sun_renderer); |
||||
|
||||
// FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
|
||||
// fpp.addFilter(sun_renderer);
|
||||
// viewPort.addProcessor(fpp);
|
||||
|
||||
rootNode.setShadowMode(RenderQueue.ShadowMode.CastAndReceive); |
||||
|
||||
// Camera
|
||||
viewPort.setBackgroundColor(new ColorRGBA(.6f, .6f, .6f, 1f)); |
||||
ChaseCamera chaseCam = new ChaseCamera(cam, inputManager); |
||||
|
||||
|
||||
// Objects
|
||||
// Ground Object
|
||||
final Geometry groundBoxWhite = new Geometry("Box", new Box(7.5f, 7.5f, .25f)); |
||||
float[] f = {-FastMath.PI / 2, 3 * FastMath.PI / 2, 0f}; |
||||
groundBoxWhite.setLocalRotation(new Quaternion(f)); |
||||
groundBoxWhite.move(7.5f, -.75f, 7.5f); |
||||
final Material groundMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); |
||||
groundMaterial.setColor("Diffuse", new ColorRGBA(.9f, .9f, .9f, .9f)); |
||||
groundBoxWhite.setMaterial(groundMaterial); |
||||
groundBoxWhite.addControl(chaseCam); |
||||
rootNode.attachChild(groundBoxWhite); |
||||
|
||||
// Planter
|
||||
Geometry planterBox = new Geometry("Box", new Box(.5f, .5f, .5f)); |
||||
final Material planterMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); |
||||
planterMaterial.setTexture("DiffuseMap", assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg")); |
||||
planterBox.setMaterial(groundMaterial); |
||||
planterBox.setLocalTranslation(10, 0, 9); |
||||
rootNode.attachChild(planterBox); |
||||
|
||||
// Action!
|
||||
inputManager.addMapping("on", new KeyTrigger(KeyInput.KEY_Z)); |
||||
inputManager.addMapping("off", new KeyTrigger(KeyInput.KEY_X)); |
||||
|
||||
inputManager.addListener(new AnalogListener() { |
||||
@Override |
||||
public void onAnalog(String s, float v, float v1) { |
||||
if (s.equals("on")) { |
||||
groundBoxWhite.setMaterial(planterMaterial); |
||||
} |
||||
if (s.equals("off")) { |
||||
groundBoxWhite.setMaterial(groundMaterial); |
||||
} |
||||
} |
||||
}, "on", "off"); |
||||
|
||||
inputEnabled = true; |
||||
} |
||||
} |
@ -0,0 +1,96 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.light; |
||||
|
||||
import com.jme3.app.ChaseCameraAppState; |
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.light.AmbientLight; |
||||
import com.jme3.light.PointLight; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.FastMath; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.shape.Box; |
||||
import com.jme3.util.TangentBinormalGenerator; |
||||
|
||||
/** |
||||
* |
||||
* @author Nehon |
||||
*/ |
||||
public class TestTangentCube extends SimpleApplication { |
||||
|
||||
public static void main(String... args) { |
||||
TestTangentCube app = new TestTangentCube(); |
||||
app.start(); |
||||
} |
||||
|
||||
@Override |
||||
public void simpleInitApp() { |
||||
Box aBox = new Box(1, 1, 1); |
||||
Geometry aGeometry = new Geometry("Box", aBox); |
||||
TangentBinormalGenerator.generate(aBox); |
||||
|
||||
Material aMaterial = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); |
||||
aMaterial.setTexture("DiffuseMap", |
||||
assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall.jpg")); |
||||
aMaterial.setTexture("NormalMap", |
||||
assetManager.loadTexture("Textures/Terrain/BrickWall/BrickWall_normal.jpg")); |
||||
aMaterial.setBoolean("UseMaterialColors", false); |
||||
aMaterial.setColor("Diffuse", ColorRGBA.White); |
||||
aMaterial.setColor("Specular", ColorRGBA.White); |
||||
aMaterial.setFloat("Shininess", 64f); |
||||
aGeometry.setMaterial(aMaterial); |
||||
|
||||
// Rotate 45 degrees to see multiple faces
|
||||
aGeometry.rotate(FastMath.QUARTER_PI, FastMath.QUARTER_PI, 0.0f); |
||||
rootNode.attachChild(aGeometry); |
||||
|
||||
/** |
||||
* Must add a light to make the lit object visible! |
||||
*/ |
||||
PointLight aLight = new PointLight(); |
||||
aLight.setPosition(new Vector3f(0, 3, 3)); |
||||
aLight.setColor(ColorRGBA.Red); |
||||
rootNode.addLight(aLight); |
||||
//
|
||||
// AmbientLight bLight = new AmbientLight();
|
||||
// bLight.setColor(ColorRGBA.Gray);
|
||||
// rootNode.addLight(bLight);
|
||||
|
||||
|
||||
ChaseCameraAppState chaser = new ChaseCameraAppState(); |
||||
chaser.setTarget(aGeometry); |
||||
getStateManager().attach(chaser); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,71 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.light.pbr; |
||||
|
||||
import com.jme3.environment.generation.JobProgressAdapter; |
||||
import com.jme3.light.LightProbe; |
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
|
||||
/** |
||||
* A basic logger for environment map rendering progress. |
||||
* @author nehon |
||||
*/ |
||||
public class ConsoleProgressReporter extends JobProgressAdapter<LightProbe>{ |
||||
|
||||
private static final Logger logger = Logger.getLogger(ConsoleProgressReporter.class.getName()); |
||||
|
||||
long time; |
||||
|
||||
@Override |
||||
public void start() { |
||||
time = System.currentTimeMillis(); |
||||
logger.log(Level.INFO,"Starting generation"); |
||||
} |
||||
|
||||
@Override |
||||
public void progress(double value) { |
||||
logger.log(Level.INFO, "Progress : {0}%", (value * 100)); |
||||
} |
||||
|
||||
@Override |
||||
public void step(String message) { |
||||
logger.info(message); |
||||
} |
||||
|
||||
@Override |
||||
public void done(LightProbe result) { |
||||
long end = System.currentTimeMillis(); |
||||
logger.log(Level.INFO, "Generation done in {0}", ((float)(end - time) / 1000f)); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,378 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.light.pbr; |
||||
|
||||
import com.jme3.app.SimpleApplication; |
||||
import com.jme3.bounding.BoundingSphere; |
||||
import com.jme3.input.CameraInput; |
||||
import com.jme3.input.KeyInput; |
||||
import com.jme3.input.MouseInput; |
||||
import com.jme3.input.controls.ActionListener; |
||||
import com.jme3.input.controls.KeyTrigger; |
||||
import com.jme3.input.controls.MouseAxisTrigger; |
||||
import com.jme3.light.AmbientLight; |
||||
import com.jme3.light.DirectionalLight; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector2f; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.renderer.queue.RenderQueue.ShadowMode; |
||||
import com.jme3.scene.Geometry; |
||||
import com.jme3.scene.Spatial; |
||||
import com.jme3.scene.shape.Box; |
||||
import com.jme3.scene.shape.Sphere; |
||||
import com.jme3.shadow.DirectionalLightShadowRenderer; |
||||
import com.jme3.shadow.EdgeFilteringMode; |
||||
|
||||
import com.jme3.environment.LightProbeFactory; |
||||
import com.jme3.environment.EnvironmentCamera; |
||||
import com.jme3.environment.util.LightsDebugState; |
||||
import com.jme3.light.LightProbe; |
||||
import com.jme3.material.TechniqueDef; |
||||
import com.jme3.post.FilterPostProcessor; |
||||
import com.jme3.post.filters.BloomFilter; |
||||
import com.jme3.post.filters.FXAAFilter; |
||||
import com.jme3.post.filters.ToneMapFilter; |
||||
import com.jme3.post.ssao.SSAOFilter; |
||||
import com.jme3.scene.Node; |
||||
import com.jme3.texture.plugins.ktx.KTXLoader; |
||||
import com.jme3.util.SkyFactory; |
||||
import com.jme3.util.TangentBinormalGenerator; |
||||
|
||||
public class TestPbrEnv extends SimpleApplication implements ActionListener { |
||||
|
||||
public static final int SHADOWMAP_SIZE = 1024; |
||||
private Spatial[] obj; |
||||
private Material[] mat; |
||||
private DirectionalLightShadowRenderer dlsr; |
||||
private LightsDebugState debugState; |
||||
|
||||
private EnvironmentCamera envCam; |
||||
|
||||
private Geometry ground; |
||||
private Material matGroundU; |
||||
private Material matGroundL; |
||||
|
||||
private Geometry camGeom; |
||||
|
||||
public static void main(String[] args) { |
||||
TestPbrEnv app = new TestPbrEnv(); |
||||
app.start(); |
||||
} |
||||
|
||||
|
||||
public void loadScene() { |
||||
|
||||
renderManager.setPreferredLightMode(TechniqueDef.LightMode.SinglePass); |
||||
renderManager.setSinglePassLightBatchSize(3); |
||||
obj = new Spatial[2]; |
||||
// Setup first view
|
||||
|
||||
mat = new Material[2]; |
||||
mat[0] = assetManager.loadMaterial("jme3test/light/pbr/pbrMat.j3m"); |
||||
//mat[1] = assetManager.loadMaterial("Textures/Terrain/Pond/Pond.j3m");
|
||||
mat[1] = assetManager.loadMaterial("jme3test/light/pbr/pbrMat2.j3m"); |
||||
// mat[1].setBoolean("UseMaterialColors", true);
|
||||
// mat[1].setColor("Ambient", ColorRGBA.White.mult(0.5f));
|
||||
// mat[1].setColor("Diffuse", ColorRGBA.White.clone());
|
||||
|
||||
obj[0] = new Geometry("sphere", new Sphere(30, 30, 2)); |
||||
obj[0].setShadowMode(ShadowMode.CastAndReceive); |
||||
obj[1] = new Geometry("cube", new Box(1.0f, 1.0f, 1.0f)); |
||||
obj[1].setShadowMode(ShadowMode.CastAndReceive); |
||||
TangentBinormalGenerator.generate(obj[1]); |
||||
TangentBinormalGenerator.generate(obj[0]); |
||||
|
||||
// for (int i = 0; i < 60; i++) {
|
||||
// Spatial t = obj[FastMath.nextRandomInt(0, obj.length - 1)].clone(false);
|
||||
// t.setName("Cube" + i);
|
||||
// t.setLocalScale(FastMath.nextRandomFloat() * 10f);
|
||||
// t.setMaterial(mat[FastMath.nextRandomInt(0, mat.length - 1)]);
|
||||
// rootNode.attachChild(t);
|
||||
// t.setLocalTranslation(FastMath.nextRandomFloat() * 200f, FastMath.nextRandomFloat() * 30f + 20, 30f * (i + 2f));
|
||||
// }
|
||||
|
||||
for (int i = 0; i < 2; i++) { |
||||
Spatial t = obj[0].clone(false); |
||||
t.setName("Cube" + i); |
||||
t.setLocalScale( 10f); |
||||
t.setMaterial(mat[1].clone()); |
||||
rootNode.attachChild(t); |
||||
t.setLocalTranslation(i * 200f+ 100f, 50, 800f * (i)); |
||||
} |
||||
|
||||
Box b = new Box(1000, 2, 1000); |
||||
b.scaleTextureCoordinates(new Vector2f(20, 20)); |
||||
ground = new Geometry("soil", b); |
||||
TangentBinormalGenerator.generate(ground); |
||||
ground.setLocalTranslation(0, 10, 550); |
||||
matGroundU = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
matGroundU.setColor("Color", ColorRGBA.Green); |
||||
|
||||
// matGroundL = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
|
||||
// Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");
|
||||
// grass.setWrap(WrapMode.Repeat);
|
||||
// matGroundL.setTexture("DiffuseMap", grass);
|
||||
|
||||
matGroundL = assetManager.loadMaterial("jme3test/light/pbr/pbrMat4.j3m"); |
||||
|
||||
ground.setMaterial(matGroundL); |
||||
|
||||
//ground.setShadowMode(ShadowMode.CastAndReceive);
|
||||
rootNode.attachChild(ground); |
||||
|
||||
l = new DirectionalLight(); |
||||
l.setColor(ColorRGBA.White); |
||||
//l.setDirection(new Vector3f(0.5973172f, -0.16583486f, 0.7846725f).normalizeLocal());
|
||||
l.setDirection(new Vector3f(-0.2823181f, -0.41889593f, 0.863031f).normalizeLocal()); |
||||
|
||||
rootNode.addLight(l); |
||||
|
||||
AmbientLight al = new AmbientLight(); |
||||
al.setColor(ColorRGBA.White.mult(0.5f)); |
||||
// rootNode.addLight(al);
|
||||
|
||||
//Spatial sky = SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", SkyFactory.EnvMapType.CubeMap);
|
||||
Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap); |
||||
sky.setLocalScale(350); |
||||
|
||||
rootNode.attachChild(sky); |
||||
} |
||||
DirectionalLight l; |
||||
|
||||
@Override |
||||
public void simpleInitApp() { |
||||
assetManager.registerLoader(KTXLoader.class, "ktx"); |
||||
|
||||
|
||||
// put the camera in a bad position
|
||||
cam.setLocation(new Vector3f(-52.433647f, 68.69636f, -118.60924f)); |
||||
cam.setRotation(new Quaternion(0.10294232f, 0.25269797f, -0.027049713f, 0.96167296f)); |
||||
|
||||
flyCam.setMoveSpeed(100); |
||||
|
||||
loadScene(); |
||||
|
||||
dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 4); |
||||
dlsr.setLight(l); |
||||
//dlsr.setLambda(0.55f);
|
||||
dlsr.setShadowIntensity(0.5f); |
||||
dlsr.setEdgeFilteringMode(EdgeFilteringMode.PCFPOISSON); |
||||
//dlsr.displayDebug();
|
||||
// viewPort.addProcessor(dlsr);
|
||||
|
||||
FilterPostProcessor fpp = new FilterPostProcessor(assetManager); |
||||
|
||||
fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(6.0f))); |
||||
SSAOFilter ssao = new SSAOFilter(); |
||||
ssao.setIntensity(5); |
||||
|
||||
fpp.addFilter(ssao); |
||||
|
||||
BloomFilter bloomFilter = new BloomFilter(); |
||||
fpp.addFilter(bloomFilter); |
||||
fpp.addFilter(new FXAAFilter()); |
||||
//viewPort.addProcessor(fpp);
|
||||
|
||||
initInputs(); |
||||
|
||||
// envManager = new EnvironmentManager();
|
||||
// getStateManager().attach(envManager);
|
||||
//
|
||||
envCam = new EnvironmentCamera(); |
||||
getStateManager().attach(envCam); |
||||
|
||||
debugState = new LightsDebugState(); |
||||
debugState.setProbeScale(5); |
||||
getStateManager().attach(debugState); |
||||
|
||||
camGeom = new Geometry("camGeom", new Sphere(16, 16, 2)); |
||||
// Material m = new Material(assetManager, "Common/MatDefs/Misc/UnshadedNodes.j3md");
|
||||
// m.setColor("Color", ColorRGBA.Green);
|
||||
Material m = assetManager.loadMaterial("jme3test/light/pbr/pbrMat3.j3m"); |
||||
camGeom.setMaterial(m); |
||||
camGeom.setLocalTranslation(0, 20, 0); |
||||
camGeom.setLocalScale(5); |
||||
rootNode.attachChild(camGeom); |
||||
|
||||
// envManager.setScene(rootNode);
|
||||
|
||||
// MaterialDebugAppState debug = new MaterialDebugAppState();
|
||||
// debug.registerBinding("MatDefs/PBRLighting.frag", rootNode);
|
||||
// getStateManager().attach(debug);
|
||||
|
||||
flyCam.setDragToRotate(true); |
||||
setPauseOnLostFocus(false); |
||||
|
||||
// cam.lookAt(camGeom.getWorldTranslation(), Vector3f.UNIT_Y);
|
||||
|
||||
} |
||||
|
||||
private void fixFLyCamInputs() { |
||||
inputManager.deleteMapping(CameraInput.FLYCAM_LEFT); |
||||
inputManager.deleteMapping(CameraInput.FLYCAM_RIGHT); |
||||
inputManager.deleteMapping(CameraInput.FLYCAM_UP); |
||||
inputManager.deleteMapping(CameraInput.FLYCAM_DOWN); |
||||
|
||||
inputManager.addMapping(CameraInput.FLYCAM_LEFT, new MouseAxisTrigger(MouseInput.AXIS_X, true)); |
||||
|
||||
inputManager.addMapping(CameraInput.FLYCAM_RIGHT, new MouseAxisTrigger(MouseInput.AXIS_X, false)); |
||||
|
||||
inputManager.addMapping(CameraInput.FLYCAM_UP, new MouseAxisTrigger(MouseInput.AXIS_Y, false)); |
||||
|
||||
inputManager.addMapping(CameraInput.FLYCAM_DOWN, new MouseAxisTrigger(MouseInput.AXIS_Y, true)); |
||||
|
||||
inputManager.addListener(flyCam, CameraInput.FLYCAM_LEFT, CameraInput.FLYCAM_RIGHT, CameraInput.FLYCAM_UP, CameraInput.FLYCAM_DOWN); |
||||
} |
||||
|
||||
private void initInputs() { |
||||
inputManager.addMapping("switchGroundMat", new KeyTrigger(KeyInput.KEY_M)); |
||||
inputManager.addMapping("snapshot", new KeyTrigger(KeyInput.KEY_SPACE)); |
||||
inputManager.addMapping("fc", new KeyTrigger(KeyInput.KEY_F)); |
||||
inputManager.addMapping("debugProbe", new KeyTrigger(KeyInput.KEY_RETURN)); |
||||
inputManager.addMapping("debugTex", new KeyTrigger(KeyInput.KEY_T)); |
||||
inputManager.addMapping("up", new KeyTrigger(KeyInput.KEY_UP)); |
||||
inputManager.addMapping("down", new KeyTrigger(KeyInput.KEY_DOWN)); |
||||
inputManager.addMapping("right", new KeyTrigger(KeyInput.KEY_RIGHT)); |
||||
inputManager.addMapping("left", new KeyTrigger(KeyInput.KEY_LEFT)); |
||||
|
||||
inputManager.addListener(this, "switchGroundMat", "snapshot", "debugTex", "debugProbe", "fc", "up", "down", "left", "right"); |
||||
} |
||||
|
||||
private LightProbe lastProbe; |
||||
private Node debugGui ; |
||||
|
||||
public void onAction(String name, boolean keyPressed, float tpf) { |
||||
|
||||
if (name.equals("switchGroundMat") && keyPressed) { |
||||
if (ground.getMaterial() == matGroundL) { |
||||
ground.setMaterial(matGroundU); |
||||
} else { |
||||
|
||||
ground.setMaterial(matGroundL); |
||||
} |
||||
} |
||||
|
||||
if (name.equals("snapshot") && keyPressed) { |
||||
envCam.setPosition(camGeom.getWorldTranslation()); |
||||
lastProbe = LightProbeFactory.makeProbe(envCam, rootNode, new ConsoleProgressReporter()); |
||||
((BoundingSphere)lastProbe.getBounds()).setRadius(200); |
||||
rootNode.addLight(lastProbe); |
||||
|
||||
} |
||||
|
||||
if (name.equals("fc") && keyPressed) { |
||||
|
||||
flyCam.setEnabled(true); |
||||
} |
||||
|
||||
if (name.equals("debugProbe") && keyPressed) { |
||||
//getStateManager().getState(EnvironmentCamera.class).toggleDebug();
|
||||
if (!debugState.isEnabled()) { |
||||
debugState.setEnabled(true); |
||||
debugState.setDebugMode(LightsDebugState.DebugMode.IrradianceMap); |
||||
} else if (debugState.getDebugMode() == LightsDebugState.DebugMode.IrradianceMap) { |
||||
debugState.setDebugMode(LightsDebugState.DebugMode.PrefilteredEnvMap); |
||||
} else if (debugState.getDebugMode() == LightsDebugState.DebugMode.PrefilteredEnvMap) { |
||||
debugState.setEnabled(false); |
||||
} |
||||
|
||||
} |
||||
|
||||
if (name.equals("debugTex") && keyPressed) { |
||||
if(debugGui == null || debugGui.getParent() == null){ |
||||
debugGui = lastProbe.getDebugGui(assetManager); |
||||
debugGui.setLocalTranslation(10, 200, 0); |
||||
guiNode.attachChild(debugGui); |
||||
} else if(debugGui != null){ |
||||
debugGui.removeFromParent(); |
||||
} |
||||
} |
||||
|
||||
if (name.equals("up")) { |
||||
up = keyPressed; |
||||
} |
||||
if (name.equals("down")) { |
||||
down = keyPressed; |
||||
} |
||||
if (name.equals("right")) { |
||||
right = keyPressed; |
||||
} |
||||
if (name.equals("left")) { |
||||
left = keyPressed; |
||||
} |
||||
if (name.equals("fwd")) { |
||||
fwd = keyPressed; |
||||
} |
||||
if (name.equals("back")) { |
||||
back = keyPressed; |
||||
} |
||||
|
||||
} |
||||
boolean up = false; |
||||
boolean down = false; |
||||
boolean left = false; |
||||
boolean right = false; |
||||
boolean fwd = false; |
||||
boolean back = false; |
||||
float time = 0; |
||||
float s = 50f; |
||||
boolean initialized = false; |
||||
|
||||
@Override |
||||
public void simpleUpdate(float tpf) { |
||||
|
||||
if (!initialized) { |
||||
fixFLyCamInputs(); |
||||
initialized = true; |
||||
} |
||||
float val = tpf * s; |
||||
if (up) { |
||||
camGeom.move(0, 0, val); |
||||
} |
||||
if (down) { |
||||
camGeom.move(0, 0, -val); |
||||
|
||||
} |
||||
if (right) { |
||||
camGeom.move(-val, 0, 0); |
||||
|
||||
} |
||||
if (left) { |
||||
camGeom.move(val, 0, 0); |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,180 @@ |
||||
/* |
||||
* Copyright (c) 2009-2015 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.KeyTrigger; |
||||
import com.jme3.light.DirectionalLight; |
||||
import com.jme3.material.Material; |
||||
import com.jme3.math.ColorRGBA; |
||||
import com.jme3.math.Quaternion; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.post.FilterPostProcessor; |
||||
import com.jme3.post.filters.BloomFilter; |
||||
import com.jme3.post.filters.BloomFilter.GlowMode; |
||||
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.scene.shape.Box; |
||||
import com.jme3.util.SkyFactory; |
||||
|
||||
public class TestBloomAlphaThreshold extends SimpleApplication |
||||
{ |
||||
|
||||
float angle; |
||||
Spatial lightMdl; |
||||
Spatial teapot; |
||||
Geometry frustumMdl; |
||||
WireFrustum frustum; |
||||
boolean active = true; |
||||
FilterPostProcessor fpp; |
||||
|
||||
public static void main(String[] args) |
||||
{ |
||||
TestBloomAlphaThreshold app = new TestBloomAlphaThreshold(); |
||||
app.start(); |
||||
} |
||||
|
||||
@Override |
||||
public void simpleInitApp() |
||||
{ |
||||
// put the camera in a bad position
|
||||
cam.setLocation(new Vector3f(-2.336393f, 11.91392f, -10)); |
||||
cam.setRotation(new Quaternion(0.23602544f, 0.11321983f, -0.027698677f, 0.96473104f)); |
||||
// cam.setFrustumFar(1000);
|
||||
|
||||
Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); |
||||
|
||||
mat.setFloat("Shininess", 15f); |
||||
mat.setBoolean("UseMaterialColors", true); |
||||
mat.setColor("Ambient", ColorRGBA.Yellow.mult(0.2f)); |
||||
mat.setColor("Diffuse", ColorRGBA.Yellow.mult(0.2f)); |
||||
mat.setColor("Specular", ColorRGBA.Yellow.mult(0.8f)); |
||||
mat.setColor("GlowColor", ColorRGBA.Green); |
||||
|
||||
Material matSoil = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); |
||||
matSoil.setFloat("Shininess", 15f); |
||||
matSoil.setBoolean("UseMaterialColors", true); |
||||
matSoil.setColor("Ambient", ColorRGBA.Gray); |
||||
matSoil.setColor("Diffuse", ColorRGBA.Black); |
||||
matSoil.setColor("Specular", ColorRGBA.Gray); |
||||
|
||||
teapot = assetManager.loadModel("Models/Teapot/Teapot.obj"); |
||||
teapot.setLocalTranslation(0, 0, 10); |
||||
|
||||
teapot.setMaterial(mat); |
||||
teapot.setShadowMode(ShadowMode.CastAndReceive); |
||||
teapot.setLocalScale(10.0f); |
||||
rootNode.attachChild(teapot); |
||||
|
||||
Geometry soil = new Geometry("soil", new Box(new Vector3f(0, -13, 550), 800, 10, 700)); |
||||
soil.setMaterial(matSoil); |
||||
soil.setShadowMode(ShadowMode.CastAndReceive); |
||||
rootNode.attachChild(soil); |
||||
|
||||
Material matBox = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
||||
matBox.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png")); |
||||
matBox.setFloat("AlphaDiscardThreshold", 0.5f); |
||||
|
||||
Geometry box = new Geometry("box", new Box(new Vector3f(-3.5f, 10, -2), 2, 2, 2)); |
||||
box.setMaterial(matBox); |
||||
box.setQueueBucket(RenderQueue.Bucket.Translucent); |
||||
// box.setShadowMode(ShadowMode.CastAndReceive);
|
||||
rootNode.attachChild(box); |
||||
|
||||
DirectionalLight light = new DirectionalLight(); |
||||
light.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); |
||||
light.setColor(ColorRGBA.White.mult(1.5f)); |
||||
rootNode.addLight(light); |
||||
|
||||
// load sky
|
||||
Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Bright/FullskiesBlueClear03.dds", false); |
||||
sky.setCullHint(Spatial.CullHint.Never); |
||||
rootNode.attachChild(sky); |
||||
|
||||
fpp = new FilterPostProcessor(assetManager); |
||||
int numSamples = getContext().getSettings().getSamples(); |
||||
if (numSamples > 0) |
||||
{ |
||||
fpp.setNumSamples(numSamples); |
||||
} |
||||
|
||||
BloomFilter bloom = new BloomFilter(GlowMode.Objects); |
||||
bloom.setDownSamplingFactor(2); |
||||
bloom.setBlurScale(1.37f); |
||||
bloom.setExposurePower(3.30f); |
||||
bloom.setExposureCutOff(0.2f); |
||||
bloom.setBloomIntensity(2.45f); |
||||
BloomUI ui = new BloomUI(inputManager, bloom); |
||||
|
||||
viewPort.addProcessor(fpp); |
||||
fpp.addFilter(bloom); |
||||
initInputs(); |
||||
|
||||
} |
||||
|
||||
private void initInputs() |
||||
{ |
||||
inputManager.addMapping("toggle", new KeyTrigger(KeyInput.KEY_SPACE)); |
||||
|
||||
ActionListener acl = new ActionListener() |
||||
{ |
||||
|
||||
@Override |
||||
public void onAction(String name, boolean keyPressed, float tpf) |
||||
{ |
||||
if (name.equals("toggle") && keyPressed) |
||||
{ |
||||
if (active) |
||||
{ |
||||
active = false; |
||||
viewPort.removeProcessor(fpp); |
||||
} |
||||
else |
||||
{ |
||||
active = true; |
||||
viewPort.addProcessor(fpp); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
inputManager.addListener(acl, "toggle"); |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,13 @@ |
||||
Material My Material : Common/MatDefs/Light/PBRLighting.j3md { |
||||
MaterialParameters { |
||||
Roughness : 0.1 |
||||
BaseColor : 1.0 0.2 0.2 1.0 |
||||
Metallic : 0.0 |
||||
EmissivePower : 0.0 |
||||
EmissiveIntensity : 0.0 |
||||
Emissive : 1.0 0.8 0.8 1.0 |
||||
ParallaxHeight : 0.0 |
||||
} |
||||
AdditionalRenderState { |
||||
} |
||||
} |
@ -0,0 +1,12 @@ |
||||
Material My Material : Common/MatDefs/Light/PBRLighting.j3md { |
||||
MaterialParameters { |
||||
Metallic : 0.0 |
||||
Roughness : 0.0 |
||||
BaseColor : 0.8 0.81960785 0.39607844 1.0 |
||||
EmissiveIntensity : 5.0 |
||||
EmissivePower : 2.0 |
||||
Emissive : 1.0 0.0 0.0 1.0 |
||||
} |
||||
AdditionalRenderState { |
||||
} |
||||
} |
@ -0,0 +1,9 @@ |
||||
Material My Material : Common/MatDefs/Light/PBRLighting.j3md { |
||||
MaterialParameters { |
||||
BaseColor : 0.6 0.6 0.6 1.0 |
||||
Metallic : 1.0 |
||||
Roughness : 0.05 |
||||
} |
||||
AdditionalRenderState { |
||||
} |
||||
} |
@ -0,0 +1,11 @@ |
||||
Material My Material : Common/MatDefs/Light/PBRLighting.j3md { |
||||
MaterialParameters { |
||||
BaseColorMap : Repeat Textures/Terrain/BrickWall/BrickWall.jpg |
||||
Roughness : 0.01 |
||||
NormalMap : Repeat Textures/Terrain/BrickWall/BrickWall_normal.jpg |
||||
Metallic : 1.0 |
||||
BaseColor : 1.0 1.0 1.0 1.0 |
||||
} |
||||
AdditionalRenderState { |
||||
} |
||||
} |
Loading…
Reference in new issue