AbstractShadowRenderer.java 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /*
  2. * Copyright (c) 2009-2012 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. import java.io.IOException;
  34. import java.util.ArrayList;
  35. import java.util.List;
  36. import com.jme3.asset.AssetManager;
  37. import com.jme3.export.InputCapsule;
  38. import com.jme3.export.JmeExporter;
  39. import com.jme3.export.JmeImporter;
  40. import com.jme3.export.OutputCapsule;
  41. import com.jme3.export.Savable;
  42. import com.jme3.material.Material;
  43. import com.jme3.math.ColorRGBA;
  44. import com.jme3.math.Matrix4f;
  45. import com.jme3.math.Vector3f;
  46. import com.jme3.post.SceneProcessor;
  47. import com.jme3.renderer.Camera;
  48. import com.jme3.renderer.Caps;
  49. import com.jme3.renderer.RenderManager;
  50. import com.jme3.renderer.Renderer;
  51. import com.jme3.renderer.ViewPort;
  52. import com.jme3.renderer.queue.GeometryList;
  53. import com.jme3.renderer.queue.OpaqueComparator;
  54. import com.jme3.renderer.queue.RenderQueue;
  55. import com.jme3.renderer.queue.RenderQueue.ShadowMode;
  56. import com.jme3.scene.Geometry;
  57. import com.jme3.scene.Spatial;
  58. import com.jme3.scene.debug.WireFrustum;
  59. import com.jme3.texture.FrameBuffer;
  60. import com.jme3.texture.Image.Format;
  61. import com.jme3.texture.Texture.MagFilter;
  62. import com.jme3.texture.Texture.MinFilter;
  63. import com.jme3.texture.Texture.ShadowCompareMode;
  64. import com.jme3.texture.Texture2D;
  65. import com.jme3.ui.Picture;
  66. /**
  67. * abstract shadow renderer that holds commons feature to have for a shadow
  68. * renderer
  69. *
  70. * @author Rémy Bouquet aka Nehon
  71. */
  72. public abstract class AbstractShadowRenderer implements SceneProcessor, Savable {
  73. protected int nbShadowMaps = 1;
  74. protected float shadowMapSize;
  75. protected float shadowIntensity = 0.7f;
  76. protected RenderManager renderManager;
  77. protected ViewPort viewPort;
  78. protected FrameBuffer[] shadowFB;
  79. protected Texture2D[] shadowMaps;
  80. protected Texture2D dummyTex;
  81. protected Material preshadowMat;
  82. protected Material postshadowMat;
  83. protected Matrix4f[] lightViewProjectionsMatrices;
  84. protected AssetManager assetManager;
  85. protected boolean debug = false;
  86. protected float edgesThickness = 1.0f;
  87. protected EdgeFilteringMode edgeFilteringMode = EdgeFilteringMode.Bilinear;
  88. protected CompareMode shadowCompareMode = CompareMode.Hardware;
  89. protected Picture[] dispPic;
  90. protected boolean flushQueues = true;
  91. // define if the fallback material should be used.
  92. protected boolean needsfallBackMaterial = false;
  93. //Name of the post material technique
  94. protected String postTechniqueName = "PostShadow";
  95. //flags to know when to change params in the materials
  96. //a list of material of the post shadow queue geometries.
  97. protected List<Material> matCache = new ArrayList<Material>();
  98. protected GeometryList sceneReceivers;
  99. protected GeometryList lightReceivers = new GeometryList(new OpaqueComparator());
  100. protected GeometryList shadowMapOccluders = new GeometryList(new OpaqueComparator());
  101. private String[] shadowMapStringCache;
  102. private String[] lightViewStringCache;
  103. //used to skip the post pass when there are no shadow casters.
  104. protected boolean skipPostPass;
  105. /**
  106. * used for serialization
  107. */
  108. protected AbstractShadowRenderer(){
  109. }
  110. /**
  111. * Create an abstract shadow renderer, this is to be called in extending
  112. * classes
  113. *
  114. * @param assetManager the application asset manager
  115. * @param shadowMapSize the size of the rendered shadowmaps (512,1024,2048,
  116. * etc...)
  117. * @param nbShadowMaps the number of shadow maps rendered (the more shadow
  118. * maps the more quality, the less fps).
  119. */
  120. protected AbstractShadowRenderer(AssetManager assetManager, int shadowMapSize, int nbShadowMaps) {
  121. this.assetManager = assetManager;
  122. this.nbShadowMaps = nbShadowMaps;
  123. this.shadowMapSize = shadowMapSize;
  124. init(assetManager, nbShadowMaps, shadowMapSize);
  125. }
  126. private void init(AssetManager assetManager, int nbShadowMaps, int shadowMapSize) {
  127. this.postshadowMat = new Material(assetManager, "Common/MatDefs/Shadow/PostShadow.j3md");
  128. shadowFB = new FrameBuffer[nbShadowMaps];
  129. shadowMaps = new Texture2D[nbShadowMaps];
  130. dispPic = new Picture[nbShadowMaps];
  131. lightViewProjectionsMatrices = new Matrix4f[nbShadowMaps];
  132. shadowMapStringCache = new String[nbShadowMaps];
  133. lightViewStringCache = new String[nbShadowMaps];
  134. //DO NOT COMMENT THIS (it prevent the OSX incomplete read buffer crash)
  135. dummyTex = new Texture2D(shadowMapSize, shadowMapSize, Format.RGBA8);
  136. preshadowMat = new Material(assetManager, "Common/MatDefs/Shadow/PreShadow.j3md");
  137. postshadowMat.setFloat("ShadowMapSize", shadowMapSize);
  138. for (int i = 0; i < nbShadowMaps; i++) {
  139. lightViewProjectionsMatrices[i] = new Matrix4f();
  140. shadowFB[i] = new FrameBuffer(shadowMapSize, shadowMapSize, 1);
  141. shadowMaps[i] = new Texture2D(shadowMapSize, shadowMapSize, Format.Depth);
  142. shadowFB[i].setDepthTexture(shadowMaps[i]);
  143. //DO NOT COMMENT THIS (it prevent the OSX incomplete read buffer crash)
  144. shadowFB[i].setColorTexture(dummyTex);
  145. shadowMapStringCache[i] = "ShadowMap" + i;
  146. lightViewStringCache[i] = "LightViewProjectionMatrix" + i;
  147. postshadowMat.setTexture(shadowMapStringCache[i], shadowMaps[i]);
  148. //quads for debuging purpose
  149. dispPic[i] = new Picture("Picture" + i);
  150. dispPic[i].setTexture(assetManager, shadowMaps[i], false);
  151. }
  152. setShadowCompareMode(shadowCompareMode);
  153. setEdgeFilteringMode(edgeFilteringMode);
  154. setShadowIntensity(shadowIntensity);
  155. }
  156. /**
  157. * set the post shadow material for this renderer
  158. *
  159. * @param postShadowMat
  160. */
  161. protected final void setPostShadowMaterial(Material postShadowMat) {
  162. this.postshadowMat = postShadowMat;
  163. postshadowMat.setFloat("ShadowMapSize", shadowMapSize);
  164. for (int i = 0; i < nbShadowMaps; i++) {
  165. postshadowMat.setTexture(shadowMapStringCache[i], shadowMaps[i]);
  166. }
  167. setShadowCompareMode(shadowCompareMode);
  168. setEdgeFilteringMode(edgeFilteringMode);
  169. setShadowIntensity(shadowIntensity);
  170. }
  171. /**
  172. * Sets the filtering mode for shadow edges see {@link EdgeFilteringMode}
  173. * for more info
  174. *
  175. * @param EdgeFilteringMode
  176. */
  177. final public void setEdgeFilteringMode(EdgeFilteringMode filterMode) {
  178. if (filterMode == null) {
  179. throw new NullPointerException();
  180. }
  181. this.edgeFilteringMode = filterMode;
  182. postshadowMat.setInt("FilterMode", filterMode.getMaterialParamValue());
  183. postshadowMat.setFloat("PCFEdge", edgesThickness);
  184. if (shadowCompareMode == CompareMode.Hardware) {
  185. for (Texture2D shadowMap : shadowMaps) {
  186. if (filterMode == EdgeFilteringMode.Bilinear) {
  187. shadowMap.setMagFilter(MagFilter.Bilinear);
  188. shadowMap.setMinFilter(MinFilter.BilinearNoMipMaps);
  189. } else {
  190. shadowMap.setMagFilter(MagFilter.Nearest);
  191. shadowMap.setMinFilter(MinFilter.NearestNoMipMaps);
  192. }
  193. }
  194. }
  195. }
  196. /**
  197. * returns the the edge filtering mode
  198. *
  199. * @see EdgeFilteringMode
  200. * @return
  201. */
  202. public EdgeFilteringMode getEdgeFilteringMode() {
  203. return edgeFilteringMode;
  204. }
  205. /**
  206. * sets the shadow compare mode see {@link CompareMode} for more info
  207. *
  208. * @param compareMode
  209. */
  210. final public void setShadowCompareMode(CompareMode compareMode) {
  211. if (compareMode == null) {
  212. throw new IllegalArgumentException("Shadow compare mode cannot be null");
  213. }
  214. this.shadowCompareMode = compareMode;
  215. for (Texture2D shadowMap : shadowMaps) {
  216. if (compareMode == CompareMode.Hardware) {
  217. shadowMap.setShadowCompareMode(ShadowCompareMode.LessOrEqual);
  218. if (edgeFilteringMode == EdgeFilteringMode.Bilinear) {
  219. shadowMap.setMagFilter(MagFilter.Bilinear);
  220. shadowMap.setMinFilter(MinFilter.BilinearNoMipMaps);
  221. } else {
  222. shadowMap.setMagFilter(MagFilter.Nearest);
  223. shadowMap.setMinFilter(MinFilter.NearestNoMipMaps);
  224. }
  225. } else {
  226. shadowMap.setShadowCompareMode(ShadowCompareMode.Off);
  227. shadowMap.setMagFilter(MagFilter.Nearest);
  228. shadowMap.setMinFilter(MinFilter.NearestNoMipMaps);
  229. }
  230. }
  231. postshadowMat.setBoolean("HardwareShadows", compareMode == CompareMode.Hardware);
  232. }
  233. /**
  234. * returns the shadow compare mode
  235. *
  236. * @see CompareMode
  237. * @return the shadowCompareMode
  238. */
  239. public CompareMode getShadowCompareMode() {
  240. return shadowCompareMode;
  241. }
  242. //debug function that create a displayable frustrum
  243. protected Geometry createFrustum(Vector3f[] pts, int i) {
  244. WireFrustum frustum = new WireFrustum(pts);
  245. Geometry frustumMdl = new Geometry("f", frustum);
  246. frustumMdl.setCullHint(Spatial.CullHint.Never);
  247. frustumMdl.setShadowMode(ShadowMode.Off);
  248. Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
  249. mat.getAdditionalRenderState().setWireframe(true);
  250. frustumMdl.setMaterial(mat);
  251. switch (i) {
  252. case 0:
  253. frustumMdl.getMaterial().setColor("Color", ColorRGBA.Pink);
  254. break;
  255. case 1:
  256. frustumMdl.getMaterial().setColor("Color", ColorRGBA.Red);
  257. break;
  258. case 2:
  259. frustumMdl.getMaterial().setColor("Color", ColorRGBA.Green);
  260. break;
  261. case 3:
  262. frustumMdl.getMaterial().setColor("Color", ColorRGBA.Blue);
  263. break;
  264. default:
  265. frustumMdl.getMaterial().setColor("Color", ColorRGBA.White);
  266. break;
  267. }
  268. frustumMdl.updateGeometricState();
  269. return frustumMdl;
  270. }
  271. public void initialize(RenderManager rm, ViewPort vp) {
  272. renderManager = rm;
  273. viewPort = vp;
  274. //checking for caps to chosse the appropriate post material technique
  275. if (renderManager.getRenderer().getCaps().contains(Caps.GLSL150)) {
  276. postTechniqueName = "PostShadow15";
  277. } else {
  278. postTechniqueName = "PostShadow";
  279. }
  280. }
  281. public boolean isInitialized() {
  282. return viewPort != null;
  283. }
  284. /**
  285. * This mehtod is called once per frame. it is responsible for updating the
  286. * shadow cams according to the light view.
  287. *
  288. * @param viewCam the scene cam
  289. */
  290. protected abstract void updateShadowCams(Camera viewCam);
  291. /**
  292. * this method must return the geomtryList that contains the oclluders to be
  293. * rendered in the shadow map
  294. *
  295. * @param shadowMapIndex the index of the shadow map being rendered
  296. * @param sceneOccluders the occluders of the whole scene
  297. * @param sceneReceivers the recievers of the whole scene
  298. * @return
  299. */
  300. protected abstract GeometryList getOccludersToRender(int shadowMapIndex, GeometryList sceneOccluders, GeometryList sceneReceivers, GeometryList shadowMapOccluders);
  301. /**
  302. * return the shadow camera to use for rendering the shadow map according
  303. * the given index
  304. *
  305. * @param shadowMapIndex the index of the shadow map being rendered
  306. * @return the shadowCam
  307. */
  308. protected abstract Camera getShadowCam(int shadowMapIndex);
  309. /**
  310. * responsible for displaying the frustum of the shadow cam for debug
  311. * purpose
  312. *
  313. * @param shadowMapIndex
  314. */
  315. protected void doDisplayFrustumDebug(int shadowMapIndex) {
  316. }
  317. @SuppressWarnings("fallthrough")
  318. public void postQueue(RenderQueue rq) {
  319. GeometryList occluders = rq.getShadowQueueContent(ShadowMode.Cast);
  320. sceneReceivers = rq.getShadowQueueContent(ShadowMode.Receive);
  321. skipPostPass = false;
  322. if (sceneReceivers.size() == 0 || occluders.size() == 0) {
  323. skipPostPass = true;
  324. return;
  325. }
  326. updateShadowCams(viewPort.getCamera());
  327. Renderer r = renderManager.getRenderer();
  328. renderManager.setForcedMaterial(preshadowMat);
  329. renderManager.setForcedTechnique("PreShadow");
  330. for (int shadowMapIndex = 0; shadowMapIndex < nbShadowMaps; shadowMapIndex++) {
  331. if (debugfrustums) {
  332. doDisplayFrustumDebug(shadowMapIndex);
  333. }
  334. renderShadowMap(shadowMapIndex, occluders, sceneReceivers);
  335. }
  336. debugfrustums = false;
  337. if (flushQueues) {
  338. occluders.clear();
  339. }
  340. //restore setting for future rendering
  341. r.setFrameBuffer(viewPort.getOutputFrameBuffer());
  342. renderManager.setForcedMaterial(null);
  343. renderManager.setForcedTechnique(null);
  344. renderManager.setCamera(viewPort.getCamera(), false);
  345. }
  346. protected void renderShadowMap(int shadowMapIndex, GeometryList occluders, GeometryList receivers) {
  347. shadowMapOccluders = getOccludersToRender(shadowMapIndex, occluders, receivers, shadowMapOccluders);
  348. Camera shadowCam = getShadowCam(shadowMapIndex);
  349. //saving light view projection matrix for this split
  350. lightViewProjectionsMatrices[shadowMapIndex].set(shadowCam.getViewProjectionMatrix());
  351. renderManager.setCamera(shadowCam, false);
  352. renderManager.getRenderer().setFrameBuffer(shadowFB[shadowMapIndex]);
  353. renderManager.getRenderer().clearBuffers(false, true, false);
  354. // render shadow casters to shadow map
  355. viewPort.getQueue().renderShadowQueue(shadowMapOccluders, renderManager, shadowCam, true);
  356. }
  357. boolean debugfrustums = false;
  358. public void displayFrustum() {
  359. debugfrustums = true;
  360. }
  361. //debug only : displays depth shadow maps
  362. protected void displayShadowMap(Renderer r) {
  363. Camera cam = viewPort.getCamera();
  364. renderManager.setCamera(cam, true);
  365. int h = cam.getHeight();
  366. for (int i = 0; i < dispPic.length; i++) {
  367. dispPic[i].setPosition((128 * i) + (150 + 64 * (i + 1)), h / 20f);
  368. dispPic[i].setWidth(128);
  369. dispPic[i].setHeight(128);
  370. dispPic[i].updateGeometricState();
  371. renderManager.renderGeometry(dispPic[i]);
  372. }
  373. renderManager.setCamera(cam, false);
  374. }
  375. /**
  376. * For dubuging purpose Allow to "snapshot" the current frustrum to the
  377. * scene
  378. */
  379. public void displayDebug() {
  380. debug = true;
  381. }
  382. abstract GeometryList getReceivers(GeometryList sceneReceivers, GeometryList lightReceivers);
  383. public void postFrame(FrameBuffer out) {
  384. if (skipPostPass) {
  385. return;
  386. }
  387. if (debug) {
  388. displayShadowMap(renderManager.getRenderer());
  389. }
  390. lightReceivers = getReceivers(sceneReceivers, lightReceivers);
  391. if (lightReceivers.size() != 0) {
  392. //setting params to recieving geometry list
  393. setMatParams();
  394. Camera cam = viewPort.getCamera();
  395. //some materials in the scene does not have a post shadow technique so we're using the fall back material
  396. if (needsfallBackMaterial) {
  397. renderManager.setForcedMaterial(postshadowMat);
  398. }
  399. //forcing the post shadow technique and render state
  400. renderManager.setForcedTechnique(postTechniqueName);
  401. //rendering the post shadow pass
  402. viewPort.getQueue().renderShadowQueue(lightReceivers, renderManager, cam, false);
  403. if (flushQueues) {
  404. sceneReceivers.clear();
  405. }
  406. //resetting renderManager settings
  407. renderManager.setForcedTechnique(null);
  408. renderManager.setForcedMaterial(null);
  409. renderManager.setCamera(cam, false);
  410. }
  411. }
  412. /**
  413. * This method is called once per frame and is responsible of setting the
  414. * material parameters than sub class may need to set on the post material
  415. *
  416. * @param material the materail to use for the post shadow pass
  417. */
  418. protected abstract void setMaterialParameters(Material material);
  419. private void setMatParams() {
  420. GeometryList l = viewPort.getQueue().getShadowQueueContent(ShadowMode.Receive);
  421. //iteration throught all the geometries of the list to gather the materials
  422. matCache.clear();
  423. for (int i = 0; i < l.size(); i++) {
  424. Material mat = l.get(i).getMaterial();
  425. //checking if the material has the post technique and adding it to the material cache
  426. if (mat.getMaterialDef().getTechniqueDef(postTechniqueName) != null) {
  427. if (!matCache.contains(mat)) {
  428. matCache.add(mat);
  429. }
  430. } else {
  431. needsfallBackMaterial = true;
  432. }
  433. }
  434. //iterating through the mat cache and setting the parameters
  435. for (Material mat : matCache) {
  436. mat.setFloat("ShadowMapSize", shadowMapSize);
  437. for (int j = 0; j < nbShadowMaps; j++) {
  438. mat.setMatrix4(lightViewStringCache[j], lightViewProjectionsMatrices[j]);
  439. }
  440. for (int j = 0; j < nbShadowMaps; j++) {
  441. mat.setTexture(shadowMapStringCache[j], shadowMaps[j]);
  442. }
  443. mat.setBoolean("HardwareShadows", shadowCompareMode == CompareMode.Hardware);
  444. mat.setInt("FilterMode", edgeFilteringMode.getMaterialParamValue());
  445. mat.setFloat("PCFEdge", edgesThickness);
  446. mat.setFloat("ShadowIntensity", shadowIntensity);
  447. setMaterialParameters(mat);
  448. }
  449. //At least one material of the receiving geoms does not support the post shadow techniques
  450. //so we fall back to the forced material solution (transparent shadows won't be supported for these objects)
  451. if (needsfallBackMaterial) {
  452. setPostShadowParams();
  453. }
  454. }
  455. /**
  456. * for internal use only
  457. */
  458. protected void setPostShadowParams() {
  459. setMaterialParameters(postshadowMat);
  460. for (int j = 0; j < nbShadowMaps; j++) {
  461. postshadowMat.setMatrix4(lightViewStringCache[j], lightViewProjectionsMatrices[j]);
  462. postshadowMat.setTexture(shadowMapStringCache[j], shadowMaps[j]);
  463. }
  464. }
  465. public void preFrame(float tpf) {
  466. }
  467. public void cleanup() {
  468. }
  469. public void reshape(ViewPort vp, int w, int h) {
  470. }
  471. /**
  472. * returns the shdaow intensity
  473. *
  474. * @see #setShadowIntensity(float shadowIntensity)
  475. * @return shadowIntensity
  476. */
  477. public float getShadowIntensity() {
  478. return shadowIntensity;
  479. }
  480. /**
  481. * Set the shadowIntensity, the value should be between 0 and 1, a 0 value
  482. * gives a bright and invisilble shadow, a 1 value gives a pitch black
  483. * shadow, default is 0.7
  484. *
  485. * @param shadowIntensity the darkness of the shadow
  486. */
  487. final public void setShadowIntensity(float shadowIntensity) {
  488. this.shadowIntensity = shadowIntensity;
  489. postshadowMat.setFloat("ShadowIntensity", shadowIntensity);
  490. }
  491. /**
  492. * returns the edges thickness
  493. *
  494. * @see #setEdgesThickness(int edgesThickness)
  495. * @return edgesThickness
  496. */
  497. public int getEdgesThickness() {
  498. return (int) (edgesThickness * 10);
  499. }
  500. /**
  501. * Sets the shadow edges thickness. default is 1, setting it to lower values
  502. * can help to reduce the jagged effect of the shadow edges
  503. *
  504. * @param edgesThickness
  505. */
  506. public void setEdgesThickness(int edgesThickness) {
  507. this.edgesThickness = Math.max(1, Math.min(edgesThickness, 10));
  508. this.edgesThickness *= 0.1f;
  509. postshadowMat.setFloat("PCFEdge", edgesThickness);
  510. }
  511. /**
  512. * returns true if the PssmRenderer flushed the shadow queues
  513. *
  514. * @return flushQueues
  515. */
  516. public boolean isFlushQueues() {
  517. return flushQueues;
  518. }
  519. /**
  520. * Set this to false if you want to use several PssmRederers to have
  521. * multiple shadows cast by multiple light sources. Make sure the last
  522. * PssmRenderer in the stack DO flush the queues, but not the others
  523. *
  524. * @param flushQueues
  525. */
  526. public void setFlushQueues(boolean flushQueues) {
  527. this.flushQueues = flushQueues;
  528. }
  529. public void read(JmeImporter im) throws IOException {
  530. InputCapsule ic = (InputCapsule) im.getCapsule(this);
  531. assetManager = im.getAssetManager();
  532. nbShadowMaps = ic.readInt("nbShadowMaps", 1);
  533. shadowMapSize = ic.readInt("shadowMapSize", 0);
  534. shadowIntensity = ic.readFloat("shadowIntensity", 0.7f);
  535. edgeFilteringMode = ic.readEnum("edgeFilteringMode", EdgeFilteringMode.class, EdgeFilteringMode.Bilinear);
  536. shadowCompareMode = ic.readEnum("shadowCompareMode", CompareMode.class, CompareMode.Hardware);
  537. flushQueues = ic.readBoolean("flushQueues", false);
  538. init(assetManager, nbShadowMaps, (int) shadowMapSize);
  539. edgesThickness = ic.readFloat("edgesThickness", 1.0f);
  540. postshadowMat.setFloat("PCFEdge", edgesThickness);
  541. }
  542. public void write(JmeExporter ex) throws IOException {
  543. OutputCapsule oc = (OutputCapsule) ex.getCapsule(this);
  544. oc.write(nbShadowMaps, "nbShadowMaps", 1);
  545. oc.write(shadowMapSize, "shadowMapSize", 0);
  546. oc.write(shadowIntensity, "shadowIntensity", 0.7f);
  547. oc.write(edgeFilteringMode, "edgeFilteringMode", EdgeFilteringMode.Bilinear);
  548. oc.write(shadowCompareMode, "shadowCompareMode", CompareMode.Hardware);
  549. oc.write(flushQueues, "flushQueues", false);
  550. oc.write(edgesThickness, "edgesThickness", 1.0f);
  551. }
  552. }