aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Gouesse <[email protected]>2019-06-05 22:24:27 +0200
committerJulien Gouesse <[email protected]>2019-06-05 22:24:27 +0200
commitcd25e068e4b9c3c9895e533d9285905576f95b07 (patch)
tree5790fa9d0fa8b46f4f526a4d33f848a7186ebdd4
parent8c8bf9a4c7ac81db0fc73bdd6fb7020f1880b1e3 (diff)
Fixes some errors in the Java documentation of ardor3d-examples
-rw-r--r--ardor3d-examples/src/main/java/com/ardor3d/example/PropertiesDialog.java36
-rw-r--r--ardor3d-examples/src/main/java/com/ardor3d/example/PropertiesGameSettings.java98
-rw-r--r--ardor3d-examples/src/main/java/com/ardor3d/example/benchmark/ball/BubbleMarkExample.java33
-rw-r--r--ardor3d-examples/src/main/java/com/ardor3d/example/effect/ParallelSplitShadowMapExample.java2
-rw-r--r--ardor3d-examples/src/main/java/com/ardor3d/example/terrain/InMemoryTerrainExample.java2
-rw-r--r--ardor3d-examples/src/main/java/com/ardor3d/example/terrain/ProceduralTerrainExample.java2
-rw-r--r--ardor3d-examples/src/main/java/com/ardor3d/example/terrain/TerrainWaterExample.java2
-rw-r--r--ardor3d-examples/src/main/java/com/ardor3d/example/terrain/ZupTerrainExample.java2
-rw-r--r--ardor3d-examples/src/main/java/com/ardor3d/example/ui/BMTextExample.java26
9 files changed, 150 insertions, 53 deletions
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/PropertiesDialog.java b/ardor3d-examples/src/main/java/com/ardor3d/example/PropertiesDialog.java
index a0c22b1..ce426ee 100644
--- a/ardor3d-examples/src/main/java/com/ardor3d/example/PropertiesDialog.java
+++ b/ardor3d-examples/src/main/java/com/ardor3d/example/PropertiesDialog.java
@@ -62,7 +62,8 @@ public final class PropertiesDialog extends JDialog {
private DisplayMode[] modes = null;
// Array of windowed resolutions
- private final String[] windowedResolutions = { "640 x 480", "800 x 600", "1024 x 768", "1152 x 864", "1920 x 1080" };
+ private final String[] windowedResolutions = { "640 x 480", "800 x 600", "1024 x 768", "1152 x 864",
+ "1920 x 1080" };
// Array of possible samples
private final String[] samples = { "0 samples", "1 samples", "2 samples", "4 samples", "8 samples" };
@@ -127,6 +128,8 @@ public final class PropertiesDialog extends JDialog {
* @param imageFile
* the image file to use as the title of the dialog; <code>null</code> will result in to image being
* displayed
+ * @param mainThreadTasks
+ * the stack of tasks to run on the main thread
* @throws Ardor3dException
* if the source is <code>null</code>
*/
@@ -145,6 +148,7 @@ public final class PropertiesDialog extends JDialog {
* the image file to use as the title of the dialog; <code>null</code> will result in to image being
* displayed
* @param mainThreadTasks
+ * the stack of tasks to run on the main thread
* @throws Ardor3dException
* if the source is <code>null</code>
*/
@@ -508,6 +512,9 @@ public final class PropertiesDialog extends JDialog {
/**
* Utility method for converting a String denoting a file into a URL.
*
+ * @param file
+ * the string denoting a file
+ *
* @return a URL pointing to the file or null
*/
private static URL getURL(final String file) {
@@ -525,6 +532,11 @@ public final class PropertiesDialog extends JDialog {
/**
* Returns every unique resolution from an array of <code>DisplayMode</code>s.
+ *
+ * @param modes
+ * the display modes
+ *
+ * @return the resolutions
*/
private static String[] getResolutions(final DisplayMode[] modes) {
final List<String> resolutions = new ArrayList<>(modes.length);
@@ -542,6 +554,13 @@ public final class PropertiesDialog extends JDialog {
/**
* Returns every possible bit depth for the given resolution.
+ *
+ * @param resolution
+ * the resolution
+ * @param modes
+ * the display modes
+ *
+ * @return the bit depths
*/
private static String[] getDepths(final String resolution, final DisplayMode[] modes) {
final Set<String> depths = new TreeSet<>(new Comparator<String>() {
@@ -558,8 +577,9 @@ public final class PropertiesDialog extends JDialog {
}
final String res = modes[i].getWidth() + " x " + modes[i].getHeight();
- final String depth = (modes[i].getBitDepth() != DisplayMode.BIT_DEPTH_MULTI) ? modes[i].getBitDepth()
- + " bpp" : "? bpp";
+ final String depth = (modes[i].getBitDepth() != DisplayMode.BIT_DEPTH_MULTI)
+ ? modes[i].getBitDepth() + " bpp"
+ : "? bpp";
if (res.equals(resolution) && !depths.contains(depth)) {
depths.add(depth);
}
@@ -572,6 +592,13 @@ public final class PropertiesDialog extends JDialog {
/**
* Returns every possible refresh rate for the given resolution.
+ *
+ * @param resolution
+ * the resolution
+ * @param modes
+ * the display modes
+ *
+ * @return the refresh rates
*/
private static String[] getFrequencies(final String resolution, final DisplayMode[] modes) {
final List<String> freqs = new ArrayList<>(4);
@@ -661,7 +688,8 @@ public final class PropertiesDialog extends JDialog {
boolean ready = false;
DisplayMode[] modes = null;
- ModesRetriever() {}
+ ModesRetriever() {
+ }
@Override
public void run() {
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/PropertiesGameSettings.java b/ardor3d-examples/src/main/java/com/ardor3d/example/PropertiesGameSettings.java
index 996cc57..66e354b 100644
--- a/ardor3d-examples/src/main/java/com/ardor3d/example/PropertiesGameSettings.java
+++ b/ardor3d-examples/src/main/java/com/ardor3d/example/PropertiesGameSettings.java
@@ -156,6 +156,7 @@ public class PropertiesGameSettings {
*
* @throws InternalError
* in all cases
+ * @return the alpha bits
*/
public int getAlphaBits() {
final String s = prop.getProperty("ALPHA_BITS");
@@ -174,6 +175,8 @@ public class PropertiesGameSettings {
/**
* This is only getting the "default" value, which may not be changed by end-users.
+ *
+ * @return the widget image of the default settings
*/
public String getDefaultSettingsWidgetImage() {
return defaultSettingsWidgetImage;
@@ -199,6 +202,7 @@ public class PropertiesGameSettings {
*
* @throws InternalError
* in all cases
+ * @return the depth bits
*/
public int getDepthBits() {
final String s = prop.getProperty("DEPTH_BITS");
@@ -220,6 +224,7 @@ public class PropertiesGameSettings {
*
* @throws InternalError
* in all cases
+ * @return the frame rate
*/
public int getFramerate() {
final String s = prop.getProperty("FRAMERATE");
@@ -246,6 +251,8 @@ public class PropertiesGameSettings {
*
* @deprecated Use method isFullscreen instead.
* @see #isFullscreen()
+ *
+ * @return <code>true</code> if the full screen mode is enabled
*/
@Deprecated
public boolean getFullscreen() {
@@ -302,6 +309,7 @@ public class PropertiesGameSettings {
*
* @throws InternalError
* in all cases
+ * @return the samples
*/
public int getSamples() {
final String s = prop.getProperty("SAMPLES");
@@ -313,6 +321,7 @@ public class PropertiesGameSettings {
*
* @throws InternalError
* in all cases
+ * @return the stencil bits
*/
public int getStencilBits() {
final String s = prop.getProperty("STENCIL_BITS");
@@ -354,6 +363,7 @@ public class PropertiesGameSettings {
*
* @throws InternalError
* in all cases
+ * @return <code>true</code> if the music is enabled
*/
public boolean isMusic() {
final String s = prop.getProperty("MUSIC");
@@ -369,6 +379,7 @@ public class PropertiesGameSettings {
*
* @throws InternalError
* in all cases
+ * @return <code>true</code> if the special effects are enabled
*/
public boolean isSFX() {
final String s = prop.getProperty("SFX");
@@ -380,6 +391,7 @@ public class PropertiesGameSettings {
*
* @throws InternalError
* in all cases
+ * @return <code>true</code> if the vertical sync is enabled
*/
public boolean isVerticalSync() {
final String s = prop.getProperty("VERTICAL_SYNC");
@@ -413,6 +425,9 @@ public class PropertiesGameSettings {
/**
* Removes specified property, if present.
+ *
+ * @param name
+ * the name of the property to remove
*/
public void remove(final String name) {
prop.remove(name);
@@ -444,6 +459,8 @@ public class PropertiesGameSettings {
* the frequency of the monitor.
* @param fullscreen
* use fullscreen or not.
+ * @param renderer
+ * the string denoting the renderer
* @deprecated
* @return true if save was successful, false otherwise.
*/
@@ -470,12 +487,20 @@ public class PropertiesGameSettings {
/**
* Sets a property.
+ *
+ * @param name
+ * the name of the property
+ * @param value
+ * the value of the property
*/
public void set(final String name, final String value) {
prop.setProperty(name, value);
}
/**
+ * @param alphaBits
+ * the alpha bits to set
+ *
* @throws InternalError
* in all cases
*/
@@ -484,18 +509,22 @@ public class PropertiesGameSettings {
}
/**
+ * @param name
+ * the name of the property
+ * @param value
+ * the value of the property
* @see #set(String, String)
- * @throws RuntimeSetting
- * for IO failure
*/
public void setBoolean(final String name, final boolean value) {
set(name, Boolean.toString(value));
}
/**
+ * @param name
+ * the name of the property
+ * @param value
+ * the value of the property
* @see #set(String, String)
- * @throws RuntimeSetting
- * for IO failure
*/
public void setByteArray(final String name, final byte[] value) {
set(name, new String(value));
@@ -506,6 +535,8 @@ public class PropertiesGameSettings {
}
/**
+ * @param depthBits
+ * the depth bits to set
* @throws InternalError
* in all cases
*/
@@ -514,18 +545,24 @@ public class PropertiesGameSettings {
}
/**
+ * @param name
+ * the name of the property
+ * @param value
+ * the value of the property
+ *
* @see #set(String, String)
- * @throws RuntimeSetting
- * for IO failure
*/
public void setDouble(final String name, final double value) {
set(name, Double.toString(value));
}
/**
+ * @param name
+ * the name of the property
+ * @param value
+ * the value of the property
+ *
* @see #set(String, String)
- * @throws RuntimeSetting
- * for IO failure
*/
public void setFloat(final String name, final float value) {
set(name, Float.toString(value));
@@ -534,6 +571,8 @@ public class PropertiesGameSettings {
/**
* @throws InternalError
* in all cases
+ * @param framerate
+ * the frame rate
*/
public void setFramerate(final int framerate) {
setInt("FRAMERATE", framerate);
@@ -552,9 +591,12 @@ public class PropertiesGameSettings {
}
/**
+ * @param name
+ * the name of the property
+ * @param value
+ * the value of the property
+ *
* @see #set(String, String)
- * @throws RuntimeSetting
- * for IO failure
*/
public void setInt(final String name, final int value) {
set(name, Integer.toString(value));
@@ -565,9 +607,12 @@ public class PropertiesGameSettings {
}
/**
+ * @param name
+ * the name of the property
+ * @param value
+ * the value of the property
+ *
* @see #set(String, String)
- * @throws RuntimeSetting
- * for IO failure
*/
public void setLong(final String name, final long value) {
set(name, Long.toString(value));
@@ -576,6 +621,8 @@ public class PropertiesGameSettings {
/**
* @throws InternalError
* in all cases
+ * @param music
+ * <code>true</code> if the music is enabled
*/
public void setMusic(final boolean music) {
setBoolean("MUSIC", music);
@@ -585,6 +632,11 @@ public class PropertiesGameSettings {
* Not implemented. Properties can not store an arbitrary Object in human-readable format. Use set(String, String)
* instead.
*
+ * @param name
+ * the name of the property
+ * @param value
+ * the value of the property
+ *
* @see #set(String, String)
* @throws InternalError
* in all cases
@@ -600,6 +652,8 @@ public class PropertiesGameSettings {
}
/**
+ * @param samples
+ * the samples
* @throws InternalError
* in all cases
*/
@@ -608,6 +662,8 @@ public class PropertiesGameSettings {
}
/**
+ * @param sfx
+ * <code>true</code> if the special effects are enabled
* @throws InternalError
* in all cases
*/
@@ -616,6 +672,9 @@ public class PropertiesGameSettings {
}
/**
+ * @param stencilBits
+ * the stencil bits
+ *
* @throws InternalError
* in all cases
*/
@@ -624,6 +683,9 @@ public class PropertiesGameSettings {
}
/**
+ * @param verticalSync
+ * <code>true</code> if the vertical sync is enabled
+ *
* @throws InternalError
* in all cases
*/
@@ -636,10 +698,8 @@ public class PropertiesGameSettings {
}
/**
- * save() method which throws only a RuntimeExceptin.
+ * save() method which throws only a RuntimeException.
*
- * @throws RuntimeSetting
- * for IO failure
* @see #save()
*/
public void wrappedSave() {
@@ -654,16 +714,14 @@ public class PropertiesGameSettings {
/**
* Sets default* static variables according to GameSettings.DEFAULT_* values and an optional .properties file. Note
* that we are talking about <b>defaults</b> here, not user-specific settings.
- * <P/>
+ * <p>
* This method should be called once the game name is known to the subclass. To override any default with your
* subclass (as opposed to by using a .properties file), just set the static variable before or after calling this
* method (before or after depends on the precedence you want among programmatic and declarative DEFAULT_*, default*
* settings).
- * <P/>
+ * </p>
* Add new setting names by making your own method which does its own thing and calls
- * AbstractGameSettings.assignDefaults(propfilename).
- * <P/>
- * Property file paths are relative to CLASSPATH element roots.
+ * AbstractGameSettings.assignDefaults(propfilename). Property file paths are relative to CLASSPATH element roots.
*
* @param propFileName
* Properties file read as CLASSPATH resource. If you give null, no properties file will be loaded.
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/benchmark/ball/BubbleMarkExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/benchmark/ball/BubbleMarkExample.java
index c7cd8bb..b2f2e64 100644
--- a/ardor3d-examples/src/main/java/com/ardor3d/example/benchmark/ball/BubbleMarkExample.java
+++ b/ardor3d-examples/src/main/java/com/ardor3d/example/benchmark/ball/BubbleMarkExample.java
@@ -3,7 +3,7 @@
*
* This file is part of Ardor3D.
*
- * Ardor3D is free software: you can redistribute it and/or modify it
+ * Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/
@@ -44,7 +44,6 @@ import com.ardor3d.util.resource.SimpleResourceLocator;
* <p>
* The famous BubbleMark UI test, recreated using quads.
* </p>
- * <p>
* There are several system params you can use to modify the test:
* <ul>
* <li>-Dvsync=true -- ask the canvas to use vertical sync to lock to the monitor refresh rate.</li>
@@ -56,11 +55,10 @@ import com.ardor3d.util.resource.SimpleResourceLocator;
* targetFPS) Not compatible with sync=true.</li>
* <li>-DtargetFPS=# -- set the target frame rate (fps) for adaptive mode. (default is 200)</li>
* </ul>
- * </p>
*/
@Purpose(htmlDescriptionKey = "com.ardor3d.example.benchmark.ball.BubbleMarkExample", //
-thumbnailPath = "com/ardor3d/example/media/thumbnails/benchmark_ball_BubbleMarkExample.jpg", //
-maxHeapMemory = 64)
+ thumbnailPath = "com/ardor3d/example/media/thumbnails/benchmark_ball_BubbleMarkExample.jpg", //
+ maxHeapMemory = 64)
public class BubbleMarkExample implements Scene {
// Our native window, not the gl surface itself.
@@ -79,17 +77,20 @@ public class BubbleMarkExample implements Scene {
private BasicText frameRateLabel;
- private static final int width = (System.getProperty("width") != null ? Integer.parseInt(System
- .getProperty("width")) : 500);
- private static final int height = (System.getProperty("height") != null ? Integer.parseInt(System
- .getProperty("height")) : 300);
+ private static final int width = (System.getProperty("width") != null
+ ? Integer.parseInt(System.getProperty("width"))
+ : 500);
+ private static final int height = (System.getProperty("height") != null
+ ? Integer.parseInt(System.getProperty("height"))
+ : 300);
private final boolean skipBallCollide = ("true".equalsIgnoreCase(System.getProperty("noBallCollide")));
private boolean adaptiveStable = !("true".equalsIgnoreCase(System.getProperty("adaptive")));
- private static final int adaptiveTargetFPS = (System.getProperty("targetFPS") != null ? Integer.parseInt(System
- .getProperty("targetFPS")) : 200);
+ private static final int adaptiveTargetFPS = (System.getProperty("targetFPS") != null
+ ? Integer.parseInt(System.getProperty("targetFPS"))
+ : 200);
private int frames = 0;
private long startTime = System.currentTimeMillis();
@@ -131,7 +132,7 @@ public class BubbleMarkExample implements Scene {
/**
* Setup a native canvas and canvas renderer.
- *
+ *
* @return the canvas.
*/
private NativeCanvas initCanvas() {
@@ -151,8 +152,8 @@ public class BubbleMarkExample implements Scene {
// Set the location of our example resources.
try {
- final SimpleResourceLocator srl = new SimpleResourceLocator(ResourceLocatorTool.getClassPathResource(
- BubbleMarkExample.class, "com/ardor3d/example/media/"));
+ final SimpleResourceLocator srl = new SimpleResourceLocator(
+ ResourceLocatorTool.getClassPathResource(BubbleMarkExample.class, "com/ardor3d/example/media/"));
ResourceLocatorTool.addResourceLocator(ResourceLocatorTool.TYPE_TEXTURE, srl);
} catch (final URISyntaxException ex) {
ex.printStackTrace();
@@ -248,8 +249,8 @@ public class BubbleMarkExample implements Scene {
} else if (ratio > 4.0) {
ratio = 4.0;
}
- final int newN = Math.max(1, (ratio > 1.1 || ratio < 0.9) ? (int) (N * ratio) : (ratio > 1.025) ? N + 1
- : (ratio < 0.975) ? N - 1 : N);
+ final int newN = Math.max(1, (ratio > 1.1 || ratio < 0.9) ? (int) (N * ratio)
+ : (ratio > 1.025) ? N + 1 : (ratio < 0.975) ? N - 1 : N);
if (newN != N) {
resetBalls(newN);
} else {
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/effect/ParallelSplitShadowMapExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/effect/ParallelSplitShadowMapExample.java
index 56dc5f7..bced17d 100644
--- a/ardor3d-examples/src/main/java/com/ardor3d/example/effect/ParallelSplitShadowMapExample.java
+++ b/ardor3d-examples/src/main/java/com/ardor3d/example/effect/ParallelSplitShadowMapExample.java
@@ -1 +1 @@
-/** * Copyright (c) 2008-2018 Ardor Labs, Inc. * * This file is part of Ardor3D. * * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ package com.ardor3d.example.effect; import com.ardor3d.bounding.BoundingBox; import com.ardor3d.example.ExampleBase; import com.ardor3d.example.Purpose; import com.ardor3d.extension.shadow.map.ParallelSplitShadowMapPass; import com.ardor3d.extension.shadow.map.ShadowCasterManager; import com.ardor3d.framework.Canvas; import com.ardor3d.image.Texture; import com.ardor3d.image.Texture2D; import com.ardor3d.input.Key; import com.ardor3d.input.logical.InputTrigger; import com.ardor3d.input.logical.KeyPressedCondition; import com.ardor3d.input.logical.TriggerAction; import com.ardor3d.input.logical.TwoInputStates; import com.ardor3d.light.DirectionalLight; import com.ardor3d.light.Light; import com.ardor3d.light.PointLight; import com.ardor3d.math.Matrix3; import com.ardor3d.math.Vector3; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.pass.BasicPassManager; import com.ardor3d.renderer.pass.RenderPass; import com.ardor3d.renderer.queue.RenderBucketType; import com.ardor3d.renderer.state.BlendState; import com.ardor3d.renderer.state.BlendState.TestFunction; import com.ardor3d.renderer.state.CullState; import com.ardor3d.renderer.state.MaterialState; import com.ardor3d.renderer.state.MaterialState.ColorMaterial; import com.ardor3d.renderer.state.TextureState; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.Spatial; import com.ardor3d.scenegraph.controller.SpatialController; import com.ardor3d.scenegraph.hint.CullHint; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.hint.TextureCombineMode; import com.ardor3d.scenegraph.shape.Box; import com.ardor3d.scenegraph.shape.Quad; import com.ardor3d.scenegraph.shape.Torus; import com.ardor3d.scenegraph.visitor.UpdateModelBoundVisitor; import com.ardor3d.ui.text.BasicText; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.TextureManager; /** * Example showing the parallel split shadow mapping technique. Requires GLSL support. */ @Purpose(htmlDescriptionKey = "com.ardor3d.example.effect.ParallelSplitShadowMapExample", // thumbnailPath = "com/ardor3d/example/media/thumbnails/effect_ParallelSplitShadowMapExample.jpg", // maxHeapMemory = 64) public class ParallelSplitShadowMapExample extends ExampleBase { /** Pssm shadow map pass. */ private ParallelSplitShadowMapPass _pssmPass; /** Pass manager. */ private BasicPassManager _passManager; /** Quads used for debug showing shadowmaps. */ private Quad _orthoQuad[]; /** Flag for turning on/off light movement. */ private boolean _updateLight = false; /** Temp vec for updating light pos. */ private final Vector3 lightPosition = new Vector3(10000, 5000, 10000); /** Text fields used to present info about the example. */ private final BasicText _exampleInfo[] = new BasicText[12]; /** Flag to make sure quads are updated on reinitialization of shadow renderer */ private boolean _quadsDirty = true; /** Console fps output */ private double counter = 0; private int frames = 0; /** * The main method. * * @param args * the arguments */ public static void main(final String[] args) { start(ParallelSplitShadowMapExample.class); } /** * Update the PassManager and light. * * @param timer * the application timer */ @Override protected void updateExample(final ReadOnlyTimer timer) { _passManager.updatePasses(timer.getTimePerFrame()); if (_updateLight) { final double time = timer.getTimeInSeconds() * 0.2; lightPosition.set(Math.sin(time) * 10000.0, 5000.0, Math.cos(time) * 10000.0); } counter += timer.getTimePerFrame(); frames++; if (counter > 1) { final double fps = (frames / counter); counter = 0; frames = 0; System.out.printf("%7.1f FPS\n", fps); } } /** * Initialize pssm if needed. Update light position. Render scene. * * @param renderer * the renderer */ @Override protected void renderExample(final Renderer renderer) { if (!_pssmPass.isInitialised()) { _pssmPass.init(renderer); } updateQuadTextures(renderer); // Update the shadowpass "light" position. Iow it's camera. final Light light = _lightState.get(0); if (light instanceof PointLight) { ((PointLight) light).setLocation(lightPosition); } else if (light instanceof DirectionalLight) { ((DirectionalLight) light).setDirection(lightPosition.normalize(null).negateLocal()); } _passManager.renderPasses(renderer); } /** * Initialize pssm pass and scene. */ @Override protected void initExample() { // Setup main camera. _canvas.setTitle("Parallel Split Shadow Maps - Example"); _canvas.getCanvasRenderer().getCamera().setLocation(new Vector3(250, 200, -250)); _canvas.getCanvasRenderer() .getCamera() .setFrustumPerspective( 45.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth() / (float) _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0, 10000); _canvas.getCanvasRenderer().getCamera().lookAt(new Vector3(0, 0, 0), Vector3.UNIT_Y); _controlHandle.setMoveSpeed(200); // Setup some standard states for the scene. final CullState cullFrontFace = new CullState(); cullFrontFace.setEnabled(true); cullFrontFace.setCullFace(CullState.Face.Back); _root.setRenderState(cullFrontFace); final TextureState ts = new TextureState(); ts.setEnabled(true); ts.setTexture(TextureManager.load("images/ardor3d_white_256.jpg", Texture.MinificationFilter.Trilinear, true)); _root.setRenderState(ts); final MaterialState ms = new MaterialState(); ms.setColorMaterial(ColorMaterial.Diffuse); _root.setRenderState(ms); _passManager = new BasicPassManager(); // setup some quads for debug viewing. final RenderPass renderPass = new RenderPass(); final int quadSize = _canvas.getCanvasRenderer().getCamera().getWidth() / 10; _orthoQuad = new Quad[ParallelSplitShadowMapPass._MAX_SPLITS]; for (int i = 0; i < ParallelSplitShadowMapPass._MAX_SPLITS; i++) { _orthoQuad[i] = new Quad("OrthoQuad", quadSize, quadSize); _orthoQuad[i].setTranslation(new Vector3((quadSize / 2 + 5) + (quadSize + 5) * i, (quadSize / 2 + 5), 1)); _orthoQuad[i].getSceneHints().setRenderBucketType(RenderBucketType.Ortho); _orthoQuad[i].getSceneHints().setLightCombineMode(LightCombineMode.Off); _orthoQuad[i].getSceneHints().setTextureCombineMode(TextureCombineMode.Replace); _orthoQuad[i].getSceneHints().setCullHint(CullHint.Never); renderPass.add(_orthoQuad[i]); } // Create scene objects. setupTerrain(); final RenderPass rootPass = new RenderPass(); rootPass.add(_root); _lightState.detachAll(); final DirectionalLight light = new DirectionalLight(); // final PointLight light = new PointLight(); light.setEnabled(true); _lightState.attach(light); // Create pssm pass _pssmPass = new ParallelSplitShadowMapPass(light, 1024, 3); _pssmPass.add(_root); _pssmPass.setUseSceneTexturing(true); _pssmPass.setUseObjectCullFace(true); final Node occluders = setupOccluders(); ShadowCasterManager.INSTANCE.addSpatial(occluders); // Populate passmanager with passes. _passManager.add(rootPass); _passManager.add(_pssmPass); _passManager.add(renderPass); // Setup textfields for presenting example info. final Node textNodes = new Node("Text"); renderPass.add(textNodes); textNodes.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); textNodes.getSceneHints().setLightCombineMode(LightCombineMode.Off); final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight(); for (int i = 0; i < _exampleInfo.length; i++) { _exampleInfo[i] = BasicText.createDefaultTextLabel("Text", "", 16); _exampleInfo[i].setTranslation(new Vector3(10, infoStartY - (i + 1) * 20, 0)); textNodes.attachChild(_exampleInfo[i]); } textNodes.updateGeometricState(0.0); updateText(); // Register keyboard triggers for manipulating example _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ZERO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setDrawShaderDebug(!_pssmPass.isDrawShaderDebug()); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ONE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _updateLight = !_updateLight; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.TWO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setUpdateMainCamera(!_pssmPass.isUpdateMainCamera()); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.THREE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setDrawDebug(!_pssmPass.isDrawDebug()); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FOUR), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (_pssmPass.getNumOfSplits() > ParallelSplitShadowMapPass._MIN_SPLITS) { _pssmPass.setNumOfSplits(_pssmPass.getNumOfSplits() - 1); updateText(); _quadsDirty = true; } } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FIVE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (_pssmPass.getNumOfSplits() < ParallelSplitShadowMapPass._MAX_SPLITS) { _pssmPass.setNumOfSplits(_pssmPass.getNumOfSplits() + 1); updateText(); _quadsDirty = true; } } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SIX), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (_pssmPass.getShadowMapSize() > 1) { _pssmPass.setShadowMapSize(_pssmPass.getShadowMapSize() / 2); updateText(); _quadsDirty = true; } } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SEVEN), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (_pssmPass.getShadowMapSize() < 2048) { _pssmPass.setShadowMapSize(_pssmPass.getShadowMapSize() * 2); updateText(); _quadsDirty = true; } } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.EIGHT), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final double maxShadowDistance = _pssmPass.getMaxShadowDistance(); if (maxShadowDistance > 200.0) { _pssmPass.setMaxShadowDistance(maxShadowDistance - 100.0); updateText(); } } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.NINE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final double maxShadowDistance = _pssmPass.getMaxShadowDistance(); _pssmPass.setMaxShadowDistance(maxShadowDistance + 100.0); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.U), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setNumOfSplits(1); _pssmPass.setShadowMapSize(1024); updateText(); _quadsDirty = true; } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.I), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setNumOfSplits(3); _pssmPass.setShadowMapSize(512); updateText(); _quadsDirty = true; } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.J), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setUseSceneTexturing(!_pssmPass.isUseSceneTexturing()); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.K), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setUseObjectCullFace(!_pssmPass.isUseObjectCullFace()); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SPACE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setEnabled(!_pssmPass.isEnabled()); updateText(); _quadsDirty = true; } })); // Make sure all boundings are updated. _root.acceptVisitor(new UpdateModelBoundVisitor(), false); } /** * Setup debug quads to render pssm shadowmaps. */ private void updateQuadTextures(final Renderer r) { if (!_quadsDirty) { return; } _quadsDirty = false; _pssmPass.reinit(r); for (int i = 0; i < _pssmPass.getNumOfSplits(); i++) { final TextureState screen = new TextureState(); final Texture2D copy = new Texture2D(); copy.setTextureKey(_pssmPass.getShadowMapTexture(i).getTextureKey()); screen.setTexture(copy); _orthoQuad[i].setRenderState(screen); _orthoQuad[i].getSceneHints().setCullHint(CullHint.Never); _orthoQuad[i].updateGeometricState(0.0); } for (int i = _pssmPass.getNumOfSplits(); i < ParallelSplitShadowMapPass._MAX_SPLITS; i++) { _orthoQuad[i].getSceneHints().setCullHint(CullHint.Always); } } /** * Update text information. */ private void updateText() { _exampleInfo[0].setText("[0] Debug shader draw: " + _pssmPass.isDrawShaderDebug()); _exampleInfo[1].setText("[1] Update light: " + _updateLight); _exampleInfo[2].setText("[2] Update main camera: " + _pssmPass.isUpdateMainCamera()); _exampleInfo[3].setText("[3] Debug draw: " + _pssmPass.isDrawDebug()); _exampleInfo[4].setText("[4/5] Number of splits: " + _pssmPass.getNumOfSplits()); _exampleInfo[5].setText("[6/7] Shadow map size: " + _pssmPass.getShadowMapSize()); _exampleInfo[6].setText("[8/9] Max shadow distance: " + _pssmPass.getMaxShadowDistance()); _exampleInfo[7].setText("[U] Setup 1 split of size 1024"); _exampleInfo[8].setText("[I] Setup 3 splits of size 512"); _exampleInfo[9].setText("[J] Use scene texturing: " + _pssmPass.isUseSceneTexturing()); _exampleInfo[10].setText("[K] Use object cull face: " + _pssmPass.isUseObjectCullFace()); _exampleInfo[11].setText("[SPACE] toggle PSSM pass: " + (_pssmPass.isEnabled() ? "enabled" : "disabled")); } /** * Setup terrain. */ private void setupTerrain() { final Box box = new Box("box", new Vector3(), 10000, 10, 10000); box.setModelBound(new BoundingBox()); box.addController(new SpatialController<Box>() { double timer = 0; @Override public void update(final double time, final Box caller) { timer += time; caller.setTranslation(Math.sin(timer) * 20.0, 0, Math.cos(timer) * 20.0); } }); _root.attachChild(box); } /** * Setup occluders. */ private Node setupOccluders() { final Node occluders = new Node("occs"); _root.attachChild(occluders); for (int i = 0; i < 30; i++) { final double w = Math.random() * 40 + 10; final double y = Math.random() * 20 + 10; final Box b = new Box("box", new Vector3(), w, y, w); b.setModelBound(new BoundingBox()); final double x = Math.random() * 1000 - 500; final double z = Math.random() * 1000 - 500; b.setTranslation(new Vector3(x, y, z)); occluders.attachChild(b); } final Torus torusWithoutShadows = new Torus("torus", 32, 10, 15.0f, 20.0f); torusWithoutShadows.setModelBound(new BoundingBox()); torusWithoutShadows.getSceneHints().setCastsShadows(false); torusWithoutShadows.setTranslation(0, 50, -100); occluders.attachChild(torusWithoutShadows); final Torus torus = new Torus("torus", 64, 12, 10.0f, 15.0f); torus.setModelBound(new BoundingBox()); occluders.attachChild(torus); torus.addController(new SpatialController<Torus>() { double timer = 0; Matrix3 rotation = new Matrix3(); @Override public void update(final double time, final Torus caller) { timer += time; caller.setTranslation(Math.sin(timer) * 40.0, Math.sin(timer) * 50.0 + 20.0, Math.cos(timer) * 40.0); rotation.fromAngles(timer * 0.4, timer * 0.4, timer * 0.4); caller.setRotation(rotation); } }); // Attach "billboard" with an alpha test. occluders.attachChild(makeBillBoard()); return occluders; } private Spatial makeBillBoard() { final Node billboard = new Node("bb"); billboard.getSceneHints().setRenderBucketType(RenderBucketType.Transparent); final Quad q1 = new Quad("font block", 150, 200); q1.setTranslation(0, 80, 0); q1.setModelBound(new BoundingBox()); final CullState cs = new CullState(); cs.setCullFace(CullState.Face.None); q1.setRenderState(cs); billboard.attachChild(q1); final TextureState ts = new TextureState(); ts.setEnabled(true); ts.setTexture(TextureManager.load("fonts/OkasaSansSerif-35-medium-regular_00.png", Texture.MinificationFilter.Trilinear, true)); billboard.setRenderState(ts); final BlendState bs = new BlendState(); bs.setEnabled(true); bs.setBlendEnabled(false); bs.setTestEnabled(true); bs.setTestFunction(TestFunction.GreaterThan); bs.setReference(0.7f); billboard.setRenderState(bs); return billboard; } } \ No newline at end of file
+/** * Copyright (c) 2008-2018 Ardor Labs, Inc. * * This file is part of Ardor3D. * * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ package com.ardor3d.example.effect; import com.ardor3d.bounding.BoundingBox; import com.ardor3d.example.ExampleBase; import com.ardor3d.example.Purpose; import com.ardor3d.extension.shadow.map.ParallelSplitShadowMapPass; import com.ardor3d.extension.shadow.map.ShadowCasterManager; import com.ardor3d.framework.Canvas; import com.ardor3d.image.Texture; import com.ardor3d.image.Texture2D; import com.ardor3d.input.Key; import com.ardor3d.input.logical.InputTrigger; import com.ardor3d.input.logical.KeyPressedCondition; import com.ardor3d.input.logical.TriggerAction; import com.ardor3d.input.logical.TwoInputStates; import com.ardor3d.light.DirectionalLight; import com.ardor3d.light.Light; import com.ardor3d.light.PointLight; import com.ardor3d.math.Matrix3; import com.ardor3d.math.Vector3; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.pass.BasicPassManager; import com.ardor3d.renderer.pass.RenderPass; import com.ardor3d.renderer.queue.RenderBucketType; import com.ardor3d.renderer.state.BlendState; import com.ardor3d.renderer.state.BlendState.TestFunction; import com.ardor3d.renderer.state.CullState; import com.ardor3d.renderer.state.MaterialState; import com.ardor3d.renderer.state.MaterialState.ColorMaterial; import com.ardor3d.renderer.state.TextureState; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.Spatial; import com.ardor3d.scenegraph.controller.SpatialController; import com.ardor3d.scenegraph.hint.CullHint; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.hint.TextureCombineMode; import com.ardor3d.scenegraph.shape.Box; import com.ardor3d.scenegraph.shape.Quad; import com.ardor3d.scenegraph.shape.Torus; import com.ardor3d.scenegraph.visitor.UpdateModelBoundVisitor; import com.ardor3d.ui.text.BasicText; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.TextureManager; /** * Example showing the parallel split shadow mapping technique. Requires GLSL support. */ @Purpose(htmlDescriptionKey = "com.ardor3d.example.effect.ParallelSplitShadowMapExample", // thumbnailPath = "com/ardor3d/example/media/thumbnails/effect_ParallelSplitShadowMapExample.jpg", // maxHeapMemory = 64) public class ParallelSplitShadowMapExample extends ExampleBase { /** Pssm shadow map pass. */ private ParallelSplitShadowMapPass _pssmPass; /** Pass manager. */ private BasicPassManager _passManager; /** Quads used for debug showing shadowmaps. */ private Quad _orthoQuad[]; /** Flag for turning on/off light movement. */ private boolean _updateLight = false; /** Temp vec for updating light pos. */ private final Vector3 lightPosition = new Vector3(10000, 5000, 10000); /** Text fields used to present info about the example. */ private final BasicText _exampleInfo[] = new BasicText[12]; /** Flag to make sure quads are updated on reinitialization of shadow renderer */ private boolean _quadsDirty = true; /** Console fps output */ private double counter = 0; private int frames = 0; /** * The main method. * * @param args * the arguments */ public static void main(final String[] args) { start(ParallelSplitShadowMapExample.class); } /** * Update the PassManager and light. * * @param timer * the application timer */ @Override protected void updateExample(final ReadOnlyTimer timer) { _passManager.updatePasses(timer.getTimePerFrame()); if (_updateLight) { final double time = timer.getTimeInSeconds() * 0.2; lightPosition.set(Math.sin(time) * 10000.0, 5000.0, Math.cos(time) * 10000.0); } counter += timer.getTimePerFrame(); frames++; if (counter > 1) { final double fps = (frames / counter); counter = 0; frames = 0; System.out.printf("%7.1f FPS\n", fps); } } /** * Initialize pssm if needed. Update light position. Render scene. * * @param renderer * the renderer */ @Override protected void renderExample(final Renderer renderer) { if (!_pssmPass.isInitialised()) { _pssmPass.init(renderer); } updateQuadTextures(renderer); // Update the shadowpass "light" position. Iow it's camera. final Light light = _lightState.get(0); if (light instanceof PointLight) { ((PointLight) light).setLocation(lightPosition); } else if (light instanceof DirectionalLight) { ((DirectionalLight) light).setDirection(lightPosition.normalize(null).negateLocal()); } _passManager.renderPasses(renderer); } /** * Initialize pssm pass and scene. */ @Override protected void initExample() { // Setup main camera. _canvas.setTitle("Parallel Split Shadow Maps - Example"); _canvas.getCanvasRenderer().getCamera().setLocation(new Vector3(250, 200, -250)); _canvas.getCanvasRenderer().getCamera().setFrustumPerspective(45.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth() / (float) _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0, 10000); _canvas.getCanvasRenderer().getCamera().lookAt(new Vector3(0, 0, 0), Vector3.UNIT_Y); _controlHandle.setMoveSpeed(200); // Setup some standard states for the scene. final CullState cullFrontFace = new CullState(); cullFrontFace.setEnabled(true); cullFrontFace.setCullFace(CullState.Face.Back); _root.setRenderState(cullFrontFace); final TextureState ts = new TextureState(); ts.setEnabled(true); ts.setTexture(TextureManager.load("images/ardor3d_white_256.jpg", Texture.MinificationFilter.Trilinear, true)); _root.setRenderState(ts); final MaterialState ms = new MaterialState(); ms.setColorMaterial(ColorMaterial.Diffuse); _root.setRenderState(ms); _passManager = new BasicPassManager(); // setup some quads for debug viewing. final RenderPass renderPass = new RenderPass(); final int quadSize = _canvas.getCanvasRenderer().getCamera().getWidth() / 10; _orthoQuad = new Quad[ParallelSplitShadowMapPass._MAX_SPLITS]; for (int i = 0; i < ParallelSplitShadowMapPass._MAX_SPLITS; i++) { _orthoQuad[i] = new Quad("OrthoQuad", quadSize, quadSize); _orthoQuad[i].setTranslation(new Vector3((quadSize / 2 + 5) + (quadSize + 5) * i, (quadSize / 2 + 5), 1)); _orthoQuad[i].getSceneHints().setRenderBucketType(RenderBucketType.Ortho); _orthoQuad[i].getSceneHints().setLightCombineMode(LightCombineMode.Off); _orthoQuad[i].getSceneHints().setTextureCombineMode(TextureCombineMode.Replace); _orthoQuad[i].getSceneHints().setCullHint(CullHint.Never); renderPass.add(_orthoQuad[i]); } // Create scene objects. setupTerrain(); final RenderPass rootPass = new RenderPass(); rootPass.add(_root); _lightState.detachAll(); final DirectionalLight light = new DirectionalLight(); // final PointLight light = new PointLight(); light.setEnabled(true); _lightState.attach(light); // Create pssm pass _pssmPass = new ParallelSplitShadowMapPass(light, 1024, 3); _pssmPass.add(_root); _pssmPass.setUseSceneTexturing(true); _pssmPass.setUseObjectCullFace(true); final Node occluders = setupOccluders(); ShadowCasterManager.INSTANCE.addSpatial(occluders); // Populate passmanager with passes. _passManager.add(rootPass); _passManager.add(_pssmPass); _passManager.add(renderPass); // Setup textfields for presenting example info. final Node textNodes = new Node("Text"); renderPass.add(textNodes); textNodes.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); textNodes.getSceneHints().setLightCombineMode(LightCombineMode.Off); final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight(); for (int i = 0; i < _exampleInfo.length; i++) { _exampleInfo[i] = BasicText.createDefaultTextLabel("Text", "", 16); _exampleInfo[i].setTranslation(new Vector3(10, infoStartY - (i + 1) * 20, 0)); textNodes.attachChild(_exampleInfo[i]); } textNodes.updateGeometricState(0.0); updateText(); // Register keyboard triggers for manipulating example _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ZERO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setDrawShaderDebug(!_pssmPass.isDrawShaderDebug()); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ONE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _updateLight = !_updateLight; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.TWO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setUpdateMainCamera(!_pssmPass.isUpdateMainCamera()); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.THREE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setDrawDebug(!_pssmPass.isDrawDebug()); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FOUR), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (_pssmPass.getNumOfSplits() > ParallelSplitShadowMapPass._MIN_SPLITS) { _pssmPass.setNumOfSplits(_pssmPass.getNumOfSplits() - 1); updateText(); _quadsDirty = true; } } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FIVE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (_pssmPass.getNumOfSplits() < ParallelSplitShadowMapPass._MAX_SPLITS) { _pssmPass.setNumOfSplits(_pssmPass.getNumOfSplits() + 1); updateText(); _quadsDirty = true; } } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SIX), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (_pssmPass.getShadowMapSize() > 1) { _pssmPass.setShadowMapSize(_pssmPass.getShadowMapSize() / 2); updateText(); _quadsDirty = true; } } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SEVEN), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (_pssmPass.getShadowMapSize() < 2048) { _pssmPass.setShadowMapSize(_pssmPass.getShadowMapSize() * 2); updateText(); _quadsDirty = true; } } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.EIGHT), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final double maxShadowDistance = _pssmPass.getMaxShadowDistance(); if (maxShadowDistance > 200.0) { _pssmPass.setMaxShadowDistance(maxShadowDistance - 100.0); updateText(); } } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.NINE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final double maxShadowDistance = _pssmPass.getMaxShadowDistance(); _pssmPass.setMaxShadowDistance(maxShadowDistance + 100.0); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.U), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setNumOfSplits(1); _pssmPass.setShadowMapSize(1024); updateText(); _quadsDirty = true; } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.I), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setNumOfSplits(3); _pssmPass.setShadowMapSize(512); updateText(); _quadsDirty = true; } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.J), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setUseSceneTexturing(!_pssmPass.isUseSceneTexturing()); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.K), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setUseObjectCullFace(!_pssmPass.isUseObjectCullFace()); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SPACE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _pssmPass.setEnabled(!_pssmPass.isEnabled()); updateText(); _quadsDirty = true; } })); // Make sure all boundings are updated. _root.acceptVisitor(new UpdateModelBoundVisitor(), false); } /** * Setup debug quads to render pssm shadowmaps. * * @param r * the renderer */ private void updateQuadTextures(final Renderer r) { if (!_quadsDirty) { return; } _quadsDirty = false; _pssmPass.reinit(r); for (int i = 0; i < _pssmPass.getNumOfSplits(); i++) { final TextureState screen = new TextureState(); final Texture2D copy = new Texture2D(); copy.setTextureKey(_pssmPass.getShadowMapTexture(i).getTextureKey()); screen.setTexture(copy); _orthoQuad[i].setRenderState(screen); _orthoQuad[i].getSceneHints().setCullHint(CullHint.Never); _orthoQuad[i].updateGeometricState(0.0); } for (int i = _pssmPass.getNumOfSplits(); i < ParallelSplitShadowMapPass._MAX_SPLITS; i++) { _orthoQuad[i].getSceneHints().setCullHint(CullHint.Always); } } /** * Update text information. */ private void updateText() { _exampleInfo[0].setText("[0] Debug shader draw: " + _pssmPass.isDrawShaderDebug()); _exampleInfo[1].setText("[1] Update light: " + _updateLight); _exampleInfo[2].setText("[2] Update main camera: " + _pssmPass.isUpdateMainCamera()); _exampleInfo[3].setText("[3] Debug draw: " + _pssmPass.isDrawDebug()); _exampleInfo[4].setText("[4/5] Number of splits: " + _pssmPass.getNumOfSplits()); _exampleInfo[5].setText("[6/7] Shadow map size: " + _pssmPass.getShadowMapSize()); _exampleInfo[6].setText("[8/9] Max shadow distance: " + _pssmPass.getMaxShadowDistance()); _exampleInfo[7].setText("[U] Setup 1 split of size 1024"); _exampleInfo[8].setText("[I] Setup 3 splits of size 512"); _exampleInfo[9].setText("[J] Use scene texturing: " + _pssmPass.isUseSceneTexturing()); _exampleInfo[10].setText("[K] Use object cull face: " + _pssmPass.isUseObjectCullFace()); _exampleInfo[11].setText("[SPACE] toggle PSSM pass: " + (_pssmPass.isEnabled() ? "enabled" : "disabled")); } /** * Setup terrain. */ private void setupTerrain() { final Box box = new Box("box", new Vector3(), 10000, 10, 10000); box.setModelBound(new BoundingBox()); box.addController(new SpatialController<Box>() { double timer = 0; @Override public void update(final double time, final Box caller) { timer += time; caller.setTranslation(Math.sin(timer) * 20.0, 0, Math.cos(timer) * 20.0); } }); _root.attachChild(box); } /** * Setup occluders. * * @return the node containing the occluders */ private Node setupOccluders() { final Node occluders = new Node("occs"); _root.attachChild(occluders); for (int i = 0; i < 30; i++) { final double w = Math.random() * 40 + 10; final double y = Math.random() * 20 + 10; final Box b = new Box("box", new Vector3(), w, y, w); b.setModelBound(new BoundingBox()); final double x = Math.random() * 1000 - 500; final double z = Math.random() * 1000 - 500; b.setTranslation(new Vector3(x, y, z)); occluders.attachChild(b); } final Torus torusWithoutShadows = new Torus("torus", 32, 10, 15.0f, 20.0f); torusWithoutShadows.setModelBound(new BoundingBox()); torusWithoutShadows.getSceneHints().setCastsShadows(false); torusWithoutShadows.setTranslation(0, 50, -100); occluders.attachChild(torusWithoutShadows); final Torus torus = new Torus("torus", 64, 12, 10.0f, 15.0f); torus.setModelBound(new BoundingBox()); occluders.attachChild(torus); torus.addController(new SpatialController<Torus>() { double timer = 0; Matrix3 rotation = new Matrix3(); @Override public void update(final double time, final Torus caller) { timer += time; caller.setTranslation(Math.sin(timer) * 40.0, Math.sin(timer) * 50.0 + 20.0, Math.cos(timer) * 40.0); rotation.fromAngles(timer * 0.4, timer * 0.4, timer * 0.4); caller.setRotation(rotation); } }); // Attach "billboard" with an alpha test. occluders.attachChild(makeBillBoard()); return occluders; } private Spatial makeBillBoard() { final Node billboard = new Node("bb"); billboard.getSceneHints().setRenderBucketType(RenderBucketType.Transparent); final Quad q1 = new Quad("font block", 150, 200); q1.setTranslation(0, 80, 0); q1.setModelBound(new BoundingBox()); final CullState cs = new CullState(); cs.setCullFace(CullState.Face.None); q1.setRenderState(cs); billboard.attachChild(q1); final TextureState ts = new TextureState(); ts.setEnabled(true); ts.setTexture(TextureManager.load("fonts/OkasaSansSerif-35-medium-regular_00.png", Texture.MinificationFilter.Trilinear, true)); billboard.setRenderState(ts); final BlendState bs = new BlendState(); bs.setEnabled(true); bs.setBlendEnabled(false); bs.setTestEnabled(true); bs.setTestFunction(TestFunction.GreaterThan); bs.setReference(0.7f); billboard.setRenderState(bs); return billboard; } } \ No newline at end of file
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/InMemoryTerrainExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/InMemoryTerrainExample.java
index d1de7d6..8bea9b7 100644
--- a/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/InMemoryTerrainExample.java
+++ b/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/InMemoryTerrainExample.java
@@ -1 +1 @@
-/** * Copyright (c) 2008-2014 Ardor Labs, Inc. * * This file is part of Ardor3D. * * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ package com.ardor3d.example.terrain; import java.util.concurrent.Callable; import com.ardor3d.example.ExampleBase; import com.ardor3d.example.Purpose; import com.ardor3d.extension.terrain.client.Terrain; import com.ardor3d.extension.terrain.client.TerrainBuilder; import com.ardor3d.extension.terrain.client.TerrainDataProvider; import com.ardor3d.extension.terrain.providers.inmemory.InMemoryTerrainDataProvider; import com.ardor3d.extension.terrain.providers.inmemory.data.InMemoryTerrainData; import com.ardor3d.framework.Canvas; import com.ardor3d.framework.CanvasRenderer; import com.ardor3d.image.Texture; import com.ardor3d.input.Key; import com.ardor3d.input.logical.InputTrigger; import com.ardor3d.input.logical.KeyPressedCondition; import com.ardor3d.input.logical.TriggerAction; import com.ardor3d.input.logical.TwoInputStates; import com.ardor3d.intersection.PickingUtil; import com.ardor3d.intersection.PrimitivePickResults; import com.ardor3d.light.DirectionalLight; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.Ray3; import com.ardor3d.math.Vector3; import com.ardor3d.renderer.Camera; import com.ardor3d.renderer.RenderContext; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.queue.RenderBucketType; import com.ardor3d.renderer.state.CullState; import com.ardor3d.renderer.state.FogState; import com.ardor3d.renderer.state.FogState.DensityFunction; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.extension.Skybox; import com.ardor3d.scenegraph.hint.CullHint; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.shape.Sphere; import com.ardor3d.ui.text.BasicText; import com.ardor3d.util.GameTaskQueue; import com.ardor3d.util.GameTaskQueueManager; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.TextureManager; /** * Example showing the Geometry Clipmap Terrain system with 'MegaTextures' streaming from an in-memory data source. * Requires GLSL support. */ @Purpose(htmlDescriptionKey = "com.ardor3d.example.terrain.InMemoryTerrainExample", // thumbnailPath = "com/ardor3d/example/media/thumbnails/terrain_InMemoryTerrainExample.jpg", // maxHeapMemory = 128) public class InMemoryTerrainExample extends ExampleBase { private boolean updateTerrain = true; private final float farPlane = 8000.0f; private Terrain terrain; private final Sphere sphere = new Sphere("sp", 16, 16, 1); private final Ray3 pickRay = new Ray3(); private boolean groundCamera = false; private Camera terrainCamera; private Skybox skybox; private InMemoryTerrainData inMemoryTerrainData; /** Text fields used to present info about the example. */ private final BasicText _exampleInfo[] = new BasicText[6]; public static void main(final String[] args) { ExampleBase.start(InMemoryTerrainExample.class); } @Override protected void updateExample(final ReadOnlyTimer timer) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); // Make sure camera is above terrain final double height = terrain.getHeightAt(camera.getLocation().getX(), camera.getLocation().getZ()); if (height > -Float.MAX_VALUE && (groundCamera || camera.getLocation().getY() < height + 3)) { camera.setLocation(new Vector3(camera.getLocation().getX(), height + 3, camera.getLocation().getZ())); } if (updateTerrain) { terrainCamera.set(camera); } skybox.setTranslation(camera.getLocation()); // if we're picking... if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { // Set up our pick ray pickRay.setOrigin(camera.getLocation()); pickRay.setDirection(camera.getDirection()); // do pick and move the sphere final PrimitivePickResults pickResults = new PrimitivePickResults(); pickResults.setCheckDistance(true); PickingUtil.findPick(_root, pickRay, pickResults); if (pickResults.getNumber() != 0) { final Vector3 intersectionPoint = pickResults.getPickData(0).getIntersectionRecord() .getIntersectionPoint(0); sphere.setTranslation(intersectionPoint); // XXX: maybe change the color of the ball for valid vs. invalid? } } } /** * Initialize pssm pass and scene. */ @Override protected void initExample() { // Setup main camera. _canvas.setTitle("Terrain Example"); _canvas.getCanvasRenderer().getCamera().setLocation(new Vector3(0, 300, 0)); _canvas.getCanvasRenderer().getCamera().lookAt(new Vector3(1, 300, 1), Vector3.UNIT_Y); _canvas.getCanvasRenderer() .getCamera() .setFrustumPerspective( 70.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth() / _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0f, farPlane); final CanvasRenderer canvasRenderer = _canvas.getCanvasRenderer(); final RenderContext renderContext = canvasRenderer.getRenderContext(); final Renderer renderer = canvasRenderer.getRenderer(); GameTaskQueueManager.getManager(renderContext).getQueue(GameTaskQueue.RENDER).enqueue(new Callable<Void>() { @Override public Void call() throws Exception { renderer.setBackgroundColor(ColorRGBA.GRAY); return null; } }); _controlHandle.setMoveSpeed(200); setupDefaultStates(); sphere.getSceneHints().setAllPickingHints(false); sphere.getSceneHints().setCullHint(CullHint.Always); _root.attachChild(sphere); try { // Keep a separate camera to be able to freeze terrain update final Camera camera = _canvas.getCanvasRenderer().getCamera(); terrainCamera = new Camera(camera); inMemoryTerrainData = new InMemoryTerrainData(2048, 9, 128, new Vector3(1, 200, 1)); final TerrainDataProvider terrainDataProvider = new InMemoryTerrainDataProvider(inMemoryTerrainData, true); terrain = new TerrainBuilder(terrainDataProvider, terrainCamera).setShowDebugPanels(true).build(); _root.attachChild(terrain); } catch (final Exception ex1) { System.out.println("Problem setting up terrain..."); ex1.printStackTrace(); } skybox = buildSkyBox(); skybox.getSceneHints().setAllPickingHints(false); _root.attachChild(skybox); // Setup labels for presenting example info. final Node textNodes = new Node("Text"); _root.attachChild(textNodes); textNodes.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); textNodes.getSceneHints().setLightCombineMode(LightCombineMode.Off); final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight() / 2; for (int i = 0; i < _exampleInfo.length; i++) { _exampleInfo[i] = BasicText.createDefaultTextLabel("Text", "", 16); _exampleInfo[i].setTranslation(new Vector3(10, infoStartY - i * 20, 0)); textNodes.attachChild(_exampleInfo[i]); } textNodes.updateGeometricState(0.0); updateText(); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.V), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (!inMemoryTerrainData.isRunning()) { inMemoryTerrainData.startUpdates(); } else { inMemoryTerrainData.stopUpdates(); } updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.U), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { updateTerrain = !updateTerrain; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ONE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(5); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.TWO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(50); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.THREE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(400); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FOUR), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(1000); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SPACE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { groundCamera = !groundCamera; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.P), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { sphere.getSceneHints().setCullHint(CullHint.Always); } else if (sphere.getSceneHints().getCullHint() == CullHint.Always) { sphere.getSceneHints().setCullHint(CullHint.Dynamic); } updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.R), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setShowDebug(!terrain.getTextureClipmap().isShowDebug()); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.G), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.reloadShader(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FIVE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() / 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SIX), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() * 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SEVEN), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX() + 500.0, camera.getLocation().getY(), camera .getLocation().getZ()); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.EIGHT), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX() - 500.0, camera.getLocation().getY(), camera .getLocation().getZ()); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.NINE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation() .getZ() + 1500.0); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ZERO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation() .getZ() - 1500.0); } })); } private void setupDefaultStates() { _lightState.detachAll(); final DirectionalLight dLight = new DirectionalLight(); dLight.setEnabled(true); dLight.setAmbient(new ColorRGBA(0.4f, 0.4f, 0.5f, 1)); dLight.setDiffuse(new ColorRGBA(0.6f, 0.6f, 0.5f, 1)); dLight.setSpecular(new ColorRGBA(0.3f, 0.3f, 0.2f, 1)); dLight.setDirection(new Vector3(-1, -1, -1).normalizeLocal()); _lightState.attach(dLight); _lightState.setEnabled(true); final CullState cs = new CullState(); cs.setEnabled(true); cs.setCullFace(CullState.Face.Back); _root.setRenderState(cs); final FogState fs = new FogState(); fs.setStart(farPlane / 2.0f); fs.setEnd(farPlane); fs.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f)); fs.setDensityFunction(DensityFunction.Linear); _root.setRenderState(fs); } /** * Builds the sky box. */ private Skybox buildSkyBox() { final Skybox skybox = new Skybox("skybox", 10, 10, 10); final String dir = "images/skybox/"; final Texture north = TextureManager .load(dir + "1.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture south = TextureManager .load(dir + "3.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture east = TextureManager.load(dir + "2.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture west = TextureManager.load(dir + "4.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture up = TextureManager.load(dir + "6.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture down = TextureManager.load(dir + "5.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); skybox.setTexture(Skybox.Face.North, north); skybox.setTexture(Skybox.Face.West, west); skybox.setTexture(Skybox.Face.South, south); skybox.setTexture(Skybox.Face.East, east); skybox.setTexture(Skybox.Face.Up, up); skybox.setTexture(Skybox.Face.Down, down); return skybox; } /** * Update text information. */ private void updateText() { _exampleInfo[0].setText("[1/2/3] Moving speed: " + _controlHandle.getMoveSpeed() * 3.6 + " km/h"); _exampleInfo[1].setText("[P] Do picking: " + (sphere.getSceneHints().getCullHint() == CullHint.Dynamic)); _exampleInfo[2].setText("[SPACE] Toggle fly/walk: " + (groundCamera ? "walk" : "fly")); _exampleInfo[3].setText("[J] Regenerate heightmap/texture"); _exampleInfo[4].setText("[U] Freeze terrain(debug): " + !updateTerrain); _exampleInfo[5].setText("[V] Updating terrain data: " + inMemoryTerrainData.isRunning()); } } \ No newline at end of file
+/** * Copyright (c) 2008-2014 Ardor Labs, Inc. * * This file is part of Ardor3D. * * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ package com.ardor3d.example.terrain; import java.util.concurrent.Callable; import com.ardor3d.example.ExampleBase; import com.ardor3d.example.Purpose; import com.ardor3d.extension.terrain.client.Terrain; import com.ardor3d.extension.terrain.client.TerrainBuilder; import com.ardor3d.extension.terrain.client.TerrainDataProvider; import com.ardor3d.extension.terrain.providers.inmemory.InMemoryTerrainDataProvider; import com.ardor3d.extension.terrain.providers.inmemory.data.InMemoryTerrainData; import com.ardor3d.framework.Canvas; import com.ardor3d.framework.CanvasRenderer; import com.ardor3d.image.Texture; import com.ardor3d.input.Key; import com.ardor3d.input.logical.InputTrigger; import com.ardor3d.input.logical.KeyPressedCondition; import com.ardor3d.input.logical.TriggerAction; import com.ardor3d.input.logical.TwoInputStates; import com.ardor3d.intersection.PickingUtil; import com.ardor3d.intersection.PrimitivePickResults; import com.ardor3d.light.DirectionalLight; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.Ray3; import com.ardor3d.math.Vector3; import com.ardor3d.renderer.Camera; import com.ardor3d.renderer.RenderContext; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.queue.RenderBucketType; import com.ardor3d.renderer.state.CullState; import com.ardor3d.renderer.state.FogState; import com.ardor3d.renderer.state.FogState.DensityFunction; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.extension.Skybox; import com.ardor3d.scenegraph.hint.CullHint; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.shape.Sphere; import com.ardor3d.ui.text.BasicText; import com.ardor3d.util.GameTaskQueue; import com.ardor3d.util.GameTaskQueueManager; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.TextureManager; /** * Example showing the Geometry Clipmap Terrain system with 'MegaTextures' streaming from an in-memory data source. * Requires GLSL support. */ @Purpose(htmlDescriptionKey = "com.ardor3d.example.terrain.InMemoryTerrainExample", // thumbnailPath = "com/ardor3d/example/media/thumbnails/terrain_InMemoryTerrainExample.jpg", // maxHeapMemory = 128) public class InMemoryTerrainExample extends ExampleBase { private boolean updateTerrain = true; private final float farPlane = 8000.0f; private Terrain terrain; private final Sphere sphere = new Sphere("sp", 16, 16, 1); private final Ray3 pickRay = new Ray3(); private boolean groundCamera = false; private Camera terrainCamera; private Skybox skybox; private InMemoryTerrainData inMemoryTerrainData; /** Text fields used to present info about the example. */ private final BasicText _exampleInfo[] = new BasicText[6]; public static void main(final String[] args) { ExampleBase.start(InMemoryTerrainExample.class); } @Override protected void updateExample(final ReadOnlyTimer timer) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); // Make sure camera is above terrain final double height = terrain.getHeightAt(camera.getLocation().getX(), camera.getLocation().getZ()); if (height > -Float.MAX_VALUE && (groundCamera || camera.getLocation().getY() < height + 3)) { camera.setLocation(new Vector3(camera.getLocation().getX(), height + 3, camera.getLocation().getZ())); } if (updateTerrain) { terrainCamera.set(camera); } skybox.setTranslation(camera.getLocation()); // if we're picking... if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { // Set up our pick ray pickRay.setOrigin(camera.getLocation()); pickRay.setDirection(camera.getDirection()); // do pick and move the sphere final PrimitivePickResults pickResults = new PrimitivePickResults(); pickResults.setCheckDistance(true); PickingUtil.findPick(_root, pickRay, pickResults); if (pickResults.getNumber() != 0) { final Vector3 intersectionPoint = pickResults.getPickData(0).getIntersectionRecord() .getIntersectionPoint(0); sphere.setTranslation(intersectionPoint); // XXX: maybe change the color of the ball for valid vs. invalid? } } } /** * Initialize pssm pass and scene. */ @Override protected void initExample() { // Setup main camera. _canvas.setTitle("Terrain Example"); _canvas.getCanvasRenderer().getCamera().setLocation(new Vector3(0, 300, 0)); _canvas.getCanvasRenderer().getCamera().lookAt(new Vector3(1, 300, 1), Vector3.UNIT_Y); _canvas.getCanvasRenderer().getCamera().setFrustumPerspective(70.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth() / _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0f, farPlane); final CanvasRenderer canvasRenderer = _canvas.getCanvasRenderer(); final RenderContext renderContext = canvasRenderer.getRenderContext(); final Renderer renderer = canvasRenderer.getRenderer(); GameTaskQueueManager.getManager(renderContext).getQueue(GameTaskQueue.RENDER).enqueue(new Callable<Void>() { @Override public Void call() throws Exception { renderer.setBackgroundColor(ColorRGBA.GRAY); return null; } }); _controlHandle.setMoveSpeed(200); setupDefaultStates(); sphere.getSceneHints().setAllPickingHints(false); sphere.getSceneHints().setCullHint(CullHint.Always); _root.attachChild(sphere); try { // Keep a separate camera to be able to freeze terrain update final Camera camera = _canvas.getCanvasRenderer().getCamera(); terrainCamera = new Camera(camera); inMemoryTerrainData = new InMemoryTerrainData(2048, 9, 128, new Vector3(1, 200, 1)); final TerrainDataProvider terrainDataProvider = new InMemoryTerrainDataProvider(inMemoryTerrainData, true); terrain = new TerrainBuilder(terrainDataProvider, terrainCamera).setShowDebugPanels(true).build(); _root.attachChild(terrain); } catch (final Exception ex1) { System.out.println("Problem setting up terrain..."); ex1.printStackTrace(); } skybox = buildSkyBox(); skybox.getSceneHints().setAllPickingHints(false); _root.attachChild(skybox); // Setup labels for presenting example info. final Node textNodes = new Node("Text"); _root.attachChild(textNodes); textNodes.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); textNodes.getSceneHints().setLightCombineMode(LightCombineMode.Off); final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight() / 2; for (int i = 0; i < _exampleInfo.length; i++) { _exampleInfo[i] = BasicText.createDefaultTextLabel("Text", "", 16); _exampleInfo[i].setTranslation(new Vector3(10, infoStartY - i * 20, 0)); textNodes.attachChild(_exampleInfo[i]); } textNodes.updateGeometricState(0.0); updateText(); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.V), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (!inMemoryTerrainData.isRunning()) { inMemoryTerrainData.startUpdates(); } else { inMemoryTerrainData.stopUpdates(); } updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.U), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { updateTerrain = !updateTerrain; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ONE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(5); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.TWO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(50); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.THREE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(400); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FOUR), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(1000); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SPACE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { groundCamera = !groundCamera; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.P), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { sphere.getSceneHints().setCullHint(CullHint.Always); } else if (sphere.getSceneHints().getCullHint() == CullHint.Always) { sphere.getSceneHints().setCullHint(CullHint.Dynamic); } updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.R), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setShowDebug(!terrain.getTextureClipmap().isShowDebug()); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.G), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.reloadShader(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FIVE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() / 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SIX), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() * 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SEVEN), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX() + 500.0, camera.getLocation().getY(), camera.getLocation().getZ()); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.EIGHT), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX() - 500.0, camera.getLocation().getY(), camera.getLocation().getZ()); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.NINE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation().getZ() + 1500.0); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ZERO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation().getZ() - 1500.0); } })); } private void setupDefaultStates() { _lightState.detachAll(); final DirectionalLight dLight = new DirectionalLight(); dLight.setEnabled(true); dLight.setAmbient(new ColorRGBA(0.4f, 0.4f, 0.5f, 1)); dLight.setDiffuse(new ColorRGBA(0.6f, 0.6f, 0.5f, 1)); dLight.setSpecular(new ColorRGBA(0.3f, 0.3f, 0.2f, 1)); dLight.setDirection(new Vector3(-1, -1, -1).normalizeLocal()); _lightState.attach(dLight); _lightState.setEnabled(true); final CullState cs = new CullState(); cs.setEnabled(true); cs.setCullFace(CullState.Face.Back); _root.setRenderState(cs); final FogState fs = new FogState(); fs.setStart(farPlane / 2.0f); fs.setEnd(farPlane); fs.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f)); fs.setDensityFunction(DensityFunction.Linear); _root.setRenderState(fs); } /** * Builds the sky box. * * @return the sky box */ private Skybox buildSkyBox() { final Skybox skybox = new Skybox("skybox", 10, 10, 10); final String dir = "images/skybox/"; final Texture north = TextureManager.load(dir + "1.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture south = TextureManager.load(dir + "3.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture east = TextureManager.load(dir + "2.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture west = TextureManager.load(dir + "4.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture up = TextureManager.load(dir + "6.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture down = TextureManager.load(dir + "5.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); skybox.setTexture(Skybox.Face.North, north); skybox.setTexture(Skybox.Face.West, west); skybox.setTexture(Skybox.Face.South, south); skybox.setTexture(Skybox.Face.East, east); skybox.setTexture(Skybox.Face.Up, up); skybox.setTexture(Skybox.Face.Down, down); return skybox; } /** * Update text information. */ private void updateText() { _exampleInfo[0].setText("[1/2/3] Moving speed: " + _controlHandle.getMoveSpeed() * 3.6 + " km/h"); _exampleInfo[1].setText("[P] Do picking: " + (sphere.getSceneHints().getCullHint() == CullHint.Dynamic)); _exampleInfo[2].setText("[SPACE] Toggle fly/walk: " + (groundCamera ? "walk" : "fly")); _exampleInfo[3].setText("[J] Regenerate heightmap/texture"); _exampleInfo[4].setText("[U] Freeze terrain(debug): " + !updateTerrain); _exampleInfo[5].setText("[V] Updating terrain data: " + inMemoryTerrainData.isRunning()); } } \ No newline at end of file
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/ProceduralTerrainExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/ProceduralTerrainExample.java
index a647485..e387682 100644
--- a/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/ProceduralTerrainExample.java
+++ b/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/ProceduralTerrainExample.java
@@ -1 +1 @@
-/** * Copyright (c) 2008-2014 Ardor Labs, Inc. * * This file is part of Ardor3D. * * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ package com.ardor3d.example.terrain; import java.util.concurrent.Callable; import com.ardor3d.example.ExampleBase; import com.ardor3d.example.Purpose; import com.ardor3d.extension.terrain.client.Terrain; import com.ardor3d.extension.terrain.client.TerrainBuilder; import com.ardor3d.extension.terrain.client.TerrainDataProvider; import com.ardor3d.extension.terrain.providers.procedural.ProceduralTerrainDataProvider; import com.ardor3d.framework.Canvas; import com.ardor3d.framework.CanvasRenderer; import com.ardor3d.image.Texture; import com.ardor3d.input.Key; import com.ardor3d.input.logical.InputTrigger; import com.ardor3d.input.logical.KeyPressedCondition; import com.ardor3d.input.logical.TriggerAction; import com.ardor3d.input.logical.TwoInputStates; import com.ardor3d.intersection.PickingUtil; import com.ardor3d.intersection.PrimitivePickResults; import com.ardor3d.light.DirectionalLight; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.Ray3; import com.ardor3d.math.Vector3; import com.ardor3d.math.functions.FbmFunction3D; import com.ardor3d.math.functions.Function3D; import com.ardor3d.math.functions.Functions; import com.ardor3d.renderer.Camera; import com.ardor3d.renderer.RenderContext; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.queue.RenderBucketType; import com.ardor3d.renderer.state.CullState; import com.ardor3d.renderer.state.FogState; import com.ardor3d.renderer.state.FogState.DensityFunction; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.extension.Skybox; import com.ardor3d.scenegraph.hint.CullHint; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.shape.Sphere; import com.ardor3d.ui.text.BasicText; import com.ardor3d.util.GameTaskQueue; import com.ardor3d.util.GameTaskQueueManager; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.TextureManager; /** * Example showing the Geometry Clipmap Terrain system with 'MegaTextures' using content procedurally generated * on-the-fly. Requires GLSL support. */ @Purpose(htmlDescriptionKey = "com.ardor3d.example.terrain.ProceduralTerrainExample", // thumbnailPath = "com/ardor3d/example/media/thumbnails/terrain_ProceduralTerrainExample.jpg", // maxHeapMemory = 64) public class ProceduralTerrainExample extends ExampleBase { private boolean updateTerrain = true; private final float farPlane = 8000.0f; private Terrain terrain; private final Sphere sphere = new Sphere("sp", 16, 16, 1); private final Ray3 pickRay = new Ray3(); private boolean groundCamera = false; private Camera terrainCamera; private Skybox skybox; /** Text fields used to present info about the example. */ private final BasicText _exampleInfo[] = new BasicText[5]; public static void main(final String[] args) { ExampleBase.start(ProceduralTerrainExample.class); } @Override protected void updateExample(final ReadOnlyTimer timer) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); // Make sure camera is above terrain final double height = terrain.getHeightAt(camera.getLocation().getX(), camera.getLocation().getZ()); if (height > -Float.MAX_VALUE && (groundCamera || camera.getLocation().getY() < height + 3)) { camera.setLocation(new Vector3(camera.getLocation().getX(), height + 3, camera.getLocation().getZ())); } if (updateTerrain) { terrainCamera.set(camera); } skybox.setTranslation(camera.getLocation()); // if we're picking... if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { // Set up our pick ray pickRay.setOrigin(camera.getLocation()); pickRay.setDirection(camera.getDirection()); // do pick and move the sphere final PrimitivePickResults pickResults = new PrimitivePickResults(); pickResults.setCheckDistance(true); PickingUtil.findPick(_root, pickRay, pickResults); if (pickResults.getNumber() != 0) { final Vector3 intersectionPoint = pickResults.getPickData(0).getIntersectionRecord() .getIntersectionPoint(0); sphere.setTranslation(intersectionPoint); // XXX: maybe change the color of the ball for valid vs. invalid? } } } /** * Initialize pssm pass and scene. */ @Override protected void initExample() { // Setup main camera. _canvas.setTitle("Procedural Terrain Example"); _canvas.getCanvasRenderer().getCamera().setLocation(new Vector3(0, 300, 0)); _canvas.getCanvasRenderer().getCamera().lookAt(new Vector3(1, 300, 1), Vector3.UNIT_Y); _canvas.getCanvasRenderer() .getCamera() .setFrustumPerspective( 70.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth() / _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0f, farPlane); final CanvasRenderer canvasRenderer = _canvas.getCanvasRenderer(); final RenderContext renderContext = canvasRenderer.getRenderContext(); final Renderer renderer = canvasRenderer.getRenderer(); GameTaskQueueManager.getManager(renderContext).getQueue(GameTaskQueue.RENDER).enqueue(new Callable<Void>() { @Override public Void call() throws Exception { renderer.setBackgroundColor(ColorRGBA.BLUE); return null; } }); _controlHandle.setMoveSpeed(50); setupDefaultStates(); sphere.getSceneHints().setAllPickingHints(false); sphere.getSceneHints().setCullHint(CullHint.Always); _root.attachChild(sphere); try { // Keep a separate camera to be able to freeze terrain update final Camera camera = _canvas.getCanvasRenderer().getCamera(); terrainCamera = new Camera(camera); final double scale = 1.0 / 4000.0; Function3D functionTmp = new FbmFunction3D(Functions.simplexNoise(), 9, 0.5, 0.5, 3.14); functionTmp = Functions.clamp(functionTmp, -1.2, 1.2); final Function3D function = Functions.scaleInput(functionTmp, scale, scale, 1); final TerrainDataProvider terrainDataProvider = new ProceduralTerrainDataProvider(function, new Vector3(1, 200, 1), -1.2f, 1.2f); terrain = new TerrainBuilder(terrainDataProvider, terrainCamera).setShowDebugPanels(true).build(); _root.attachChild(terrain); } catch (final Exception ex1) { System.out.println("Problem setting up terrain..."); ex1.printStackTrace(); } skybox = buildSkyBox(); skybox.getSceneHints().setAllPickingHints(false); _root.attachChild(skybox); // Setup labels for presenting example info. final Node textNodes = new Node("Text"); _root.attachChild(textNodes); textNodes.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); textNodes.getSceneHints().setLightCombineMode(LightCombineMode.Off); final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight() / 2; for (int i = 0; i < _exampleInfo.length; i++) { _exampleInfo[i] = BasicText.createDefaultTextLabel("Text", "", 16); _exampleInfo[i].setTranslation(new Vector3(10, infoStartY - i * 20, 0)); textNodes.attachChild(_exampleInfo[i]); } textNodes.updateGeometricState(0.0); updateText(); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.U), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { updateTerrain = !updateTerrain; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ONE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(5); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.TWO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(50); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.THREE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(200); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FOUR), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(500); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SPACE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { groundCamera = !groundCamera; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.P), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { sphere.getSceneHints().setCullHint(CullHint.Always); } else if (sphere.getSceneHints().getCullHint() == CullHint.Always) { sphere.getSceneHints().setCullHint(CullHint.Dynamic); } updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.R), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setShowDebug(!terrain.getTextureClipmap().isShowDebug()); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.G), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.reloadShader(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FIVE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() / 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SIX), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() * 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SEVEN), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(-5000, 500, -5000); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.EIGHT), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(5000, 500, 5000); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.NINE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation() .getZ() + 1500.0); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ZERO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation() .getZ() - 1500.0); } })); } private void setupDefaultStates() { _lightState.detachAll(); final DirectionalLight dLight = new DirectionalLight(); dLight.setEnabled(true); dLight.setAmbient(new ColorRGBA(0.4f, 0.4f, 0.5f, 1)); dLight.setDiffuse(new ColorRGBA(0.6f, 0.6f, 0.5f, 1)); dLight.setSpecular(new ColorRGBA(0.3f, 0.3f, 0.2f, 1)); dLight.setDirection(new Vector3(-1, -1, -1).normalizeLocal()); _lightState.attach(dLight); _lightState.setEnabled(true); final CullState cs = new CullState(); cs.setEnabled(true); cs.setCullFace(CullState.Face.Back); _root.setRenderState(cs); final FogState fs = new FogState(); fs.setStart(farPlane / 2.0f); fs.setEnd(farPlane); fs.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f)); fs.setDensityFunction(DensityFunction.Linear); _root.setRenderState(fs); } /** * Builds the sky box. */ private Skybox buildSkyBox() { final Skybox skybox = new Skybox("skybox", 10, 10, 10); final String dir = "images/skybox/"; final Texture north = TextureManager .load(dir + "1.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture south = TextureManager .load(dir + "3.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture east = TextureManager.load(dir + "2.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture west = TextureManager.load(dir + "4.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture up = TextureManager.load(dir + "6.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture down = TextureManager.load(dir + "5.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); skybox.setTexture(Skybox.Face.North, north); skybox.setTexture(Skybox.Face.West, west); skybox.setTexture(Skybox.Face.South, south); skybox.setTexture(Skybox.Face.East, east); skybox.setTexture(Skybox.Face.Up, up); skybox.setTexture(Skybox.Face.Down, down); return skybox; } /** * Update text information. */ private void updateText() { _exampleInfo[0].setText("[1/2/3/4] Moving speed: " + _controlHandle.getMoveSpeed() * 3.6 + " km/h"); _exampleInfo[1].setText("[P] Do picking: " + (sphere.getSceneHints().getCullHint() == CullHint.Dynamic)); _exampleInfo[2].setText("[SPACE] Toggle fly/walk: " + (groundCamera ? "walk" : "fly")); _exampleInfo[3].setText("[J] Regenerate heightmap/texture"); _exampleInfo[4].setText("[U] Freeze terrain(debug): " + !updateTerrain); } } \ No newline at end of file
+/** * Copyright (c) 2008-2014 Ardor Labs, Inc. * * This file is part of Ardor3D. * * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ package com.ardor3d.example.terrain; import java.util.concurrent.Callable; import com.ardor3d.example.ExampleBase; import com.ardor3d.example.Purpose; import com.ardor3d.extension.terrain.client.Terrain; import com.ardor3d.extension.terrain.client.TerrainBuilder; import com.ardor3d.extension.terrain.client.TerrainDataProvider; import com.ardor3d.extension.terrain.providers.procedural.ProceduralTerrainDataProvider; import com.ardor3d.framework.Canvas; import com.ardor3d.framework.CanvasRenderer; import com.ardor3d.image.Texture; import com.ardor3d.input.Key; import com.ardor3d.input.logical.InputTrigger; import com.ardor3d.input.logical.KeyPressedCondition; import com.ardor3d.input.logical.TriggerAction; import com.ardor3d.input.logical.TwoInputStates; import com.ardor3d.intersection.PickingUtil; import com.ardor3d.intersection.PrimitivePickResults; import com.ardor3d.light.DirectionalLight; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.Ray3; import com.ardor3d.math.Vector3; import com.ardor3d.math.functions.FbmFunction3D; import com.ardor3d.math.functions.Function3D; import com.ardor3d.math.functions.Functions; import com.ardor3d.renderer.Camera; import com.ardor3d.renderer.RenderContext; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.queue.RenderBucketType; import com.ardor3d.renderer.state.CullState; import com.ardor3d.renderer.state.FogState; import com.ardor3d.renderer.state.FogState.DensityFunction; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.extension.Skybox; import com.ardor3d.scenegraph.hint.CullHint; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.shape.Sphere; import com.ardor3d.ui.text.BasicText; import com.ardor3d.util.GameTaskQueue; import com.ardor3d.util.GameTaskQueueManager; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.TextureManager; /** * Example showing the Geometry Clipmap Terrain system with 'MegaTextures' using content procedurally generated * on-the-fly. Requires GLSL support. */ @Purpose(htmlDescriptionKey = "com.ardor3d.example.terrain.ProceduralTerrainExample", // thumbnailPath = "com/ardor3d/example/media/thumbnails/terrain_ProceduralTerrainExample.jpg", // maxHeapMemory = 64) public class ProceduralTerrainExample extends ExampleBase { private boolean updateTerrain = true; private final float farPlane = 8000.0f; private Terrain terrain; private final Sphere sphere = new Sphere("sp", 16, 16, 1); private final Ray3 pickRay = new Ray3(); private boolean groundCamera = false; private Camera terrainCamera; private Skybox skybox; /** Text fields used to present info about the example. */ private final BasicText _exampleInfo[] = new BasicText[5]; public static void main(final String[] args) { ExampleBase.start(ProceduralTerrainExample.class); } @Override protected void updateExample(final ReadOnlyTimer timer) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); // Make sure camera is above terrain final double height = terrain.getHeightAt(camera.getLocation().getX(), camera.getLocation().getZ()); if (height > -Float.MAX_VALUE && (groundCamera || camera.getLocation().getY() < height + 3)) { camera.setLocation(new Vector3(camera.getLocation().getX(), height + 3, camera.getLocation().getZ())); } if (updateTerrain) { terrainCamera.set(camera); } skybox.setTranslation(camera.getLocation()); // if we're picking... if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { // Set up our pick ray pickRay.setOrigin(camera.getLocation()); pickRay.setDirection(camera.getDirection()); // do pick and move the sphere final PrimitivePickResults pickResults = new PrimitivePickResults(); pickResults.setCheckDistance(true); PickingUtil.findPick(_root, pickRay, pickResults); if (pickResults.getNumber() != 0) { final Vector3 intersectionPoint = pickResults.getPickData(0).getIntersectionRecord() .getIntersectionPoint(0); sphere.setTranslation(intersectionPoint); // XXX: maybe change the color of the ball for valid vs. invalid? } } } /** * Initialize pssm pass and scene. */ @Override protected void initExample() { // Setup main camera. _canvas.setTitle("Procedural Terrain Example"); _canvas.getCanvasRenderer().getCamera().setLocation(new Vector3(0, 300, 0)); _canvas.getCanvasRenderer().getCamera().lookAt(new Vector3(1, 300, 1), Vector3.UNIT_Y); _canvas.getCanvasRenderer().getCamera().setFrustumPerspective(70.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth() / _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0f, farPlane); final CanvasRenderer canvasRenderer = _canvas.getCanvasRenderer(); final RenderContext renderContext = canvasRenderer.getRenderContext(); final Renderer renderer = canvasRenderer.getRenderer(); GameTaskQueueManager.getManager(renderContext).getQueue(GameTaskQueue.RENDER).enqueue(new Callable<Void>() { @Override public Void call() throws Exception { renderer.setBackgroundColor(ColorRGBA.BLUE); return null; } }); _controlHandle.setMoveSpeed(50); setupDefaultStates(); sphere.getSceneHints().setAllPickingHints(false); sphere.getSceneHints().setCullHint(CullHint.Always); _root.attachChild(sphere); try { // Keep a separate camera to be able to freeze terrain update final Camera camera = _canvas.getCanvasRenderer().getCamera(); terrainCamera = new Camera(camera); final double scale = 1.0 / 4000.0; Function3D functionTmp = new FbmFunction3D(Functions.simplexNoise(), 9, 0.5, 0.5, 3.14); functionTmp = Functions.clamp(functionTmp, -1.2, 1.2); final Function3D function = Functions.scaleInput(functionTmp, scale, scale, 1); final TerrainDataProvider terrainDataProvider = new ProceduralTerrainDataProvider(function, new Vector3(1, 200, 1), -1.2f, 1.2f); terrain = new TerrainBuilder(terrainDataProvider, terrainCamera).setShowDebugPanels(true).build(); _root.attachChild(terrain); } catch (final Exception ex1) { System.out.println("Problem setting up terrain..."); ex1.printStackTrace(); } skybox = buildSkyBox(); skybox.getSceneHints().setAllPickingHints(false); _root.attachChild(skybox); // Setup labels for presenting example info. final Node textNodes = new Node("Text"); _root.attachChild(textNodes); textNodes.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); textNodes.getSceneHints().setLightCombineMode(LightCombineMode.Off); final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight() / 2; for (int i = 0; i < _exampleInfo.length; i++) { _exampleInfo[i] = BasicText.createDefaultTextLabel("Text", "", 16); _exampleInfo[i].setTranslation(new Vector3(10, infoStartY - i * 20, 0)); textNodes.attachChild(_exampleInfo[i]); } textNodes.updateGeometricState(0.0); updateText(); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.U), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { updateTerrain = !updateTerrain; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ONE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(5); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.TWO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(50); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.THREE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(200); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FOUR), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(500); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SPACE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { groundCamera = !groundCamera; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.P), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { sphere.getSceneHints().setCullHint(CullHint.Always); } else if (sphere.getSceneHints().getCullHint() == CullHint.Always) { sphere.getSceneHints().setCullHint(CullHint.Dynamic); } updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.R), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setShowDebug(!terrain.getTextureClipmap().isShowDebug()); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.G), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.reloadShader(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FIVE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() / 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SIX), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() * 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SEVEN), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(-5000, 500, -5000); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.EIGHT), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(5000, 500, 5000); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.NINE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation().getZ() + 1500.0); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ZERO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation().getZ() - 1500.0); } })); } private void setupDefaultStates() { _lightState.detachAll(); final DirectionalLight dLight = new DirectionalLight(); dLight.setEnabled(true); dLight.setAmbient(new ColorRGBA(0.4f, 0.4f, 0.5f, 1)); dLight.setDiffuse(new ColorRGBA(0.6f, 0.6f, 0.5f, 1)); dLight.setSpecular(new ColorRGBA(0.3f, 0.3f, 0.2f, 1)); dLight.setDirection(new Vector3(-1, -1, -1).normalizeLocal()); _lightState.attach(dLight); _lightState.setEnabled(true); final CullState cs = new CullState(); cs.setEnabled(true); cs.setCullFace(CullState.Face.Back); _root.setRenderState(cs); final FogState fs = new FogState(); fs.setStart(farPlane / 2.0f); fs.setEnd(farPlane); fs.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f)); fs.setDensityFunction(DensityFunction.Linear); _root.setRenderState(fs); } /** * Builds the sky box. * * @return the sky box */ private Skybox buildSkyBox() { final Skybox skybox = new Skybox("skybox", 10, 10, 10); final String dir = "images/skybox/"; final Texture north = TextureManager.load(dir + "1.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture south = TextureManager.load(dir + "3.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture east = TextureManager.load(dir + "2.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture west = TextureManager.load(dir + "4.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture up = TextureManager.load(dir + "6.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture down = TextureManager.load(dir + "5.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); skybox.setTexture(Skybox.Face.North, north); skybox.setTexture(Skybox.Face.West, west); skybox.setTexture(Skybox.Face.South, south); skybox.setTexture(Skybox.Face.East, east); skybox.setTexture(Skybox.Face.Up, up); skybox.setTexture(Skybox.Face.Down, down); return skybox; } /** * Update text information. */ private void updateText() { _exampleInfo[0].setText("[1/2/3/4] Moving speed: " + _controlHandle.getMoveSpeed() * 3.6 + " km/h"); _exampleInfo[1].setText("[P] Do picking: " + (sphere.getSceneHints().getCullHint() == CullHint.Dynamic)); _exampleInfo[2].setText("[SPACE] Toggle fly/walk: " + (groundCamera ? "walk" : "fly")); _exampleInfo[3].setText("[J] Regenerate heightmap/texture"); _exampleInfo[4].setText("[U] Freeze terrain(debug): " + !updateTerrain); } } \ No newline at end of file
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/TerrainWaterExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/TerrainWaterExample.java
index b17b63f..b6a3781 100644
--- a/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/TerrainWaterExample.java
+++ b/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/TerrainWaterExample.java
@@ -1 +1 @@
-/** * Copyright (c) 2008-2014 Ardor Labs, Inc. * * This file is part of Ardor3D. * * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ package com.ardor3d.example.terrain; import java.nio.FloatBuffer; import com.ardor3d.example.ExampleBase; import com.ardor3d.example.Purpose; import com.ardor3d.extension.effect.water.WaterNode; import com.ardor3d.extension.terrain.client.Terrain; import com.ardor3d.extension.terrain.client.TerrainBuilder; import com.ardor3d.extension.terrain.client.TerrainDataProvider; import com.ardor3d.extension.terrain.providers.procedural.ProceduralTerrainDataProvider; import com.ardor3d.framework.Canvas; import com.ardor3d.image.Texture; import com.ardor3d.input.Key; import com.ardor3d.input.logical.InputTrigger; import com.ardor3d.input.logical.KeyPressedCondition; import com.ardor3d.input.logical.TriggerAction; import com.ardor3d.input.logical.TwoInputStates; import com.ardor3d.intersection.PickingUtil; import com.ardor3d.intersection.PrimitivePickResults; import com.ardor3d.light.DirectionalLight; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.Plane; import com.ardor3d.math.Ray3; import com.ardor3d.math.Vector3; import com.ardor3d.math.functions.FbmFunction3D; import com.ardor3d.math.functions.Function3D; import com.ardor3d.math.functions.Functions; import com.ardor3d.renderer.Camera; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.queue.RenderBucketType; import com.ardor3d.renderer.state.CullState; import com.ardor3d.renderer.state.FogState; import com.ardor3d.renderer.state.FogState.DensityFunction; import com.ardor3d.renderer.state.TextureState; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.extension.Skybox; import com.ardor3d.scenegraph.hint.CullHint; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.shape.Quad; import com.ardor3d.scenegraph.shape.Sphere; import com.ardor3d.ui.text.BasicText; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.TextureManager; /** * Example showing how to combine the terrain and water systems. Requires GLSL support. */ @Purpose(htmlDescriptionKey = "com.ardor3d.example.terrain.TerrainWaterExample", // thumbnailPath = "com/ardor3d/example/media/thumbnails/terrain_TerrainWaterExample.jpg", // maxHeapMemory = 128) public class TerrainWaterExample extends ExampleBase { private final int SIZE = 2048; private Terrain terrain; private boolean updateTerrain = true; private final float farPlane = 3500.0f; private final float heightOffset = 3.0f; /** The water instance taking care of the water rendering. */ private WaterNode waterNode; private boolean aboveWater = true; /** Node containing debug quads for showing waternode render textures. */ private Node debugQuadsNode; /** The quad used as geometry for the water. */ private Quad waterQuad; private boolean groundCamera = false; private Camera terrainCamera; private Skybox skybox; private final Sphere sphere = new Sphere("sp", 16, 16, 1); private final double textureScale = 0.05; private FogState fogState; private boolean showUI = true; private final Ray3 pickRay = new Ray3(); /** Text fields used to present info about the example. */ private final BasicText _exampleInfo[] = new BasicText[8]; /** * The main method. * * @param args * the arguments */ public static void main(final String[] args) { start(TerrainWaterExample.class); } private double counter = 0; private int frames = 0; /** * Update the PassManager, skybox, camera position, etc. * * @param timer * the application timer */ @Override protected void updateExample(final ReadOnlyTimer timer) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); final double height = terrain.getHeightAt(camera.getLocation().getX(), camera.getLocation().getZ()) + heightOffset; if (groundCamera || camera.getLocation().getY() < height) { camera.setLocation(new Vector3(camera.getLocation().getX(), height, camera.getLocation().getZ())); } if (aboveWater && camera.getLocation().getY() < waterNode.getWaterHeight()) { fogState.setStart(-1000f); fogState.setEnd(farPlane / 10f); fogState.setColor(new ColorRGBA(0.0f, 0.0f, 0.1f, 1.0f)); aboveWater = false; } else if (!aboveWater && camera.getLocation().getY() >= waterNode.getWaterHeight()) { fogState.setStart(farPlane / 2.0f); fogState.setEnd(farPlane); fogState.setColor(new ColorRGBA(0.96f, 0.97f, 1.0f, 1.0f)); aboveWater = true; } if (updateTerrain) { terrainCamera.set(camera); } skybox.setTranslation(camera.getLocation()); counter += timer.getTimePerFrame(); frames++; if (counter > 1) { final double fps = (frames / counter); counter = 0; frames = 0; System.out.printf("%7.1f FPS\n", fps); } // if we're picking... if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { // Set up our pick ray pickRay.setOrigin(camera.getLocation()); pickRay.setDirection(camera.getDirection()); // do pick and move the sphere final PrimitivePickResults pickResults = new PrimitivePickResults(); pickResults.setCheckDistance(true); PickingUtil.findPick(_root, pickRay, pickResults); if (pickResults.getNumber() != 0) { final Vector3 intersectionPoint = pickResults.getPickData(0).getIntersectionRecord() .getIntersectionPoint(0); sphere.setTranslation(intersectionPoint); // XXX: maybe change the color of the ball for valid vs. invalid? } } final Vector3 transVec = new Vector3(camera.getLocation().getX(), waterNode.getWaterHeight(), camera .getLocation().getZ()); setTextureCoords(0, transVec.getX(), -transVec.getZ(), textureScale); // vertex coords setVertexCoords(transVec.getX(), transVec.getY(), transVec.getZ()); waterNode.update(timer.getTimePerFrame()); } /** * Render example. * * @param renderer * the renderer */ @Override protected void renderExample(final Renderer renderer) { super.renderExample(renderer); if (debugQuadsNode == null) { createDebugQuads(); _root.attachChild(debugQuadsNode); } } /** * Initialize pssm pass and scene. */ @Override protected void initExample() { // Setup main camera. _canvas.setTitle("Terrain + Water - Example"); _canvas.getCanvasRenderer().getCamera().setLocation(new Vector3(0, 100, 0)); _canvas.getCanvasRenderer().getCamera().lookAt(new Vector3(0, 100, 1), Vector3.UNIT_Y); _canvas.getCanvasRenderer().getCamera().setFrustumPerspective( 65.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth() / _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0f, farPlane); _controlHandle.setMoveSpeed(50); _lightState.detachAll(); final DirectionalLight dLight = new DirectionalLight(); dLight.setEnabled(true); dLight.setAmbient(new ColorRGBA(0.4f, 0.4f, 0.5f, 1)); dLight.setDiffuse(new ColorRGBA(0.6f, 0.6f, 0.5f, 1)); dLight.setSpecular(new ColorRGBA(0.3f, 0.3f, 0.2f, 1)); dLight.setDirection(new Vector3(-1, -1, -1).normalizeLocal()); _lightState.attach(dLight); _lightState.setEnabled(true); final CullState cs = new CullState(); cs.setEnabled(true); cs.setCullFace(CullState.Face.Back); _root.setRenderState(cs); fogState = new FogState(); fogState.setStart(farPlane / 2.0f); fogState.setEnd(farPlane); fogState.setColor(new ColorRGBA(0.96f, 0.97f, 1.0f, 1.0f)); fogState.setDensityFunction(DensityFunction.Linear); _root.setRenderState(fogState); // add our sphere, but have it off for now. sphere.getSceneHints().setCullHint(CullHint.Always); sphere.getSceneHints().setAllPickingHints(false); _root.attachChild(sphere); try { // Keep a separate camera to be able to freeze terrain update final Camera camera = _canvas.getCanvasRenderer().getCamera(); terrainCamera = new Camera(camera); final double scale = 1.0 / 4000.0; Function3D functionTmp = new FbmFunction3D(Functions.simplexNoise(), 9, 0.5, 0.5, 3.14); functionTmp = Functions.clamp(functionTmp, -1.2, 1.2); final Function3D function = Functions.scaleInput(functionTmp, scale, scale, 1); final TerrainDataProvider terrainDataProvider = new ProceduralTerrainDataProvider(function, new Vector3(1, 200, 1), -1.2f, 1.2f); terrain = new TerrainBuilder(terrainDataProvider, terrainCamera).setShowDebugPanels(true).build(); } catch (final Exception ex1) { ex1.printStackTrace(); } final Node reflectedNode = new Node("reflectNode"); reflectedNode.attachChild(terrain); skybox = buildSkyBox(); skybox.getSceneHints().setAllPickingHints(false); reflectedNode.attachChild(skybox); final Camera cam = _canvas.getCanvasRenderer().getCamera(); // Create a new WaterNode with refraction enabled. waterNode = new WaterNode(cam, 2, false, true); // Setup textures to use for the water. waterNode.setNormalMapTextureString("images/water/normalmap3.dds"); waterNode.setDudvMapTextureString("images/water/dudvmap.png"); waterNode.setFallbackMapTextureString("images/water/water2.png"); waterNode.useFadeToFogColor(true); waterNode.setSpeedReflection(0.02); waterNode.setSpeedReflection(-0.01); // setting to default value just to show waterNode.setWaterPlane(new Plane(new Vector3(0.0, 1.0, 0.0), 40.0)); // Create a quad to use as geometry for the water. waterQuad = new Quad("waterQuad", 1, 1); // Hack the quad normals to point up in the y-axis. Since we are manipulating the vertices as // we move this is more convenient than rotating the quad. final FloatBuffer normBuf = waterQuad.getMeshData().getNormalBuffer(); normBuf.clear(); normBuf.put(0).put(1).put(0); normBuf.put(0).put(1).put(0); normBuf.put(0).put(1).put(0); normBuf.put(0).put(1).put(0); waterNode.attachChild(waterQuad); waterNode.addReflectedScene(reflectedNode); waterNode.setSkybox(skybox); _root.attachChild(reflectedNode); _root.attachChild(waterNode); // Setup cam above water and terrain final Camera camera = _canvas.getCanvasRenderer().getCamera(); final double height = Math.max(terrain.getHeightAt(camera.getLocation().getX(), camera.getLocation().getZ()), waterNode.getWaterHeight()) + heightOffset; if (camera.getLocation().getY() < height) { camera.setLocation(new Vector3(camera.getLocation().getX(), height, camera.getLocation().getZ())); } // Setup labels for presenting example info. final Node textNodes = new Node("Text"); _root.attachChild(textNodes); textNodes.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); textNodes.getSceneHints().setLightCombineMode(LightCombineMode.Off); final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight() - 20; for (int i = 0; i < _exampleInfo.length; i++) { _exampleInfo[i] = BasicText.createDefaultTextLabel("Text", "", 16); _exampleInfo[i].setTranslation(new Vector3(10, infoStartY - i * 20, 0)); textNodes.attachChild(_exampleInfo[i]); } textNodes.updateGeometricState(0.0); updateText(); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.U), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { updateTerrain = !updateTerrain; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ONE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(5); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.TWO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(50); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.THREE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(400); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SPACE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { groundCamera = !groundCamera; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.P), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { sphere.getSceneHints().setCullHint( sphere.getSceneHints().getCullHint() == CullHint.Always ? CullHint.Dynamic : CullHint.Always); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.V), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { showUI = !showUI; if (showUI) { textNodes.getSceneHints().setCullHint(CullHint.Never); debugQuadsNode.getSceneHints().setCullHint(CullHint.Never); } else { textNodes.getSceneHints().setCullHint(CullHint.Always); debugQuadsNode.getSceneHints().setCullHint(CullHint.Always); } updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.B), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { waterNode.setDoBlurReflection(!waterNode.isDoBlurReflection()); waterNode.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.F), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(new Vector3(camera.getLocation().getX() + 5000, camera.getLocation().getY(), camera .getLocation().getZ())); updateText(); } })); } /** * Sets the vertex coords of the quad. * * @param x * the x * @param y * the y * @param z * the z */ private void setVertexCoords(final double x, final double y, final double z) { final FloatBuffer vertBuf = waterQuad.getMeshData().getVertexBuffer(); vertBuf.clear(); vertBuf.put((float) (x - farPlane)).put((float) y).put((float) (z - farPlane)); vertBuf.put((float) (x - farPlane)).put((float) y).put((float) (z + farPlane)); vertBuf.put((float) (x + farPlane)).put((float) y).put((float) (z + farPlane)); vertBuf.put((float) (x + farPlane)).put((float) y).put((float) (z - farPlane)); } /** * Sets the texture coords of the quad. * * @param buffer * the buffer * @param x * the x * @param y * the y * @param textureScale * the texture scale */ private void setTextureCoords(final int buffer, double x, double y, double textureScale) { x *= textureScale * 0.5f; y *= textureScale * 0.5f; textureScale = farPlane * textureScale; FloatBuffer texBuf; texBuf = waterQuad.getMeshData().getTextureBuffer(buffer); texBuf.clear(); texBuf.put((float) x).put((float) (textureScale + y)); texBuf.put((float) x).put((float) y); texBuf.put((float) (textureScale + x)).put((float) y); texBuf.put((float) (textureScale + x)).put((float) (textureScale + y)); } /** * Builds the sky box. */ private Skybox buildSkyBox() { final Skybox skybox = new Skybox("skybox", 10, 10, 10); final String dir = "images/skybox/"; final Texture north = TextureManager .load(dir + "1.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture south = TextureManager .load(dir + "3.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture east = TextureManager.load(dir + "2.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture west = TextureManager.load(dir + "4.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture up = TextureManager.load(dir + "6.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture down = TextureManager.load(dir + "5.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); skybox.setTexture(Skybox.Face.North, north); skybox.setTexture(Skybox.Face.West, west); skybox.setTexture(Skybox.Face.South, south); skybox.setTexture(Skybox.Face.East, east); skybox.setTexture(Skybox.Face.Up, up); skybox.setTexture(Skybox.Face.Down, down); return skybox; } /** * Update text information. */ private void updateText() { _exampleInfo[0].setText("Heightmap size: " + SIZE + "x" + SIZE); _exampleInfo[1].setText("Spec: One meter per heightmap value"); _exampleInfo[2].setText("[1/2/3] Moving speed: " + _controlHandle.getMoveSpeed() + " m/s"); _exampleInfo[3].setText("[U] Update terrain: " + updateTerrain); _exampleInfo[4].setText("[SPACE] Toggle fly/walk: " + (groundCamera ? "walk" : "fly")); _exampleInfo[5].setText("[P] Toggle showing a sphere that follows the ground using picking: " + (sphere.getSceneHints().getCullHint() != CullHint.Always)); _exampleInfo[6].setText("[B] Blur reflection: " + waterNode.isDoBlurReflection()); _exampleInfo[7].setText("[V] Show/Hide UI"); } /** * Creates the debug quads. */ private void createDebugQuads() { debugQuadsNode = new Node("quadNode"); debugQuadsNode.getSceneHints().setCullHint(CullHint.Never); final double quadSize = _canvas.getCanvasRenderer().getCamera().getWidth() / 10; Quad debugQuad = new Quad("reflectionQuad", quadSize, quadSize); debugQuad.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); debugQuad.getSceneHints().setCullHint(CullHint.Never); debugQuad.getSceneHints().setLightCombineMode(LightCombineMode.Off); TextureState ts = new TextureState(); ts.setTexture(waterNode.getTextureReflect()); debugQuad.setRenderState(ts); debugQuad.setTranslation(quadSize * 0.6, quadSize * 1.0, 1.0); debugQuadsNode.attachChild(debugQuad); if (waterNode.getTextureRefract() != null) { debugQuad = new Quad("refractionQuad", quadSize, quadSize); debugQuad.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); debugQuad.getSceneHints().setCullHint(CullHint.Never); debugQuad.getSceneHints().setLightCombineMode(LightCombineMode.Off); ts = new TextureState(); ts.setTexture(waterNode.getTextureRefract()); debugQuad.setRenderState(ts); debugQuad.setTranslation(quadSize * 0.6, quadSize * 2.1, 1.0); debugQuadsNode.attachChild(debugQuad); } } } \ No newline at end of file
+/** * Copyright (c) 2008-2014 Ardor Labs, Inc. * * This file is part of Ardor3D. * * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ package com.ardor3d.example.terrain; import java.nio.FloatBuffer; import com.ardor3d.example.ExampleBase; import com.ardor3d.example.Purpose; import com.ardor3d.extension.effect.water.WaterNode; import com.ardor3d.extension.terrain.client.Terrain; import com.ardor3d.extension.terrain.client.TerrainBuilder; import com.ardor3d.extension.terrain.client.TerrainDataProvider; import com.ardor3d.extension.terrain.providers.procedural.ProceduralTerrainDataProvider; import com.ardor3d.framework.Canvas; import com.ardor3d.image.Texture; import com.ardor3d.input.Key; import com.ardor3d.input.logical.InputTrigger; import com.ardor3d.input.logical.KeyPressedCondition; import com.ardor3d.input.logical.TriggerAction; import com.ardor3d.input.logical.TwoInputStates; import com.ardor3d.intersection.PickingUtil; import com.ardor3d.intersection.PrimitivePickResults; import com.ardor3d.light.DirectionalLight; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.Plane; import com.ardor3d.math.Ray3; import com.ardor3d.math.Vector3; import com.ardor3d.math.functions.FbmFunction3D; import com.ardor3d.math.functions.Function3D; import com.ardor3d.math.functions.Functions; import com.ardor3d.renderer.Camera; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.queue.RenderBucketType; import com.ardor3d.renderer.state.CullState; import com.ardor3d.renderer.state.FogState; import com.ardor3d.renderer.state.FogState.DensityFunction; import com.ardor3d.renderer.state.TextureState; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.extension.Skybox; import com.ardor3d.scenegraph.hint.CullHint; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.shape.Quad; import com.ardor3d.scenegraph.shape.Sphere; import com.ardor3d.ui.text.BasicText; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.TextureManager; /** * Example showing how to combine the terrain and water systems. Requires GLSL support. */ @Purpose(htmlDescriptionKey = "com.ardor3d.example.terrain.TerrainWaterExample", // thumbnailPath = "com/ardor3d/example/media/thumbnails/terrain_TerrainWaterExample.jpg", // maxHeapMemory = 128) public class TerrainWaterExample extends ExampleBase { private final int SIZE = 2048; private Terrain terrain; private boolean updateTerrain = true; private final float farPlane = 3500.0f; private final float heightOffset = 3.0f; /** The water instance taking care of the water rendering. */ private WaterNode waterNode; private boolean aboveWater = true; /** Node containing debug quads for showing waternode render textures. */ private Node debugQuadsNode; /** The quad used as geometry for the water. */ private Quad waterQuad; private boolean groundCamera = false; private Camera terrainCamera; private Skybox skybox; private final Sphere sphere = new Sphere("sp", 16, 16, 1); private final double textureScale = 0.05; private FogState fogState; private boolean showUI = true; private final Ray3 pickRay = new Ray3(); /** Text fields used to present info about the example. */ private final BasicText _exampleInfo[] = new BasicText[8]; /** * The main method. * * @param args * the arguments */ public static void main(final String[] args) { start(TerrainWaterExample.class); } private double counter = 0; private int frames = 0; /** * Update the PassManager, skybox, camera position, etc. * * @param timer * the application timer */ @Override protected void updateExample(final ReadOnlyTimer timer) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); final double height = terrain.getHeightAt(camera.getLocation().getX(), camera.getLocation().getZ()) + heightOffset; if (groundCamera || camera.getLocation().getY() < height) { camera.setLocation(new Vector3(camera.getLocation().getX(), height, camera.getLocation().getZ())); } if (aboveWater && camera.getLocation().getY() < waterNode.getWaterHeight()) { fogState.setStart(-1000f); fogState.setEnd(farPlane / 10f); fogState.setColor(new ColorRGBA(0.0f, 0.0f, 0.1f, 1.0f)); aboveWater = false; } else if (!aboveWater && camera.getLocation().getY() >= waterNode.getWaterHeight()) { fogState.setStart(farPlane / 2.0f); fogState.setEnd(farPlane); fogState.setColor(new ColorRGBA(0.96f, 0.97f, 1.0f, 1.0f)); aboveWater = true; } if (updateTerrain) { terrainCamera.set(camera); } skybox.setTranslation(camera.getLocation()); counter += timer.getTimePerFrame(); frames++; if (counter > 1) { final double fps = (frames / counter); counter = 0; frames = 0; System.out.printf("%7.1f FPS\n", fps); } // if we're picking... if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { // Set up our pick ray pickRay.setOrigin(camera.getLocation()); pickRay.setDirection(camera.getDirection()); // do pick and move the sphere final PrimitivePickResults pickResults = new PrimitivePickResults(); pickResults.setCheckDistance(true); PickingUtil.findPick(_root, pickRay, pickResults); if (pickResults.getNumber() != 0) { final Vector3 intersectionPoint = pickResults.getPickData(0).getIntersectionRecord() .getIntersectionPoint(0); sphere.setTranslation(intersectionPoint); // XXX: maybe change the color of the ball for valid vs. invalid? } } final Vector3 transVec = new Vector3(camera.getLocation().getX(), waterNode.getWaterHeight(), camera.getLocation().getZ()); setTextureCoords(0, transVec.getX(), -transVec.getZ(), textureScale); // vertex coords setVertexCoords(transVec.getX(), transVec.getY(), transVec.getZ()); waterNode.update(timer.getTimePerFrame()); } /** * Render example. * * @param renderer * the renderer */ @Override protected void renderExample(final Renderer renderer) { super.renderExample(renderer); if (debugQuadsNode == null) { createDebugQuads(); _root.attachChild(debugQuadsNode); } } /** * Initialize pssm pass and scene. */ @Override protected void initExample() { // Setup main camera. _canvas.setTitle("Terrain + Water - Example"); _canvas.getCanvasRenderer().getCamera().setLocation(new Vector3(0, 100, 0)); _canvas.getCanvasRenderer().getCamera().lookAt(new Vector3(0, 100, 1), Vector3.UNIT_Y); _canvas.getCanvasRenderer().getCamera().setFrustumPerspective(65.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth() / _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0f, farPlane); _controlHandle.setMoveSpeed(50); _lightState.detachAll(); final DirectionalLight dLight = new DirectionalLight(); dLight.setEnabled(true); dLight.setAmbient(new ColorRGBA(0.4f, 0.4f, 0.5f, 1)); dLight.setDiffuse(new ColorRGBA(0.6f, 0.6f, 0.5f, 1)); dLight.setSpecular(new ColorRGBA(0.3f, 0.3f, 0.2f, 1)); dLight.setDirection(new Vector3(-1, -1, -1).normalizeLocal()); _lightState.attach(dLight); _lightState.setEnabled(true); final CullState cs = new CullState(); cs.setEnabled(true); cs.setCullFace(CullState.Face.Back); _root.setRenderState(cs); fogState = new FogState(); fogState.setStart(farPlane / 2.0f); fogState.setEnd(farPlane); fogState.setColor(new ColorRGBA(0.96f, 0.97f, 1.0f, 1.0f)); fogState.setDensityFunction(DensityFunction.Linear); _root.setRenderState(fogState); // add our sphere, but have it off for now. sphere.getSceneHints().setCullHint(CullHint.Always); sphere.getSceneHints().setAllPickingHints(false); _root.attachChild(sphere); try { // Keep a separate camera to be able to freeze terrain update final Camera camera = _canvas.getCanvasRenderer().getCamera(); terrainCamera = new Camera(camera); final double scale = 1.0 / 4000.0; Function3D functionTmp = new FbmFunction3D(Functions.simplexNoise(), 9, 0.5, 0.5, 3.14); functionTmp = Functions.clamp(functionTmp, -1.2, 1.2); final Function3D function = Functions.scaleInput(functionTmp, scale, scale, 1); final TerrainDataProvider terrainDataProvider = new ProceduralTerrainDataProvider(function, new Vector3(1, 200, 1), -1.2f, 1.2f); terrain = new TerrainBuilder(terrainDataProvider, terrainCamera).setShowDebugPanels(true).build(); } catch (final Exception ex1) { ex1.printStackTrace(); } final Node reflectedNode = new Node("reflectNode"); reflectedNode.attachChild(terrain); skybox = buildSkyBox(); skybox.getSceneHints().setAllPickingHints(false); reflectedNode.attachChild(skybox); final Camera cam = _canvas.getCanvasRenderer().getCamera(); // Create a new WaterNode with refraction enabled. waterNode = new WaterNode(cam, 2, false, true); // Setup textures to use for the water. waterNode.setNormalMapTextureString("images/water/normalmap3.dds"); waterNode.setDudvMapTextureString("images/water/dudvmap.png"); waterNode.setFallbackMapTextureString("images/water/water2.png"); waterNode.useFadeToFogColor(true); waterNode.setSpeedReflection(0.02); waterNode.setSpeedReflection(-0.01); // setting to default value just to show waterNode.setWaterPlane(new Plane(new Vector3(0.0, 1.0, 0.0), 40.0)); // Create a quad to use as geometry for the water. waterQuad = new Quad("waterQuad", 1, 1); // Hack the quad normals to point up in the y-axis. Since we are manipulating the vertices as // we move this is more convenient than rotating the quad. final FloatBuffer normBuf = waterQuad.getMeshData().getNormalBuffer(); normBuf.clear(); normBuf.put(0).put(1).put(0); normBuf.put(0).put(1).put(0); normBuf.put(0).put(1).put(0); normBuf.put(0).put(1).put(0); waterNode.attachChild(waterQuad); waterNode.addReflectedScene(reflectedNode); waterNode.setSkybox(skybox); _root.attachChild(reflectedNode); _root.attachChild(waterNode); // Setup cam above water and terrain final Camera camera = _canvas.getCanvasRenderer().getCamera(); final double height = Math.max(terrain.getHeightAt(camera.getLocation().getX(), camera.getLocation().getZ()), waterNode.getWaterHeight()) + heightOffset; if (camera.getLocation().getY() < height) { camera.setLocation(new Vector3(camera.getLocation().getX(), height, camera.getLocation().getZ())); } // Setup labels for presenting example info. final Node textNodes = new Node("Text"); _root.attachChild(textNodes); textNodes.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); textNodes.getSceneHints().setLightCombineMode(LightCombineMode.Off); final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight() - 20; for (int i = 0; i < _exampleInfo.length; i++) { _exampleInfo[i] = BasicText.createDefaultTextLabel("Text", "", 16); _exampleInfo[i].setTranslation(new Vector3(10, infoStartY - i * 20, 0)); textNodes.attachChild(_exampleInfo[i]); } textNodes.updateGeometricState(0.0); updateText(); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.U), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { updateTerrain = !updateTerrain; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ONE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(5); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.TWO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(50); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.THREE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(400); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SPACE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { groundCamera = !groundCamera; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.P), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { sphere.getSceneHints().setCullHint( sphere.getSceneHints().getCullHint() == CullHint.Always ? CullHint.Dynamic : CullHint.Always); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.V), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { showUI = !showUI; if (showUI) { textNodes.getSceneHints().setCullHint(CullHint.Never); debugQuadsNode.getSceneHints().setCullHint(CullHint.Never); } else { textNodes.getSceneHints().setCullHint(CullHint.Always); debugQuadsNode.getSceneHints().setCullHint(CullHint.Always); } updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.B), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { waterNode.setDoBlurReflection(!waterNode.isDoBlurReflection()); waterNode.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.F), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(new Vector3(camera.getLocation().getX() + 5000, camera.getLocation().getY(), camera.getLocation().getZ())); updateText(); } })); } /** * Sets the vertex coords of the quad. * * @param x * the x * @param y * the y * @param z * the z */ private void setVertexCoords(final double x, final double y, final double z) { final FloatBuffer vertBuf = waterQuad.getMeshData().getVertexBuffer(); vertBuf.clear(); vertBuf.put((float) (x - farPlane)).put((float) y).put((float) (z - farPlane)); vertBuf.put((float) (x - farPlane)).put((float) y).put((float) (z + farPlane)); vertBuf.put((float) (x + farPlane)).put((float) y).put((float) (z + farPlane)); vertBuf.put((float) (x + farPlane)).put((float) y).put((float) (z - farPlane)); } /** * Sets the texture coords of the quad. * * @param buffer * the buffer * @param x * the x * @param y * the y * @param textureScale * the texture scale */ private void setTextureCoords(final int buffer, double x, double y, double textureScale) { x *= textureScale * 0.5f; y *= textureScale * 0.5f; textureScale = farPlane * textureScale; FloatBuffer texBuf; texBuf = waterQuad.getMeshData().getTextureBuffer(buffer); texBuf.clear(); texBuf.put((float) x).put((float) (textureScale + y)); texBuf.put((float) x).put((float) y); texBuf.put((float) (textureScale + x)).put((float) y); texBuf.put((float) (textureScale + x)).put((float) (textureScale + y)); } /** * Builds the sky box. * * @return the sky box */ private Skybox buildSkyBox() { final Skybox skybox = new Skybox("skybox", 10, 10, 10); final String dir = "images/skybox/"; final Texture north = TextureManager.load(dir + "1.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture south = TextureManager.load(dir + "3.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture east = TextureManager.load(dir + "2.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture west = TextureManager.load(dir + "4.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture up = TextureManager.load(dir + "6.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture down = TextureManager.load(dir + "5.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); skybox.setTexture(Skybox.Face.North, north); skybox.setTexture(Skybox.Face.West, west); skybox.setTexture(Skybox.Face.South, south); skybox.setTexture(Skybox.Face.East, east); skybox.setTexture(Skybox.Face.Up, up); skybox.setTexture(Skybox.Face.Down, down); return skybox; } /** * Update text information. */ private void updateText() { _exampleInfo[0].setText("Heightmap size: " + SIZE + "x" + SIZE); _exampleInfo[1].setText("Spec: One meter per heightmap value"); _exampleInfo[2].setText("[1/2/3] Moving speed: " + _controlHandle.getMoveSpeed() + " m/s"); _exampleInfo[3].setText("[U] Update terrain: " + updateTerrain); _exampleInfo[4].setText("[SPACE] Toggle fly/walk: " + (groundCamera ? "walk" : "fly")); _exampleInfo[5].setText("[P] Toggle showing a sphere that follows the ground using picking: " + (sphere.getSceneHints().getCullHint() != CullHint.Always)); _exampleInfo[6].setText("[B] Blur reflection: " + waterNode.isDoBlurReflection()); _exampleInfo[7].setText("[V] Show/Hide UI"); } /** * Creates the debug quads. */ private void createDebugQuads() { debugQuadsNode = new Node("quadNode"); debugQuadsNode.getSceneHints().setCullHint(CullHint.Never); final double quadSize = _canvas.getCanvasRenderer().getCamera().getWidth() / 10; Quad debugQuad = new Quad("reflectionQuad", quadSize, quadSize); debugQuad.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); debugQuad.getSceneHints().setCullHint(CullHint.Never); debugQuad.getSceneHints().setLightCombineMode(LightCombineMode.Off); TextureState ts = new TextureState(); ts.setTexture(waterNode.getTextureReflect()); debugQuad.setRenderState(ts); debugQuad.setTranslation(quadSize * 0.6, quadSize * 1.0, 1.0); debugQuadsNode.attachChild(debugQuad); if (waterNode.getTextureRefract() != null) { debugQuad = new Quad("refractionQuad", quadSize, quadSize); debugQuad.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); debugQuad.getSceneHints().setCullHint(CullHint.Never); debugQuad.getSceneHints().setLightCombineMode(LightCombineMode.Off); ts = new TextureState(); ts.setTexture(waterNode.getTextureRefract()); debugQuad.setRenderState(ts); debugQuad.setTranslation(quadSize * 0.6, quadSize * 2.1, 1.0); debugQuadsNode.attachChild(debugQuad); } } } \ No newline at end of file
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/ZupTerrainExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/ZupTerrainExample.java
index b9369d3..ba33fd9 100644
--- a/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/ZupTerrainExample.java
+++ b/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/ZupTerrainExample.java
@@ -1 +1 @@
-/** * Copyright (c) 2008-2014 Ardor Labs, Inc. * * This file is part of Ardor3D. * * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ package com.ardor3d.example.terrain; import java.util.concurrent.Callable; import com.ardor3d.example.ExampleBase; import com.ardor3d.example.Purpose; import com.ardor3d.extension.terrain.client.Terrain; import com.ardor3d.extension.terrain.client.TerrainBuilder; import com.ardor3d.extension.terrain.client.TerrainDataProvider; import com.ardor3d.extension.terrain.heightmap.MidPointHeightMapGenerator; import com.ardor3d.extension.terrain.providers.array.ArrayTerrainDataProvider; import com.ardor3d.framework.Canvas; import com.ardor3d.framework.CanvasRenderer; import com.ardor3d.image.Texture; import com.ardor3d.input.Key; import com.ardor3d.input.logical.InputTrigger; import com.ardor3d.input.logical.KeyPressedCondition; import com.ardor3d.input.logical.TriggerAction; import com.ardor3d.input.logical.TwoInputStates; import com.ardor3d.intersection.PickingUtil; import com.ardor3d.intersection.PrimitivePickResults; import com.ardor3d.light.DirectionalLight; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.MathUtils; import com.ardor3d.math.Quaternion; import com.ardor3d.math.Ray3; import com.ardor3d.math.Vector3; import com.ardor3d.renderer.Camera; import com.ardor3d.renderer.RenderContext; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.queue.RenderBucketType; import com.ardor3d.renderer.state.CullState; import com.ardor3d.renderer.state.FogState; import com.ardor3d.renderer.state.FogState.DensityFunction; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.extension.Skybox; import com.ardor3d.scenegraph.hint.CullHint; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.shape.Sphere; import com.ardor3d.ui.text.BasicText; import com.ardor3d.util.GameTaskQueue; import com.ardor3d.util.GameTaskQueueManager; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.TextureManager; /** * Example showing the Geometry Clipmap Terrain system with 'MegaTextures' using Z-Up. This is done by flipping the * terrain system from y-up to z-up and inverting interactions with it back to the y-up terrain coordinate space. * Requires GLSL support. */ @Purpose(htmlDescriptionKey = "com.ardor3d.example.terrain.ZupTerrainExample", // thumbnailPath = "com/ardor3d/example/media/thumbnails/terrain_ZupTerrainExample.jpg", // maxHeapMemory = 128) public class ZupTerrainExample extends ExampleBase { private boolean updateTerrain = true; private final float farPlane = 10000.0f; private Terrain terrain; private final Sphere sphere = new Sphere("sp", 16, 16, 1); private final Ray3 pickRay = new Ray3(); private boolean groundCamera = false; private Camera terrainCamera; private Skybox skybox; /** Text fields used to present info about the example. */ private final BasicText _exampleInfo[] = new BasicText[5]; public static void main(final String[] args) { ExampleBase.start(ZupTerrainExample.class); } @Override protected void updateExample(final ReadOnlyTimer timer) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); // Make sure camera is above terrain pickRay.setOrigin(camera.getLocation()); pickRay.setDirection(Vector3.NEG_UNIT_Z); final PrimitivePickResults pickResultsCam = new PrimitivePickResults(); pickResultsCam.setCheckDistance(true); PickingUtil.findPick(terrain, pickRay, pickResultsCam); if (pickResultsCam.getNumber() != 0) { final Vector3 intersectionPoint = pickResultsCam.getPickData(0).getIntersectionRecord() .getIntersectionPoint(0); final double height = intersectionPoint.getZ(); if (height > -Float.MAX_VALUE && (groundCamera || camera.getLocation().getZ() < height + 5)) { camera.setLocation(new Vector3(camera.getLocation().getX(), camera.getLocation().getY(), height + 5)); } } if (updateTerrain) { terrainCamera.set(camera); } skybox.setTranslation(camera.getLocation()); // if we're picking... if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { // Set up our pick ray pickRay.setOrigin(camera.getLocation()); pickRay.setDirection(camera.getDirection()); // do pick and move the sphere final PrimitivePickResults pickResults = new PrimitivePickResults(); pickResults.setCheckDistance(true); PickingUtil.findPick(_root, pickRay, pickResults); if (pickResults.getNumber() != 0) { final Vector3 intersectionPoint = pickResults.getPickData(0).getIntersectionRecord() .getIntersectionPoint(0); sphere.setTranslation(intersectionPoint); // XXX: maybe change the color of the ball for valid vs. invalid? } } } /** * Initialize pssm pass and scene. */ @Override protected void initExample() { // Setup main camera. _canvas.setTitle("Z-up Terrain Example"); _canvas.getCanvasRenderer().getCamera().setLocation(new Vector3(0, 0, 300)); _canvas.getCanvasRenderer().getCamera().lookAt(new Vector3(1, -1, 300), Vector3.UNIT_Z); _canvas.getCanvasRenderer() .getCamera() .setFrustumPerspective( 70.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth() / _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0f, farPlane); final CanvasRenderer canvasRenderer = _canvas.getCanvasRenderer(); final RenderContext renderContext = canvasRenderer.getRenderContext(); final Renderer renderer = canvasRenderer.getRenderer(); GameTaskQueueManager.getManager(renderContext).getQueue(GameTaskQueue.RENDER).enqueue(new Callable<Void>() { @Override public Void call() throws Exception { renderer.setBackgroundColor(ColorRGBA.GRAY); return null; } }); _controlHandle.setUpAxis(Vector3.UNIT_Z); _controlHandle.setMoveSpeed(200); setupDefaultStates(); sphere.getSceneHints().setAllPickingHints(false); sphere.getSceneHints().setCullHint(CullHint.Always); _root.attachChild(sphere); try { // Keep a separate camera to be able to freeze terrain update final Camera camera = _canvas.getCanvasRenderer().getCamera(); terrainCamera = new Camera(camera); final int SIZE = 2048; final MidPointHeightMapGenerator raw = new MidPointHeightMapGenerator(SIZE, 0.5f); raw.setHeightRange(0.2f); final float[] heightMap = raw.getHeightData(); final TerrainDataProvider terrainDataProvider = new ArrayTerrainDataProvider(heightMap, SIZE, new Vector3( 1, 300, 1)); terrain = new TerrainBuilder(terrainDataProvider, terrainCamera).setShowDebugPanels(true).build(); terrain.setRotation(new Quaternion().fromAngleAxis(MathUtils.HALF_PI, Vector3.UNIT_X)); _root.attachChild(terrain); } catch (final Exception ex1) { System.out.println("Problem setting up terrain..."); ex1.printStackTrace(); } skybox = buildSkyBox(); skybox.getSceneHints().setAllPickingHints(false); _root.attachChild(skybox); // Setup labels for presenting example info. final Node textNodes = new Node("Text"); _root.attachChild(textNodes); textNodes.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); textNodes.getSceneHints().setLightCombineMode(LightCombineMode.Off); final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight() / 2; for (int i = 0; i < _exampleInfo.length; i++) { _exampleInfo[i] = BasicText.createDefaultTextLabel("Text", "", 16); _exampleInfo[i].setTranslation(new Vector3(10, infoStartY - i * 20, 0)); textNodes.attachChild(_exampleInfo[i]); } textNodes.updateGeometricState(0.0); updateText(); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.U), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { updateTerrain = !updateTerrain; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ONE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(5); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.TWO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(50); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.THREE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(400); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FOUR), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(1000); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SPACE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { groundCamera = !groundCamera; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.P), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { sphere.getSceneHints().setCullHint(CullHint.Always); } else if (sphere.getSceneHints().getCullHint() == CullHint.Always) { sphere.getSceneHints().setCullHint(CullHint.Dynamic); } updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.R), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setShowDebug(!terrain.getTextureClipmap().isShowDebug()); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.G), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.reloadShader(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FIVE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() / 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SIX), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() * 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SEVEN), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX() + 500.0, camera.getLocation().getY(), camera .getLocation().getZ()); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.EIGHT), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX() - 500.0, camera.getLocation().getY(), camera .getLocation().getZ()); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.NINE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation() .getZ() + 500.0); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ZERO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation() .getZ() - 500.0); } })); } private void setupDefaultStates() { _lightState.detachAll(); final DirectionalLight dLight = new DirectionalLight(); dLight.setEnabled(true); dLight.setAmbient(new ColorRGBA(0.4f, 0.4f, 0.5f, 1)); dLight.setDiffuse(new ColorRGBA(0.6f, 0.6f, 0.5f, 1)); dLight.setSpecular(new ColorRGBA(0.3f, 0.3f, 0.2f, 1)); dLight.setDirection(new Vector3(-1, -1, -1).normalizeLocal()); _lightState.attach(dLight); _lightState.setEnabled(true); final CullState cs = new CullState(); cs.setEnabled(true); cs.setCullFace(CullState.Face.Back); _root.setRenderState(cs); final FogState fs = new FogState(); fs.setStart(farPlane / 2.0f); fs.setEnd(farPlane); fs.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f)); fs.setDensityFunction(DensityFunction.Linear); _root.setRenderState(fs); } /** * Builds the sky box. */ private Skybox buildSkyBox() { final Skybox skybox = new Skybox("skybox", 10, 10, 10); final String dir = "images/skybox/"; final Texture north = TextureManager .load(dir + "1.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture south = TextureManager .load(dir + "3.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture east = TextureManager.load(dir + "2.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture west = TextureManager.load(dir + "4.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture up = TextureManager.load(dir + "6.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture down = TextureManager.load(dir + "5.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); skybox.setTexture(Skybox.Face.North, north); skybox.setTexture(Skybox.Face.West, west); skybox.setTexture(Skybox.Face.South, south); skybox.setTexture(Skybox.Face.East, east); skybox.setTexture(Skybox.Face.Up, up); skybox.setTexture(Skybox.Face.Down, down); skybox.setRotation(new Quaternion().fromAngleAxis(MathUtils.HALF_PI, Vector3.UNIT_X)); return skybox; } /** * Update text information. */ private void updateText() { _exampleInfo[0].setText("[1/2/3] Moving speed: " + _controlHandle.getMoveSpeed() * 3.6 + " km/h"); _exampleInfo[1].setText("[P] Do picking: " + (sphere.getSceneHints().getCullHint() == CullHint.Dynamic)); _exampleInfo[2].setText("[SPACE] Toggle fly/walk: " + (groundCamera ? "walk" : "fly")); _exampleInfo[3].setText("[J] Regenerate heightmap/texture"); _exampleInfo[4].setText("[U] Freeze terrain(debug): " + !updateTerrain); } } \ No newline at end of file
+/** * Copyright (c) 2008-2014 Ardor Labs, Inc. * * This file is part of Ardor3D. * * Ardor3D is free software: you can redistribute it and/or modify it * under the terms of its license which may be found in the accompanying * LICENSE file or at <http://www.ardor3d.com/LICENSE>. */ package com.ardor3d.example.terrain; import java.util.concurrent.Callable; import com.ardor3d.example.ExampleBase; import com.ardor3d.example.Purpose; import com.ardor3d.extension.terrain.client.Terrain; import com.ardor3d.extension.terrain.client.TerrainBuilder; import com.ardor3d.extension.terrain.client.TerrainDataProvider; import com.ardor3d.extension.terrain.heightmap.MidPointHeightMapGenerator; import com.ardor3d.extension.terrain.providers.array.ArrayTerrainDataProvider; import com.ardor3d.framework.Canvas; import com.ardor3d.framework.CanvasRenderer; import com.ardor3d.image.Texture; import com.ardor3d.input.Key; import com.ardor3d.input.logical.InputTrigger; import com.ardor3d.input.logical.KeyPressedCondition; import com.ardor3d.input.logical.TriggerAction; import com.ardor3d.input.logical.TwoInputStates; import com.ardor3d.intersection.PickingUtil; import com.ardor3d.intersection.PrimitivePickResults; import com.ardor3d.light.DirectionalLight; import com.ardor3d.math.ColorRGBA; import com.ardor3d.math.MathUtils; import com.ardor3d.math.Quaternion; import com.ardor3d.math.Ray3; import com.ardor3d.math.Vector3; import com.ardor3d.renderer.Camera; import com.ardor3d.renderer.RenderContext; import com.ardor3d.renderer.Renderer; import com.ardor3d.renderer.queue.RenderBucketType; import com.ardor3d.renderer.state.CullState; import com.ardor3d.renderer.state.FogState; import com.ardor3d.renderer.state.FogState.DensityFunction; import com.ardor3d.scenegraph.Node; import com.ardor3d.scenegraph.extension.Skybox; import com.ardor3d.scenegraph.hint.CullHint; import com.ardor3d.scenegraph.hint.LightCombineMode; import com.ardor3d.scenegraph.shape.Sphere; import com.ardor3d.ui.text.BasicText; import com.ardor3d.util.GameTaskQueue; import com.ardor3d.util.GameTaskQueueManager; import com.ardor3d.util.ReadOnlyTimer; import com.ardor3d.util.TextureManager; /** * Example showing the Geometry Clipmap Terrain system with 'MegaTextures' using Z-Up. This is done by flipping the * terrain system from y-up to z-up and inverting interactions with it back to the y-up terrain coordinate space. * Requires GLSL support. */ @Purpose(htmlDescriptionKey = "com.ardor3d.example.terrain.ZupTerrainExample", // thumbnailPath = "com/ardor3d/example/media/thumbnails/terrain_ZupTerrainExample.jpg", // maxHeapMemory = 128) public class ZupTerrainExample extends ExampleBase { private boolean updateTerrain = true; private final float farPlane = 10000.0f; private Terrain terrain; private final Sphere sphere = new Sphere("sp", 16, 16, 1); private final Ray3 pickRay = new Ray3(); private boolean groundCamera = false; private Camera terrainCamera; private Skybox skybox; /** Text fields used to present info about the example. */ private final BasicText _exampleInfo[] = new BasicText[5]; public static void main(final String[] args) { ExampleBase.start(ZupTerrainExample.class); } @Override protected void updateExample(final ReadOnlyTimer timer) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); // Make sure camera is above terrain pickRay.setOrigin(camera.getLocation()); pickRay.setDirection(Vector3.NEG_UNIT_Z); final PrimitivePickResults pickResultsCam = new PrimitivePickResults(); pickResultsCam.setCheckDistance(true); PickingUtil.findPick(terrain, pickRay, pickResultsCam); if (pickResultsCam.getNumber() != 0) { final Vector3 intersectionPoint = pickResultsCam.getPickData(0).getIntersectionRecord() .getIntersectionPoint(0); final double height = intersectionPoint.getZ(); if (height > -Float.MAX_VALUE && (groundCamera || camera.getLocation().getZ() < height + 5)) { camera.setLocation(new Vector3(camera.getLocation().getX(), camera.getLocation().getY(), height + 5)); } } if (updateTerrain) { terrainCamera.set(camera); } skybox.setTranslation(camera.getLocation()); // if we're picking... if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { // Set up our pick ray pickRay.setOrigin(camera.getLocation()); pickRay.setDirection(camera.getDirection()); // do pick and move the sphere final PrimitivePickResults pickResults = new PrimitivePickResults(); pickResults.setCheckDistance(true); PickingUtil.findPick(_root, pickRay, pickResults); if (pickResults.getNumber() != 0) { final Vector3 intersectionPoint = pickResults.getPickData(0).getIntersectionRecord() .getIntersectionPoint(0); sphere.setTranslation(intersectionPoint); // XXX: maybe change the color of the ball for valid vs. invalid? } } } /** * Initialize pssm pass and scene. */ @Override protected void initExample() { // Setup main camera. _canvas.setTitle("Z-up Terrain Example"); _canvas.getCanvasRenderer().getCamera().setLocation(new Vector3(0, 0, 300)); _canvas.getCanvasRenderer().getCamera().lookAt(new Vector3(1, -1, 300), Vector3.UNIT_Z); _canvas.getCanvasRenderer().getCamera().setFrustumPerspective(70.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth() / _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0f, farPlane); final CanvasRenderer canvasRenderer = _canvas.getCanvasRenderer(); final RenderContext renderContext = canvasRenderer.getRenderContext(); final Renderer renderer = canvasRenderer.getRenderer(); GameTaskQueueManager.getManager(renderContext).getQueue(GameTaskQueue.RENDER).enqueue(new Callable<Void>() { @Override public Void call() throws Exception { renderer.setBackgroundColor(ColorRGBA.GRAY); return null; } }); _controlHandle.setUpAxis(Vector3.UNIT_Z); _controlHandle.setMoveSpeed(200); setupDefaultStates(); sphere.getSceneHints().setAllPickingHints(false); sphere.getSceneHints().setCullHint(CullHint.Always); _root.attachChild(sphere); try { // Keep a separate camera to be able to freeze terrain update final Camera camera = _canvas.getCanvasRenderer().getCamera(); terrainCamera = new Camera(camera); final int SIZE = 2048; final MidPointHeightMapGenerator raw = new MidPointHeightMapGenerator(SIZE, 0.5f); raw.setHeightRange(0.2f); final float[] heightMap = raw.getHeightData(); final TerrainDataProvider terrainDataProvider = new ArrayTerrainDataProvider(heightMap, SIZE, new Vector3(1, 300, 1)); terrain = new TerrainBuilder(terrainDataProvider, terrainCamera).setShowDebugPanels(true).build(); terrain.setRotation(new Quaternion().fromAngleAxis(MathUtils.HALF_PI, Vector3.UNIT_X)); _root.attachChild(terrain); } catch (final Exception ex1) { System.out.println("Problem setting up terrain..."); ex1.printStackTrace(); } skybox = buildSkyBox(); skybox.getSceneHints().setAllPickingHints(false); _root.attachChild(skybox); // Setup labels for presenting example info. final Node textNodes = new Node("Text"); _root.attachChild(textNodes); textNodes.getSceneHints().setRenderBucketType(RenderBucketType.Ortho); textNodes.getSceneHints().setLightCombineMode(LightCombineMode.Off); final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight() / 2; for (int i = 0; i < _exampleInfo.length; i++) { _exampleInfo[i] = BasicText.createDefaultTextLabel("Text", "", 16); _exampleInfo[i].setTranslation(new Vector3(10, infoStartY - i * 20, 0)); textNodes.attachChild(_exampleInfo[i]); } textNodes.updateGeometricState(0.0); updateText(); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.U), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { updateTerrain = !updateTerrain; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ONE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(5); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.TWO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(50); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.THREE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(400); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FOUR), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { _controlHandle.setMoveSpeed(1000); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SPACE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { groundCamera = !groundCamera; updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.P), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { if (sphere.getSceneHints().getCullHint() == CullHint.Dynamic) { sphere.getSceneHints().setCullHint(CullHint.Always); } else if (sphere.getSceneHints().getCullHint() == CullHint.Always) { sphere.getSceneHints().setCullHint(CullHint.Dynamic); } updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.R), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setShowDebug(!terrain.getTextureClipmap().isShowDebug()); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.G), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.reloadShader(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.FIVE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() / 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SIX), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { terrain.getTextureClipmap().setScale(terrain.getTextureClipmap().getScale() * 2); terrain.reloadShader(); updateText(); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.SEVEN), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX() + 500.0, camera.getLocation().getY(), camera.getLocation().getZ()); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.EIGHT), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX() - 500.0, camera.getLocation().getY(), camera.getLocation().getZ()); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.NINE), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation().getZ() + 500.0); } })); _logicalLayer.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ZERO), new TriggerAction() { @Override public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) { final Camera camera = _canvas.getCanvasRenderer().getCamera(); camera.setLocation(camera.getLocation().getX(), camera.getLocation().getY(), camera.getLocation().getZ() - 500.0); } })); } private void setupDefaultStates() { _lightState.detachAll(); final DirectionalLight dLight = new DirectionalLight(); dLight.setEnabled(true); dLight.setAmbient(new ColorRGBA(0.4f, 0.4f, 0.5f, 1)); dLight.setDiffuse(new ColorRGBA(0.6f, 0.6f, 0.5f, 1)); dLight.setSpecular(new ColorRGBA(0.3f, 0.3f, 0.2f, 1)); dLight.setDirection(new Vector3(-1, -1, -1).normalizeLocal()); _lightState.attach(dLight); _lightState.setEnabled(true); final CullState cs = new CullState(); cs.setEnabled(true); cs.setCullFace(CullState.Face.Back); _root.setRenderState(cs); final FogState fs = new FogState(); fs.setStart(farPlane / 2.0f); fs.setEnd(farPlane); fs.setColor(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f)); fs.setDensityFunction(DensityFunction.Linear); _root.setRenderState(fs); } /** * Builds the sky box. * * @return the sky box */ private Skybox buildSkyBox() { final Skybox skybox = new Skybox("skybox", 10, 10, 10); final String dir = "images/skybox/"; final Texture north = TextureManager.load(dir + "1.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture south = TextureManager.load(dir + "3.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture east = TextureManager.load(dir + "2.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture west = TextureManager.load(dir + "4.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture up = TextureManager.load(dir + "6.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); final Texture down = TextureManager.load(dir + "5.jpg", Texture.MinificationFilter.BilinearNearestMipMap, true); skybox.setTexture(Skybox.Face.North, north); skybox.setTexture(Skybox.Face.West, west); skybox.setTexture(Skybox.Face.South, south); skybox.setTexture(Skybox.Face.East, east); skybox.setTexture(Skybox.Face.Up, up); skybox.setTexture(Skybox.Face.Down, down); skybox.setRotation(new Quaternion().fromAngleAxis(MathUtils.HALF_PI, Vector3.UNIT_X)); return skybox; } /** * Update text information. */ private void updateText() { _exampleInfo[0].setText("[1/2/3] Moving speed: " + _controlHandle.getMoveSpeed() * 3.6 + " km/h"); _exampleInfo[1].setText("[P] Do picking: " + (sphere.getSceneHints().getCullHint() == CullHint.Dynamic)); _exampleInfo[2].setText("[SPACE] Toggle fly/walk: " + (groundCamera ? "walk" : "fly")); _exampleInfo[3].setText("[J] Regenerate heightmap/texture"); _exampleInfo[4].setText("[U] Freeze terrain(debug): " + !updateTerrain); } } \ No newline at end of file
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/ui/BMTextExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/ui/BMTextExample.java
index 96ba209..094cb6d 100644
--- a/ardor3d-examples/src/main/java/com/ardor3d/example/ui/BMTextExample.java
+++ b/ardor3d-examples/src/main/java/com/ardor3d/example/ui/BMTextExample.java
@@ -3,7 +3,7 @@
*
* This file is part of Ardor3D.
*
- * Ardor3D is free software: you can redistribute it and/or modify it
+ * Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/
@@ -40,8 +40,8 @@ import com.ardor3d.util.GameTaskQueueManager;
* Illustrates how to modify text properties (e.g. font, color, alignment) and display on a canvas.
*/
@Purpose(htmlDescriptionKey = "com.ardor3d.example.ui.BMTextExample", //
-thumbnailPath = "com/ardor3d/example/media/thumbnails/ui_BMTextExample.jpg", //
-maxHeapMemory = 64)
+ thumbnailPath = "com/ardor3d/example/media/thumbnails/ui_BMTextExample.jpg", //
+ maxHeapMemory = 64)
public class BMTextExample extends ExampleBase {
private final Matrix3 rotate = new Matrix3();
@@ -73,8 +73,9 @@ public class BMTextExample extends ExampleBase {
}
/**
- *
+ *
* @param topNode
+ * the top node
*/
// -----------------------------------------------------
void addTextTestNodes(final Node topNode) {
@@ -159,7 +160,7 @@ public class BMTextExample extends ExampleBase {
}
/**
- *
+ *
* @param text
* the text object
* @return the proper contents to use for our text object.
@@ -175,7 +176,7 @@ public class BMTextExample extends ExampleBase {
}
/**
- *
+ * @return the spatial controller of the bitmap text
*/
// -----------------------------------------------------
SpatialController<BMText> createFontChanger() {
@@ -210,7 +211,7 @@ public class BMTextExample extends ExampleBase {
}
/**
- *
+ * @return the spatial controller of the node
*/
// -----------------------------------------------------
private SpatialController<Node> createNodeMover() {
@@ -231,7 +232,16 @@ public class BMTextExample extends ExampleBase {
}
/**
- *
+ *
+ *
+ * @param parent
+ * the parent node
+ * @param x
+ * the abscissa
+ * @param y
+ * the ordinate
+ * @param z
+ * the applicate
*/
// -----------------------------------------------------
void newBox(final Node parent, final double x, final double y, final double z) {