| /******************************************************************************* |
| * Copyright (c) 2018 Agence spatiale canadienne / Canadian Space Agency |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| <<<<<<< HEAD |
| * Pierre Allard - initial API and implementation |
| * |
| ======= |
| * Pierre Allard - initial API and implementation |
| * |
| >>>>>>> refs/heads/eclipse_pa |
| * SPDX-License-Identifier: EPL-1.0 |
| *******************************************************************************/ |
| package org.eclipse.apogy.core.environment.earth.surface.ui.jme3.scene_objects; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.concurrent.Callable; |
| |
| import javax.vecmath.Matrix4d; |
| import javax.vecmath.Vector3d; |
| |
| import org.eclipse.apogy.common.topology.ApogyCommonTopologyFacade; |
| import org.eclipse.apogy.common.topology.TransformNode; |
| import org.eclipse.apogy.common.topology.ui.NodePresentation; |
| import org.eclipse.apogy.common.topology.ui.jme3.JME3Application; |
| import org.eclipse.apogy.common.topology.ui.jme3.JME3RenderEngineDelegate; |
| import org.eclipse.apogy.common.topology.ui.jme3.JME3Utilities; |
| import org.eclipse.apogy.common.topology.ui.jme3.scene_objects.DefaultJME3SceneObject; |
| import org.eclipse.apogy.core.environment.StarField; |
| import org.eclipse.apogy.core.environment.earth.surface.EarthSky; |
| import org.eclipse.apogy.core.environment.earth.surface.EarthSkyNode; |
| import org.eclipse.apogy.core.environment.earth.surface.ui.EarthSurfaceUIUtilities; |
| import org.eclipse.apogy.core.environment.earth.surface.ui.jme3.Activator; |
| import org.eclipse.apogy.core.environment.earth.surface.ui.jme3.EarthSurfaceEnvironmentJMEConstants; |
| import org.eclipse.apogy.core.environment.earth.surface.ui.jme3.EnvironmentUIJME3Utilities; |
| import org.eclipse.apogy.core.environment.earth.surface.ui.jme3.preferences.ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants; |
| import org.eclipse.apogy.core.environment.earth.surface.ui.scene_objects.EarthSkySceneObject; |
| import org.eclipse.apogy.core.environment.ui.StarFieldPresentation; |
| import org.eclipse.apogy.core.environment.ui.scene_objects.StarFieldSceneObject; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.jobs.Job; |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.notify.impl.AdapterImpl; |
| import org.eclipse.jface.util.IPropertyChangeListener; |
| import org.eclipse.jface.util.PropertyChangeEvent; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import com.jme3.asset.AssetManager; |
| import com.jme3.asset.plugins.FileLocator; |
| import com.jme3.light.DirectionalLight; |
| import com.jme3.material.Material; |
| import com.jme3.material.RenderState.FaceCullMode; |
| import com.jme3.math.ColorRGBA; |
| import com.jme3.math.Vector3f; |
| import com.jme3.post.FilterPostProcessor; |
| import com.jme3.post.filters.BloomFilter; |
| import com.jme3.renderer.queue.RenderQueue.ShadowMode; |
| import com.jme3.scene.Geometry; |
| import com.jme3.scene.Node; |
| import com.jme3.scene.Spatial; |
| import com.jme3.scene.shape.Sphere; |
| import com.jme3.shadow.DirectionalLightShadowFilter; |
| import com.jme3.shadow.DirectionalLightShadowRenderer; |
| import com.jme3.shadow.EdgeFilteringMode; |
| |
| public class EarthSkyNodeJME3Object extends DefaultJME3SceneObject<EarthSkyNode> |
| implements IPropertyChangeListener, EarthSkySceneObject { |
| private static final Logger Logger = LoggerFactory.getLogger(EarthSkyNodeJME3Object.class); |
| |
| private Adapter sunAdapter; |
| private Adapter moonAdapter; |
| |
| private EarthSky earthSky; |
| private AssetManager assetManager; |
| |
| private static ColorRGBA SUN_SPHERE_COLOR = new ColorRGBA(1.0f, 0.0f, 0.0f, 1.0f); // new ColorRGBA(0.976470588f, |
| // 0.968627451f, 0.6f, 1.0f); |
| private static ColorRGBA MOON_SPHERE_COLOR = new ColorRGBA(1f, 1f, 1f, 0.2f); |
| |
| // Horizon |
| private boolean horizonVisible = true; |
| |
| // Sun |
| private Node sunTransform = null; |
| private Geometry sunSphere; |
| private DirectionalLight sunLight; |
| |
| private boolean sunVisible = false; |
| private boolean sunShadowsEnabled = true; |
| private boolean sunCastingShadows = false; |
| |
| // Moon |
| private Node moonTransform = null; |
| private Geometry moonSphere; |
| private DirectionalLight moonLight; |
| |
| private boolean moonVisible = false; |
| private boolean moonShadowsEnabled = true; |
| private boolean moonCastingShadows = false; |
| |
| @SuppressWarnings("unused") |
| private boolean enableBloom = true; |
| private FilterPostProcessor bloomFilterPostProcessor; |
| private BloomFilter bloomFilter; |
| |
| private int shadowMapSize = 2048; |
| private FilterPostProcessor shadowsFilterPostProcessor; |
| private DirectionalLightShadowRenderer directionalLightShadowRenderer; |
| private DirectionalLightShadowFilter directionalLightShadowFilter; |
| |
| private Spatial sky = null; |
| private float alpha = 1.0f; |
| |
| public EarthSkyNodeJME3Object(EarthSkyNode node, JME3RenderEngineDelegate jme3RenderEngineDelegate) { |
| super(node, jme3RenderEngineDelegate); |
| |
| this.assetManager = this.jme3Application.getAssetManager(); |
| this.assetManager.registerLocator("/", FileLocator.class); |
| |
| this.earthSky = (EarthSky) node.getSky(); |
| |
| Job job = new Job("EarthSkyNodeJME3Object initialize.") { |
| @Override |
| protected IStatus run(IProgressMonitor monitor) { |
| EarthSkyNodeJME3Object.this.jme3Application.enqueue(new Callable<Object>() { |
| @Override |
| public Object call() throws Exception { |
| // Attaches the Sun. |
| attachSun(); |
| |
| // Attaches the Moon. |
| attachMoon(); |
| |
| // Updates Geometry. |
| requestUpdate(); |
| |
| // Blooming |
| enableBloom(org.eclipse.apogy.core.environment.earth.surface.ui.jme3.Activator.getDefault() |
| .getPreferenceStore().getBoolean( |
| ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_BLOOM_ENABLED_ID)); |
| |
| // Shadow map. |
| setShadowMapSize(org.eclipse.apogy.core.environment.earth.surface.ui.jme3.Activator.getDefault() |
| .getPreferenceStore() |
| .getInt(ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_SHADOW_MAP_SIZE_ID)); |
| |
| // Shadows from Sun |
| setSunShadowsEnabled(org.eclipse.apogy.core.environment.earth.surface.ui.jme3.Activator |
| .getDefault().getPreferenceStore().getBoolean( |
| ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_SUN_CAST_SHADOWS_ENABLED_ID)); |
| |
| // Shadows from Moon. |
| setMoonShadowsEnabled(org.eclipse.apogy.core.environment.earth.surface.ui.jme3.Activator |
| .getDefault().getPreferenceStore().getBoolean( |
| ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_MOON_CAST_SHADOWS_ENABLED_ID)); |
| |
| // Updates Visibility and Shadows. |
| updateSunMoonVisibilityAndShadows(); |
| |
| // Listens for changes on the EarthSky. |
| EarthSkyNodeJME3Object.this.earthSky.getSun().getParent().eAdapters().add(getSunAdapter()); |
| EarthSkyNodeJME3Object.this.earthSky.getMoon().getParent().eAdapters().add(getMoonAdapter()); |
| |
| EarthSkyNodeJME3Object.this.sky = EnvironmentUIJME3Utilities |
| .createSky(EarthSkyNodeJME3Object.this.assetManager, "Textures/ClearSky/"); |
| EarthSkyNodeJME3Object.this.jme3Application.getSceneRoot() |
| .attachChild(EarthSkyNodeJME3Object.this.sky); |
| |
| return null; |
| } |
| }); |
| return Status.OK_STATUS; |
| } |
| }; |
| job.schedule(); |
| |
| Activator.getDefault().getPreferenceStore().addPropertyChangeListener(this); |
| } |
| |
| @Override |
| public void updateGeometry(float tpf) { |
| // Updates the Sun and Moon visibility and Shadows Status. |
| updateSunMoonVisibilityAndShadows(); |
| |
| // Updates the Sun position |
| updateSun(); |
| |
| // Updates the moon Position. |
| updateMoon(); |
| } |
| |
| @Override |
| public void dispose() { |
| // Disable Shadows. |
| setLightSourceCreatingShadow(null); |
| |
| // Disable bloom. |
| if (this.jme3Application.getViewPort().getProcessors().contains(getBloomFilterPostProcessor())) { |
| this.jme3Application.getViewPort().removeProcessor(getBloomFilterPostProcessor()); |
| } |
| |
| // Detach Sun light |
| if (this.sunLight != null) { |
| this.jme3Application.getRootNode().removeLight(this.sunLight); |
| } |
| |
| // Detach Moon light |
| if (this.moonLight != null) { |
| this.jme3Application.getRootNode().removeLight(this.moonLight); |
| } |
| |
| super.dispose(); |
| } |
| |
| @Override |
| public void propertyChange(final PropertyChangeEvent event) { |
| this.jme3Application.enqueue(new Callable<Object>() { |
| @Override |
| public Object call() throws Exception { |
| if (event.getProperty().compareTo( |
| ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_BLOOM_ENABLED_ID) == 0) { |
| boolean value = org.eclipse.apogy.core.environment.earth.surface.ui.jme3.Activator.getDefault() |
| .getPreferenceStore().getBoolean( |
| ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_BLOOM_ENABLED_ID); |
| enableBloom(value); |
| updateSun(); |
| } else if (event.getProperty().compareTo( |
| ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_SHADOW_MAP_SIZE_ID) == 0) { |
| setShadowMapSize(org.eclipse.apogy.core.environment.earth.surface.ui.jme3.Activator.getDefault() |
| .getPreferenceStore() |
| .getInt(ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_SHADOW_MAP_SIZE_ID)); |
| } else if (event.getProperty().compareTo( |
| ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_SUN_CAST_SHADOWS_ENABLED_ID) == 0) { |
| boolean value = org.eclipse.apogy.core.environment.earth.surface.ui.jme3.Activator.getDefault() |
| .getPreferenceStore().getBoolean( |
| ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_SUN_CAST_SHADOWS_ENABLED_ID); |
| setSunShadowsEnabled(value); |
| } else if (event.getProperty().compareTo( |
| ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_MOON_CAST_SHADOWS_ENABLED_ID) == 0) { |
| boolean value = org.eclipse.apogy.core.environment.earth.surface.ui.jme3.Activator.getDefault() |
| .getPreferenceStore().getBoolean( |
| ApogyEarthSurfaceEnvironmentUIJME3PreferencesConstants.DEFAULT_MOON_CAST_SHADOWS_ENABLED_ID); |
| setMoonShadowsEnabled(value); |
| } |
| |
| return null; |
| } |
| }); |
| } |
| |
| @Override |
| public List<Geometry> getGeometries() { |
| List<Geometry> geometries = new ArrayList<Geometry>(); |
| if (this.sunSphere != null) |
| geometries.add(this.sunSphere); |
| if (this.moonSphere != null) |
| geometries.add(this.moonSphere); |
| |
| geometries.addAll(super.getGeometries()); |
| |
| return geometries; |
| } |
| |
| @Override |
| public void setHorizonVisible(final boolean newHorizonVisible) { |
| // TODO this.horizonVisible = newHorizonVisible; |
| |
| this.horizonVisible = true; |
| |
| Logger.info("Setting Horizon visibility to <" + newHorizonVisible + ">."); |
| this.jme3Application.enqueue(new Callable<Object>() { |
| @Override |
| public Object call() throws Exception { |
| if (getAttachmentNode() != null) { |
| if (EarthSkyNodeJME3Object.this.horizonVisible) { |
| // TODO getAttachmentNode().attachChild(getHorizon()); |
| } else { |
| // TODO getAttachmentNode().detachChild(getHorizon()); |
| } |
| } else { |
| Logger.error("Failed to set Horizon visibility to <" + newHorizonVisible + ">."); |
| } |
| return null; |
| } |
| }); |
| } |
| |
| /** |
| * Enables or disable produced by the Sun. |
| * |
| * @param newSunShadowsEnabled Enable flag for Sun shadows. |
| */ |
| public void setSunShadowsEnabled(boolean newSunShadowsEnabled) { |
| this.sunShadowsEnabled = newSunShadowsEnabled; |
| |
| this.jme3Application.enqueue(new Callable<Object>() { |
| @Override |
| public Object call() throws Exception { |
| updateSun(); |
| updateMoon(); |
| return null; |
| } |
| }); |
| } |
| |
| /** |
| * Returns whether or not shadows produced by the Sun are enabled. |
| * |
| * @return True if Sun shadows are enabled, false otherwise. |
| */ |
| public boolean areSunShadowsEnabled() { |
| return this.sunShadowsEnabled; |
| } |
| |
| /** |
| * Enables or disable produced by the Moon. |
| * |
| * @param newMoonShadowsEnabled Enable flag for Moon shadows. |
| */ |
| public void setMoonShadowsEnabled(boolean newMoonShadowsEnabled) { |
| this.moonShadowsEnabled = newMoonShadowsEnabled; |
| |
| this.jme3Application.enqueue(new Callable<Object>() { |
| @Override |
| public Object call() throws Exception { |
| updateSun(); |
| updateMoon(); |
| return null; |
| } |
| }); |
| } |
| |
| /** |
| * Returns whether or not shadows produced by the Moon are enabled. |
| * |
| * @return True if Moon shadows are enabled, false otherwise. |
| */ |
| public boolean areMoonShadowsEnabled() { |
| return this.moonShadowsEnabled; |
| } |
| |
| /** |
| * Returns whether or not the Sun is producing shadows. |
| * |
| * @return True if the Sun produces shadows, false otherwise. |
| */ |
| private boolean isSunCastingShadows() { |
| return this.sunCastingShadows; |
| } |
| |
| /** |
| * Return weather the Sun is currently visible. |
| * |
| * @return True if the Sun is visible, false otherwise. |
| */ |
| private boolean isSunVisible() { |
| return this.sunVisible; |
| } |
| |
| /** |
| * Return weather the Moon is currently visible. |
| * |
| * @return True if the Moon is visible, false otherwise. |
| */ |
| private boolean isMoonVisible() { |
| return this.moonVisible; |
| } |
| |
| /** |
| * Returns whether or not the Moon is producing shadows. |
| * |
| * @return True if the Moon produces shadows, false otherwise. |
| */ |
| private boolean isMoonCastingShadows() { |
| return this.moonCastingShadows; |
| } |
| |
| /** |
| * Updates the Sun and Moon visiblity based on the shadows settings and their |
| * elevation. |
| */ |
| private void updateSunMoonVisibilityAndShadows() { |
| // Computes Sun Visibility |
| TransformNode sunTranformNode = (TransformNode) this.earthSky.getSun().getParent(); |
| Matrix4d mSun = ApogyCommonTopologyFacade.INSTANCE.expressNodeInRootFrame(sunTranformNode); |
| Vector3d vSun = new Vector3d(); |
| mSun.get(vSun); |
| vSun.normalize(); |
| |
| double rSun = vSun.length(); |
| double sunAltitude = Math.asin(vSun.z / rSun); |
| |
| // Sun is visible is above the horizon. |
| this.sunVisible = (sunAltitude > 0); |
| |
| // Sun cast shadows only if enabled, and the Sun is above horizon |
| this.sunCastingShadows = areSunShadowsEnabled() && this.sunVisible; |
| |
| // Computes Moon Visibility |
| TransformNode moonTranformNode = (TransformNode) this.earthSky.getMoon().getParent(); |
| Matrix4d mMoon = ApogyCommonTopologyFacade.INSTANCE.expressNodeInRootFrame(moonTranformNode); |
| Vector3d vMoon = new Vector3d(); |
| mMoon.get(vMoon); |
| vMoon.normalize(); |
| |
| double rMoon = vMoon.length(); |
| double moonAltitude = Math.asin(vMoon.z / rMoon); |
| |
| // Moon is visible is above the horizon. |
| this.moonVisible = (moonAltitude > 0); |
| |
| // Moon cast shadows only if enabled, and the Sun is not visible and the Moon is |
| // above horizon |
| this.moonCastingShadows = areMoonShadowsEnabled() && this.moonVisible && !this.sunVisible; |
| |
| // Updates the light creating shadows. |
| if (isSunCastingShadows()) { |
| setLightSourceCreatingShadow(getSunLight()); |
| } else if (isMoonCastingShadows()) { |
| setLightSourceCreatingShadow(getMoonLight()); |
| } else { |
| setLightSourceCreatingShadow(null); |
| } |
| } |
| |
| /** |
| * Selects which light (Sun, Moon, or none) is used to cast shadows. |
| * |
| * @param light The light that cast shadows, Can be null. |
| */ |
| private void setLightSourceCreatingShadow(DirectionalLight light) { |
| if (this.jme3Application != null) { |
| if (light != null) { |
| if (!this.jme3Application.getViewPort().getProcessors().contains(getDirectionalLightShadowRenderer())) { |
| this.jme3Application.getViewPort().addProcessor(getDirectionalLightShadowRenderer()); |
| } |
| |
| if (!this.jme3Application.getViewPort().getProcessors().contains(getSunFilterPostProcessor())) { |
| this.jme3Application.getViewPort().addProcessor(getSunFilterPostProcessor()); |
| } |
| |
| getDirectionalLightShadowRenderer().setLight(light); |
| getDirectionalLightShadowFilter().setLight(light); |
| } else { |
| // Removes Shadow Processors. |
| if (this.jme3Application.getViewPort().getProcessors().contains(getDirectionalLightShadowRenderer())) { |
| this.jme3Application.getViewPort().removeProcessor(getDirectionalLightShadowRenderer()); |
| } |
| |
| if (this.jme3Application.getViewPort().getProcessors().contains(getSunFilterPostProcessor())) { |
| this.jme3Application.getViewPort().removeProcessor(getSunFilterPostProcessor()); |
| } |
| } |
| } |
| } |
| |
| private void enableBloom(boolean newEnableBloom) { |
| this.enableBloom = newEnableBloom; |
| |
| if (this.jme3Application != null) { |
| if (newEnableBloom) { |
| if (!this.jme3Application.getViewPort().getProcessors().contains(getBloomFilterPostProcessor())) { |
| this.jme3Application.getViewPort().addProcessor(getBloomFilterPostProcessor()); |
| } |
| |
| Logger.info("Enabled Bloom."); |
| } else { |
| if (this.jme3Application.getViewPort().getProcessors().contains(getBloomFilterPostProcessor())) { |
| this.jme3Application.getViewPort().removeProcessor(getBloomFilterPostProcessor()); |
| } |
| |
| Logger.info("Disabled Bloom."); |
| } |
| } |
| } |
| |
| private FilterPostProcessor getBloomFilterPostProcessor() { |
| if (this.bloomFilterPostProcessor == null) { |
| this.bloomFilterPostProcessor = new FilterPostProcessor(this.assetManager); |
| this.bloomFilterPostProcessor.addFilter(getBloomFilter()); |
| } |
| |
| return this.bloomFilterPostProcessor; |
| } |
| |
| /** |
| * Return the BloomFilter used to give the Sun and Moon an aura. |
| * |
| * @return The BloomFilter. |
| */ |
| private BloomFilter getBloomFilter() { |
| if (this.bloomFilter == null) { |
| this.bloomFilter = new BloomFilter(BloomFilter.GlowMode.Objects); |
| this.bloomFilter.setDownSamplingFactor(2); |
| this.bloomFilter.setBlurScale(1.5f); |
| this.bloomFilter.setExposurePower(3.30f); |
| this.bloomFilter.setExposureCutOff(0.2f); |
| this.bloomFilter.setBloomIntensity(20f); |
| } |
| |
| return this.bloomFilter; |
| } |
| |
| private void setShadowMapSize(int newShadowMapSize) { |
| this.shadowMapSize = newShadowMapSize; |
| |
| if (this.jme3Application != null) { |
| if (this.jme3Application.getViewPort().getProcessors().contains(getDirectionalLightShadowRenderer())) { |
| this.jme3Application.getViewPort().removeProcessor(getDirectionalLightShadowRenderer()); |
| } |
| |
| if (this.jme3Application.getViewPort().getProcessors().contains(getSunFilterPostProcessor())) { |
| this.jme3Application.getViewPort().removeProcessor(getSunFilterPostProcessor()); |
| } |
| |
| this.shadowsFilterPostProcessor = null; |
| this.directionalLightShadowRenderer = null; |
| this.directionalLightShadowFilter = null; |
| |
| // Force shadow filter to be reloaded if required. |
| updateSunMoonVisibilityAndShadows(); |
| } |
| |
| Logger.info("Shadow Map Size set to <" + newShadowMapSize + ">."); |
| } |
| |
| /** |
| * Gets the DirectionalLightShadowRenderer used to cast shadow from the Sun or |
| * the Moon. |
| * |
| * @return The DirectionalLightShadowRenderer. |
| */ |
| private DirectionalLightShadowRenderer getDirectionalLightShadowRenderer() { |
| if (this.directionalLightShadowRenderer == null) { |
| // Shadows from Sun |
| this.directionalLightShadowRenderer = new DirectionalLightShadowRenderer(this.assetManager, |
| this.shadowMapSize, 3); |
| this.directionalLightShadowRenderer.setLight(getSunLight()); |
| this.directionalLightShadowRenderer.setLambda(0.55f); |
| this.directionalLightShadowRenderer.setShadowIntensity(0.6f); |
| this.directionalLightShadowRenderer.setEdgeFilteringMode(EdgeFilteringMode.Nearest); |
| this.directionalLightShadowRenderer.setEnabledStabilization(true); |
| } |
| |
| return this.directionalLightShadowRenderer; |
| } |
| |
| private FilterPostProcessor getSunFilterPostProcessor() { |
| if (this.shadowsFilterPostProcessor == null) { |
| this.shadowsFilterPostProcessor = new FilterPostProcessor(this.assetManager); |
| this.shadowsFilterPostProcessor.addFilter(getDirectionalLightShadowFilter()); |
| } |
| |
| return this.shadowsFilterPostProcessor; |
| } |
| |
| /** |
| * Gets the DirectionalLightShadowFilter used to cast shadow from the Sun or the |
| * Moon. |
| * |
| * @return The DirectionalLightShadowFilter. |
| */ |
| private DirectionalLightShadowFilter getDirectionalLightShadowFilter() { |
| if (this.directionalLightShadowFilter == null) { |
| this.directionalLightShadowFilter = new DirectionalLightShadowFilter(this.assetManager, this.shadowMapSize, |
| 3); |
| this.directionalLightShadowFilter.setLight(getSunLight()); |
| this.directionalLightShadowFilter.setLambda(0.55f); |
| this.directionalLightShadowFilter.setShadowIntensity(0.6f); |
| this.directionalLightShadowFilter.setEdgeFilteringMode(EdgeFilteringMode.Nearest); |
| this.directionalLightShadowFilter.setEnabled(false); |
| } |
| |
| return this.directionalLightShadowFilter; |
| } |
| |
| /*--------------------------------------------------------------------------------------------------------------* |
| * Sun |
| * --------------------------------------------------------------------------------------------------------------*/ |
| |
| private void attachSun() { |
| getAttachmentNode().attachChild(getSunTransform()); |
| getSunTransform().attachChild(getSunSphere()); |
| |
| if (this.jme3Application != null) { |
| this.jme3Application.getRootNode().addLight(getSunLight()); |
| } |
| } |
| |
| private void updateSun() { |
| // Updates first visibility and shadow casting. |
| updateSunMoonVisibilityAndShadows(); |
| |
| TransformNode sunTranformNode = (TransformNode) this.earthSky.getSun().getParent(); |
| Vector3d v = new Vector3d(sunTranformNode.getPosition().asTuple3d()); |
| v.normalize(); |
| |
| // Update the sun light |
| updateSunLight(); |
| |
| // Updates sun position. |
| v.scale(EarthSurfaceEnvironmentJMEConstants.SUN_AND_MOON_RADIUS); |
| getSunTransform().setLocalTranslation((float) v.x, (float) v.y, (float) v.z); |
| |
| // Computes the atmosphere and stars transparency. |
| this.alpha = (float) (1.0 - EarthSurfaceUIUtilities.INSTANCE |
| .getSkyTransparency(this.earthSky.getSunHorizontalCoordinates().getAltitude())); |
| ; |
| |
| Material mat = ((Geometry) this.sky).getMaterial(); |
| mat.setFloat("Alpha", this.alpha); |
| mat.setVector3("SunPosition", getSunTransform().getWorldTranslation()); |
| |
| StarFieldSceneObject starFieldSceneObject = resolveStarFieldSceneObject(); |
| if (starFieldSceneObject != null) { |
| starFieldSceneObject.setTransparency(this.alpha); |
| } |
| } |
| |
| private StarFieldSceneObject resolveStarFieldSceneObject() { |
| if (this.earthSky != null) { |
| StarField node = this.earthSky.getStarField(); |
| if (node != null) { |
| NodePresentation nodePresentation = org.eclipse.apogy.common.topology.ui.Activator |
| .getTopologyPresentationRegistry().getPresentationNode(node); |
| if (nodePresentation instanceof StarFieldPresentation) { |
| if (nodePresentation.getSceneObject() instanceof StarFieldSceneObject) { |
| return (StarFieldSceneObject) nodePresentation.getSceneObject(); |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| private Node getSunTransform() { |
| if (this.sunTransform == null) { |
| this.sunTransform = new Node("Sun Transform"); |
| } |
| |
| return this.sunTransform; |
| } |
| |
| private Geometry getSunSphere() { |
| if (this.sunSphere == null) { |
| // float sunRadius = (float) |
| // (EarthSurfaceEnvironmentJMEConstants.SUN_AND_MOON_RADIUS * |
| // Math.tan(earthSky.getSunAngularDiameter() / 2.0) ); |
| |
| // The sun does not have to be shown anymore, it is now very small. |
| float sunRadius = 0.01f; |
| |
| Sphere sphere = new Sphere(10, 36, sunRadius); |
| Material mat = new Material(this.assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
| mat.setColor("GlowColor", SUN_SPHERE_COLOR.clone()); |
| mat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); |
| |
| this.sunSphere = new Geometry("Sun", sphere); |
| this.sunSphere.setMaterial(mat); |
| this.sunSphere.setShadowMode(ShadowMode.Off); |
| } |
| return this.sunSphere; |
| } |
| |
| private DirectionalLight getSunLight() { |
| if (this.sunLight == null) { |
| TransformNode sunTransformNode = (TransformNode) this.earthSky.getSun().getParent(); |
| |
| float x = (float) sunTransformNode.getPosition().getX(); |
| float y = (float) sunTransformNode.getPosition().getY(); |
| float z = (float) sunTransformNode.getPosition().getZ(); |
| |
| Vector3f direction = new Vector3f(x, y, z); |
| |
| this.sunLight = new DirectionalLight(); |
| this.sunLight.setName("Sun"); |
| this.sunLight.setDirection(direction.normalize()); |
| this.sunLight.setColor(getSunColor(direction)); |
| } |
| |
| return this.sunLight; |
| } |
| |
| private void updateSunLight() { |
| TransformNode sunTranformNode = (TransformNode) this.earthSky.getSun().getParent(); |
| Matrix4d m = ApogyCommonTopologyFacade.INSTANCE.expressNodeInRootFrame(sunTranformNode); |
| |
| Vector3d v = new Vector3d(); |
| m.get(v); |
| v.normalize(); |
| |
| Vector3f direction = new Vector3f((float) v.x, (float) v.y, (float) v.z); |
| |
| // Updates color. |
| ColorRGBA color = getSunColor(direction); |
| getSunLight().setColor(color); |
| |
| // Updates direction. |
| direction.negateLocal(); |
| getSunLight().setDirection(direction.normalize()); |
| |
| // Update Glow Color. |
| Material mat = getSunSphere().getMaterial().clone(); |
| mat.setColor("GlowColor", color.clone()); |
| getSunSphere().setMaterial(mat); |
| } |
| |
| private ColorRGBA getSunColor(Vector3f sunPosition) { |
| double r = sunPosition.length(); |
| double sunAltitude = Math.asin(sunPosition.z / r); |
| |
| ColorRGBA sunColor = null; |
| |
| if (isSunVisible()) { |
| sunColor = JME3Utilities.convertToColorRGBA(EarthSurfaceUIUtilities.INSTANCE.getSunLightColor(sunAltitude)); |
| } else { |
| sunColor = ColorRGBA.BlackNoAlpha; |
| } |
| return sunColor; |
| } |
| |
| /*--------------------------------------------------------------------------------------------------------------* |
| * Moon |
| * --------------------------------------------------------------------------------------------------------------*/ |
| |
| private void attachMoon() { |
| getAttachmentNode().attachChild(getMoonTransform()); |
| getMoonTransform().attachChild(getMoonSphere()); |
| |
| if (this.jme3Application instanceof JME3Application) { |
| JME3Application viewer = this.jme3Application; |
| viewer.getRootNode().addLight(getMoonLight()); |
| } |
| } |
| |
| private void updateMoon() { |
| // Updates first visibility and shadow casting. |
| updateSunMoonVisibilityAndShadows(); |
| |
| // Updates the moon transform. |
| TransformNode moonTranformNode = (TransformNode) this.earthSky.getMoon().getParent(); |
| Vector3d v = new Vector3d(moonTranformNode.getPosition().asTuple3d()); |
| v.normalize(); |
| v.scale(EarthSurfaceEnvironmentJMEConstants.SUN_AND_MOON_RADIUS); |
| getMoonTransform().setLocalTranslation((float) v.x, (float) v.y, (float) v.z); |
| |
| // Update the moon light |
| updateMoonLight(); |
| } |
| |
| private void updateMoonLight() { |
| TransformNode moonTranformNode = (TransformNode) this.earthSky.getMoon().getParent(); |
| |
| Matrix4d m = ApogyCommonTopologyFacade.INSTANCE.expressNodeInRootFrame(moonTranformNode); |
| |
| Vector3d v = new Vector3d(); |
| m.get(v); |
| v.normalize(); |
| |
| Vector3f direction = new Vector3f((float) v.x, (float) v.y, (float) v.z); |
| |
| // Updates color. |
| ColorRGBA color = getMoonColor(direction); |
| getMoonLight().setColor(color); |
| |
| // Update Glow Color. |
| Material mat = getSunSphere().getMaterial().clone(); |
| mat.setColor("GlowColor", color.clone()); |
| getMoonSphere().setMaterial(mat); |
| |
| // Updates direction. |
| direction.negateLocal(); |
| getMoonLight().setDirection(direction.normalize()); |
| } |
| |
| private DirectionalLight getMoonLight() { |
| if (this.moonLight == null) { |
| TransformNode sunTransformNode = (TransformNode) this.earthSky.getMoon().getParent(); |
| |
| float x = (float) sunTransformNode.getPosition().getX(); |
| float y = (float) sunTransformNode.getPosition().getY(); |
| float z = (float) sunTransformNode.getPosition().getZ(); |
| |
| Vector3f direction = new Vector3f(x, y, z); |
| |
| this.moonLight = new DirectionalLight(); |
| this.moonLight.setName("Moon"); |
| this.moonLight.setDirection(direction.normalize()); |
| this.moonLight.setColor(getMoonColor(direction)); |
| } |
| |
| return this.moonLight; |
| } |
| |
| private ColorRGBA getMoonColor(Vector3f moonPosition) { |
| ColorRGBA moonColor = null; |
| |
| // If the sun is up, turn off the moon |
| if (this.sunVisible) { |
| moonColor = new ColorRGBA(0, 0, 0, 0); |
| } else { |
| double rMoon = moonPosition.length(); |
| double moonAltitude = Math.asin(moonPosition.z / rMoon); |
| |
| if (isMoonVisible()) { |
| moonColor = JME3Utilities |
| .convertToColorRGBA(EarthSurfaceUIUtilities.INSTANCE.getSunLightColor(moonAltitude)); |
| } else { |
| moonColor = ColorRGBA.BlackNoAlpha; |
| } |
| } |
| |
| return moonColor; |
| } |
| |
| private Node getMoonTransform() { |
| if (this.moonTransform == null) { |
| this.moonTransform = new Node("Moon Transform"); |
| } |
| |
| return this.moonTransform; |
| } |
| |
| private Geometry getMoonSphere() { |
| if (this.moonSphere == null) { |
| float moonRadius = (float) (EarthSurfaceEnvironmentJMEConstants.SUN_AND_MOON_RADIUS |
| * Math.tan(this.earthSky.getMoonAngularDiameter() / 2.0)); |
| |
| Sphere sphere = new Sphere(10, 36, moonRadius); |
| Material mat = new Material(this.assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); |
| mat.setColor("GlowColor", MOON_SPHERE_COLOR.clone()); |
| mat.getAdditionalRenderState().setFaceCullMode(FaceCullMode.Off); |
| |
| this.moonSphere = new Geometry("Moon", sphere); |
| this.moonSphere.setMaterial(mat); |
| this.moonSphere.setShadowMode(ShadowMode.Off); |
| } |
| return this.moonSphere; |
| } |
| |
| /*--------------------------------------------------------------------------------------------------------------* |
| * Adapters |
| * --------------------------------------------------------------------------------------------------------------*/ |
| |
| private Adapter getSunAdapter() { |
| if (this.sunAdapter == null) { |
| this.sunAdapter = new AdapterImpl() { |
| @Override |
| public void notifyChanged(org.eclipse.emf.common.notify.Notification msg) { |
| EarthSkyNodeJME3Object.this.jme3Application.enqueue(new Callable<Object>() { |
| @Override |
| public Object call() throws Exception { |
| updateSun(); |
| return null; |
| } |
| }); |
| } |
| }; |
| } |
| |
| return this.sunAdapter; |
| } |
| |
| private Adapter getMoonAdapter() { |
| if (this.moonAdapter == null) { |
| this.moonAdapter = new AdapterImpl() { |
| @Override |
| public void notifyChanged(org.eclipse.emf.common.notify.Notification msg) { |
| EarthSkyNodeJME3Object.this.jme3Application.enqueue(new Callable<Object>() { |
| @Override |
| public Object call() throws Exception { |
| updateMoon(); |
| return null; |
| } |
| }); |
| } |
| }; |
| } |
| |
| return this.moonAdapter; |
| } |
| } |