OSDN Git Service

Documented com.jme3.shadow
authorremy.bouquet@gmail.com <remy.bouquet@gmail.com@75d07b2b-3a1a-0410-a2c5-0572b91ccdca>
Tue, 14 Jun 2011 21:20:24 +0000 (21:20 +0000)
committerremy.bouquet@gmail.com <remy.bouquet@gmail.com@75d07b2b-3a1a-0410-a2c5-0572b91ccdca>
Tue, 14 Jun 2011 21:20:24 +0000 (21:20 +0000)
git-svn-id: http://jmonkeyengine.googlecode.com/svn/trunk@7631 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

engine/src/desktop-fx/com/jme3/shadow/BasicShadowRenderer.java
engine/src/desktop-fx/com/jme3/shadow/PssmShadowRenderer.java
engine/src/desktop-fx/com/jme3/shadow/PssmShadowUtil.java
engine/src/desktop-fx/com/jme3/shadow/ShadowCamera.java
engine/src/desktop-fx/com/jme3/shadow/ShadowUtil.java

index 8ea5008..73a2c73 100644 (file)
@@ -29,7 +29,6 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
  */\r
-\r
 package com.jme3.shadow;\r
 \r
 import com.jme3.material.Material;\r
@@ -48,74 +47,98 @@ import com.jme3.texture.Image.Format;
 import com.jme3.texture.Texture2D;\r
 import com.jme3.ui.Picture;\r
 \r
