diff options
author | Julien Gouesse <[email protected]> | 2014-08-08 23:34:00 +0200 |
---|---|---|
committer | Julien Gouesse <[email protected]> | 2014-08-08 23:34:00 +0200 |
commit | 83554a405f4e806d5b2252312c960d1d0131bbad (patch) | |
tree | 54c3848048dd3f04bb170209794b006082f18f79 | |
parent | 79e98d5f52750d7a4dc3652922de369f1ee16b70 (diff) |
Renames the variable of the directional light in order to avoid name shadowing
-rw-r--r-- | ardor3d-examples/src/main/java/com/ardor3d/example/terrain/MountainShadowTerrainExample.java | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/MountainShadowTerrainExample.java b/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/MountainShadowTerrainExample.java index a699d74..ede8ebf 100644 --- a/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/MountainShadowTerrainExample.java +++ b/ardor3d-examples/src/main/java/com/ardor3d/example/terrain/MountainShadowTerrainExample.java @@ -1 +1 @@ -/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/
package com.ardor3d.example.terrain;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.EnumSet;
import java.util.concurrent.Callable;
import javax.imageio.ImageIO;
import com.ardor3d.example.ExampleBase;
import com.ardor3d.example.Purpose;
import com.ardor3d.extension.model.collada.jdom.ColladaImporter;
import com.ardor3d.extension.model.collada.jdom.data.ColladaStorage;
import com.ardor3d.extension.shadow.map.ParallelSplitShadowMapPass;
import com.ardor3d.extension.shadow.map.ParallelSplitShadowMapPass.Filter;
import com.ardor3d.extension.terrain.client.Terrain;
import com.ardor3d.extension.terrain.client.TerrainBuilder;
import com.ardor3d.extension.terrain.client.UrlInputSupplier;
import com.ardor3d.extension.terrain.heightmap.ImageHeightMap;
import com.ardor3d.extension.terrain.providers.array.ArrayTerrainDataProvider;
import com.ardor3d.extension.ui.Orientation;
import com.ardor3d.extension.ui.UIButton;
import com.ardor3d.extension.ui.UIFrame;
import com.ardor3d.extension.ui.UIFrame.FrameButtons;
import com.ardor3d.extension.ui.UIHud;
import com.ardor3d.extension.ui.UILabel;
import com.ardor3d.extension.ui.UIPanel;
import com.ardor3d.extension.ui.UISlider;
import com.ardor3d.extension.ui.event.ActionEvent;
import com.ardor3d.extension.ui.event.ActionListener;
import com.ardor3d.extension.ui.layout.RowLayout;
import com.ardor3d.extension.ui.text.StyleConstants;
import com.ardor3d.extension.ui.util.Insets;
import com.ardor3d.framework.Canvas;
import com.ardor3d.framework.CanvasRenderer;
import com.ardor3d.image.Image;
import com.ardor3d.image.Texture;
import com.ardor3d.image.Texture2D;
import com.ardor3d.image.util.awt.AWTImageLoader;
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.math.ColorRGBA;
import com.ardor3d.math.MathUtils;
import com.ardor3d.math.Quaternion;
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.FogState;
import com.ardor3d.renderer.state.FogState.DensityFunction;
import com.ardor3d.renderer.state.RenderState.StateType;
import com.ardor3d.renderer.state.TextureState;
import com.ardor3d.renderer.state.ZBufferState;
import com.ardor3d.scenegraph.Node;
import com.ardor3d.scenegraph.hint.CullHint;
import com.ardor3d.scenegraph.hint.LightCombineMode;
import com.ardor3d.scenegraph.hint.TextureCombineMode;
import com.ardor3d.scenegraph.shape.Quad;
import com.ardor3d.util.GameTaskQueue;
import com.ardor3d.util.GameTaskQueueManager;
import com.ardor3d.util.ReadOnlyTimer;
import com.ardor3d.util.geom.Debugger;
import com.ardor3d.util.resource.ResourceLocatorTool;
/**
* Example showing the Geometry Clipmap Terrain system with 'MegaTextures' where the terrain data is provided from a
* float array populated from a heightmap generated from an Image. Requires GLSL support.
*/
@Purpose(htmlDescriptionKey = "com.ardor3d.example.terrain.ImageMapTerrainExample", //
thumbnailPath = "com/ardor3d/example/media/thumbnails/terrain_ImageMapTerrainExample.jpg", //
maxHeapMemory = 128)
public class MountainShadowTerrainExample extends ExampleBase {
private final float farPlane = 8000.0f;
/** Quads used for debug showing shadowmaps. */
private Quad _orthoQuad[];
private Terrain terrain;
private final Node terrainNode = new Node("terrain");
private boolean groundCamera = false;
private Camera terrainCamera;
/** Text fields used to present info about the example. */
private final UILabel _exampleInfo[] = new UILabel[2];
/** Pssm shadow map pass. */
private ParallelSplitShadowMapPass _pssmPass;
private DirectionalLight light;
private double lightTime;
private boolean moveLight = false;
private UIHud hud;
public static void main(final String[] args) {
ExampleBase._minDepthBits = 24;
ExampleBase.start(MountainShadowTerrainExample.class);
}
@Override
protected void renderExample(final Renderer renderer) {
// Lazy init since it needs the renderer...
if (!_pssmPass.isInitialised()) {
_pssmPass.init(renderer);
_pssmPass.setPssmShader(terrain.getGeometryClipmapShader());
for (int i = 0; i < _pssmPass.getNumOfSplits(); i++) {
terrain.getClipTextureState().setTexture(_pssmPass.getShadowMapTexture(i), i + 1);
}
for (int i = 0; i < ParallelSplitShadowMapPass._MAX_SPLITS; i++) {
terrain.getGeometryClipmapShader().setUniform("shadowMap" + i, i + 1);
}
}
terrain.getGeometryClipmapShader().setUniform("lightDir", light.getDirection());
for (int i = 0; i < _pssmPass.getNumOfSplits(); i++) {
TextureState screen = (TextureState) _orthoQuad[i].getLocalRenderState(StateType.Texture);
Texture copy;
if (screen == null) {
screen = new TextureState();
_orthoQuad[i].setRenderState(screen);
copy = new Texture2D();
screen.setTexture(copy);
_orthoQuad[i].updateGeometricState(0.0);
} else {
copy = screen.getTexture();
}
copy.setTextureKey(_pssmPass.getShadowMapTexture(i).getTextureKey());
}
// XXX: Use a rougher LOD for shadows - tweak?
terrain.setMinVisibleLevel(4);
// Update shadowmaps - this will update our terrain camera to light pos
_pssmPass.updateShadowMaps(renderer);
// XXX: reset LOD for drawing from view camera
terrain.setMinVisibleLevel(0);
// Render scene and terrain with shadows
terrainNode.onDraw(renderer);
_root.onDraw(renderer);
// Render overlay shadows for all objects except the terrain
renderer.renderBuckets();
_pssmPass.renderShadowedScene(renderer);
renderer.renderBuckets();
// draw ui
renderer.draw(hud);
}
private double counter = 0;
private int frames = 0;
@Override
protected void updateExample(final ReadOnlyTimer timer) {
counter += timer.getTimePerFrame();
frames++;
if (counter > 1) {
final double fps = frames / counter;
counter = 0;
frames = 0;
System.out.printf("%7.1f FPS\n", fps);
}
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()));
terrainCamera.set(camera);
} else {
terrainCamera.set(_canvas.getCanvasRenderer().getCamera());
}
// move terrain to view pos
terrainNode.updateGeometricState(timer.getTimePerFrame());
hud.updateGeometricState(timer.getTimePerFrame());
if (moveLight) {
lightTime += timer.getTimePerFrame();
light.setDirection(new Vector3(Math.sin(lightTime), -.8, Math.cos(lightTime)).normalizeLocal());
}
}
/**
* Initialize pssm pass and scene.
*/
@Override
protected void initExample() {
// Setup main camera.
_canvas.setTitle("Terrain Example");
final Camera canvasCamera = _canvas.getCanvasRenderer().getCamera();
canvasCamera.setLocation(new Vector3(2176, 790, 688));
canvasCamera.lookAt(new Vector3(canvasCamera.getLocation()).addLocal(-0.87105768019686, -0.4349655341112313,
0.22817427967541867), Vector3.UNIT_Y);
canvasCamera.setFrustumPerspective(45.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth()
/ _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0f, farPlane);
final CanvasRenderer canvasRenderer = _canvas.getCanvasRenderer();
final RenderContext renderContext = canvasRenderer.getRenderContext();
final Renderer renderer = canvasRenderer.getRenderer();
GameTaskQueueManager.getManager(renderContext).getQueue(GameTaskQueue.RENDER).enqueue(new Callable<Void>() {
@Override
public Void call() throws Exception {
renderer.setBackgroundColor(ColorRGBA.BLUE);
return null;
}
});
_controlHandle.setMoveSpeed(400);
setupDefaultStates();
addRover();
addUI();
// Initialize PSSM shadows
_pssmPass = new ParallelSplitShadowMapPass(light, 2048, 4);
_pssmPass.setFiltering(Filter.None);
_pssmPass.setRenderShadowedScene(false);
_pssmPass.setKeepMainShader(true);
// _pssmPass.setMinimumLightDistance(500); // XXX: Tune this
_pssmPass.setUseSceneTexturing(false);
_pssmPass.setUseObjectCullFace(false);
_pssmPass.getShadowOffsetState().setFactor(1.1f);
_pssmPass.getShadowOffsetState().setUnits(4.0f);
// _pssmPass.setDrawDebug(true);
// TODO: backside lock test
final Quad floor = new Quad("floor", 2048, 2048);
floor.updateModelBound();
floor.setRotation(new Quaternion().fromAngleAxis(MathUtils.HALF_PI, Vector3.UNIT_X));
floor.setTranslation(1024, 0, 1024);
terrainNode.attachChild(floor);
_pssmPass.addBoundsReceiver(terrainNode);
// Add objects that will get shadowed through overlay render
_pssmPass.add(_root);
// Add our occluders that will produce shadows
_pssmPass.addOccluder(terrainNode);
_pssmPass.addOccluder(_root);
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].setScale(1, -1, 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);
hud.attachChild(_orthoQuad[i]);
}
try {
// Keep a separate camera to be able to freeze terrain update
final Camera camera = _canvas.getCanvasRenderer().getCamera();
terrainCamera = new Camera(camera);
// IMAGE LOADING AND CONVERSION TO HEIGHTMAP DONE HERE
final BufferedImage heightmap = ImageIO.read(ResourceLocatorTool.getClassPathResource(
MountainShadowTerrainExample.class, "com/ardor3d/example/media/images/heightmap.jpg"));
final Image ardorImage = AWTImageLoader.makeArdor3dImage(heightmap, false);
final float[] heightMap = ImageHeightMap.generateHeightMap(ardorImage, 0.05f, .33f);
// END OF IMAGE CONVERSION
final int SIZE = ardorImage.getWidth();
final ArrayTerrainDataProvider terrainDataProvider = new ArrayTerrainDataProvider(heightMap, SIZE,
new Vector3(5, 2048, 5), true);
terrainDataProvider.setHeightMax(0.34f);
final TerrainBuilder builder = new TerrainBuilder(terrainDataProvider, terrainCamera)
.setShowDebugPanels(true);
terrain = builder.build();
terrain.setPixelShader(new UrlInputSupplier(ResourceLocatorTool.getClassPathResource(
ShadowedTerrainExample.class,
"com/ardor3d/extension/terrain/shadowedGeometryClipmapShader_normalMap.frag")));
terrain.reloadShader();
terrain.getGeometryClipmapShader().setUniform("normalMap", 5);
terrainNode.attachChild(terrain);
terrain.setCullingEnabled(false);
} catch (final Exception ex1) {
System.out.println("Problem setting up terrain...");
ex1.printStackTrace();
}
final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight() / 2;
for (int i = 0; i < _exampleInfo.length; i++) {
_exampleInfo[i] = new UILabel("Text");
_exampleInfo[i].setForegroundColor(ColorRGBA.WHITE, true);
_exampleInfo[i].addFontStyle(StyleConstants.KEY_SIZE, 16);
_exampleInfo[i].addFontStyle(StyleConstants.KEY_BOLD, Boolean.TRUE);
_exampleInfo[i].setTranslation(new Vector3(10, infoStartY - i * 20, 0));
hud.add(_exampleInfo[i]);
}
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();
}
}));
}
private void addRover() {
try {
final ColladaStorage storage = new ColladaImporter().load("collada/sketchup/NASA Mars Rover.dae");
final Node rover = storage.getScene();
rover.setTranslation(440, 102, 160.1);
rover.setScale(3);
rover.setRotation(new Quaternion().fromAngleAxis(-MathUtils.HALF_PI, Vector3.UNIT_X));
_root.attachChild(rover);
} catch (final IOException ex) {
ex.printStackTrace();
}
}
private void setupDefaultStates() {
terrainNode.setRenderState(_lightState);
terrainNode.setRenderState(_wireframeState);
terrainNode.setRenderState(new ZBufferState());
_lightState.detachAll();
light = new DirectionalLight();
light.setEnabled(true);
light.setAmbient(new ColorRGBA(0.4f, 0.4f, 0.5f, 1));
light.setDiffuse(new ColorRGBA(0.6f, 0.6f, 0.5f, 1));
light.setSpecular(new ColorRGBA(0.3f, 0.3f, 0.2f, 1));
light.setDirection(new Vector3(-1, -1, -1).normalizeLocal());
_lightState.attach(light);
_lightState.setEnabled(true);
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);
terrainNode.setRenderState(fs);
}
/**
* Update text information.
*/
private void updateText() {
_exampleInfo[0].setText("[1/2/3/4] Moving speed: " + _controlHandle.getMoveSpeed() * 3.6 + " km/h");
_exampleInfo[1].setText("[SPACE] Toggle fly/walk: " + (groundCamera ? "walk" : "fly"));
}
@Override
protected void updateLogicalLayer(final ReadOnlyTimer timer) {
hud.getLogicalLayer().checkTriggers(timer.getTimePerFrame());
}
@Override
protected void renderDebug(final Renderer renderer) {
super.renderDebug(renderer);
if (_showBounds) {
Debugger.drawBounds(terrainNode, renderer, true);
}
}
private void addUI() {
// setup hud
hud = new UIHud();
hud.setupInput(_canvas, _physicalLayer, _logicalLayer);
hud.setMouseManager(_mouseManager);
final UIFrame frame = new UIFrame("Controls", EnumSet.noneOf(FrameButtons.class));
frame.setResizeable(false);
final UILabel distLabel = new UILabel("Max Shadow Distance: 1500");
final UISlider distSlider = new UISlider(Orientation.Horizontal, 0, 2000, 1500);
distSlider.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent event) {
_pssmPass.setMaxShadowDistance(distSlider.getValue());
distLabel.setText("Max Shadow Distance: " + distSlider.getValue());
}
});
final UIButton updateCamera = new UIButton("Update Shadow Camera");
updateCamera.setSelectable(true);
updateCamera.setSelected(true);
updateCamera.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent event) {
_pssmPass.setUpdateMainCamera(updateCamera.isSelected());
updateText();
}
});
final UIButton rotateLight = new UIButton("Rotate Light");
rotateLight.setSelectable(true);
rotateLight.setSelected(false);
rotateLight.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent event) {
moveLight = rotateLight.isSelected();
updateText();
}
});
final UIPanel panel = new UIPanel(new RowLayout(false, true, false));
panel.setPadding(new Insets(10, 20, 10, 20));
panel.add(distLabel);
panel.add(distSlider);
panel.add(updateCamera);
panel.add(rotateLight);
frame.setContentPanel(panel);
frame.pack();
final Camera cam = _canvas.getCanvasRenderer().getCamera();
frame.setLocalXY(cam.getWidth() - frame.getLocalComponentWidth(),
cam.getHeight() - frame.getLocalComponentHeight());
hud.add(frame);
}
}
\ No newline at end of file +/**
* Copyright (c) 2008-2012 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/
package com.ardor3d.example.terrain;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.EnumSet;
import java.util.concurrent.Callable;
import javax.imageio.ImageIO;
import com.ardor3d.example.ExampleBase;
import com.ardor3d.example.Purpose;
import com.ardor3d.extension.model.collada.jdom.ColladaImporter;
import com.ardor3d.extension.model.collada.jdom.data.ColladaStorage;
import com.ardor3d.extension.shadow.map.ParallelSplitShadowMapPass;
import com.ardor3d.extension.shadow.map.ParallelSplitShadowMapPass.Filter;
import com.ardor3d.extension.terrain.client.Terrain;
import com.ardor3d.extension.terrain.client.TerrainBuilder;
import com.ardor3d.extension.terrain.client.UrlInputSupplier;
import com.ardor3d.extension.terrain.heightmap.ImageHeightMap;
import com.ardor3d.extension.terrain.providers.array.ArrayTerrainDataProvider;
import com.ardor3d.extension.ui.Orientation;
import com.ardor3d.extension.ui.UIButton;
import com.ardor3d.extension.ui.UIFrame;
import com.ardor3d.extension.ui.UIFrame.FrameButtons;
import com.ardor3d.extension.ui.UIHud;
import com.ardor3d.extension.ui.UILabel;
import com.ardor3d.extension.ui.UIPanel;
import com.ardor3d.extension.ui.UISlider;
import com.ardor3d.extension.ui.event.ActionEvent;
import com.ardor3d.extension.ui.event.ActionListener;
import com.ardor3d.extension.ui.layout.RowLayout;
import com.ardor3d.extension.ui.text.StyleConstants;
import com.ardor3d.extension.ui.util.Insets;
import com.ardor3d.framework.Canvas;
import com.ardor3d.framework.CanvasRenderer;
import com.ardor3d.image.Image;
import com.ardor3d.image.Texture;
import com.ardor3d.image.Texture2D;
import com.ardor3d.image.util.awt.AWTImageLoader;
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.math.ColorRGBA;
import com.ardor3d.math.MathUtils;
import com.ardor3d.math.Quaternion;
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.FogState;
import com.ardor3d.renderer.state.FogState.DensityFunction;
import com.ardor3d.renderer.state.RenderState.StateType;
import com.ardor3d.renderer.state.TextureState;
import com.ardor3d.renderer.state.ZBufferState;
import com.ardor3d.scenegraph.Node;
import com.ardor3d.scenegraph.hint.CullHint;
import com.ardor3d.scenegraph.hint.LightCombineMode;
import com.ardor3d.scenegraph.hint.TextureCombineMode;
import com.ardor3d.scenegraph.shape.Quad;
import com.ardor3d.util.GameTaskQueue;
import com.ardor3d.util.GameTaskQueueManager;
import com.ardor3d.util.ReadOnlyTimer;
import com.ardor3d.util.geom.Debugger;
import com.ardor3d.util.resource.ResourceLocatorTool;
/**
* Example showing the Geometry Clipmap Terrain system with 'MegaTextures' where the terrain data is provided from a
* float array populated from a heightmap generated from an Image. Requires GLSL support.
*/
@Purpose(htmlDescriptionKey = "com.ardor3d.example.terrain.ImageMapTerrainExample", //
thumbnailPath = "com/ardor3d/example/media/thumbnails/terrain_ImageMapTerrainExample.jpg", //
maxHeapMemory = 128)
public class MountainShadowTerrainExample extends ExampleBase {
private final float farPlane = 8000.0f;
/** Quads used for debug showing shadowmaps. */
private Quad _orthoQuad[];
private Terrain terrain;
private final Node terrainNode = new Node("terrain");
private boolean groundCamera = false;
private Camera terrainCamera;
/** Text fields used to present info about the example. */
private final UILabel _exampleInfo[] = new UILabel[2];
/** Pssm shadow map pass. */
private ParallelSplitShadowMapPass _pssmPass;
private DirectionalLight directionalLight;
private double lightTime;
private boolean moveLight = false;
private UIHud hud;
public static void main(final String[] args) {
ExampleBase._minDepthBits = 24;
ExampleBase.start(MountainShadowTerrainExample.class);
}
@Override
protected void renderExample(final Renderer renderer) {
// Lazy init since it needs the renderer...
if (!_pssmPass.isInitialised()) {
_pssmPass.init(renderer);
_pssmPass.setPssmShader(terrain.getGeometryClipmapShader());
for (int i = 0; i < _pssmPass.getNumOfSplits(); i++) {
terrain.getClipTextureState().setTexture(_pssmPass.getShadowMapTexture(i), i + 1);
}
for (int i = 0; i < ParallelSplitShadowMapPass._MAX_SPLITS; i++) {
terrain.getGeometryClipmapShader().setUniform("shadowMap" + i, i + 1);
}
}
terrain.getGeometryClipmapShader().setUniform("lightDir", directionalLight.getDirection());
for (int i = 0; i < _pssmPass.getNumOfSplits(); i++) {
TextureState screen = (TextureState) _orthoQuad[i].getLocalRenderState(StateType.Texture);
Texture copy;
if (screen == null) {
screen = new TextureState();
_orthoQuad[i].setRenderState(screen);
copy = new Texture2D();
screen.setTexture(copy);
_orthoQuad[i].updateGeometricState(0.0);
} else {
copy = screen.getTexture();
}
copy.setTextureKey(_pssmPass.getShadowMapTexture(i).getTextureKey());
}
// XXX: Use a rougher LOD for shadows - tweak?
terrain.setMinVisibleLevel(4);
// Update shadowmaps - this will update our terrain camera to light pos
_pssmPass.updateShadowMaps(renderer);
// XXX: reset LOD for drawing from view camera
terrain.setMinVisibleLevel(0);
// Render scene and terrain with shadows
terrainNode.onDraw(renderer);
_root.onDraw(renderer);
// Render overlay shadows for all objects except the terrain
renderer.renderBuckets();
_pssmPass.renderShadowedScene(renderer);
renderer.renderBuckets();
// draw ui
renderer.draw(hud);
}
private double counter = 0;
private int frames = 0;
@Override
protected void updateExample(final ReadOnlyTimer timer) {
counter += timer.getTimePerFrame();
frames++;
if (counter > 1) {
final double fps = frames / counter;
counter = 0;
frames = 0;
System.out.printf("%7.1f FPS\n", fps);
}
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()));
terrainCamera.set(camera);
} else {
terrainCamera.set(_canvas.getCanvasRenderer().getCamera());
}
// move terrain to view pos
terrainNode.updateGeometricState(timer.getTimePerFrame());
hud.updateGeometricState(timer.getTimePerFrame());
if (moveLight) {
lightTime += timer.getTimePerFrame();
directionalLight.setDirection(new Vector3(Math.sin(lightTime), -.8, Math.cos(lightTime)).normalizeLocal());
}
}
/**
* Initialize pssm pass and scene.
*/
@Override
protected void initExample() {
// Setup main camera.
_canvas.setTitle("Terrain Example");
final Camera canvasCamera = _canvas.getCanvasRenderer().getCamera();
canvasCamera.setLocation(new Vector3(2176, 790, 688));
canvasCamera.lookAt(new Vector3(canvasCamera.getLocation()).addLocal(-0.87105768019686, -0.4349655341112313,
0.22817427967541867), Vector3.UNIT_Y);
canvasCamera.setFrustumPerspective(45.0, (float) _canvas.getCanvasRenderer().getCamera().getWidth()
/ _canvas.getCanvasRenderer().getCamera().getHeight(), 1.0f, farPlane);
final CanvasRenderer canvasRenderer = _canvas.getCanvasRenderer();
final RenderContext renderContext = canvasRenderer.getRenderContext();
final Renderer renderer = canvasRenderer.getRenderer();
GameTaskQueueManager.getManager(renderContext).getQueue(GameTaskQueue.RENDER).enqueue(new Callable<Void>() {
@Override
public Void call() throws Exception {
renderer.setBackgroundColor(ColorRGBA.BLUE);
return null;
}
});
_controlHandle.setMoveSpeed(400);
setupDefaultStates();
addRover();
addUI();
// Initialize PSSM shadows
_pssmPass = new ParallelSplitShadowMapPass(directionalLight, 2048, 4);
_pssmPass.setFiltering(Filter.None);
_pssmPass.setRenderShadowedScene(false);
_pssmPass.setKeepMainShader(true);
// _pssmPass.setMinimumLightDistance(500); // XXX: Tune this
_pssmPass.setUseSceneTexturing(false);
_pssmPass.setUseObjectCullFace(false);
_pssmPass.getShadowOffsetState().setFactor(1.1f);
_pssmPass.getShadowOffsetState().setUnits(4.0f);
// _pssmPass.setDrawDebug(true);
// TODO: backside lock test
final Quad floor = new Quad("floor", 2048, 2048);
floor.updateModelBound();
floor.setRotation(new Quaternion().fromAngleAxis(MathUtils.HALF_PI, Vector3.UNIT_X));
floor.setTranslation(1024, 0, 1024);
terrainNode.attachChild(floor);
_pssmPass.addBoundsReceiver(terrainNode);
// Add objects that will get shadowed through overlay render
_pssmPass.add(_root);
// Add our occluders that will produce shadows
_pssmPass.addOccluder(terrainNode);
_pssmPass.addOccluder(_root);
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].setScale(1, -1, 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);
hud.attachChild(_orthoQuad[i]);
}
try {
// Keep a separate camera to be able to freeze terrain update
final Camera camera = _canvas.getCanvasRenderer().getCamera();
terrainCamera = new Camera(camera);
// IMAGE LOADING AND CONVERSION TO HEIGHTMAP DONE HERE
final BufferedImage heightmap = ImageIO.read(ResourceLocatorTool.getClassPathResource(
MountainShadowTerrainExample.class, "com/ardor3d/example/media/images/heightmap.jpg"));
final Image ardorImage = AWTImageLoader.makeArdor3dImage(heightmap, false);
final float[] heightMap = ImageHeightMap.generateHeightMap(ardorImage, 0.05f, .33f);
// END OF IMAGE CONVERSION
final int SIZE = ardorImage.getWidth();
final ArrayTerrainDataProvider terrainDataProvider = new ArrayTerrainDataProvider(heightMap, SIZE,
new Vector3(5, 2048, 5), true);
terrainDataProvider.setHeightMax(0.34f);
final TerrainBuilder builder = new TerrainBuilder(terrainDataProvider, terrainCamera)
.setShowDebugPanels(true);
terrain = builder.build();
terrain.setPixelShader(new UrlInputSupplier(ResourceLocatorTool.getClassPathResource(
ShadowedTerrainExample.class,
"com/ardor3d/extension/terrain/shadowedGeometryClipmapShader_normalMap.frag")));
terrain.reloadShader();
terrain.getGeometryClipmapShader().setUniform("normalMap", 5);
terrainNode.attachChild(terrain);
terrain.setCullingEnabled(false);
} catch (final Exception ex1) {
System.out.println("Problem setting up terrain...");
ex1.printStackTrace();
}
final double infoStartY = _canvas.getCanvasRenderer().getCamera().getHeight() / 2;
for (int i = 0; i < _exampleInfo.length; i++) {
_exampleInfo[i] = new UILabel("Text");
_exampleInfo[i].setForegroundColor(ColorRGBA.WHITE, true);
_exampleInfo[i].addFontStyle(StyleConstants.KEY_SIZE, 16);
_exampleInfo[i].addFontStyle(StyleConstants.KEY_BOLD, Boolean.TRUE);
_exampleInfo[i].setTranslation(new Vector3(10, infoStartY - i * 20, 0));
hud.add(_exampleInfo[i]);
}
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();
}
}));
}
private void addRover() {
try {
final ColladaStorage storage = new ColladaImporter().load("collada/sketchup/NASA Mars Rover.dae");
final Node rover = storage.getScene();
rover.setTranslation(440, 102, 160.1);
rover.setScale(3);
rover.setRotation(new Quaternion().fromAngleAxis(-MathUtils.HALF_PI, Vector3.UNIT_X));
_root.attachChild(rover);
} catch (final IOException ex) {
ex.printStackTrace();
}
}
private void setupDefaultStates() {
terrainNode.setRenderState(_lightState);
terrainNode.setRenderState(_wireframeState);
terrainNode.setRenderState(new ZBufferState());
_lightState.detachAll();
directionalLight = new DirectionalLight();
directionalLight.setEnabled(true);
directionalLight.setAmbient(new ColorRGBA(0.4f, 0.4f, 0.5f, 1));
directionalLight.setDiffuse(new ColorRGBA(0.6f, 0.6f, 0.5f, 1));
directionalLight.setSpecular(new ColorRGBA(0.3f, 0.3f, 0.2f, 1));
directionalLight.setDirection(new Vector3(-1, -1, -1).normalizeLocal());
_lightState.attach(directionalLight);
_lightState.setEnabled(true);
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);
terrainNode.setRenderState(fs);
}
/**
* Update text information.
*/
private void updateText() {
_exampleInfo[0].setText("[1/2/3/4] Moving speed: " + _controlHandle.getMoveSpeed() * 3.6 + " km/h");
_exampleInfo[1].setText("[SPACE] Toggle fly/walk: " + (groundCamera ? "walk" : "fly"));
}
@Override
protected void updateLogicalLayer(final ReadOnlyTimer timer) {
hud.getLogicalLayer().checkTriggers(timer.getTimePerFrame());
}
@Override
protected void renderDebug(final Renderer renderer) {
super.renderDebug(renderer);
if (_showBounds) {
Debugger.drawBounds(terrainNode, renderer, true);
}
}
private void addUI() {
// setup hud
hud = new UIHud();
hud.setupInput(_canvas, _physicalLayer, _logicalLayer);
hud.setMouseManager(_mouseManager);
final UIFrame frame = new UIFrame("Controls", EnumSet.noneOf(FrameButtons.class));
frame.setResizeable(false);
final UILabel distLabel = new UILabel("Max Shadow Distance: 1500");
final UISlider distSlider = new UISlider(Orientation.Horizontal, 0, 2000, 1500);
distSlider.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent event) {
_pssmPass.setMaxShadowDistance(distSlider.getValue());
distLabel.setText("Max Shadow Distance: " + distSlider.getValue());
}
});
final UIButton updateCamera = new UIButton("Update Shadow Camera");
updateCamera.setSelectable(true);
updateCamera.setSelected(true);
updateCamera.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent event) {
_pssmPass.setUpdateMainCamera(updateCamera.isSelected());
updateText();
}
});
final UIButton rotateLight = new UIButton("Rotate Light");
rotateLight.setSelectable(true);
rotateLight.setSelected(false);
rotateLight.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent event) {
moveLight = rotateLight.isSelected();
updateText();
}
});
final UIPanel panel = new UIPanel(new RowLayout(false, true, false));
panel.setPadding(new Insets(10, 20, 10, 20));
panel.add(distLabel);
panel.add(distSlider);
panel.add(updateCamera);
panel.add(rotateLight);
frame.setContentPanel(panel);
frame.pack();
final Camera cam = _canvas.getCanvasRenderer().getCamera();
frame.setLocalXY(cam.getWidth() - frame.getLocalComponentWidth(),
cam.getHeight() - frame.getLocalComponentHeight());
hud.add(frame);
}
}
\ No newline at end of file |