Dropped the use of the irradiance Map for LightProbes, only the spherical harmonics coeffs are stored and used to recompose indirect diffuse color in the shader.
Also added a tweak to get the specular dominant direction when sampling the prefiltered env maps. It gives better result on low roughness materials.
This commit is contained in:
		
							parent
							
								
									0da2bfe0ba
								
							
						
					
					
						commit
						e6a55e9d3a
					
				| @ -31,12 +31,9 @@ | |||||||
|  */ |  */ | ||||||
| package com.jme3.environment; | package com.jme3.environment; | ||||||
| 
 | 
 | ||||||
|  | import com.jme3.environment.generation.*; | ||||||
| import com.jme3.light.LightProbe; | import com.jme3.light.LightProbe; | ||||||
| import com.jme3.environment.generation.JobProgressListener; |  | ||||||
| import com.jme3.environment.generation.PrefilteredEnvMapFaceGenerator; |  | ||||||
| import com.jme3.environment.generation.IrradianceMapGenerator; |  | ||||||
| import com.jme3.environment.util.EnvMapUtils; | import com.jme3.environment.util.EnvMapUtils; | ||||||
| import com.jme3.environment.generation.JobProgressAdapter; |  | ||||||
| import com.jme3.app.Application; | import com.jme3.app.Application; | ||||||
| import com.jme3.scene.Node; | import com.jme3.scene.Node; | ||||||
| import com.jme3.scene.Spatial; | import com.jme3.scene.Spatial; | ||||||
| @ -115,7 +112,6 @@ public class LightProbeFactory { | |||||||
|     public static LightProbe makeProbe(final EnvironmentCamera envCam, Spatial scene, final JobProgressListener<LightProbe> listener) { |     public static LightProbe makeProbe(final EnvironmentCamera envCam, Spatial scene, final JobProgressListener<LightProbe> listener) { | ||||||
|         final LightProbe probe = new LightProbe(); |         final LightProbe probe = new LightProbe(); | ||||||
|         probe.setPosition(envCam.getPosition()); |         probe.setPosition(envCam.getPosition()); | ||||||
|         probe.setIrradianceMap(EnvMapUtils.createIrradianceMap(envCam.getSize(), envCam.getImageFormat())); |  | ||||||
|         probe.setPrefilteredMap(EnvMapUtils.createPrefilteredEnvMap(envCam.getSize(), envCam.getImageFormat())); |         probe.setPrefilteredMap(EnvMapUtils.createPrefilteredEnvMap(envCam.getSize(), envCam.getImageFormat())); | ||||||
|         envCam.snapshot(scene, new JobProgressAdapter<TextureCubeMap>() { |         envCam.snapshot(scene, new JobProgressAdapter<TextureCubeMap>() { | ||||||
| 
 | 
 | ||||||
| @ -153,15 +149,12 @@ public class LightProbeFactory { | |||||||
|          |          | ||||||
|         probe.setReady(false); |         probe.setReady(false); | ||||||
| 
 | 
 | ||||||
|         if(probe.getIrradianceMap() != null) { |         if (probe.getPrefilteredEnvMap() != null) { | ||||||
|             probe.getIrradianceMap().getImage().dispose(); |  | ||||||
|             probe.getPrefilteredEnvMap().getImage().dispose(); |             probe.getPrefilteredEnvMap().getImage().dispose(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         probe.setIrradianceMap(EnvMapUtils.createIrradianceMap(envCam.getSize(), envCam.getImageFormat())); |  | ||||||
|         probe.setPrefilteredMap(EnvMapUtils.createPrefilteredEnvMap(envCam.getSize(), envCam.getImageFormat())); |         probe.setPrefilteredMap(EnvMapUtils.createPrefilteredEnvMap(envCam.getSize(), envCam.getImageFormat())); | ||||||
| 
 | 
 | ||||||
|          |  | ||||||
|         envCam.snapshot(scene, new JobProgressAdapter<TextureCubeMap>() { |         envCam.snapshot(scene, new JobProgressAdapter<TextureCubeMap>() { | ||||||
| 
 | 
 | ||||||
|             @Override |             @Override | ||||||
| @ -174,7 +167,7 @@ public class LightProbeFactory { | |||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * Internally called to generate the maps. |      * Internally called to generate the maps. | ||||||
|      * This method will spawn 7 thread (one for the IrradianceMap, and one for each face of the prefiltered env map). |      * This method will spawn 7 thread (one for the Irradiance spherical harmonics generator, and one for each face of the prefiltered env map). | ||||||
|      * Those threads will be executed in a ScheduledThreadPoolExecutor that will be shutdown when the genration is done. |      * Those threads will be executed in a ScheduledThreadPoolExecutor that will be shutdown when the genration is done. | ||||||
|      *  |      *  | ||||||
|      * @param envMap the raw env map rendered by the env camera |      * @param envMap the raw env map rendered by the env camera | ||||||
| @ -183,20 +176,20 @@ public class LightProbeFactory { | |||||||
|      * @param listener a progress listener. (can be null if no progress reporting is needed) |      * @param listener a progress listener. (can be null if no progress reporting is needed) | ||||||
|      */ |      */ | ||||||
|     private static void generatePbrMaps(TextureCubeMap envMap, final LightProbe probe, Application app, final JobProgressListener<LightProbe> listener) { |     private static void generatePbrMaps(TextureCubeMap envMap, final LightProbe probe, Application app, final JobProgressListener<LightProbe> listener) { | ||||||
|         IrradianceMapGenerator irrMapGenerator; |         IrradianceSphericalHarmonicsGenerator irrShGenerator; | ||||||
|         PrefilteredEnvMapFaceGenerator[] pemGenerators = new PrefilteredEnvMapFaceGenerator[6]; |         PrefilteredEnvMapFaceGenerator[] pemGenerators = new PrefilteredEnvMapFaceGenerator[6]; | ||||||
| 
 | 
 | ||||||
|         final JobState jobState = new JobState(new ScheduledThreadPoolExecutor(7)); |         final JobState jobState = new JobState(new ScheduledThreadPoolExecutor(7)); | ||||||
| 
 | 
 | ||||||
|         irrMapGenerator = new IrradianceMapGenerator(app, new JobListener(listener, jobState, probe, 6)); |         irrShGenerator = new IrradianceSphericalHarmonicsGenerator(app, new JobListener(listener, jobState, probe, 6)); | ||||||
|         int size = envMap.getImage().getWidth(); |         int size = envMap.getImage().getWidth(); | ||||||
|         irrMapGenerator.setGenerationParam(EnvMapUtils.duplicateCubeMap(envMap), size, EnvMapUtils.FixSeamsMethod.Wrap, probe.getIrradianceMap()); |         irrShGenerator.setGenerationParam(EnvMapUtils.duplicateCubeMap(envMap), probe); | ||||||
| 
 | 
 | ||||||
|         jobState.executor.execute(irrMapGenerator); |         jobState.executor.execute(irrShGenerator); | ||||||
| 
 | 
 | ||||||
|         for (int i = 0; i < pemGenerators.length; i++) { |         for (int i = 0; i < pemGenerators.length; i++) { | ||||||
|             pemGenerators[i] = new PrefilteredEnvMapFaceGenerator(app, i, new JobListener(listener, jobState, probe, i)); |             pemGenerators[i] = new PrefilteredEnvMapFaceGenerator(app, i, new JobListener(listener, jobState, probe, i)); | ||||||
|             pemGenerators[i].setGenerationParam(EnvMapUtils.duplicateCubeMap(envMap), size, EnvMapUtils.FixSeamsMethod.Wrap, probe.getPrefilteredEnvMap()); |             pemGenerators[i].setGenerationParam(EnvMapUtils.duplicateCubeMap(envMap), size, EnvMapUtils.FixSeamsMethod.None, probe.getPrefilteredEnvMap()); | ||||||
|             jobState.executor.execute(pemGenerators[i]); |             jobState.executor.execute(pemGenerators[i]); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,176 +0,0 @@ | |||||||
| /* |  | ||||||
|  * Copyright (c) 2009-2015 jMonkeyEngine |  | ||||||
|  * All rights reserved. |  | ||||||
|  * |  | ||||||
|  * Redistribution and use in source and binary forms, with or without |  | ||||||
|  * modification, are permitted provided that the following conditions are |  | ||||||
|  * met: |  | ||||||
|  * |  | ||||||
|  * * Redistributions of source code must retain the above copyright |  | ||||||
|  *   notice, this list of conditions and the following disclaimer. |  | ||||||
|  * |  | ||||||
|  * * Redistributions in binary form must reproduce the above copyright |  | ||||||
|  *   notice, this list of conditions and the following disclaimer in the |  | ||||||
|  *   documentation and/or other materials provided with the distribution. |  | ||||||
|  * |  | ||||||
|  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors |  | ||||||
|  *   may be used to endorse or promote products derived from this software |  | ||||||
|  *   without specific prior written permission. |  | ||||||
|  * |  | ||||||
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |  | ||||||
|  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |  | ||||||
|  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |  | ||||||
|  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |  | ||||||
|  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |  | ||||||
|  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |  | ||||||
|  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |  | ||||||
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |  | ||||||
|  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |  | ||||||
|  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |  | ||||||
|  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |  | ||||||
|  */ |  | ||||||
| package com.jme3.environment.generation; |  | ||||||
| 
 |  | ||||||
| import com.jme3.environment.util.CubeMapWrapper; |  | ||||||
| import com.jme3.environment.util.EnvMapUtils; |  | ||||||
| import com.jme3.app.Application; |  | ||||||
| import com.jme3.math.ColorRGBA; |  | ||||||
| import com.jme3.math.Vector3f; |  | ||||||
| import com.jme3.texture.TextureCubeMap; |  | ||||||
| import static com.jme3.environment.util.EnvMapUtils.shBandFactor; |  | ||||||
| import com.jme3.util.BufferUtils; |  | ||||||
| import java.nio.ByteBuffer; |  | ||||||
| import java.util.concurrent.Callable; |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * |  | ||||||
|  * Generates the Irradiance map for PBR. This job can be lauched from a separate |  | ||||||
|  * thread. |  | ||||||
|  * |  | ||||||
|  * TODO there is a lot of duplicate code here with the EnvMapUtils. |  | ||||||
|  * |  | ||||||
|  * @author Nehon |  | ||||||
|  */ |  | ||||||
| //TODO there is a lot of duplicate code here with the EnvMapUtils. We should,  |  | ||||||
| //either leverage the code from the util class either remove it and only allow  |  | ||||||
| //parallel generation using this runnable. |  | ||||||
| public class IrradianceMapGenerator extends RunnableWithProgress { |  | ||||||
| 
 |  | ||||||
|     private int targetMapSize; |  | ||||||
|     private EnvMapUtils.FixSeamsMethod fixSeamsMethod; |  | ||||||
|     private TextureCubeMap sourceMap; |  | ||||||
|     private TextureCubeMap store; |  | ||||||
|     private final Application app; |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Creates an Irradiance map generator. The app is needed to enqueue the |  | ||||||
|      * call to the EnvironmentCamera when the generation is done, so that this |  | ||||||
|      * process is thread safe. |  | ||||||
|      * |  | ||||||
|      * @param app the Application |  | ||||||
|      * @param listener |  | ||||||
|      */ |  | ||||||
|     public IrradianceMapGenerator(Application app, JobProgressListener<Integer> listener) { |  | ||||||
|         super(listener); |  | ||||||
|         this.app = app; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Fills all the genration parameters |  | ||||||
|      * |  | ||||||
|      * @param sourceMap the source cube map |  | ||||||
|      * @param targetMapSize the size of the generated map (width or height in |  | ||||||
|      * pixel) |  | ||||||
|      * @param fixSeamsMethod the method used to fix seams as described here |  | ||||||
|      * {@link EnvMapUtils.FixSeamsMethod} |  | ||||||
|      * |  | ||||||
|      * @param store The cube map to store the result in. |  | ||||||
|      */ |  | ||||||
|     public void setGenerationParam(TextureCubeMap sourceMap, int targetMapSize, EnvMapUtils.FixSeamsMethod fixSeamsMethod, TextureCubeMap store) { |  | ||||||
|         this.sourceMap = sourceMap; |  | ||||||
|         this.targetMapSize = targetMapSize; |  | ||||||
|         this.fixSeamsMethod = fixSeamsMethod; |  | ||||||
|         this.store = store; |  | ||||||
|         reset(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |  | ||||||
|     public void run() { |  | ||||||
|         app.enqueue(new Callable<Void>() { |  | ||||||
| 
 |  | ||||||
|             @Override |  | ||||||
|             public Void call() throws Exception { |  | ||||||
|                 listener.start(); |  | ||||||
|                 return null; |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|         try { |  | ||||||
|             Vector3f[] shCoeffs = EnvMapUtils.getSphericalHarmonicsCoefficents(sourceMap); |  | ||||||
|             store = generateIrradianceMap(shCoeffs, targetMapSize, fixSeamsMethod, store); |  | ||||||
|         } catch (Exception e) { |  | ||||||
|             e.printStackTrace(); |  | ||||||
|         } |  | ||||||
|         app.enqueue(new Callable<Void>() { |  | ||||||
| 
 |  | ||||||
|             @Override |  | ||||||
|             public Void call() throws Exception { |  | ||||||
|                 listener.done(6); |  | ||||||
|                 return null; |  | ||||||
|             } |  | ||||||
|         }); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Generates the Irradiance map (used for image based difuse lighting) from |  | ||||||
|      * Spherical Harmonics coefficients previously computed with |  | ||||||
|      * {@link EnvMapUtils#getSphericalHarmonicsCoefficents(com.jme3.texture.TextureCubeMap)} |  | ||||||
|      * |  | ||||||
|      * @param shCoeffs the SH coeffs |  | ||||||
|      * @param targetMapSize the size of the irradiance map to generate |  | ||||||
|      * @param fixSeamsMethod the method to fix seams |  | ||||||
|      * @param store |  | ||||||
|      * @return The irradiance cube map for the given coefficients |  | ||||||
|      */ |  | ||||||
|     public TextureCubeMap generateIrradianceMap(Vector3f[] shCoeffs, int targetMapSize, EnvMapUtils.FixSeamsMethod fixSeamsMethod, TextureCubeMap store) { |  | ||||||
|         TextureCubeMap irrCubeMap = store; |  | ||||||
| 
 |  | ||||||
|         setEnd(6 + 6); |  | ||||||
|         for (int i = 0; i < 6; i++) { |  | ||||||
|             ByteBuffer buf = BufferUtils.createByteBuffer(targetMapSize * targetMapSize * store.getImage().getFormat().getBitsPerPixel() / 8); |  | ||||||
|             irrCubeMap.getImage().setData(i, buf); |  | ||||||
|             progress(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         Vector3f texelVect = new Vector3f(); |  | ||||||
|         ColorRGBA color = new ColorRGBA(ColorRGBA.Black); |  | ||||||
|         float[] shDir = new float[9]; |  | ||||||
|         CubeMapWrapper envMapWriter = new CubeMapWrapper(irrCubeMap); |  | ||||||
|         for (int face = 0; face < 6; face++) { |  | ||||||
| 
 |  | ||||||
|             for (int y = 0; y < targetMapSize; y++) { |  | ||||||
|                 for (int x = 0; x < targetMapSize; x++) { |  | ||||||
|                     EnvMapUtils.getVectorFromCubemapFaceTexCoord(x, y, targetMapSize, face, texelVect, fixSeamsMethod); |  | ||||||
|                     EnvMapUtils.evalShBasis(texelVect, shDir); |  | ||||||
|                     color.set(0, 0, 0, 0); |  | ||||||
|                     for (int i = 0; i < EnvMapUtils.NUM_SH_COEFFICIENT; i++) { |  | ||||||
|                         color.set(color.r + shCoeffs[i].x * shDir[i] * shBandFactor[i], |  | ||||||
|                                 color.g + shCoeffs[i].y * shDir[i] * shBandFactor[i], |  | ||||||
|                                 color.b + shCoeffs[i].z * shDir[i] * shBandFactor[i], |  | ||||||
|                                 1.0f); |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     //clamping the color because very low value close to zero produce artifacts |  | ||||||
|                     color.r = Math.max(0.0001f, color.r); |  | ||||||
|                     color.g = Math.max(0.0001f, color.g); |  | ||||||
|                     color.b = Math.max(0.0001f, color.b); |  | ||||||
| 
 |  | ||||||
|                     envMapWriter.setPixel(x, y, face, color); |  | ||||||
|                      |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             progress(); |  | ||||||
|         } |  | ||||||
|         return irrCubeMap; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
| @ -0,0 +1,117 @@ | |||||||
|  | /* | ||||||
|  |  * Copyright (c) 2009-2015 jMonkeyEngine | ||||||
|  |  * All rights reserved. | ||||||
|  |  * | ||||||
|  |  * Redistribution and use in source and binary forms, with or without | ||||||
|  |  * modification, are permitted provided that the following conditions are | ||||||
|  |  * met: | ||||||
|  |  * | ||||||
|  |  * * Redistributions of source code must retain the above copyright | ||||||
|  |  *   notice, this list of conditions and the following disclaimer. | ||||||
|  |  * | ||||||
|  |  * * Redistributions in binary form must reproduce the above copyright | ||||||
|  |  *   notice, this list of conditions and the following disclaimer in the | ||||||
|  |  *   documentation and/or other materials provided with the distribution. | ||||||
|  |  * | ||||||
|  |  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors | ||||||
|  |  *   may be used to endorse or promote products derived from this software | ||||||
|  |  *   without specific prior written permission. | ||||||
|  |  * | ||||||
|  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||||
|  |  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||||||
|  |  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | ||||||
|  |  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR | ||||||
|  |  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||||||
|  |  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||||||
|  |  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||||||
|  |  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||||||
|  |  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||||||
|  |  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||||||
|  |  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
|  |  */ | ||||||
|  | package com.jme3.environment.generation; | ||||||
|  | 
 | ||||||
|  | import com.jme3.app.Application; | ||||||
|  | import com.jme3.environment.util.CubeMapWrapper; | ||||||
|  | import com.jme3.environment.util.EnvMapUtils; | ||||||
|  | import com.jme3.light.LightProbe; | ||||||
|  | import com.jme3.math.ColorRGBA; | ||||||
|  | import com.jme3.math.Vector3f; | ||||||
|  | import com.jme3.texture.TextureCubeMap; | ||||||
|  | import com.jme3.util.BufferUtils; | ||||||
|  | 
 | ||||||
|  | import java.nio.ByteBuffer; | ||||||
|  | import java.util.concurrent.Callable; | ||||||
|  | 
 | ||||||
|  | import static com.jme3.environment.util.EnvMapUtils.shBandFactor; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Generates the Irradiance map for PBR. This job can be launched from a separate | ||||||
|  |  * thread. | ||||||
|  |  * <p> | ||||||
|  |  * This is not used as we use spherical harmonics directly now, but we may need this code again at some point | ||||||
|  |  * | ||||||
|  |  * @author Nehon | ||||||
|  |  */ | ||||||
|  | public class IrradianceSphericalHarmonicsGenerator extends RunnableWithProgress { | ||||||
|  | 
 | ||||||
|  |     private TextureCubeMap sourceMap; | ||||||
|  |     private LightProbe store; | ||||||
|  |     private final Application app; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Creates an Irradiance map generator. The app is needed to enqueue the | ||||||
|  |      * call to the EnvironmentCamera when the generation is done, so that this | ||||||
|  |      * process is thread safe. | ||||||
|  |      * | ||||||
|  |      * @param app      the Application | ||||||
|  |      * @param listener | ||||||
|  |      */ | ||||||
|  |     public IrradianceSphericalHarmonicsGenerator(Application app, JobProgressListener<Integer> listener) { | ||||||
|  |         super(listener); | ||||||
|  |         this.app = app; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * Fills all the genration parameters | ||||||
|  |      * | ||||||
|  |      * @param sourceMap the source cube map | ||||||
|  |      *                  {@link EnvMapUtils.FixSeamsMethod} | ||||||
|  |      * @param store     The cube map to store the result in. | ||||||
|  |      */ | ||||||
|  |     public void setGenerationParam(TextureCubeMap sourceMap, LightProbe store) { | ||||||
|  |         this.sourceMap = sourceMap; | ||||||
|  | 
 | ||||||
|  |         this.store = store; | ||||||
|  |         reset(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void run() { | ||||||
|  |         app.enqueue(new Callable<Void>() { | ||||||
|  | 
 | ||||||
|  |             @Override | ||||||
|  |             public Void call() throws Exception { | ||||||
|  |                 listener.start(); | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |         try { | ||||||
|  |             Vector3f[] shCoeffs = EnvMapUtils.getSphericalHarmonicsCoefficents(sourceMap); | ||||||
|  |             EnvMapUtils.prepareShCoefs(shCoeffs); | ||||||
|  |             store.setShCoeffs(shCoeffs); | ||||||
|  | 
 | ||||||
|  |         } catch (Exception e) { | ||||||
|  |             e.printStackTrace(); | ||||||
|  |         } | ||||||
|  |         app.enqueue(new Callable<Void>() { | ||||||
|  | 
 | ||||||
|  |             @Override | ||||||
|  |             public Void call() throws Exception { | ||||||
|  |                 listener.done(6); | ||||||
|  |                 return null; | ||||||
|  |             } | ||||||
|  |         }); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
| @ -42,19 +42,20 @@ import static com.jme3.math.FastMath.pow; | |||||||
| import static com.jme3.math.FastMath.sqrt; | import static com.jme3.math.FastMath.sqrt; | ||||||
| 
 | 
 | ||||||
| import com.jme3.texture.TextureCubeMap; | import com.jme3.texture.TextureCubeMap; | ||||||
|  | 
 | ||||||
| import static com.jme3.environment.util.EnvMapUtils.getHammersleyPoint; | import static com.jme3.environment.util.EnvMapUtils.getHammersleyPoint; | ||||||
| import static com.jme3.environment.util.EnvMapUtils.getRoughnessFromMip; | import static com.jme3.environment.util.EnvMapUtils.getRoughnessFromMip; | ||||||
| import static com.jme3.environment.util.EnvMapUtils.getSampleFromMip; | import static com.jme3.environment.util.EnvMapUtils.getSampleFromMip; | ||||||
| import static com.jme3.environment.util.EnvMapUtils.getVectorFromCubemapFaceTexCoord; | import static com.jme3.environment.util.EnvMapUtils.getVectorFromCubemapFaceTexCoord; | ||||||
|  | 
 | ||||||
| import java.util.concurrent.Callable; | import java.util.concurrent.Callable; | ||||||
| import java.util.logging.Level; | import java.util.logging.Level; | ||||||
| import java.util.logging.Logger; | import java.util.logging.Logger; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * |  | ||||||
|  * Generates one face of the prefiltered environnement map for PBR. This job can |  * Generates one face of the prefiltered environnement map for PBR. This job can | ||||||
|  * be lauched from a separate thread. |  * be lauched from a separate thread. | ||||||
|  * |  * <p> | ||||||
|  * TODO there is a lot of duplicate code here with the EnvMapUtils. |  * TODO there is a lot of duplicate code here with the EnvMapUtils. | ||||||
|  * |  * | ||||||
|  * @author Nehon |  * @author Nehon | ||||||
| @ -96,7 +97,6 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|      |  | ||||||
|     /** |     /** | ||||||
|      * Fills all the genration parameters |      * Fills all the genration parameters | ||||||
|      * |      * | ||||||
| @ -105,7 +105,6 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress { | |||||||
|      *                       pixel) |      *                       pixel) | ||||||
|      * @param fixSeamsMethod the method used to fix seams as described here |      * @param fixSeamsMethod the method used to fix seams as described here | ||||||
|      *                       {@link EnvMapUtils.FixSeamsMethod} |      *                       {@link EnvMapUtils.FixSeamsMethod} | ||||||
|      * |  | ||||||
|      * @param store          The cube map to store the result in. |      * @param store          The cube map to store the result in. | ||||||
|      */ |      */ | ||||||
|     public void setGenerationParam(TextureCubeMap sourceMap, int targetMapSize, EnvMapUtils.FixSeamsMethod fixSeamsMethod, TextureCubeMap store) { |     public void setGenerationParam(TextureCubeMap sourceMap, int targetMapSize, EnvMapUtils.FixSeamsMethod fixSeamsMethod, TextureCubeMap store) { | ||||||
| @ -116,7 +115,7 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress { | |||||||
|         init(); |         init(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void init(){ |     private void init() { | ||||||
|         Xi.set(0, 0, 0, 0); |         Xi.set(0, 0, 0, 0); | ||||||
|         H.set(0, 0, 0); |         H.set(0, 0, 0); | ||||||
|         tmp.set(0, 0, 0); |         tmp.set(0, 0, 0); | ||||||
| @ -184,10 +183,10 @@ public class PrefilteredEnvMapFaceGenerator extends RunnableWithProgress { | |||||||
|             for (int y = 0; y < targetMipMapSize; y++) { |             for (int y = 0; y < targetMipMapSize; y++) { | ||||||
|                 for (int x = 0; x < targetMipMapSize; x++) { |                 for (int x = 0; x < targetMipMapSize; x++) { | ||||||
|                     color.set(0, 0, 0); |                     color.set(0, 0, 0); | ||||||
|                     getVectorFromCubemapFaceTexCoord(x, y, targetMipMapSize, face, texelVect, EnvMapUtils.FixSeamsMethod.None); |                     getVectorFromCubemapFaceTexCoord(x, y, targetMipMapSize, face, texelVect, fixSeamsMethod); | ||||||
|                     prefilterEnvMapTexel(sourceWrapper, roughness, texelVect, nbSamples, color); |                     prefilterEnvMapTexel(sourceWrapper, roughness, texelVect, nbSamples, color); | ||||||
| 
 | 
 | ||||||
|                     outColor.set(Math.max(color.x, 0.0001f), Math.max(color.y,0.0001f), Math.max(color.z, 0.0001f), 1); |                     outColor.set(Math.max(color.x, 0.0001f), Math.max(color.y, 0.0001f), Math.max(color.z, 0.0001f), 1); | ||||||
|                     log.log(Level.FINE, "coords {0},{1}", new Object[]{x, y}); |                     log.log(Level.FINE, "coords {0},{1}", new Object[]{x, y}); | ||||||
|                     targetWrapper.setPixel(x, y, face, mipLevel, outColor); |                     targetWrapper.setPixel(x, y, face, mipLevel, outColor); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -59,6 +59,12 @@ import com.jme3.util.TempVars; | |||||||
|  */ |  */ | ||||||
| public class EnvMapUtils { | public class EnvMapUtils { | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  |     private static final float sqrtPi = sqrt(PI); | ||||||
|  |     private static final float sqrt3Pi = sqrt(3f / PI); | ||||||
|  |     private static final float sqrt5Pi = sqrt(5f / PI); | ||||||
|  |     private static final float sqrt15Pi = sqrt(15f / PI); | ||||||
|  | 
 | ||||||
|     public final static int NUM_SH_COEFFICIENT = 9; |     public final static int NUM_SH_COEFFICIENT = 9; | ||||||
|     // See Peter-Pike Sloan paper for these coefficients |     // See Peter-Pike Sloan paper for these coefficients | ||||||
|     //http://www.ppsloan.org/publications/StupidSH36.pdf |     //http://www.ppsloan.org/publications/StupidSH36.pdf | ||||||
| @ -79,7 +85,7 @@ public class EnvMapUtils { | |||||||
|         /** |         /** | ||||||
|          * No seams fix |          * No seams fix | ||||||
|          */ |          */ | ||||||
|         None; |         None | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -111,18 +117,6 @@ public class EnvMapUtils { | |||||||
|         cubeImage.addData(backImg.getData(0)); |         cubeImage.addData(backImg.getData(0)); | ||||||
|         cubeImage.addData(frontImg.getData(0)); |         cubeImage.addData(frontImg.getData(0)); | ||||||
| 
 | 
 | ||||||
|         if (leftImg.getEfficentData() != null) { |  | ||||||
|             // also consilidate efficient data |  | ||||||
|             ArrayList<Object> efficientData = new ArrayList<Object>(6); |  | ||||||
|             efficientData.add(rightImg.getEfficentData()); |  | ||||||
|             efficientData.add(leftImg.getEfficentData()); |  | ||||||
|             efficientData.add(upImg.getEfficentData()); |  | ||||||
|             efficientData.add(downImg.getEfficentData()); |  | ||||||
|             efficientData.add(backImg.getEfficentData()); |  | ||||||
|             efficientData.add(frontImg.getEfficentData()); |  | ||||||
|             cubeImage.setEfficentData(efficientData); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         TextureCubeMap cubeMap = new TextureCubeMap(cubeImage); |         TextureCubeMap cubeMap = new TextureCubeMap(cubeImage); | ||||||
|         cubeMap.setAnisotropicFilter(0); |         cubeMap.setAnisotropicFilter(0); | ||||||
|         cubeMap.setMagFilter(Texture.MagFilter.Bilinear); |         cubeMap.setMagFilter(Texture.MagFilter.Bilinear); | ||||||
| @ -154,13 +148,6 @@ public class EnvMapUtils { | |||||||
|             cubeImage.addData(d.duplicate()); |             cubeImage.addData(d.duplicate()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (srcImg.getEfficentData() != null) { |  | ||||||
|             // also consilidate efficient data |  | ||||||
|             ArrayList<Object> efficientData = new ArrayList<Object>(6); |  | ||||||
|             efficientData.add(srcImg.getEfficentData()); |  | ||||||
|             cubeImage.setEfficentData(efficientData); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         TextureCubeMap cubeMap = new TextureCubeMap(cubeImage); |         TextureCubeMap cubeMap = new TextureCubeMap(cubeImage); | ||||||
|         cubeMap.setAnisotropicFilter(sourceMap.getAnisotropicFilter()); |         cubeMap.setAnisotropicFilter(sourceMap.getAnisotropicFilter()); | ||||||
|         cubeMap.setMagFilter(sourceMap.getMagFilter()); |         cubeMap.setMagFilter(sourceMap.getMagFilter()); | ||||||
| @ -196,7 +183,7 @@ public class EnvMapUtils { | |||||||
|     static float getSolidAngleAndVector(int x, int y, int mapSize, int face, Vector3f store, FixSeamsMethod fixSeamsMethod) { |     static float getSolidAngleAndVector(int x, int y, int mapSize, int face, Vector3f store, FixSeamsMethod fixSeamsMethod) { | ||||||
| 
 | 
 | ||||||
|         if (store == null) { |         if (store == null) { | ||||||
|             throw new IllegalArgumentException("the store parameter ust not be null"); |             throw new IllegalArgumentException("the store parameter must not be null"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /* transform from [0..res - 1] to [- (1 - 1 / res) .. (1 - 1 / res)] |         /* transform from [0..res - 1] to [- (1 - 1 / res) .. (1 - 1 / res)] | ||||||
| @ -438,7 +425,7 @@ public class EnvMapUtils { | |||||||
|         float weight; |         float weight; | ||||||
| 
 | 
 | ||||||
|         if (cubeMap.getImage().getData(0) == null) { |         if (cubeMap.getImage().getData(0) == null) { | ||||||
|             throw new IllegalStateException("The cube map must contain Efficient data, if you rendered the cube map on the GPU plase use renderer.readFrameBuffer, to create a CPU image"); |             throw new IllegalStateException("The cube map must contain Efficient data, if you rendered the cube map on the GPU please use renderer.readFrameBuffer, to create a CPU image"); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         int width = cubeMap.getImage().getWidth(); |         int width = cubeMap.getImage().getWidth(); | ||||||
| @ -495,12 +482,6 @@ public class EnvMapUtils { | |||||||
|         float yV = texelVect.y; |         float yV = texelVect.y; | ||||||
|         float zV = texelVect.z; |         float zV = texelVect.z; | ||||||
| 
 | 
 | ||||||
|         float pi = PI; |  | ||||||
|         float sqrtPi = sqrt(pi); |  | ||||||
|         float sqrt3Pi = sqrt(3f / pi); |  | ||||||
|         float sqrt5Pi = sqrt(5f / pi); |  | ||||||
|         float sqrt15Pi = sqrt(15f / pi); |  | ||||||
| 
 |  | ||||||
|         float x2 = xV * xV; |         float x2 = xV * xV; | ||||||
|         float y2 = yV * yV; |         float y2 = yV * yV; | ||||||
|         float z2 = zV * zV; |         float z2 = zV * zV; | ||||||
| @ -514,9 +495,32 @@ public class EnvMapUtils { | |||||||
|         shDir[6] = (sqrt5Pi * (-1f + 3f * z2)) / 4f; |         shDir[6] = (sqrt5Pi * (-1f + 3f * z2)) / 4f; | ||||||
|         shDir[7] = -(sqrt15Pi * xV * zV) / 2f; |         shDir[7] = -(sqrt15Pi * xV * zV) / 2f; | ||||||
|         shDir[8] = sqrt15Pi * (x2 - y2) / 4f; |         shDir[8] = sqrt15Pi * (x2 - y2) / 4f; | ||||||
|          |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public static void prepareShCoefs(Vector3f[] shCoefs) { | ||||||
|  | 
 | ||||||
|  |         float coef0 = (1f / (2f * sqrtPi)); | ||||||
|  |         float coef1 = -sqrt3Pi / 2f; | ||||||
|  |         float coef2 = -coef1; | ||||||
|  |         float coef3 = coef1; | ||||||
|  |         float coef4 = sqrt15Pi / 2f; | ||||||
|  |         float coef5 = -coef4; | ||||||
|  |         float coef6 = sqrt5Pi / 4f; | ||||||
|  |         float coef7 = coef5; | ||||||
|  |         float coef8 = sqrt15Pi / 4f; | ||||||
|  | 
 | ||||||
|  |         shCoefs[0].multLocal(coef0); | ||||||
|  |         shCoefs[1].multLocal(coef1); | ||||||
|  |         shCoefs[2].multLocal(coef2); | ||||||
|  |         shCoefs[3].multLocal(coef3); | ||||||
|  |         shCoefs[4].multLocal(coef4); | ||||||
|  |         shCoefs[5].multLocal(coef5); | ||||||
|  |         shCoefs[6].multLocal(coef6); | ||||||
|  |         shCoefs[7].multLocal(coef7); | ||||||
|  |         shCoefs[8].multLocal(coef8); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     public static Vector4f getHammersleyPoint(int i, final int nbrSample, Vector4f store) { |     public static Vector4f getHammersleyPoint(int i, final int nbrSample, Vector4f store) { | ||||||
|         if (store == null) { |         if (store == null) { | ||||||
|             store = new Vector4f(); |             store = new Vector4f(); | ||||||
| @ -734,3 +738,4 @@ public class EnvMapUtils { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | |||||||
| @ -61,26 +61,10 @@ public class LightsDebugState extends BaseAppState { | |||||||
|     private Geometry debugGeom; |     private Geometry debugGeom; | ||||||
|     private Geometry debugBounds; |     private Geometry debugBounds; | ||||||
|     private Material debugMaterial; |     private Material debugMaterial; | ||||||
|     private DebugMode debugMode = DebugMode.PrefilteredEnvMap; |  | ||||||
|     private float probeScale = 1.0f; |     private float probeScale = 1.0f; | ||||||
|     private Spatial scene = null; |     private Spatial scene = null; | ||||||
|     private final List<LightProbe> probes = new ArrayList<LightProbe>(); |     private final List<LightProbe> probes = new ArrayList<LightProbe>(); | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Debug mode for light probes |  | ||||||
|      */ |  | ||||||
|     public enum DebugMode { |  | ||||||
| 
 |  | ||||||
|         /** |  | ||||||
|          * Displays the prefiltered env maps on the debug sphere |  | ||||||
|          */ |  | ||||||
|         PrefilteredEnvMap, |  | ||||||
|         /** |  | ||||||
|          * displays the Irradiance map on the debug sphere |  | ||||||
|          */ |  | ||||||
|         IrradianceMap |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @Override |     @Override | ||||||
|     protected void initialize(Application app) { |     protected void initialize(Application app) { | ||||||
|         debugNode = new Node("Environment debug Node"); |         debugNode = new Node("Environment debug Node"); | ||||||
| @ -114,12 +98,8 @@ public class LightsDebugState extends BaseAppState { | |||||||
|                     Material m = probeGeom.getMaterial(); |                     Material m = probeGeom.getMaterial(); | ||||||
|                     probeGeom.setLocalScale(probeScale); |                     probeGeom.setLocalScale(probeScale); | ||||||
|                     if (probe.isReady()) { |                     if (probe.isReady()) { | ||||||
|                         if (debugMode == DebugMode.IrradianceMap) { |  | ||||||
|                             m.setTexture("CubeMap", probe.getIrradianceMap()); |  | ||||||
|                         } else { |  | ||||||
|                         m.setTexture("CubeMap", probe.getPrefilteredEnvMap()); |                         m.setTexture("CubeMap", probe.getPrefilteredEnvMap()); | ||||||
|                     } |                     } | ||||||
|                     } |  | ||||||
|                     n.setLocalTranslation(probe.getPosition()); |                     n.setLocalTranslation(probe.getPosition()); | ||||||
|                     n.getChild(1).setLocalScale(((BoundingSphere) probe.getBounds()).getRadius()); |                     n.getChild(1).setLocalScale(((BoundingSphere) probe.getBounds()).getRadius()); | ||||||
|                     break; |                     break; | ||||||
| @ -161,24 +141,6 @@ public class LightsDebugState extends BaseAppState { | |||||||
|         rm.renderScene(debugNode, getApplication().getViewPort()); |         rm.renderScene(debugNode, getApplication().getViewPort()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      *  |  | ||||||
|      * @see DebugMode |  | ||||||
|      * @return the debug mode |  | ||||||
|      */ |  | ||||||
|     public DebugMode getDebugMode() { |  | ||||||
|         return debugMode; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * sets the debug mode |  | ||||||
|      * @see DebugMode |  | ||||||
|      * @param debugMode the debug mode |  | ||||||
|      */ |  | ||||||
|     public void setDebugMode(DebugMode debugMode) { |  | ||||||
|         this.debugMode = debugMode; |  | ||||||
| 
 |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * returns the scale of the probe's debug sphere |      * returns the scale of the probe's debug sphere | ||||||
|  | |||||||
| @ -50,17 +50,19 @@ import com.jme3.scene.Spatial; | |||||||
| import com.jme3.texture.TextureCubeMap; | import com.jme3.texture.TextureCubeMap; | ||||||
| import com.jme3.util.TempVars; | import com.jme3.util.TempVars; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
|  | import java.util.logging.Level; | ||||||
|  | import java.util.logging.Logger; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A LightProbe is not exactly a light. It holds environment map information used for Image Based Lighting. |  * A LightProbe is not exactly a light. It holds environment map information used for Image Based Lighting. | ||||||
|  * This is used for indirect lighting in the Physically Based Rendering pipeline. |  * This is used for indirect lighting in the Physically Based Rendering pipeline. | ||||||
|  *  |  *  | ||||||
|  * A light probe has a position in world space. This is the position from where the Environment Map are rendered. |  * A light probe has a position in world space. This is the position from where the Environment Map are rendered. | ||||||
|  * There are two environment maps held by the LightProbe : |  * There are two environment data structure  held by the LightProbe : | ||||||
|  * - The irradiance map (used for indirect diffuse lighting in the PBR pipeline). |  * - The irradiance spherical harmonics factors (used for indirect diffuse lighting in the PBR pipeline). | ||||||
|  * - The prefiltered environment map (used for indirect specular lighting and reflection in the PBE pipeline). |  * - The prefiltered environment map (used for indirect specular lighting and reflection in the PBE pipeline). | ||||||
|  * Note that when instanciating the LightProbe, both those maps are null.  |  * Note that when instantiating the LightProbe, both of those structures are null. | ||||||
|  * To render them see {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)} |  * To compute them see {@link LightProbeFactory#makeProbe(com.jme3.environment.EnvironmentCamera, com.jme3.scene.Node)} | ||||||
|  * and {@link EnvironmentCamera}. |  * and {@link EnvironmentCamera}. | ||||||
|  *  |  *  | ||||||
|  * The light probe has an area of effect that is a bounding volume centered on its position. (for now only Bounding spheres are supported). |  * The light probe has an area of effect that is a bounding volume centered on its position. (for now only Bounding spheres are supported). | ||||||
| @ -75,7 +77,9 @@ import java.io.IOException; | |||||||
|  */ |  */ | ||||||
| public class LightProbe extends Light implements Savable { | public class LightProbe extends Light implements Savable { | ||||||
| 
 | 
 | ||||||
|     private TextureCubeMap irradianceMap; |     private static final Logger logger = Logger.getLogger(LightProbe.class.getName()); | ||||||
|  | 
 | ||||||
|  |     private Vector3f[] shCoeffs; | ||||||
|     private TextureCubeMap prefilteredEnvMap; |     private TextureCubeMap prefilteredEnvMap; | ||||||
|     private BoundingVolume bounds = new BoundingSphere(1.0f, Vector3f.ZERO); |     private BoundingVolume bounds = new BoundingSphere(1.0f, Vector3f.ZERO); | ||||||
|     private boolean ready = false; |     private boolean ready = false; | ||||||
| @ -90,23 +94,6 @@ public class LightProbe extends Light implements Savable { | |||||||
|     public LightProbe() {         |     public LightProbe() {         | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * returns the irradiance map texture of this Light probe. |  | ||||||
|      * Note that this Texture may not have image data yet if the LightProbe is not ready |  | ||||||
|      * @return the irradiance map  |  | ||||||
|      */ |  | ||||||
|     public TextureCubeMap getIrradianceMap() { |  | ||||||
|         return irradianceMap; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Sets the irradiance map |  | ||||||
|      * @param irradianceMap the irradiance map |  | ||||||
|      */ |  | ||||||
|     public void setIrradianceMap(TextureCubeMap irradianceMap) { |  | ||||||
|         this.irradianceMap = irradianceMap; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * returns the prefiltered environment map texture of this light probe |      * returns the prefiltered environment map texture of this light probe | ||||||
|      * Note that this Texture may not have image data yet if the LightProbe is not ready |      * Note that this Texture may not have image data yet if the LightProbe is not ready | ||||||
| @ -128,7 +115,7 @@ public class LightProbe extends Light implements Savable { | |||||||
|     public void write(JmeExporter ex) throws IOException { |     public void write(JmeExporter ex) throws IOException { | ||||||
|         super.write(ex); |         super.write(ex); | ||||||
|         OutputCapsule oc = ex.getCapsule(this); |         OutputCapsule oc = ex.getCapsule(this); | ||||||
|         oc.write(irradianceMap, "irradianceMap", null); |         oc.write(shCoeffs, "shCoeffs", null); | ||||||
|         oc.write(prefilteredEnvMap, "prefilteredEnvMap", null); |         oc.write(prefilteredEnvMap, "prefilteredEnvMap", null); | ||||||
|         oc.write(position, "position", null); |         oc.write(position, "position", null); | ||||||
|         oc.write(bounds, "bounds", new BoundingSphere(1.0f, Vector3f.ZERO)); |         oc.write(bounds, "bounds", new BoundingSphere(1.0f, Vector3f.ZERO)); | ||||||
| @ -139,11 +126,15 @@ public class LightProbe extends Light implements Savable { | |||||||
|     public void read(JmeImporter im) throws IOException { |     public void read(JmeImporter im) throws IOException { | ||||||
|         super.read(im); |         super.read(im); | ||||||
|         InputCapsule ic = im.getCapsule(this); |         InputCapsule ic = im.getCapsule(this); | ||||||
|         irradianceMap = (TextureCubeMap) ic.readSavable("irradianceMap", null); |         shCoeffs = (Vector3f[]) ic.readSavableArray("shCoeffs", null); | ||||||
|         prefilteredEnvMap = (TextureCubeMap) ic.readSavable("prefilteredEnvMap", null); |         prefilteredEnvMap = (TextureCubeMap) ic.readSavable("prefilteredEnvMap", null); | ||||||
|         position = (Vector3f) ic.readSavable("position", this); |         position = (Vector3f) ic.readSavable("position", this); | ||||||
|         bounds = (BoundingVolume) ic.readSavable("bounds", new BoundingSphere(1.0f, Vector3f.ZERO)); |         bounds = (BoundingVolume) ic.readSavable("bounds", new BoundingSphere(1.0f, Vector3f.ZERO)); | ||||||
|         ready = ic.readBoolean("ready", false); |         ready = ic.readBoolean("ready", false); | ||||||
|  |         if (shCoeffs == null) { | ||||||
|  |             ready = false; | ||||||
|  |             logger.log(Level.WARNING, "LightProbe is missing parameters, it should be recomputed. Please use lightProbeFactory.updateProbe()"); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -195,14 +186,11 @@ public class LightProbe extends Light implements Savable { | |||||||
|      */ |      */ | ||||||
|     public Node getDebugGui(AssetManager manager) { |     public Node getDebugGui(AssetManager manager) { | ||||||
|         if (!ready) { |         if (!ready) { | ||||||
|             throw new UnsupportedOperationException("This EnvProbeis not ready yet, try to test isReady()"); |             throw new UnsupportedOperationException("This EnvProbe is not ready yet, try to test isReady()"); | ||||||
|         } |         } | ||||||
|         if (debugNode == null) { |         if (debugNode == null) { | ||||||
|             debugNode = new Node("debug gui probe"); |             debugNode = new Node("debug gui probe"); | ||||||
|             Node debugPfemCm = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(getPrefilteredEnvMap(), manager); |             Node debugPfemCm = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(getPrefilteredEnvMap(), manager); | ||||||
|             Node debugIrrCm = EnvMapUtils.getCubeMapCrossDebugView(getIrradianceMap(), manager); |  | ||||||
| 
 |  | ||||||
|             debugNode.attachChild(debugIrrCm); |  | ||||||
|             debugNode.attachChild(debugPfemCm); |             debugNode.attachChild(debugPfemCm); | ||||||
|             debugPfemCm.setLocalTranslation(520, 0, 0); |             debugPfemCm.setLocalTranslation(520, 0, 0); | ||||||
|         } |         } | ||||||
| @ -210,6 +198,14 @@ public class LightProbe extends Light implements Savable { | |||||||
|         return debugNode; |         return debugNode; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public Vector3f[] getShCoeffs() { | ||||||
|  |         return shCoeffs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void setShCoeffs(Vector3f[] shCoeffs) { | ||||||
|  |         this.shCoeffs = shCoeffs; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Returns the position of the LightProbe in world space |      * Returns the position of the LightProbe in world space | ||||||
|      * @return the wolrd space position |      * @return the wolrd space position | ||||||
|  | |||||||
| @ -115,7 +115,9 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique | |||||||
|         Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); |         Uniform ambientColor = shader.getUniform("g_AmbientLightColor"); | ||||||
|         Uniform lightProbeData = shader.getUniform("g_LightProbeData"); |         Uniform lightProbeData = shader.getUniform("g_LightProbeData"); | ||||||
|         lightProbeData.setVector4Length(1); |         lightProbeData.setVector4Length(1); | ||||||
|         Uniform lightProbeIrrMap = shader.getUniform("g_IrradianceMap"); | 
 | ||||||
|  |         //TODO These 2 uniforms should be packed in an array, to ba able to have several probes and blend between them. | ||||||
|  |         Uniform shCoeffs = shader.getUniform("g_ShCoeffs"); | ||||||
|         Uniform lightProbePemMap = shader.getUniform("g_PrefEnvMap"); |         Uniform lightProbePemMap = shader.getUniform("g_PrefEnvMap"); | ||||||
| 
 | 
 | ||||||
|         lightProbe = null; |         lightProbe = null; | ||||||
| @ -132,12 +134,9 @@ public final class SinglePassAndImageBasedLightingLogic extends DefaultTechnique | |||||||
|         if(lightProbe != null){ |         if(lightProbe != null){ | ||||||
|             BoundingSphere s = (BoundingSphere)lightProbe.getBounds(); |             BoundingSphere s = (BoundingSphere)lightProbe.getBounds(); | ||||||
|             lightProbeData.setVector4InArray(lightProbe.getPosition().x, lightProbe.getPosition().y, lightProbe.getPosition().z, 1f / s.getRadius() + lightProbe.getNbMipMaps(), 0); |             lightProbeData.setVector4InArray(lightProbe.getPosition().x, lightProbe.getPosition().y, lightProbe.getPosition().z, 1f / s.getRadius() + lightProbe.getNbMipMaps(), 0); | ||||||
|  |             shCoeffs.setValue(VarType.Vector3Array, lightProbe.getShCoeffs()); | ||||||
|             //assigning new texture indexes |             //assigning new texture indexes | ||||||
|             int irrUnit = lastTexUnit++; |  | ||||||
|             int pemUnit = lastTexUnit++; |             int pemUnit = lastTexUnit++; | ||||||
| 
 |  | ||||||
|             rm.getRenderer().setTexture(irrUnit, lightProbe.getIrradianceMap()); |  | ||||||
|             lightProbeIrrMap.setValue(VarType.Int, irrUnit); |  | ||||||
|             rm.getRenderer().setTexture(pemUnit, lightProbe.getPrefilteredEnvMap()); |             rm.getRenderer().setTexture(pemUnit, lightProbe.getPrefilteredEnvMap()); | ||||||
|             lightProbePemMap.setValue(VarType.Int, pemUnit); |             lightProbePemMap.setValue(VarType.Int, pemUnit); | ||||||
|         } else { |         } else { | ||||||
|  | |||||||
| @ -24,7 +24,7 @@ varying vec3 wPosition; | |||||||
| #ifdef INDIRECT_LIGHTING | #ifdef INDIRECT_LIGHTING | ||||||
| //  uniform sampler2D m_IntegrateBRDF; | //  uniform sampler2D m_IntegrateBRDF; | ||||||
|   uniform samplerCube g_PrefEnvMap; |   uniform samplerCube g_PrefEnvMap; | ||||||
|   uniform samplerCube g_IrradianceMap; |   uniform vec3 g_ShCoeffs[9]; | ||||||
|   uniform vec4 g_LightProbeData; |   uniform vec4 g_LightProbeData; | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| @ -257,9 +257,9 @@ void main(){ | |||||||
| 
 | 
 | ||||||
|         vec3 indirectDiffuse = vec3(0.0); |         vec3 indirectDiffuse = vec3(0.0); | ||||||
|         vec3 indirectSpecular = vec3(0.0); |         vec3 indirectSpecular = vec3(0.0); | ||||||
|         indirectDiffuse = textureCube(g_IrradianceMap, normal.xyz).rgb * diffuseColor.rgb; |         indirectDiffuse = sphericalHarmonics(normal.xyz, g_ShCoeffs) * diffuseColor.rgb; | ||||||
| 
 |         vec3 dominantR = getSpecularDominantDir( normal, rv.xyz, Roughness*Roughness ); | ||||||
|         indirectSpecular = ApproximateSpecularIBLPolynomial(g_PrefEnvMap, specularColor.rgb, Roughness, ndotv, rv.xyz, nbMipMaps); |         indirectSpecular = ApproximateSpecularIBLPolynomial(g_PrefEnvMap, specularColor.rgb, Roughness, ndotv, dominantR, nbMipMaps); | ||||||
|         indirectSpecular *= vec3(horiz); |         indirectSpecular *= vec3(horiz); | ||||||
| 
 | 
 | ||||||
|         vec3 indirectLighting =  indirectDiffuse + indirectSpecular; |         vec3 indirectLighting =  indirectDiffuse + indirectSpecular; | ||||||
|  | |||||||
| @ -53,6 +53,29 @@ void PBR_ComputeDirectLightSpecWF(vec3 normal, vec3 lightDir, vec3 viewDir, | |||||||
|     outSpecular = fresnel * vec3(specular) * lightColor; |     outSpecular = fresnel * vec3(specular) * lightColor; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | vec3 sphericalHarmonics( const in vec3 normal, const vec3 sph[9] ){ | ||||||
|  |     float x = normal.x; | ||||||
|  |     float y = normal.y; | ||||||
|  |     float z = normal.z; | ||||||
|  | 
 | ||||||
|  |     vec3 result = ( | ||||||
|  |         sph[0] + | ||||||
|  | 
 | ||||||
|  |         sph[1] * y + | ||||||
|  |         sph[2] * z + | ||||||
|  |         sph[3] * x + | ||||||
|  | 
 | ||||||
|  |         sph[4] * y * x + | ||||||
|  |         sph[5] * y * z + | ||||||
|  |         sph[6] * (3.0 * z * z - 1.0) + | ||||||
|  |         sph[7] * (z * x) + | ||||||
|  |         sph[8] * (x*x - y*y) | ||||||
|  |     ); | ||||||
|  | 
 | ||||||
|  |     return max(result, vec3(0.0)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| void PBR_ComputeDirectLight(vec3 normal, vec3 lightDir, vec3 viewDir, | void PBR_ComputeDirectLight(vec3 normal, vec3 lightDir, vec3 viewDir, | ||||||
|                             vec3 lightColor, float fZero, float roughness, float ndotv, |                             vec3 lightColor, float fZero, float roughness, float ndotv, | ||||||
|                             out vec3 outDiffuse, out vec3 outSpecular){ |                             out vec3 outDiffuse, out vec3 outSpecular){ | ||||||
| @ -115,6 +138,18 @@ vec3 integrateBRDFApprox( const in vec3 specular, float roughness, float NoV ){ | |||||||
|     return specular * AB.x + AB.y; |     return specular * AB.x + AB.y; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // from Sebastien Lagarde https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf page 69 | ||||||
|  | vec3 getSpecularDominantDir(const in vec3 N, const in vec3 R, const in float realRoughness){ | ||||||
|  |     vec3 dominant; | ||||||
|  | 
 | ||||||
|  |     float smoothness = 1.0 - realRoughness; | ||||||
|  |     float lerpFactor = smoothness * (sqrt(smoothness) + realRoughness); | ||||||
|  |     // The result is not normalized as we fetch in a cubemap | ||||||
|  |     dominant = mix(N, R, lerpFactor); | ||||||
|  | 
 | ||||||
|  |     return dominant; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| vec3 ApproximateSpecularIBL(samplerCube envMap,sampler2D integrateBRDF, vec3 SpecularColor , float Roughness, float ndotv, vec3 refVec, float nbMipMaps){ | vec3 ApproximateSpecularIBL(samplerCube envMap,sampler2D integrateBRDF, vec3 SpecularColor , float Roughness, float ndotv, vec3 refVec, float nbMipMaps){ | ||||||
|     float Lod = sqrt( Roughness ) * (nbMipMaps - 1.0); |     float Lod = sqrt( Roughness ) * (nbMipMaps - 1.0); | ||||||
|     vec3 PrefilteredColor =  textureCubeLod(envMap, refVec.xyz,Lod).rgb; |     vec3 PrefilteredColor =  textureCubeLod(envMap, refVec.xyz,Lod).rgb; | ||||||
|  | |||||||
| @ -73,7 +73,6 @@ public class TestPBRLighting extends SimpleApplication { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private Node tex; |     private Node tex; | ||||||
|     private Node tex2; |  | ||||||
| 
 | 
 | ||||||
|     private Geometry model; |     private Geometry model; | ||||||
|     private DirectionalLight dl; |     private DirectionalLight dl; | ||||||
| @ -94,7 +93,7 @@ public class TestPBRLighting extends SimpleApplication { | |||||||
| 
 | 
 | ||||||
|         dl = new DirectionalLight(); |         dl = new DirectionalLight(); | ||||||
|         dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); |         dl.setDirection(new Vector3f(-1, -1, -1).normalizeLocal()); | ||||||
|         //       rootNode.addLight(dl); |         rootNode.addLight(dl); | ||||||
|         dl.setColor(ColorRGBA.White); |         dl.setColor(ColorRGBA.White); | ||||||
|         rootNode.attachChild(modelNode); |         rootNode.attachChild(modelNode); | ||||||
| 
 | 
 | ||||||
| @ -103,7 +102,7 @@ public class TestPBRLighting extends SimpleApplication { | |||||||
| //        fpp.addFilter(new FXAAFilter()); | //        fpp.addFilter(new FXAAFilter()); | ||||||
|         fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(4.0f))); |         fpp.addFilter(new ToneMapFilter(Vector3f.UNIT_XYZ.mult(4.0f))); | ||||||
| //        fpp.addFilter(new SSAOFilter(0.5f, 3, 0.2f, 0.2f)); | //        fpp.addFilter(new SSAOFilter(0.5f, 3, 0.2f, 0.2f)); | ||||||
|         // viewPort.addProcessor(fpp); |         viewPort.addProcessor(fpp); | ||||||
| 
 | 
 | ||||||
|         //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Sky_Cloudy.hdr", SkyFactory.EnvMapType.EquirectMap); |         //Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Sky_Cloudy.hdr", SkyFactory.EnvMapType.EquirectMap); | ||||||
|         Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap); |         Spatial sky = SkyFactory.createSky(assetManager, "Textures/Sky/Path.hdr", SkyFactory.EnvMapType.EquirectMap); | ||||||
| @ -143,13 +142,10 @@ public class TestPBRLighting extends SimpleApplication { | |||||||
|                     if (tex == null) { |                     if (tex == null) { | ||||||
|                         return; |                         return; | ||||||
|                     } |                     } | ||||||
|                     if (tex.getParent() == null && tex2.getParent() == null) { |                     if (tex.getParent() == null) { | ||||||
|                         guiNode.attachChild(tex); |                         guiNode.attachChild(tex); | ||||||
|                     } else if (tex2.getParent() == null) { |  | ||||||
|                         tex.removeFromParent(); |  | ||||||
|                         guiNode.attachChild(tex2); |  | ||||||
|                     } else { |                     } else { | ||||||
|                         tex2.removeFromParent(); |                         tex.removeFromParent(); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
| @ -195,6 +191,7 @@ public class TestPBRLighting extends SimpleApplication { | |||||||
| 
 | 
 | ||||||
|         MaterialDebugAppState debug = new MaterialDebugAppState(); |         MaterialDebugAppState debug = new MaterialDebugAppState(); | ||||||
|         debug.registerBinding("Common/MatDefs/Light/PBRLighting.frag", rootNode); |         debug.registerBinding("Common/MatDefs/Light/PBRLighting.frag", rootNode); | ||||||
|  |         debug.registerBinding("Common/ShaderLib/PBR.glsllib", rootNode); | ||||||
|         getStateManager().attach(debug); |         getStateManager().attach(debug); | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
| @ -211,7 +208,6 @@ public class TestPBRLighting extends SimpleApplication { | |||||||
|                 public void done(LightProbe result) { |                 public void done(LightProbe result) { | ||||||
|                     System.err.println("Done rendering env maps"); |                     System.err.println("Done rendering env maps"); | ||||||
|                     tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager); |                     tex = EnvMapUtils.getCubeMapCrossDebugViewWithMipMaps(result.getPrefilteredEnvMap(), assetManager); | ||||||
|                     tex2 = EnvMapUtils.getCubeMapCrossDebugView(result.getIrradianceMap(), assetManager); |  | ||||||
|                 } |                 } | ||||||
|             }); |             }); | ||||||
|             ((BoundingSphere) probe.getBounds()).setRadius(100); |             ((BoundingSphere) probe.getBounds()).setRadius(100); | ||||||
|  | |||||||
| @ -306,16 +306,7 @@ public class TestPbrEnv extends SimpleApplication implements ActionListener { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (name.equals("debugProbe") && keyPressed) { |         if (name.equals("debugProbe") && keyPressed) { | ||||||
|             //getStateManager().getState(EnvironmentCamera.class).toggleDebug(); |             debugState.setEnabled(!debugState.isEnabled()); | ||||||
|             if (!debugState.isEnabled()) { |  | ||||||
|                 debugState.setEnabled(true); |  | ||||||
|                 debugState.setDebugMode(LightsDebugState.DebugMode.IrradianceMap); |  | ||||||
|             } else if (debugState.getDebugMode() == LightsDebugState.DebugMode.IrradianceMap) { |  | ||||||
|                 debugState.setDebugMode(LightsDebugState.DebugMode.PrefilteredEnvMap); |  | ||||||
|             } else if (debugState.getDebugMode() == LightsDebugState.DebugMode.PrefilteredEnvMap) { |  | ||||||
|                 debugState.setEnabled(false); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|         } |         } | ||||||
|          |          | ||||||
|         if (name.equals("debugTex") && keyPressed) { |         if (name.equals("debugTex") && keyPressed) { | ||||||
|  | |||||||
| @ -54,7 +54,7 @@ public class TestGltfLoading extends SimpleApplication { | |||||||
|     Node probeNode; |     Node probeNode; | ||||||
|     float time = 0; |     float time = 0; | ||||||
|     int assetIndex = 0; |     int assetIndex = 0; | ||||||
|     boolean useAutoRotate = true; |     boolean useAutoRotate = false; | ||||||
|     private final static String indentString = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; |     private final static String indentString = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; | ||||||
|     int duration = 2; |     int duration = 2; | ||||||
|     boolean playAnim = true; |     boolean playAnim = true; | ||||||
| @ -105,25 +105,27 @@ public class TestGltfLoading extends SimpleApplication { | |||||||
| //        PointLight pl1 = new PointLight(new Vector3f(-5.0f, -5.0f, -5.0f), ColorRGBA.White.mult(0.5f), 50); | //        PointLight pl1 = new PointLight(new Vector3f(-5.0f, -5.0f, -5.0f), ColorRGBA.White.mult(0.5f), 50); | ||||||
| //        rootNode.addLight(pl1); | //        rootNode.addLight(pl1); | ||||||
| 
 | 
 | ||||||
|         loadModel("Models/gltf/box/box.gltf", Vector3f.ZERO, 1); | //        loadModel("Models/gltf/box/box.gltf", Vector3f.ZERO, 1); | ||||||
|         loadModel("Models/gltf/duck/Duck.gltf", new Vector3f(0, -1, 0), 1); | //        loadModel("Models/gltf/duck/Duck.gltf", new Vector3f(0, -1, 0), 1); | ||||||
|         loadModel("Models/gltf/damagedHelmet/damagedHelmet.gltf", Vector3f.ZERO, 1); | //        loadModel("Models/gltf/damagedHelmet/damagedHelmet.gltf", Vector3f.ZERO, 1); | ||||||
|         loadModel("Models/gltf/hornet/scene.gltf", new Vector3f(0, -0.5f, 0), 0.4f); | //        loadModel("Models/gltf/hornet/scene.gltf", new Vector3f(0, -0.5f, 0), 0.4f); | ||||||
| //        loadModel("Models/gltf/adamHead/adamHead.gltf", Vector3f.ZERO, 0.6f); | ////        loadModel("Models/gltf/adamHead/adamHead.gltf", Vector3f.ZERO, 0.6f); | ||||||
|         loadModel("Models/gltf/busterDrone/busterDrone.gltf", new Vector3f(0, 0f, 0), 0.8f); |         //      loadModel("Models/gltf/busterDrone/busterDrone.gltf", new Vector3f(0, 0f, 0), 0.8f); | ||||||
|         loadModel("Models/gltf/animatedCube/AnimatedCube.gltf", Vector3f.ZERO, 0.5f); | //        loadModel("Models/gltf/animatedCube/AnimatedCube.gltf", Vector3f.ZERO, 0.5f); | ||||||
| 
 | // | ||||||
|         //TODO need to pad tracks that doesn't have the same length than the animation. | //        //loadModel("Models/gltf/BoxAnimated/BoxAnimated.gltf", new Vector3f(0, 0f, 0), 0.8f); | ||||||
|         //loadModel("Models/gltf/BoxAnimated/BoxAnimated.gltf", new Vector3f(0, 0f, 0), 0.8f); | // | ||||||
| 
 | //        loadModel("Models/gltf/RiggedFigure/RiggedSimple.gltf", new Vector3f(0, -0.3f, 0), 0.2f); | ||||||
|         loadModel("Models/gltf/RiggedFigure/RiggedSimple.gltf", new Vector3f(0, -0.3f, 0), 0.2f); |         //loadModel("Models/gltf/RiggedFigure/RiggedFigure.gltf", new Vector3f(0, -1f, 0), 1f); | ||||||
|         loadModel("Models/gltf/RiggedFigure/RiggedFigure.gltf", new Vector3f(0, -1f, 0), 1f); |         //loadModel("Models/gltf/CesiumMan/CesiumMan.gltf", new Vector3f(0, -1, 0), 1f); | ||||||
|         loadModel("Models/gltf/CesiumMan/CesiumMan.gltf", new Vector3f(0, -1, 0), 1f); |         //loadModel("Models/gltf/BrainStem/BrainStem.gltf", new Vector3f(0, -1, 0), 1f); | ||||||
|         loadModel("Models/gltf/BrainStem/BrainStem.gltf", new Vector3f(0, -1, 0), 1f); |  | ||||||
|         //loadModel("Models/gltf/Jaime/Jaime.gltf", new Vector3f(0, -1, 0), 1f); |         //loadModel("Models/gltf/Jaime/Jaime.gltf", new Vector3f(0, -1, 0), 1f); | ||||||
|         //loadModel("Models/gltf/GiantWorm/GiantWorm.gltf", new Vector3f(0, -1, 0), 1f); | //        loadModel("Models/gltf/GiantWorm/GiantWorm.gltf", new Vector3f(0, -1, 0), 1f); | ||||||
|         //loadModel("Models/gltf/RiggedFigure/WalkingLady.gltf", new Vector3f(0, -0.f, 0), 1f); | //        //loadModel("Models/gltf/RiggedFigure/WalkingLady.gltf", new Vector3f(0, -0.f, 0), 1f); | ||||||
|         loadModel("Models/gltf/Monster/Monster.gltf", Vector3f.ZERO, 0.03f); | //        loadModel("Models/gltf/Monster/Monster.gltf", Vector3f.ZERO, 0.03f); | ||||||
|  | 
 | ||||||
|  | //        loadModel("Models/gltf/corset/Corset.gltf", new Vector3f(0, -1, 0), 20f); | ||||||
|  |         loadModel("Models/gltf/boxInter/BoxInterleaved.gltf", new Vector3f(0, 0, 0), 1f); | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|         probeNode.attachChild(assets.get(0)); |         probeNode.attachChild(assets.get(0)); | ||||||
| @ -193,12 +195,14 @@ public class TestGltfLoading extends SimpleApplication { | |||||||
|             playFirstAnim(s); |             playFirstAnim(s); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
| //        SkeletonControl ctrl = findControl(s, SkeletonControl.class); |         SkeletonControl ctrl = findControl(s, SkeletonControl.class); | ||||||
|  | 
 | ||||||
| //        //ctrl.getSpatial().removeControl(ctrl); | //        //ctrl.getSpatial().removeControl(ctrl); | ||||||
| //        if (ctrl == null) { |         if (ctrl == null) { | ||||||
| //            return; |             return; | ||||||
| //        } |         } | ||||||
| //        getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(ctrl, true); |         ctrl.setHardwareSkinningPreferred(false); | ||||||
|  |         getStateManager().getState(SkeletonDebugAppState.class).addSkeleton(ctrl, true); | ||||||
| //        AnimControl aCtrl = findControl(s, AnimControl.class); | //        AnimControl aCtrl = findControl(s, AnimControl.class); | ||||||
| //        //ctrl.getSpatial().removeControl(ctrl); | //        //ctrl.getSpatial().removeControl(ctrl); | ||||||
| //        if (aCtrl == null) { | //        if (aCtrl == null) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user