+/**\r
+ * BasicShadowRenderer uses standard shadow mapping with one map\r
+ * it's useful to render shadows in a small scene, but edges might look a bit jagged.\r
+ * \r
+ * @author Kirill Vainer\r
+ */\r
 public class BasicShadowRenderer implements SceneProcessor {\r
 \r
     private RenderManager renderManager;\r
     private ViewPort viewPort;\r
-\r
     private FrameBuffer shadowFB;\r
     private Texture2D shadowMap;\r
     private Camera shadowCam;\r
-\r
     private Material preshadowMat;\r
     private Material postshadowMat;\r
-\r
     private Picture dispPic = new Picture("Picture");\r
     private boolean noOccluders = false;\r
-\r
     private Vector3f[] points = new Vector3f[8];\r
     private Vector3f direction = new Vector3f();\r
 \r
-    public BasicShadowRenderer(AssetManager manager, int size){\r
-        shadowFB =  new FrameBuffer(size,size,1);\r
-        shadowMap = new Texture2D(size,size,Format.Depth);\r
+    /**\r
+     * Creates a BasicShadowRenderer\r
+     * @param manager the asset manager\r
+     * @param size the size of the shadow map (the map is square)\r
+     */\r
+    public BasicShadowRenderer(AssetManager manager, int size) {\r
+        shadowFB = new FrameBuffer(size, size, 1);\r
+        shadowMap = new Texture2D(size, size, Format.Depth);\r
         shadowFB.setDepthTexture(shadowMap);\r
-        shadowCam = new Camera(size,size);\r
-        \r
-        preshadowMat  = new Material(manager, "Common/MatDefs/Shadow/PreShadow.j3md");\r
+        shadowCam = new Camera(size, size);\r
+\r
+        preshadowMat = new Material(manager, "Common/MatDefs/Shadow/PreShadow.j3md");\r
         postshadowMat = new Material(manager, "Common/MatDefs/Shadow/PostShadow.j3md");\r
         postshadowMat.setTexture("ShadowMap", shadowMap);\r
 \r
         dispPic.setTexture(manager, shadowMap, false);\r
 \r
-        for (int i = 0; i < points.length; i++){\r
+        for (int i = 0; i < points.length; i++) {\r
             points[i] = new Vector3f();\r
         }\r
     }\r
 \r
-    public void initialize(RenderManager rm, ViewPort vp){\r
+    public void initialize(RenderManager rm, ViewPort vp) {\r
         renderManager = rm;\r
         viewPort = vp;\r
 \r
         reshape(vp, vp.getCamera().getWidth(), vp.getCamera().getHeight());\r
     }\r
 \r
-    public boolean isInitialized(){\r
+    public boolean isInitialized() {\r
         return viewPort != null;\r
     }\r
 \r
+    /**\r
+     * returns the light direction used for this processor\r
+     * @return \r
+     */\r
     public Vector3f getDirection() {\r
         return direction;\r
     }\r
 \r
+    /**\r
+     * sets the light direction to use to computs shadows\r
+     * @param direction \r
+     */\r
     public void setDirection(Vector3f direction) {\r
         this.direction.set(direction).normalizeLocal();\r
     }\r
 \r
+    /**\r
+     * debug only\r
+     * @return \r
+     */\r
     public Vector3f[] getPoints() {\r
         return points;\r
     }\r
 \r
-    public Camera getShadowCamera(){\r
+    /**\r
+     * debug only\r
+     * returns the shadow camera \r
+     * @return \r
+     */\r
+    public Camera getShadowCamera() {\r
         return shadowCam;\r
     }\r
 \r
-    public void postQueue(RenderQueue rq){\r
+    public void postQueue(RenderQueue rq) {\r
         GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);\r
-        if (occluders.size() == 0){\r
+        if (occluders.size() == 0) {\r
             noOccluders = true;\r
             return;\r
-        }else{\r
+        } else {\r
             noOccluders = false;\r
         }\r
 \r
@@ -124,13 +147,13 @@ public class BasicShadowRenderer implements SceneProcessor {
         // update frustum points based on current camera\r
         Camera viewCam = viewPort.getCamera();\r
         ShadowUtil.updateFrustumPoints(viewCam,\r
-                                       viewCam.getFrustumNear(),\r
-                                       viewCam.getFrustumFar(), \r
-                                       1.0f,\r
-                                       points);\r
+                viewCam.getFrustumNear(),\r
+                viewCam.getFrustumFar(),\r
+                1.0f,\r
+                points);\r
 \r
         Vector3f frustaCenter = new Vector3f();\r
-        for (Vector3f point : points){\r
+        for (Vector3f point : points) {\r
             frustaCenter.addLocal(point);\r
         }\r
         frustaCenter.multLocal(1f / 8f);\r
@@ -139,7 +162,7 @@ public class BasicShadowRenderer implements SceneProcessor {
         shadowCam.setProjectionMatrix(null);\r
         shadowCam.setParallelProjection(true);\r
 //        shadowCam.setFrustumPerspective(45, 1, 1, 20);\r
-        \r
+\r
         shadowCam.lookAtDirection(direction, Vector3f.UNIT_Y);\r
         shadowCam.update();\r
         shadowCam.setLocation(frustaCenter);\r
@@ -154,7 +177,7 @@ public class BasicShadowRenderer implements SceneProcessor {
         renderManager.setForcedMaterial(preshadowMat);\r
 \r
         r.setFrameBuffer(shadowFB);\r
-        r.clearBuffers(false,true,false);\r
+        r.clearBuffers(false, true, false);\r
         viewPort.getQueue().renderShadowQueue(ShadowMode.Cast, renderManager, shadowCam, true);\r
         r.setFrameBuffer(viewPort.getOutputFrameBuffer());\r
 \r
@@ -162,12 +185,16 @@ public class BasicShadowRenderer implements SceneProcessor {
         renderManager.setCamera(viewCam, false);\r
     }\r
 \r
-    public Picture getDisplayPicture(){\r
+    /**\r
+     * debug only\r
+     * @return \r
+     */\r
+    public Picture getDisplayPicture() {\r
         return dispPic;\r
     }\r
 \r
-    public void postFrame(FrameBuffer out){\r
-        if (!noOccluders){\r
+    public void postFrame(FrameBuffer out) {\r
+        if (!noOccluders) {\r
             postshadowMat.setMatrix4("LightViewProjectionMatrix", shadowCam.getViewProjectionMatrix());\r
             renderManager.setForcedMaterial(postshadowMat);\r
             viewPort.getQueue().renderShadowQueue(ShadowMode.Receive, renderManager, viewPort.getCamera(), true);\r
@@ -186,5 +213,4 @@ public class BasicShadowRenderer implements SceneProcessor {
         dispPic.setWidth(w / 5f);\r
         dispPic.setHeight(h / 5f);\r
     }\r
-\r
 }\r
index 4257669..67b2efb 100644 (file)
@@ -29,7 +29,6 @@
  * 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.shadow;
 
 import com.jme3.material.Material;
@@ -57,36 +56,42 @@ import com.jme3.texture.Texture.ShadowCompareMode;
 import com.jme3.texture.Texture2D;
 import com.jme3.ui.Picture;
 
+/**
+ * PssmShadow renderer use Parrallel Split Shadow Mapping technique (pssm)<br>
+ * It splits the view frustum in several parts and compute a shadow map for each one.<br>
+ * splits are distributed so that the closer they are from the camera, the smaller they are to maximize the resolution used of the shadow map.<br>
+ * This result in a better quality shadow than standard shadow mapping.<br>
+ * for more informations on this read this http://http.developer.nvidia.com/GPUGems3/gpugems3_ch10.html<br>
+ * 
+ * @author Rémy Bouquet aka Nehon
+ */
 public class PssmShadowRenderer implements SceneProcessor {
 
     /**
      * <code>FilterMode</code> specifies how shadows are filtered
      */
     public enum FilterMode {
+
         /**
          * Shadows are not filtered. Nearest sample is used, causing in blocky
          * shadows.
          */
         Nearest,
-
         /**
          * Bilinear filtering is used. Has the potential of being hardware
          * accelerated on some GPUs
          */
         Bilinear,
-
         /**
          * Dither-based sampling is used, very cheap but can look bad
          * at low resolutions.
          */
         Dither,
-
         /**
          * 4x4 percentage-closer filtering is used. Shadows will be smoother
          * at the cost of performance
          */
         PCF4,
-        
         /**
          * 8x8 percentage-closer  filtering is used. Shadows will be smoother
          * at the cost of performance
@@ -94,19 +99,21 @@ public class PssmShadowRenderer implements SceneProcessor {
         PCF8
     }
 
+    /**
+     * Specifies the shadow comparison mode 
+     */
     public enum CompareMode {
+
         /**
          * Shadow depth comparisons are done by using shader code
          */
         Software,
-
         /**
          * Shadow depth comparisons are done by using the GPU's dedicated
          * shadowing pipeline.
          */
         Hardware;
     }
-
     private int nbSplits = 3;
     private float lambda = 0.65f;
     private float shadowIntensity = 0.7f;
@@ -119,21 +126,17 @@ public class PssmShadowRenderer implements SceneProcessor {
     private Camera shadowCam;
     private Material preshadowMat;
     private Material postshadowMat;
-
     private GeometryList splitOccluders = new GeometryList(new OpaqueComparator());
     private Matrix4f[] lightViewProjectionsMatrices;
     private ColorRGBA splits;
     private float[] splitsArray;
     private boolean noOccluders = false;
-    
     private Vector3f direction = new Vector3f();
     private AssetManager assetManager;
     private boolean debug = false;
     private float edgesThickness = 1.0f;
-
     private FilterMode filterMode;
     private CompareMode compareMode;
-
     private Picture[] dispPic;
     private Vector3f[] points = new Vector3f[8];
 
@@ -154,26 +157,26 @@ public class PssmShadowRenderer implements SceneProcessor {
         dispPic = new Picture[nbSplits];
         lightViewProjectionsMatrices = new Matrix4f[nbSplits];
         splits = new ColorRGBA();
-        splitsArray = new float[nbSplits+1];
+        splitsArray = new float[nbSplits + 1];
 
         //DO NOT COMMENT THIS (it prevent the OSX incomplete read buffer crash)
-        dummyTex= new Texture2D(size, size, Format.RGBA8);
+        dummyTex = new Texture2D(size, size, Format.RGBA8);
 
-        preshadowMat  = new Material(manager, "Common/MatDefs/Shadow/PreShadow.j3md");
+        preshadowMat = new Material(manager, "Common/MatDefs/Shadow/PreShadow.j3md");
         postshadowMat = new Material(manager, "Common/MatDefs/Shadow/PostShadowPSSM.j3md");
 
         for (int i = 0; i < nbSplits; i++) {
             lightViewProjectionsMatrices[i] = new Matrix4f();
             shadowFB[i] = new FrameBuffer(size, size, 1);
             shadowMaps[i] = new Texture2D(size, size, Format.Depth);
-            
+
             shadowFB[i].setDepthTexture(shadowMaps[i]);
 
             //DO NOT COMMENT THIS (it prevent the OSX incomplete read buffer crash)
             shadowFB[i].setColorTexture(dummyTex);
 
             postshadowMat.setTexture("ShadowMap" + i, shadowMaps[i]);
-            
+
             //quads for debuging purpose
             dispPic[i] = new Picture("Picture" + i);
             dispPic[i].setTexture(manager, shadowMaps[i], false);
@@ -190,22 +193,28 @@ public class PssmShadowRenderer implements SceneProcessor {
         }
     }
 
-    public void setFilterMode(FilterMode filterMode){
-        if (filterMode == null)
+    /**
+     * Sets the filtering mode for shadow edges see {@link FilterMode} for more info
+     * @param filterMode 
+     */
+    public void setFilterMode(FilterMode filterMode) {
+        if (filterMode == null) {
             throw new NullPointerException();
+        }
 
-        if (this.filterMode == filterMode)
+        if (this.filterMode == filterMode) {
             return;
+        }
 
         this.filterMode = filterMode;
         postshadowMat.setInt("FilterMode", filterMode.ordinal());
         postshadowMat.setFloat("PCFEdge", edgesThickness);
-        if (compareMode == CompareMode.Hardware){
-            for (Texture2D shadowMap : shadowMaps){
-                if (filterMode == FilterMode.Bilinear){
+        if (compareMode == CompareMode.Hardware) {
+            for (Texture2D shadowMap : shadowMaps) {
+                if (filterMode == FilterMode.Bilinear) {
                     shadowMap.setMagFilter(MagFilter.Bilinear);
                     shadowMap.setMinFilter(MinFilter.BilinearNoMipMaps);
-                }else{
+                } else {
                     shadowMap.setMagFilter(MagFilter.Nearest);
                     shadowMap.setMinFilter(MinFilter.NearestNoMipMaps);
                 }
@@ -213,25 +222,31 @@ public class PssmShadowRenderer implements SceneProcessor {
         }
     }
 
+    /**
+     * sets the shadow compare mode see {@link CompareMode} for more info
+     * @param compareMode 
+     */
     public void setCompareMode(CompareMode compareMode) {
-        if (compareMode == null)
+        if (compareMode == null) {
             throw new NullPointerException();
+        }
 
-        if (this.compareMode == compareMode)
+        if (this.compareMode == compareMode) {
             return;
+        }
 
         this.compareMode = compareMode;
-        for (Texture2D shadowMap : shadowMaps){
-            if (compareMode == CompareMode.Hardware){
+        for (Texture2D shadowMap : shadowMaps) {
+            if (compareMode == CompareMode.Hardware) {
                 shadowMap.setShadowCompareMode(ShadowCompareMode.LessOrEqual);
-                if (filterMode == FilterMode.Bilinear){
+                if (filterMode == FilterMode.Bilinear) {
                     shadowMap.setMagFilter(MagFilter.Bilinear);
                     shadowMap.setMinFilter(MinFilter.BilinearNoMipMaps);
-                }else{
+                } else {
                     shadowMap.setMagFilter(MagFilter.Nearest);
                     shadowMap.setMinFilter(MinFilter.NearestNoMipMaps);
                 }
-            } else{
+            } else {
                 shadowMap.setShadowCompareMode(ShadowCompareMode.Off);
                 shadowMap.setMagFilter(MagFilter.Nearest);
                 shadowMap.setMinFilter(MinFilter.NearestNoMipMaps);
@@ -280,30 +295,40 @@ public class PssmShadowRenderer implements SceneProcessor {
         return viewPort != null;
     }
 
+    /**
+     * returns the light direction used by the processor
+     * @return 
+     */
     public Vector3f getDirection() {
         return direction;
     }
 
+    /**
+     * Sets the light direction to use to compute shadows
+     * @param direction 
+     */
     public void setDirection(Vector3f direction) {
         this.direction.set(direction).normalizeLocal();
     }
 
-    @SuppressWarnings("fallthrough") 
+    @SuppressWarnings("fallthrough")
     public void postQueue(RenderQueue rq) {
-        GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);        
-        if (occluders.size() == 0)
+        GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);
+        if (occluders.size() == 0) {
             return;
+        }
 
         GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive);
-        if (receivers.size() == 0)
+        if (receivers.size() == 0) {
             return;
-        
+        }
+
         Camera viewCam = viewPort.getCamera();
 
         float zFar = zFarOverride;
         if (zFar == 0) {
-            zFar=viewCam.getFrustumFar();
-          // zFar = PssmShadowUtil.computeZFar(occluders, receivers, viewCam);
+            zFar = viewCam.getFrustumFar();
+            // zFar = PssmShadowUtil.computeZFar(occluders, receivers, viewCam);
         }
         //  System.out.println("Zfar : "+zFar);
         ShadowUtil.updateFrustumPoints(viewCam, viewCam.getFrustumNear(), zFar, 1.0f, points);
@@ -322,7 +347,7 @@ public class PssmShadowRenderer implements SceneProcessor {
         PssmShadowUtil.updateFrustumSplits(splitsArray, viewCam.getFrustumNear(), zFar, lambda);
 
 
-        switch (splitsArray.length){
+        switch (splitsArray.length) {
             case 5:
                 splits.a = splitsArray[4];
             case 4:
@@ -345,25 +370,7 @@ public class PssmShadowRenderer implements SceneProcessor {
             ShadowUtil.updateFrustumPoints(viewCam, splitsArray[i], splitsArray[i + 1], 1.0f, points);
 
             //Updating shadow cam with curent split frustra
-         //   if(cropShadows){
-                ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points, splitOccluders);
-//            }else{
-//                ShadowUtil.updateShadowCamera(shadowCam, points);
-//            }           
-            //displaying the current splitted frustrum and the associated cropped light frustrums in wireframe.
-            //only for debuging purpose
-//            if (debug) {
-//                viewPort.attachScene(createFrustum(points, i));
-//                Vector3f[] pts = new Vector3f[8];
-//                for (int j = 0; j < pts.length; j++) {
-//                    pts[j] = new Vector3f();
-//                }
-//                ShadowUtil.updateFrustumPoints2(shadowCam, pts);
-//                viewPort.attachScene(createFrustum(pts, i));
-//                if (i == nbSplits-1) {
-//                    debug = false;
-//                }
-//            }
+            ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points, splitOccluders);
 
             //saving light view projection matrix for this split
             lightViewProjectionsMatrices[i] = shadowCam.getViewProjectionMatrix().clone();
@@ -373,9 +380,7 @@ public class PssmShadowRenderer implements SceneProcessor {
             r.clearBuffers(false, true, false);
 
             // render shadow casters to shadow map
-            viewPort.getQueue().renderShadowQueue(splitOccluders, renderManager,  shadowCam, true);
-            //viewPort.getQueue().renderShadowQueue(ShadowMode.Cast, renderManager, shadowCam, i == nbSplits - 1);
-            
+            viewPort.getQueue().renderShadowQueue(splitOccluders, renderManager, shadowCam, true);
         }
         occluders.clear();
         //restore setting for future rendering
@@ -383,11 +388,11 @@ public class PssmShadowRenderer implements SceneProcessor {
         renderManager.setForcedMaterial(null);
         renderManager.setForcedTechnique(null);
         renderManager.setCamera(viewCam, false);
-        
+
     }
 
     //debug only : displays depth shadow maps
-    public void displayShadowMap(Renderer r) {
+    private void displayShadowMap(Renderer r) {
         Camera cam = viewPort.getCamera();
         renderManager.setCamera(cam, true);
         int h = cam.getHeight();
@@ -421,8 +426,9 @@ public class PssmShadowRenderer implements SceneProcessor {
             renderManager.setCamera(cam, false);
 
         }
-        if (debug)
+        if (debug) {
             displayShadowMap(renderManager.getRenderer());
+        }
     }
 
     public void preFrame(float tpf) {
@@ -434,6 +440,11 @@ public class PssmShadowRenderer implements SceneProcessor {
     public void reshape(ViewPort vp, int w, int h) {
     }
 
+    /**
+     * returns the labda parameter<br>
+     * see {@link setLambda(float lambda)}
+     * @return 
+     */
     public float getLambda() {
         return lambda;
     }
@@ -450,6 +461,11 @@ public class PssmShadowRenderer implements SceneProcessor {
         this.lambda = lambda;
     }
 
+    /**
+     * How far the shadows are rendered in the view
+     * see {@link setShadowZExtend(float zFar)}
+     * @return 
+     */
     public float getShadowZExtend() {
         return zFarOverride;
     }
@@ -463,6 +479,11 @@ public class PssmShadowRenderer implements SceneProcessor {
         this.zFarOverride = zFar;
     }
 
+    /**
+     * returns the shdaow intensity<br>
+     * see {@link setShadowIntensity(float shadowIntensity)}
+     * @return 
+     */
     public float getShadowIntensity() {
         return shadowIntensity;
     }
@@ -479,14 +500,22 @@ public class PssmShadowRenderer implements SceneProcessor {
         postshadowMat.setFloat("ShadowIntensity", shadowIntensity);
     }
 
+    /**
+     * returns the edges thickness <br>
+     * see {@link setEdgesThickness(int edgesThickness)}
+     * @return 
+     */
     public int getEdgesThickness() {
         return (int) (edgesThickness * 10);
     }
 
+    /**
+     * Stes the shadow edges thickness. default is 1, setting it to lower values can help to reduce the jagged effect of the shadow edges
+     * @param edgesThickness 
+     */
     public void setEdgesThickness(int edgesThickness) {
-        this.edgesThickness = Math.max(1, Math.min(edgesThickness,10));
+        this.edgesThickness = Math.max(1, Math.min(edgesThickness, 10));
         this.edgesThickness *= 0.1f;
         postshadowMat.setFloat("PCFEdge", edgesThickness);
     }
 }
-
index 29f06aa..6de702d 100644 (file)
@@ -29,7 +29,6 @@
  * 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.shadow;
 
 import com.jme3.bounding.BoundingBox;
@@ -52,18 +51,6 @@ import static java.lang.Math.*;
  */
 public final class PssmShadowUtil {
 
-    public static void main(String[] args){
-        float[] splits = new float[5];
-        float[] splitsShader = new float[3];
-        updateFrustumSplits(splits, 1, 1000, 0.5f);
-        System.arraycopy(splits, 1, splitsShader, 0, splitsShader.length);
-        System.out.println(Arrays.toString(splitsShader));
-
-        for (int i = 0; i < splits.length-1; i++){
-            System.out.println(splits[i] + " - " + splits[i+1]);
-        }
-    }
-
     /**
      * Updates the frustum splits stores in <code>splits</code> using PSSM.
      */
@@ -86,7 +73,7 @@ public final class PssmShadowUtil {
      */
     public static float computeZFar(GeometryList occ, GeometryList recv, Camera cam) {
         Matrix4f mat = cam.getViewMatrix();
-        BoundingBox bbOcc  = ShadowUtil.computeUnionBound(occ, mat);
+        BoundingBox bbOcc = ShadowUtil.computeUnionBound(occ, mat);
         BoundingBox bbRecv = ShadowUtil.computeUnionBound(recv, mat);
 
         return min(max(bbOcc.getZExtent() - bbOcc.getCenter().z, bbRecv.getZExtent() - bbRecv.getCenter().z), cam.getFrustumFar());
index 9eba5e6..920e456 100644 (file)
@@ -29,7 +29,6 @@
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
  */\r
-\r
 package com.jme3.shadow;\r
 \r
 import com.jme3.light.DirectionalLight;\r
@@ -38,14 +37,19 @@ import com.jme3.light.PointLight;
 import com.jme3.math.Vector3f;\r
 import com.jme3.renderer.Camera;\r
 \r
+/**\r
+ * Creates a camera according to a light\r
+ * Handy to compute projection matrix of a light\r
+ * @author Kirill Vainer\r
+ */\r
 public class ShadowCamera {\r
 \r
     private Vector3f[] points = new Vector3f[8];\r
     private Light target;\r
 \r
-    public ShadowCamera(Light target){\r
+    public ShadowCamera(Light target) {\r
         this.target = target;\r
-        for (int i = 0; i < points.length; i++){\r
+        for (int i = 0; i < points.length; i++) {\r
             points[i] = new Vector3f();\r
         }\r
     }\r
@@ -53,14 +57,14 @@ public class ShadowCamera {
     /**\r
      * Updates the camera view direction and position based on the light\r
      */\r
-    private void updateLightCamera(Camera lightCam){\r
-        if (target.getType() == Light.Type.Directional){\r
+    public void updateLightCamera(Camera lightCam) {\r
+        if (target.getType() == Light.Type.Directional) {\r
             DirectionalLight dl = (DirectionalLight) target;\r
             lightCam.setParallelProjection(true);\r
             lightCam.setLocation(Vector3f.ZERO);\r
-            lightCam.lookAtDirection(dl.getDirection(), Vector3f.UNIT_Y );\r
+            lightCam.lookAtDirection(dl.getDirection(), Vector3f.UNIT_Y);\r
             lightCam.setFrustum(-1, 1, -1, 1, 1, -1);\r
-        }else{\r
+        } else {\r
             PointLight pl = (PointLight) target;\r
             lightCam.setParallelProjection(false);\r
             lightCam.setLocation(pl.getPosition());\r
@@ -68,5 +72,4 @@ public class ShadowCamera {
             lightCam.setFrustumPerspective(45, 1, 1, 300);\r
         }\r
     }\r
-\r
 }\r
index ba16f4f..981674b 100644 (file)
  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
  */\r
-\r
 package com.jme3.shadow;\r
 \r
 import com.jme3.bounding.BoundingBox;\r
 import com.jme3.bounding.BoundingVolume;\r
-import com.jme3.math.FastMath;\r
 import com.jme3.math.Matrix4f;\r
 import com.jme3.math.Transform;\r
 import com.jme3.math.Vector2f;\r
@@ -58,7 +56,12 @@ import static java.lang.Math.*;
  */\r
 public class ShadowUtil {\r
 \r
-    public static void updateFrustumPoints2(Camera viewCam, Vector3f[] points){\r
+    /**\r
+     * Updates a points arrays with the frustum corners of the provided camera.\r
+     * @param viewCam\r
+     * @param points \r
+     */\r
+    public static void updateFrustumPoints2(Camera viewCam, Vector3f[] points) {\r
         int w = viewCam.getWidth();\r
         int h = viewCam.getHeight();\r
         float n = viewCam.getFrustumNear();\r
@@ -68,7 +71,7 @@ public class ShadowUtil {
         points[1].set(viewCam.getWorldCoordinates(new Vector2f(0, h), n));\r
         points[2].set(viewCam.getWorldCoordinates(new Vector2f(w, h), n));\r
         points[3].set(viewCam.getWorldCoordinates(new Vector2f(w, 0), n));\r
-        \r
+\r
         points[4].set(viewCam.getWorldCoordinates(new Vector2f(0, 0), f));\r
         points[5].set(viewCam.getWorldCoordinates(new Vector2f(0, h), f));\r
         points[6].set(viewCam.getWorldCoordinates(new Vector2f(w, h), f));\r
@@ -87,10 +90,10 @@ public class ShadowUtil {
      * @param farOverride\r
      */\r
     public static void updateFrustumPoints(Camera viewCam,\r
-                                           float nearOverride,\r
-                                           float farOverride,\r
-                                           float scale,\r
-                                           Vector3f[] points) {\r
+            float nearOverride,\r
+            float farOverride,\r
+            float scale,\r
+            Vector3f[] points) {\r
 \r
         Vector3f pos = viewCam.getLocation();\r
         Vector3f dir = viewCam.getDirection();\r
@@ -160,6 +163,12 @@ public class ShadowUtil {
         }\r
     }\r
 \r
+    /**\r
+     * Compute bounds of a geomList\r
+     * @param list\r
+     * @param transform\r
+     * @return \r
+     */\r
     public static BoundingBox computeUnionBound(GeometryList list, Transform transform) {\r
         BoundingBox bbox = new BoundingBox();\r
         for (int i = 0; i < list.size(); i++) {\r
@@ -173,6 +182,12 @@ public class ShadowUtil {
         return bbox;\r
     }\r
 \r
+    /**\r
+     * Compute bounds of a geomList\r
+     * @param list\r
+     * @param mat\r
+     * @return \r
+     */\r
     public static BoundingBox computeUnionBound(GeometryList list, Matrix4f mat) {\r
         BoundingBox bbox = new BoundingBox();\r
         BoundingVolume store = null;\r
@@ -187,6 +202,11 @@ public class ShadowUtil {
         return bbox;\r
     }\r
 \r
+    /**\r
+     * Computes the bounds of multiple bounding volumes\r
+     * @param bv\r
+     * @return \r
+     */\r
     public static BoundingBox computeUnionBound(List<BoundingVolume> bv) {\r
         BoundingBox bbox = new BoundingBox();\r
         for (int i = 0; i < bv.size(); i++) {\r
@@ -196,6 +216,12 @@ public class ShadowUtil {
         return bbox;\r
     }\r
 \r
+    /**\r
+     * Compute bounds from an array of points\r
+     * @param pts\r
+     * @param transform\r
+     * @return \r
+     */\r
     public static BoundingBox computeBoundForPoints(Vector3f[] pts, Transform transform) {\r
         Vector3f min = new Vector3f(Vector3f.POSITIVE_INFINITY);\r
         Vector3f max = new Vector3f(Vector3f.NEGATIVE_INFINITY);\r
@@ -211,6 +237,12 @@ public class ShadowUtil {
         return new BoundingBox(center, extent.x, extent.y, extent.z);\r
     }\r
 \r
+    /**\r
+     * Compute bounds from an array of points\r
+     * @param pts\r
+     * @param mat\r
+     * @return \r
+     */\r
     public static BoundingBox computeBoundForPoints(Vector3f[] pts, Matrix4f mat) {\r
         Vector3f min = new Vector3f(Vector3f.POSITIVE_INFINITY);\r
         Vector3f max = new Vector3f(Vector3f.NEGATIVE_INFINITY);\r
@@ -228,16 +260,10 @@ public class ShadowUtil {
             max.maxLocal(temp);\r
         }\r
 \r
-//        min.x = FastMath.clamp(min.x, -1f, 1f);\r
-//        max.y = FastMath.clamp(max.y, -1f, 1f);\r
-//        min.x = FastMath.clamp(min.x, -1f, 1f);\r
-//        max.y = FastMath.clamp(max.y, -1f, 1f);\r
-\r
         Vector3f center = min.add(max).multLocal(0.5f);\r
         Vector3f extent = max.subtract(min).multLocal(0.5f);\r
         //Nehon 08/18/2010 : Added an offset to the extend to avoid banding artifacts when the frustum are aligned\r
-        return new BoundingBox(center, extent.x + 2.0f, extent.y + 2.0f, extent.z +2.5f);\r
-        //return new BoundingBox(center, extent.x, extent.y, extent.z);\r
+        return new BoundingBox(center, extent.x + 2.0f, extent.y + 2.0f, extent.z + 2.5f);\r
     }\r
 \r
     /**\r
@@ -248,7 +274,7 @@ public class ShadowUtil {
      * @param lightCam\r
      * @param points\r
      */\r
-    public static void updateShadowCamera(Camera shadowCam, Vector3f[] points){\r
+    public static void updateShadowCamera(Camera shadowCam, Vector3f[] points) {\r
         boolean ortho = shadowCam.isParallelProjection();\r
         shadowCam.setProjectionMatrix(null);\r
 \r
@@ -265,7 +291,7 @@ public class ShadowUtil {
 \r
         Vector3f splitMin = splitBB.getMin(null);\r
         Vector3f splitMax = splitBB.getMax(null);\r
-        \r
+\r
 //        splitMin.z = 0;\r
 \r
         // Create the crop matrix.\r
@@ -280,9 +306,9 @@ public class ShadowUtil {
         offsetZ = -splitMin.z * scaleZ;\r
 \r
         Matrix4f cropMatrix = new Matrix4f(scaleX, 0f, 0f, offsetX,\r
-                                           0f, scaleY, 0f, offsetY,\r
-                                           0f, 0f, scaleZ, offsetZ,\r
-                                           0f, 0f, 0f, 1f);\r
+                0f, scaleY, 0f, offsetY,\r
+                0f, 0f, scaleZ, offsetZ,\r
+                0f, 0f, 0f, 1f);\r
 \r
 \r
         Matrix4f result = new Matrix4f();\r
@@ -302,9 +328,9 @@ public class ShadowUtil {
      * @param points\r
      */\r
     public static void updateShadowCamera(GeometryList occluders,\r
-                                          GeometryList receivers,\r
-                                          Camera shadowCam,\r
-                                          Vector3f[] points){\r
+            GeometryList receivers,\r
+            Camera shadowCam,\r
+            Vector3f[] points) {\r
         updateShadowCamera(occluders, receivers, shadowCam, points, null);\r
     }\r
 \r
@@ -318,51 +344,48 @@ public class ShadowUtil {
      * @param points\r
      */\r
     public static void updateShadowCamera(GeometryList occluders,\r
-                                          GeometryList receivers,\r
-                                          Camera shadowCam,\r
-                                          Vector3f[] points,\r
-                                          GeometryList splitOccluders){\r
+            GeometryList receivers,\r
+            Camera shadowCam,\r
+            Vector3f[] points,\r
+            GeometryList splitOccluders) {\r
 \r
         boolean ortho = shadowCam.isParallelProjection();\r
 \r
         shadowCam.setProjectionMatrix(null);\r
 \r
-        if (ortho){\r
+        if (ortho) {\r
             shadowCam.setFrustum(-1, 1, -1, 1, 1, -1);\r
-        }else{\r
+        } else {\r
             shadowCam.setFrustumPerspective(45, 1, 1, 150);\r
         }\r
 \r
-        // create transform to rotate points to viewspace\r
-        //Transform t = new Transform(shadowCam.getRotation());\r
+        // create transform to rotate points to viewspace        \r
         Matrix4f viewProjMatrix = shadowCam.getViewProjectionMatrix();\r
 \r
-//        BoundingBox casterBB   = computeUnionBound(occluders, viewProjMatrix);\r
-//        BoundingBox receiverBB = computeUnionBound(receivers, viewProjMatrix);\r
-        BoundingBox splitBB    = computeBoundForPoints(points, viewProjMatrix);\r
+        BoundingBox splitBB = computeBoundForPoints(points, viewProjMatrix);\r
 \r
         ArrayList<BoundingVolume> visRecvList = new ArrayList<BoundingVolume>();\r
-        for (int i = 0; i < receivers.size(); i++){\r
+        for (int i = 0; i < receivers.size(); i++) {\r
             // convert bounding box to light's viewproj space\r
             Geometry receiver = receivers.get(i);\r
             BoundingVolume bv = receiver.getWorldBound();\r
             BoundingVolume recvBox = bv.transform(viewProjMatrix, null);\r
-            \r
-            if (splitBB.intersects(recvBox)){\r
+\r
+            if (splitBB.intersects(recvBox)) {\r
                 visRecvList.add(recvBox);\r
             }\r
         }\r
-        \r
+\r
         ArrayList<BoundingVolume> visOccList = new ArrayList<BoundingVolume>();\r
-        for (int i = 0; i < occluders.size(); i++){\r
+        for (int i = 0; i < occluders.size(); i++) {\r
             // convert bounding box to light's viewproj space\r
             Geometry occluder = occluders.get(i);\r
             BoundingVolume bv = occluder.getWorldBound();\r
             BoundingVolume occBox = bv.transform(viewProjMatrix, null);\r
 \r
             boolean intersects = splitBB.intersects(occBox);\r
-            if (!intersects && occBox instanceof BoundingBox){\r
-                BoundingBox occBB = (BoundingBox)occBox;\r
+            if (!intersects && occBox instanceof BoundingBox) {\r
+                BoundingBox occBB = (BoundingBox) occBox;\r
                 //Kirill 01/10/2011\r
                 // Extend the occluder further into the frustum\r
                 // This fixes shadow dissapearing issues when\r
@@ -371,26 +394,26 @@ public class ShadowUtil {
                 //      The number is in world units\r
                 occBB.setZExtent(occBB.getZExtent() + 50);\r
                 occBB.setCenter(occBB.getCenter().addLocal(0, 0, 25));\r
-                if (splitBB.intersects(occBB)){\r
+                if (splitBB.intersects(occBB)) {\r
                     // To prevent extending the depth range too much\r
                     // We return the bound to its former shape\r
                     // Before adding it\r
                     occBB.setZExtent(occBB.getZExtent() - 50);\r
                     occBB.setCenter(occBB.getCenter().subtractLocal(0, 0, 25));\r
                     visOccList.add(occBox);\r
-                    if(splitOccluders != null){\r
+                    if (splitOccluders != null) {\r
                         splitOccluders.add(occluder);\r
                     }\r
                 }\r
-            }else if (intersects){\r
+            } else if (intersects) {\r
                 visOccList.add(occBox);\r
-                if(splitOccluders != null){\r
+                if (splitOccluders != null) {\r
                     splitOccluders.add(occluder);\r
                 }\r
             }\r
         }\r
 \r
-        BoundingBox casterBB   = computeUnionBound(visOccList);\r
+        BoundingBox casterBB = computeUnionBound(visOccList);\r
         BoundingBox receiverBB = computeUnionBound(visRecvList);\r
 \r
         //Nehon 08/18/2010 this is to avoid shadow bleeding when the ground is set to only receive shadows\r
@@ -409,16 +432,12 @@ public class ShadowUtil {
         Vector3f splitMin = splitBB.getMin(null);\r
         Vector3f splitMax = splitBB.getMax(null);\r
 \r
-//        actualMin.x = FastMath.clamp(actualMin.x, -1, 1);\r
-//        actualMin.y = FastMath.clamp(actualMin.y, -1, 1);\r
-//        actualMax.x = FastMath.clamp(actualMax.x, -1, 1);\r
-//        actualMax.y = FastMath.clamp(actualMax.y, -1, 1);\r
-//        float far = actualMin.z + actualMax.z * 4 + 1.0f + 1.5f;\r
         splitMin.z = 0;\r
 \r
-        if (!ortho)\r
+        if (!ortho) {\r
             shadowCam.setFrustumPerspective(45, 1, 1, splitMax.z);\r
-        \r
+        }\r
+\r
         Matrix4f projMatrix = shadowCam.getProjectionMatrix();\r
 \r
         Vector3f cropMin = new Vector3f();\r
@@ -434,11 +453,6 @@ public class ShadowUtil {
         cropMin.z = min(casterMin.z, splitMin.z);\r
         cropMax.z = min(receiverMax.z, splitMax.z);\r
 \r
-//        cropMin.set(splitMin);\r
-//        cropMax.set(splitMax);\r
-\r
-//        cropMin.z = Math.min(cropMin.z, cropMax.z - cropMin.z - 1000);\r
-//        cropMin.z = Math.max(10f, cropMin.z);\r
 \r
         // Create the crop matrix.\r
         float scaleX, scaleY, scaleZ;\r
@@ -446,48 +460,26 @@ public class ShadowUtil {
 \r
         scaleX = (2.0f) / (cropMax.x - cropMin.x);\r
         scaleY = (2.0f) / (cropMax.y - cropMin.y);\r
-        \r
+\r
         offsetX = -0.5f * (cropMax.x + cropMin.x) * scaleX;\r
         offsetY = -0.5f * (cropMax.y + cropMin.y) * scaleY;\r
 \r
         scaleZ = 1.0f / (cropMax.z - cropMin.z);\r
         offsetZ = -cropMin.z * scaleZ;\r
 \r
-//        scaleZ = 2.0f / (cropMax.z - cropMin.z);\r
-//        offsetZ = -0.5f * (cropMax.z + cropMin.z) * scaleZ;\r
 \r
-        Matrix4f cropMatrix = new Matrix4f(scaleX,  0f,      0f,      offsetX,\r
-                                           0f,      scaleY,  0f,      offsetY,\r
-                                           0f,      0f,      scaleZ,  offsetZ,\r
-                                           0f,      0f,      0f,      1f);\r
 \r
-//        cropMatrix.transposeLocal();\r
-//        Matrix4f cropMatrix = new Matrix4f();\r
-//        cropMatrix.setScale(new Vector3f(scaleX, scaleY, 1f));\r
-//        cropMatrix.setTranslation(offsetX, offsetY, 0);\r
+        Matrix4f cropMatrix = new Matrix4f(scaleX, 0f, 0f, offsetX,\r
+                0f, scaleY, 0f, offsetY,\r
+                0f, 0f, scaleZ, offsetZ,\r
+                0f, 0f, 0f, 1f);\r
+\r
 \r
         Matrix4f result = new Matrix4f();\r
         result.set(cropMatrix);\r
         result.multLocal(projMatrix);\r
-//        result.set(projMatrix);\r
-//        result.multLocal(cropMatrix);\r
-        shadowCam.setProjectionMatrix(result);\r
-\r
-//        shadowCam.setFrustum(cropMin.z, cropMax.z, // near, far\r
-//                             cropMin.x, cropMax.x, // left, right\r
-//                             cropMax.y, cropMin.y); // top, bottom\r
 \r
-        // compute size and center of final frustum\r
-        //float sizeX   = (max.x - min.x) / 2f;\r
-        //float sizeY   = (max.y - min.y) / 2f;\r
-        //float offsetX = (max.x + min.x) / -2f;\r
-        //float offsetY = (max.y + min.y) / -2f;\r
-\r
-        // compute center for frustum\r
-        //temp.set(offsetX, offsetY, 0);\r
-        //invRot.mult(temp, temp);\r
+        shadowCam.setProjectionMatrix(result);\r
 \r
-        //shadowCam.setLocation(temp);\r
-        //shadowCam.setFrustum(min.z, max.z, -sizeX, sizeX, sizeY, -sizeY);\r
     }\r
 }\r