From cd25e068e4b9c3c9895e533d9285905576f95b07 Mon Sep 17 00:00:00 2001 From: Julien Gouesse Date: Wed, 5 Jun 2019 22:24:27 +0200 Subject: Fixes some errors in the Java documentation of ardor3d-examples --- .../java/com/ardor3d/example/PropertiesDialog.java | 36 +++++++- .../ardor3d/example/PropertiesGameSettings.java | 98 +++++++++++++++++----- .../example/benchmark/ball/BubbleMarkExample.java | 33 ++++---- .../effect/ParallelSplitShadowMapExample.java | 2 +- .../example/terrain/InMemoryTerrainExample.java | 2 +- .../example/terrain/ProceduralTerrainExample.java | 2 +- .../example/terrain/TerrainWaterExample.java | 2 +- .../ardor3d/example/terrain/ZupTerrainExample.java | 2 +- .../java/com/ardor3d/example/ui/BMTextExample.java | 26 ++++-- 9 files changed, 150 insertions(+), 53 deletions(-) (limited to 'ardor3d-examples') 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; null 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 null */ @@ -145,6 +148,7 @@ public final class PropertiesDialog extends JDialog { * the image file to use as the title of the dialog; null 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 null */ @@ -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 DisplayModes. + * + * @param modes + * the display modes + * + * @return the resolutions */ private static String[] getResolutions(final DisplayMode[] modes) { final List 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 depths = new TreeSet<>(new Comparator() { @@ -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 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 true 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 true 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 true 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 true 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 + * true 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 + * true 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 + * true 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 defaults here, not user-specific settings. - *

+ *

* 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). - *

+ *

* Add new setting names by making your own method which does its own thing and calls - * AbstractGameSettings.assignDefaults(propfilename). - *

- * 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 . */ @@ -44,7 +44,6 @@ import com.ardor3d.util.resource.SimpleResourceLocator; *

* The famous BubbleMark UI test, recreated using quads. *

- *

* There are several system params you can use to modify the test: *

    *
  • -Dvsync=true -- ask the canvas to use vertical sync to lock to the monitor refresh rate.
  • @@ -56,11 +55,10 @@ import com.ardor3d.util.resource.SimpleResourceLocator; * targetFPS) Not compatible with sync=true. *
  • -DtargetFPS=# -- set the target frame rate (fps) for adaptive mode. (default is 200)
  • *
- *

*/ @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 . */ 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() { 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() { 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 . */ 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() { 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() { 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 . */ 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() { @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 . */ 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() { @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 . */ 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() { @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 . */ 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() { @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 . */ 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 . */ 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 . */ 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() { @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 . */ 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() { @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 . */ @@ -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 createFontChanger() { @@ -210,7 +211,7 @@ public class BMTextExample extends ExampleBase { } /** - * + * @return the spatial controller of the node */ // ----------------------------------------------------- private SpatialController 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) { -- cgit v1.2.3