• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2009-2010 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  *   notice, this list of conditions and the following disclaimer in the
14  *   documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17  *   may be used to endorse or promote products derived from this software
18  *   without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package com.jme3.shadow;
33 
34 import com.jme3.asset.AssetManager;
35 import com.jme3.material.Material;
36 import com.jme3.math.Vector3f;
37 import com.jme3.post.SceneProcessor;
38 import com.jme3.renderer.Camera;
39 import com.jme3.renderer.RenderManager;
40 import com.jme3.renderer.Renderer;
41 import com.jme3.renderer.ViewPort;
42 import com.jme3.renderer.queue.GeometryList;
43 import com.jme3.renderer.queue.RenderQueue;
44 import com.jme3.renderer.queue.RenderQueue.ShadowMode;
45 import com.jme3.texture.FrameBuffer;
46 import com.jme3.texture.Image.Format;
47 import com.jme3.texture.Texture2D;
48 import com.jme3.ui.Picture;
49 
50 /**
51  * BasicShadowRenderer uses standard shadow mapping with one map
52  * it's useful to render shadows in a small scene, but edges might look a bit jagged.
53  *
54  * @author Kirill Vainer
55  */
56 public class BasicShadowRenderer implements SceneProcessor {
57 
58     private RenderManager renderManager;
59     private ViewPort viewPort;
60     private FrameBuffer shadowFB;
61     private Texture2D shadowMap;
62     private Camera shadowCam;
63     private Material preshadowMat;
64     private Material postshadowMat;
65     private Picture dispPic = new Picture("Picture");
66     private boolean noOccluders = false;
67     private Vector3f[] points = new Vector3f[8];
68     private Vector3f direction = new Vector3f();
69 
70     /**
71      * Creates a BasicShadowRenderer
72      * @param manager the asset manager
73      * @param size the size of the shadow map (the map is square)
74      */
BasicShadowRenderer(AssetManager manager, int size)75     public BasicShadowRenderer(AssetManager manager, int size) {
76         shadowFB = new FrameBuffer(size, size, 1);
77         shadowMap = new Texture2D(size, size, Format.Depth);
78         shadowFB.setDepthTexture(shadowMap);
79         shadowCam = new Camera(size, size);
80 
81         preshadowMat = new Material(manager, "Common/MatDefs/Shadow/PreShadow.j3md");
82         postshadowMat = new Material(manager, "Common/MatDefs/Shadow/PostShadow.j3md");
83         postshadowMat.setTexture("ShadowMap", shadowMap);
84 
85         dispPic.setTexture(manager, shadowMap, false);
86 
87         for (int i = 0; i < points.length; i++) {
88             points[i] = new Vector3f();
89         }
90     }
91 
initialize(RenderManager rm, ViewPort vp)92     public void initialize(RenderManager rm, ViewPort vp) {
93         renderManager = rm;
94         viewPort = vp;
95 
96         reshape(vp, vp.getCamera().getWidth(), vp.getCamera().getHeight());
97     }
98 
isInitialized()99     public boolean isInitialized() {
100         return viewPort != null;
101     }
102 
103     /**
104      * returns the light direction used for this processor
105      * @return
106      */
getDirection()107     public Vector3f getDirection() {
108         return direction;
109     }
110 
111     /**
112      * sets the light direction to use to computs shadows
113      * @param direction
114      */
setDirection(Vector3f direction)115     public void setDirection(Vector3f direction) {
116         this.direction.set(direction).normalizeLocal();
117     }
118 
119     /**
120      * debug only
121      * @return
122      */
getPoints()123     public Vector3f[] getPoints() {
124         return points;
125     }
126 
127     /**
128      * debug only
129      * returns the shadow camera
130      * @return
131      */
getShadowCamera()132     public Camera getShadowCamera() {
133         return shadowCam;
134     }
135 
postQueue(RenderQueue rq)136     public void postQueue(RenderQueue rq) {
137         GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);
138         if (occluders.size() == 0) {
139             noOccluders = true;
140             return;
141         } else {
142             noOccluders = false;
143         }
144 
145         GeometryList receivers = rq.getShadowQueueContent(ShadowMode.Receive);
146 
147         // update frustum points based on current camera
148         Camera viewCam = viewPort.getCamera();
149         ShadowUtil.updateFrustumPoints(viewCam,
150                 viewCam.getFrustumNear(),
151                 viewCam.getFrustumFar(),
152                 1.0f,
153                 points);
154 
155         Vector3f frustaCenter = new Vector3f();
156         for (Vector3f point : points) {
157             frustaCenter.addLocal(point);
158         }
159         frustaCenter.multLocal(1f / 8f);
160 
161         // update light direction
162         shadowCam.setProjectionMatrix(null);
163         shadowCam.setParallelProjection(true);
164 //        shadowCam.setFrustumPerspective(45, 1, 1, 20);
165 
166         shadowCam.lookAtDirection(direction, Vector3f.UNIT_Y);
167         shadowCam.update();
168         shadowCam.setLocation(frustaCenter);
169         shadowCam.update();
170         shadowCam.updateViewProjection();
171 
172         // render shadow casters to shadow map
173         ShadowUtil.updateShadowCamera(occluders, receivers, shadowCam, points);
174 
175         Renderer r = renderManager.getRenderer();
176         renderManager.setCamera(shadowCam, false);
177         renderManager.setForcedMaterial(preshadowMat);
178 
179         r.setFrameBuffer(shadowFB);
180         r.clearBuffers(false, true, false);
181         viewPort.getQueue().renderShadowQueue(ShadowMode.Cast, renderManager, shadowCam, true);
182         r.setFrameBuffer(viewPort.getOutputFrameBuffer());
183 
184         renderManager.setForcedMaterial(null);
185         renderManager.setCamera(viewCam, false);
186     }
187 
188     /**
189      * debug only
190      * @return
191      */
getDisplayPicture()192     public Picture getDisplayPicture() {
193         return dispPic;
194     }
195 
postFrame(FrameBuffer out)196     public void postFrame(FrameBuffer out) {
197         if (!noOccluders) {
198             postshadowMat.setMatrix4("LightViewProjectionMatrix", shadowCam.getViewProjectionMatrix());
199             renderManager.setForcedMaterial(postshadowMat);
200             viewPort.getQueue().renderShadowQueue(ShadowMode.Receive, renderManager, viewPort.getCamera(), true);
201             renderManager.setForcedMaterial(null);
202         }
203     }
204 
preFrame(float tpf)205     public void preFrame(float tpf) {
206     }
207 
cleanup()208     public void cleanup() {
209     }
210 
reshape(ViewPort vp, int w, int h)211     public void reshape(ViewPort vp, int w, int h) {
212         dispPic.setPosition(w / 20f, h / 20f);
213         dispPic.setWidth(w / 5f);
214         dispPic.setHeight(h / 5f);
215     }
216 }
217