RenderManager.java 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026
  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.renderer;
  33. import com.jme3.material.Material;
  34. import com.jme3.material.MaterialDef;
  35. import com.jme3.material.RenderState;
  36. import com.jme3.material.Technique;
  37. import com.jme3.math.*;
  38. import com.jme3.post.SceneProcessor;
  39. import com.jme3.renderer.queue.GeometryList;
  40. import com.jme3.renderer.queue.RenderQueue;
  41. import com.jme3.renderer.queue.RenderQueue.Bucket;
  42. import com.jme3.renderer.queue.RenderQueue.ShadowMode;
  43. import com.jme3.scene.*;
  44. import com.jme3.shader.Uniform;
  45. import com.jme3.shader.UniformBinding;
  46. import com.jme3.shader.UniformBindingManager;
  47. import com.jme3.shader.VarType;
  48. import com.jme3.system.NullRenderer;
  49. import com.jme3.system.Timer;
  50. import com.jme3.util.TempVars;
  51. import java.util.ArrayList;
  52. import java.util.Collections;
  53. import java.util.List;
  54. import java.util.logging.Logger;
  55. /**
  56. * <code>RenderManager</code> is a high-level rendering interface that is
  57. * above the Renderer implementation. RenderManager takes care
  58. * of rendering the scene graphs attached to each viewport and
  59. * handling SceneProcessors.
  60. *
  61. * @see SceneProcessor
  62. * @see ViewPort
  63. * @see Spatial
  64. */
  65. public class RenderManager {
  66. private static final Logger logger = Logger.getLogger(RenderManager.class.getName());
  67. private Renderer renderer;
  68. private UniformBindingManager uniformBindingManager = new UniformBindingManager();
  69. private ArrayList<ViewPort> preViewPorts = new ArrayList<ViewPort>();
  70. private ArrayList<ViewPort> viewPorts = new ArrayList<ViewPort>();
  71. private ArrayList<ViewPort> postViewPorts = new ArrayList<ViewPort>();
  72. private Camera prevCam = null;
  73. private Material forcedMaterial = null;
  74. private String forcedTechnique = null;
  75. private RenderState forcedRenderState = null;
  76. private boolean shader;
  77. private int viewX, viewY, viewWidth, viewHeight;
  78. private Matrix4f orthoMatrix = new Matrix4f();
  79. private String tmpTech;
  80. private boolean handleTranlucentBucket = true;
  81. /**
  82. * Create a high-level rendering interface over the
  83. * low-level rendering interface.
  84. * @param renderer
  85. */
  86. public RenderManager(Renderer renderer) {
  87. this.renderer = renderer;
  88. }
  89. /**
  90. * Returns the pre ViewPort with the given name.
  91. *
  92. * @param viewName The name of the pre ViewPort to look up
  93. * @return The ViewPort, or null if not found.
  94. *
  95. * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
  96. */
  97. public ViewPort getPreView(String viewName) {
  98. for (int i = 0; i < preViewPorts.size(); i++) {
  99. if (preViewPorts.get(i).getName().equals(viewName)) {
  100. return preViewPorts.get(i);
  101. }
  102. }
  103. return null;
  104. }
  105. /**
  106. * Removes the specified pre ViewPort.
  107. *
  108. * @param view The pre ViewPort to remove
  109. * @return True if the ViewPort was removed successfully.
  110. *
  111. * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
  112. */
  113. public boolean removePreView(ViewPort view) {
  114. return preViewPorts.remove(view);
  115. }
  116. /**
  117. * Returns the main ViewPort with the given name.
  118. *
  119. * @param viewName The name of the main ViewPort to look up
  120. * @return The ViewPort, or null if not found.
  121. *
  122. * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
  123. */
  124. public ViewPort getMainView(String viewName) {
  125. for (int i = 0; i < viewPorts.size(); i++) {
  126. if (viewPorts.get(i).getName().equals(viewName)) {
  127. return viewPorts.get(i);
  128. }
  129. }
  130. return null;
  131. }
  132. /**
  133. * Removes the main ViewPort with the specified name.
  134. *
  135. * @param viewName The main ViewPort name to remove
  136. * @return True if the ViewPort was removed successfully.
  137. *
  138. * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
  139. */
  140. public boolean removeMainView(String viewName) {
  141. for (int i = 0; i < viewPorts.size(); i++) {
  142. if (viewPorts.get(i).getName().equals(viewName)) {
  143. viewPorts.remove(i);
  144. return true;
  145. }
  146. }
  147. return false;
  148. }
  149. /**
  150. * Removes the specified main ViewPort.
  151. *
  152. * @param view The main ViewPort to remove
  153. * @return True if the ViewPort was removed successfully.
  154. *
  155. * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
  156. */
  157. public boolean removeMainView(ViewPort view) {
  158. return viewPorts.remove(view);
  159. }
  160. /**
  161. * Returns the post ViewPort with the given name.
  162. *
  163. * @param viewName The name of the post ViewPort to look up
  164. * @return The ViewPort, or null if not found.
  165. *
  166. * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
  167. */
  168. public ViewPort getPostView(String viewName) {
  169. for (int i = 0; i < postViewPorts.size(); i++) {
  170. if (postViewPorts.get(i).getName().equals(viewName)) {
  171. return postViewPorts.get(i);
  172. }
  173. }
  174. return null;
  175. }
  176. /**
  177. * Removes the post ViewPort with the specified name.
  178. *
  179. * @param viewName The post ViewPort name to remove
  180. * @return True if the ViewPort was removed successfully.
  181. *
  182. * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
  183. */
  184. public boolean removePostView(String viewName) {
  185. for (int i = 0; i < postViewPorts.size(); i++) {
  186. if (postViewPorts.get(i).getName().equals(viewName)) {
  187. postViewPorts.remove(i);
  188. return true;
  189. }
  190. }
  191. return false;
  192. }
  193. /**
  194. * Removes the specified post ViewPort.
  195. *
  196. * @param view The post ViewPort to remove
  197. * @return True if the ViewPort was removed successfully.
  198. *
  199. * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
  200. */
  201. public boolean removePostView(ViewPort view) {
  202. return postViewPorts.remove(view);
  203. }
  204. /**
  205. * Returns a read-only list of all pre ViewPorts
  206. * @return a read-only list of all pre ViewPorts
  207. * @see #createPreView(java.lang.String, com.jme3.renderer.Camera)
  208. */
  209. public List<ViewPort> getPreViews() {
  210. return Collections.unmodifiableList(preViewPorts);
  211. }
  212. /**
  213. * Returns a read-only list of all main ViewPorts
  214. * @return a read-only list of all main ViewPorts
  215. * @see #createMainView(java.lang.String, com.jme3.renderer.Camera)
  216. */
  217. public List<ViewPort> getMainViews() {
  218. return Collections.unmodifiableList(viewPorts);
  219. }
  220. /**
  221. * Returns a read-only list of all post ViewPorts
  222. * @return a read-only list of all post ViewPorts
  223. * @see #createPostView(java.lang.String, com.jme3.renderer.Camera)
  224. */
  225. public List<ViewPort> getPostViews() {
  226. return Collections.unmodifiableList(postViewPorts);
  227. }
  228. /**
  229. * Creates a new pre ViewPort, to display the given camera's content.
  230. * <p>
  231. * The view will be processed before the main and post viewports.
  232. */
  233. public ViewPort createPreView(String viewName, Camera cam) {
  234. ViewPort vp = new ViewPort(viewName, cam);
  235. preViewPorts.add(vp);
  236. return vp;
  237. }
  238. /**
  239. * Creates a new main ViewPort, to display the given camera's content.
  240. * <p>
  241. * The view will be processed before the post viewports but after
  242. * the pre viewports.
  243. */
  244. public ViewPort createMainView(String viewName, Camera cam) {
  245. ViewPort vp = new ViewPort(viewName, cam);
  246. viewPorts.add(vp);
  247. return vp;
  248. }
  249. /**
  250. * Creates a new post ViewPort, to display the given camera's content.
  251. * <p>
  252. * The view will be processed after the pre and main viewports.
  253. */
  254. public ViewPort createPostView(String viewName, Camera cam) {
  255. ViewPort vp = new ViewPort(viewName, cam);
  256. postViewPorts.add(vp);
  257. return vp;
  258. }
  259. private void notifyReshape(ViewPort vp, int w, int h) {
  260. List<SceneProcessor> processors = vp.getProcessors();
  261. for (SceneProcessor proc : processors) {
  262. if (!proc.isInitialized()) {
  263. proc.initialize(this, vp);
  264. } else {
  265. proc.reshape(vp, w, h);
  266. }
  267. }
  268. }
  269. /**
  270. * Internal use only.
  271. * Updates the resolution of all on-screen cameras to match
  272. * the given width and height.
  273. */
  274. public void notifyReshape(int w, int h) {
  275. for (ViewPort vp : preViewPorts) {
  276. if (vp.getOutputFrameBuffer() == null) {
  277. Camera cam = vp.getCamera();
  278. cam.resize(w, h, true);
  279. }
  280. notifyReshape(vp, w, h);
  281. }
  282. for (ViewPort vp : viewPorts) {
  283. if (vp.getOutputFrameBuffer() == null) {
  284. Camera cam = vp.getCamera();
  285. cam.resize(w, h, true);
  286. }
  287. notifyReshape(vp, w, h);
  288. }
  289. for (ViewPort vp : postViewPorts) {
  290. if (vp.getOutputFrameBuffer() == null) {
  291. Camera cam = vp.getCamera();
  292. cam.resize(w, h, true);
  293. }
  294. notifyReshape(vp, w, h);
  295. }
  296. }
  297. /**
  298. * Set the material to use to render all future objects.
  299. * This overrides the material set on the geometry and renders
  300. * with the provided material instead.
  301. * Use null to clear the material and return renderer to normal
  302. * functionality.
  303. * @param mat The forced material to set, or null to return to normal
  304. */
  305. public void setForcedMaterial(Material mat) {
  306. forcedMaterial = mat;
  307. }
  308. /**
  309. * Returns the forced render state previously set with
  310. * {@link #setForcedRenderState(com.jme3.material.RenderState) }.
  311. * @return the forced render state
  312. */
  313. public RenderState getForcedRenderState() {
  314. return forcedRenderState;
  315. }
  316. /**
  317. * Set the render state to use for all future objects.
  318. * This overrides the render state set on the material and instead
  319. * forces this render state to be applied for all future materials
  320. * rendered. Set to null to return to normal functionality.
  321. *
  322. * @param forcedRenderState The forced render state to set, or null
  323. * to return to normal
  324. */
  325. public void setForcedRenderState(RenderState forcedRenderState) {
  326. this.forcedRenderState = forcedRenderState;
  327. }
  328. /**
  329. * Set the timer that should be used to query the time based
  330. * {@link UniformBinding}s for material world parameters.
  331. *
  332. * @param timer The timer to query time world parameters
  333. */
  334. public void setTimer(Timer timer) {
  335. uniformBindingManager.setTimer(timer);
  336. }
  337. /**
  338. * Returns the forced technique name set.
  339. *
  340. * @return the forced technique name set.
  341. *
  342. * @see #setForcedTechnique(java.lang.String)
  343. */
  344. public String getForcedTechnique() {
  345. return forcedTechnique;
  346. }
  347. /**
  348. * Sets the forced technique to use when rendering geometries.
  349. * <p>
  350. * If the specified technique name is available on the geometry's
  351. * material, then it is used, otherwise, the
  352. * {@link #setForcedMaterial(com.jme3.material.Material) forced material} is used.
  353. * If a forced material is not set and the forced technique name cannot
  354. * be found on the material, the geometry will <em>not</em> be rendered.
  355. *
  356. * @param forcedTechnique The forced technique name to use, set to null
  357. * to return to normal functionality.
  358. *
  359. * @see #renderGeometry(com.jme3.scene.Geometry)
  360. */
  361. public void setForcedTechnique(String forcedTechnique) {
  362. this.forcedTechnique = forcedTechnique;
  363. }
  364. /**
  365. * Enable or disable alpha-to-coverage.
  366. * <p>
  367. * When alpha to coverage is enabled and the renderer implementation
  368. * supports it, then alpha blending will be replaced with alpha dissolve
  369. * if multi-sampling is also set on the renderer.
  370. * This feature allows avoiding of alpha blending artifacts due to
  371. * lack of triangle-level back-to-front sorting.
  372. *
  373. * @param value True to enable alpha-to-coverage, false otherwise.
  374. */
  375. public void setAlphaToCoverage(boolean value) {
  376. renderer.setAlphaToCoverage(value);
  377. }
  378. /**
  379. * True if the translucent bucket should automatically be rendered
  380. * by the RenderManager.
  381. *
  382. * @return Whether or not the translucent bucket is rendered.
  383. *
  384. * @see #setHandleTranslucentBucket(boolean)
  385. */
  386. public boolean isHandleTranslucentBucket() {
  387. return handleTranlucentBucket;
  388. }
  389. /**
  390. * Enable or disable rendering of the
  391. * {@link Bucket#Translucent translucent bucket}
  392. * by the RenderManager. The default is enabled.
  393. *
  394. * @param handleTranslucentBucket Whether or not the translucent bucket should
  395. * be rendered.
  396. */
  397. public void setHandleTranslucentBucket(boolean handleTranslucentBucket) {
  398. this.handleTranlucentBucket = handleTranslucentBucket;
  399. }
  400. /**
  401. * Internal use only. Sets the world matrix to use for future
  402. * rendering. This has no effect unless objects are rendered manually
  403. * using {@link Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager) }.
  404. * Using {@link #renderGeometry(com.jme3.scene.Geometry) } will
  405. * override this value.
  406. *
  407. * @param mat The world matrix to set
  408. */
  409. public void setWorldMatrix(Matrix4f mat) {
  410. if (shader) {
  411. uniformBindingManager.setWorldMatrix(mat);
  412. } else {
  413. renderer.setWorldMatrix(mat);
  414. }
  415. }
  416. /**
  417. * Internal use only.
  418. * Updates the given list of uniforms with {@link UniformBinding uniform bindings}
  419. * based on the current world state.
  420. */
  421. public void updateUniformBindings(List<Uniform> params) {
  422. uniformBindingManager.updateUniformBindings(params);
  423. }
  424. /**
  425. * Renders the given geometry.
  426. * <p>
  427. * First the proper world matrix is set, if
  428. * the geometry's {@link Geometry#setIgnoreTransform(boolean) ignore transform}
  429. * feature is enabled, the identity world matrix is used, otherwise, the
  430. * geometry's {@link Geometry#getWorldMatrix() world transform matrix} is used.
  431. * <p>
  432. * Once the world matrix is applied, the proper material is chosen for rendering.
  433. * If a {@link #setForcedMaterial(com.jme3.material.Material) forced material} is
  434. * set on this RenderManager, then it is used for rendering the geometry,
  435. * otherwise, the {@link Geometry#getMaterial() geometry's material} is used.
  436. * <p>
  437. * If a {@link #setForcedTechnique(java.lang.String) forced technique} is
  438. * set on this RenderManager, then it is selected automatically
  439. * on the geometry's material and is used for rendering. Otherwise, one
  440. * of the {@link MaterialDef#getDefaultTechniques() default techniques} is
  441. * used.
  442. * <p>
  443. * If a {@link #setForcedRenderState(com.jme3.material.RenderState) forced
  444. * render state} is set on this RenderManager, then it is used
  445. * for rendering the material, and the material's own render state is ignored.
  446. * Otherwise, the material's render state is used as intended.
  447. *
  448. * @param g The geometry to render
  449. *
  450. * @see Technique
  451. * @see RenderState
  452. * @see Material#selectTechnique(java.lang.String, com.jme3.renderer.RenderManager)
  453. * @see Material#render(com.jme3.scene.Geometry, com.jme3.renderer.RenderManager)
  454. */
  455. public void renderGeometry(Geometry g) {
  456. if (g.isIgnoreTransform()) {
  457. setWorldMatrix(Matrix4f.IDENTITY);
  458. } else {
  459. setWorldMatrix(g.getWorldMatrix());
  460. }
  461. //if forcedTechnique we try to force it for render,
  462. //if it does not exists in the mat def, we check for forcedMaterial and render the geom if not null
  463. //else the geom is not rendered
  464. if (forcedTechnique != null) {
  465. if (g.getMaterial().getMaterialDef().getTechniqueDef(forcedTechnique) != null) {
  466. tmpTech = g.getMaterial().getActiveTechnique() != null ? g.getMaterial().getActiveTechnique().getDef().getName() : "Default";
  467. g.getMaterial().selectTechnique(forcedTechnique, this);
  468. // use geometry's material
  469. g.getMaterial().render(g, this);
  470. g.getMaterial().selectTechnique(tmpTech, this);
  471. //Reverted this part from revision 6197
  472. //If forcedTechnique does not exists, and frocedMaterial is not set, the geom MUST NOT be rendered
  473. } else if (forcedMaterial != null) {
  474. // use forced material
  475. forcedMaterial.render(g, this);
  476. }
  477. } else if (forcedMaterial != null) {
  478. // use forced material
  479. forcedMaterial.render(g, this);
  480. } else {
  481. g.getMaterial().render(g, this);
  482. }
  483. }
  484. /**
  485. * Renders the given GeometryList.
  486. * <p>
  487. * For every geometry in the list, the
  488. * {@link #renderGeometry(com.jme3.scene.Geometry) } method is called.
  489. *
  490. * @param gl The geometry list to render.
  491. *
  492. * @see GeometryList
  493. * @see #renderGeometry(com.jme3.scene.Geometry)
  494. */
  495. public void renderGeometryList(GeometryList gl) {
  496. for (int i = 0; i < gl.size(); i++) {
  497. renderGeometry(gl.get(i));
  498. }
  499. }
  500. /**
  501. * If a spatial is not inside the eye frustum, it
  502. * is still rendered in the shadow frustum (shadow casting queue)
  503. * through this recursive method.
  504. */
  505. private void renderShadow(Spatial s, RenderQueue rq) {
  506. if (s instanceof Node) {
  507. Node n = (Node) s;
  508. List<Spatial> children = n.getChildren();
  509. for (int i = 0; i < children.size(); i++) {
  510. renderShadow(children.get(i), rq);
  511. }
  512. } else if (s instanceof Geometry) {
  513. Geometry gm = (Geometry) s;
  514. RenderQueue.ShadowMode shadowMode = s.getShadowMode();
  515. if (shadowMode != RenderQueue.ShadowMode.Off && shadowMode != RenderQueue.ShadowMode.Receive) {
  516. //forcing adding to shadow cast mode, culled objects doesn't have to be in the receiver queue
  517. rq.addToShadowQueue(gm, RenderQueue.ShadowMode.Cast);
  518. }
  519. }
  520. }
  521. /**
  522. * Preloads a scene for rendering.
  523. * <p>
  524. * After invocation of this method, the underlying
  525. * renderer would have uploaded any textures, shaders and meshes
  526. * used by the given scene to the video driver.
  527. * Using this method is useful when wishing to avoid the initial pause
  528. * when rendering a scene for the first time. Note that it is not
  529. * guaranteed that the underlying renderer will actually choose to upload
  530. * the data to the GPU so some pause is still to be expected.
  531. *
  532. * @param scene The scene to preload
  533. */
  534. public void preloadScene(Spatial scene) {
  535. if (scene instanceof Node) {
  536. // recurse for all children
  537. Node n = (Node) scene;
  538. List<Spatial> children = n.getChildren();
  539. for (int i = 0; i < children.size(); i++) {
  540. preloadScene(children.get(i));
  541. }
  542. } else if (scene instanceof Geometry) {
  543. // add to the render queue
  544. Geometry gm = (Geometry) scene;
  545. if (gm.getMaterial() == null) {
  546. throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
  547. }
  548. gm.getMaterial().preload(this);
  549. Mesh mesh = gm.getMesh();
  550. if (mesh != null) {
  551. for (VertexBuffer vb : mesh.getBufferList().getArray()) {
  552. if (vb.getData() != null) {
  553. renderer.updateBufferData(vb);
  554. }
  555. }
  556. }
  557. }
  558. }
  559. /**
  560. * Flattens the given scene graph into the ViewPort's RenderQueue,
  561. * checking for culling as the call goes down the graph recursively.
  562. * <p>
  563. * First, the scene is checked for culling based on the <code>Spatial</code>s
  564. * {@link Spatial#setCullHint(com.jme3.scene.Spatial.CullHint) cull hint},
  565. * if the camera frustum contains the scene, then this method is recursively
  566. * called on its children.
  567. * <p>
  568. * When the scene's leaves or {@link Geometry geometries} are reached,
  569. * they are each enqueued into the
  570. * {@link ViewPort#getQueue() ViewPort's render queue}.
  571. * <p>
  572. * In addition to enqueuing the visible geometries, this method
  573. * also scenes which cast or receive shadows, by putting them into the
  574. * RenderQueue's
  575. * {@link RenderQueue#addToShadowQueue(com.jme3.scene.Geometry, com.jme3.renderer.queue.RenderQueue.ShadowMode)
  576. * shadow queue}. Each Spatial which has its
  577. * {@link Spatial#setShadowMode(com.jme3.renderer.queue.RenderQueue.ShadowMode) shadow mode}
  578. * set to not off, will be put into the appropriate shadow queue, note that
  579. * this process does not check for frustum culling on any
  580. * {@link ShadowMode#Cast shadow casters}, as they don't have to be
  581. * in the eye camera frustum to cast shadows on objects that are inside it.
  582. *
  583. * @param scene The scene to flatten into the queue
  584. * @param vp The ViewPort provides the {@link ViewPort#getCamera() camera}
  585. * used for culling and the {@link ViewPort#getQueue() queue} used to
  586. * contain the flattened scene graph.
  587. */
  588. public void renderScene(Spatial scene, ViewPort vp) {
  589. if (scene.getParent() == null) {
  590. vp.getCamera().setPlaneState(0);
  591. }
  592. // check culling first.
  593. if (!scene.checkCulling(vp.getCamera())) {
  594. // move on to shadow-only render
  595. if ((scene.getShadowMode() != RenderQueue.ShadowMode.Off || scene instanceof Node) && scene.getCullHint()!=Spatial.CullHint.Always) {
  596. renderShadow(scene, vp.getQueue());
  597. }
  598. return;
  599. }
  600. scene.runControlRender(this, vp);
  601. if (scene instanceof Node) {
  602. // recurse for all children
  603. Node n = (Node) scene;
  604. List<Spatial> children = n.getChildren();
  605. //saving cam state for culling
  606. int camState = vp.getCamera().getPlaneState();
  607. for (int i = 0; i < children.size(); i++) {
  608. //restoring cam state before proceeding children recusively
  609. vp.getCamera().setPlaneState(camState);
  610. renderScene(children.get(i), vp);
  611. }
  612. } else if (scene instanceof Geometry) {
  613. // add to the render queue
  614. Geometry gm = (Geometry) scene;
  615. if (gm.getMaterial() == null) {
  616. throw new IllegalStateException("No material is set for Geometry: " + gm.getName());
  617. }
  618. vp.getQueue().addToQueue(gm, scene.getQueueBucket());
  619. // add to shadow queue if needed
  620. RenderQueue.ShadowMode shadowMode = scene.getShadowMode();
  621. if (shadowMode != RenderQueue.ShadowMode.Off) {
  622. vp.getQueue().addToShadowQueue(gm, shadowMode);
  623. }
  624. }
  625. }
  626. /**
  627. * Returns the camera currently used for rendering.
  628. * <p>
  629. * The camera can be set with {@link #setCamera(com.jme3.renderer.Camera, boolean) }.
  630. *
  631. * @return the camera currently used for rendering.
  632. */
  633. public Camera getCurrentCamera() {
  634. return prevCam;
  635. }
  636. /**
  637. * The renderer implementation used for rendering operations.
  638. *
  639. * @return The renderer implementation
  640. *
  641. * @see #RenderManager(com.jme3.renderer.Renderer)
  642. * @see Renderer
  643. */
  644. public Renderer getRenderer() {
  645. return renderer;
  646. }
  647. /**
  648. * Flushes the ViewPort's {@link ViewPort#getQueue() render queue}
  649. * by rendering each of its visible buckets.
  650. * By default the queues will automatically be cleared after rendering,
  651. * so there's no need to clear them manually.
  652. *
  653. * @param vp The ViewPort of which the queue will be flushed
  654. *
  655. * @see RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera)
  656. * @see #renderGeometryList(com.jme3.renderer.queue.GeometryList)
  657. */
  658. public void flushQueue(ViewPort vp) {
  659. renderViewPortQueues(vp, true);
  660. }
  661. /**
  662. * Clears the queue of the given ViewPort.
  663. * Simply calls {@link RenderQueue#clear() } on the ViewPort's
  664. * {@link ViewPort#getQueue() render queue}.
  665. *
  666. * @param vp The ViewPort of which the queue will be cleared.
  667. *
  668. * @see RenderQueue#clear()
  669. * @see ViewPort#getQueue()
  670. */
  671. public void clearQueue(ViewPort vp) {
  672. vp.getQueue().clear();
  673. }
  674. /**
  675. * Render the given viewport queues.
  676. * <p>
  677. * Changes the {@link Renderer#setDepthRange(float, float) depth range}
  678. * appropriately as expected by each queue and then calls
  679. * {@link RenderQueue#renderQueue(com.jme3.renderer.queue.RenderQueue.Bucket, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean) }
  680. * on the queue. Makes sure to restore the depth range to [0, 1]
  681. * at the end of the call.
  682. * Note that the {@link Bucket#Translucent translucent bucket} is NOT
  683. * rendered by this method. Instead the user should call
  684. * {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) }
  685. * after this call.
  686. *
  687. * @param vp the viewport of which queue should be rendered
  688. * @param flush If true, the queues will be cleared after
  689. * rendering.
  690. *
  691. * @see RenderQueue
  692. * @see #renderTranslucentQueue(com.jme3.renderer.ViewPort)
  693. */
  694. public void renderViewPortQueues(ViewPort vp, boolean flush) {
  695. RenderQueue rq = vp.getQueue();
  696. Camera cam = vp.getCamera();
  697. boolean depthRangeChanged = false;
  698. // render opaque objects with default depth range
  699. // opaque objects are sorted front-to-back, reducing overdraw
  700. rq.renderQueue(Bucket.Opaque, this, cam, flush);
  701. // render the sky, with depth range set to the farthest
  702. if (!rq.isQueueEmpty(Bucket.Sky)) {
  703. renderer.setDepthRange(1, 1);
  704. rq.renderQueue(Bucket.Sky, this, cam, flush);
  705. depthRangeChanged = true;
  706. }
  707. // transparent objects are last because they require blending with the
  708. // rest of the scene's objects. Consequently, they are sorted
  709. // back-to-front.
  710. if (!rq.isQueueEmpty(Bucket.Transparent)) {
  711. if (depthRangeChanged) {
  712. renderer.setDepthRange(0, 1);
  713. depthRangeChanged = false;
  714. }
  715. rq.renderQueue(Bucket.Transparent, this, cam, flush);
  716. }
  717. if (!rq.isQueueEmpty(Bucket.Gui)) {
  718. renderer.setDepthRange(0, 0);
  719. setCamera(cam, true);
  720. rq.renderQueue(Bucket.Gui, this, cam, flush);
  721. setCamera(cam, false);
  722. depthRangeChanged = true;
  723. }
  724. // restore range to default
  725. if (depthRangeChanged) {
  726. renderer.setDepthRange(0, 1);
  727. }
  728. }
  729. /**
  730. * Renders the {@link Bucket#Translucent translucent queue} on the viewPort.
  731. * <p>
  732. * This call does nothing unless {@link #setHandleTranslucentBucket(boolean) }
  733. * is set to true. This method clears the translucent queue after rendering
  734. * it.
  735. *
  736. * @param vp The viewport of which the translucent queue should be rendered.
  737. *
  738. * @see #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean)
  739. * @see #setHandleTranslucentBucket(boolean)
  740. */
  741. public void renderTranslucentQueue(ViewPort vp) {
  742. RenderQueue rq = vp.getQueue();
  743. if (!rq.isQueueEmpty(Bucket.Translucent) && handleTranlucentBucket) {
  744. rq.renderQueue(Bucket.Translucent, this, vp.getCamera(), true);
  745. }
  746. }
  747. private void setViewPort(Camera cam) {
  748. // this will make sure to update viewport only if needed
  749. if (cam != prevCam || cam.isViewportChanged()) {
  750. viewX = (int) (cam.getViewPortLeft() * cam.getWidth());
  751. viewY = (int) (cam.getViewPortBottom() * cam.getHeight());
  752. viewWidth = (int) ((cam.getViewPortRight() - cam.getViewPortLeft()) * cam.getWidth());
  753. viewHeight = (int) ((cam.getViewPortTop() - cam.getViewPortBottom()) * cam.getHeight());
  754. uniformBindingManager.setViewPort(viewX, viewY, viewWidth, viewHeight);
  755. renderer.setViewPort(viewX, viewY, viewWidth, viewHeight);
  756. renderer.setClipRect(viewX, viewY, viewWidth, viewHeight);
  757. cam.clearViewportChanged();
  758. prevCam = cam;
  759. // float translateX = viewWidth == viewX ? 0 : -(viewWidth + viewX) / (viewWidth - viewX);
  760. // float translateY = viewHeight == viewY ? 0 : -(viewHeight + viewY) / (viewHeight - viewY);
  761. // float scaleX = viewWidth == viewX ? 1f : 2f / (viewWidth - viewX);
  762. // float scaleY = viewHeight == viewY ? 1f : 2f / (viewHeight - viewY);
  763. //
  764. // orthoMatrix.loadIdentity();
  765. // orthoMatrix.setTranslation(translateX, translateY, 0);
  766. // orthoMatrix.setScale(scaleX, scaleY, 0);
  767. orthoMatrix.loadIdentity();
  768. orthoMatrix.setTranslation(-1f, -1f, 0f);
  769. orthoMatrix.setScale(2f / cam.getWidth(), 2f / cam.getHeight(), 0f);
  770. }
  771. }
  772. private void setViewProjection(Camera cam, boolean ortho) {
  773. if (shader) {
  774. if (ortho) {
  775. uniformBindingManager.setCamera(cam, Matrix4f.IDENTITY, orthoMatrix, orthoMatrix);
  776. } else {
  777. uniformBindingManager.setCamera(cam, cam.getViewMatrix(), cam.getProjectionMatrix(), cam.getViewProjectionMatrix());
  778. }
  779. } else {
  780. if (ortho) {
  781. renderer.setViewProjectionMatrices(Matrix4f.IDENTITY, orthoMatrix);
  782. } else {
  783. renderer.setViewProjectionMatrices(cam.getViewMatrix(),
  784. cam.getProjectionMatrix());
  785. }
  786. }
  787. }
  788. /**
  789. * Set the camera to use for rendering.
  790. * <p>
  791. * First, the camera's
  792. * {@link Camera#setViewPort(float, float, float, float) view port parameters}
  793. * are applied. Then, the camera's {@link Camera#getViewMatrix() view} and
  794. * {@link Camera#getProjectionMatrix() projection} matrices are set
  795. * on the renderer. If <code>ortho</code> is <code>true</code>, then
  796. * instead of using the camera's view and projection matrices, an ortho
  797. * matrix is computed and used instead of the view projection matrix.
  798. * The ortho matrix converts from the range (0 ~ Width, 0 ~ Height, -1 ~ +1)
  799. * to the clip range (-1 ~ +1, -1 ~ +1, -1 ~ +1).
  800. *
  801. * @param cam The camera to set
  802. * @param ortho True if to use orthographic projection (for GUI rendering),
  803. * false if to use the camera's view and projection matrices.
  804. */
  805. public void setCamera(Camera cam, boolean ortho) {
  806. setViewPort(cam);
  807. setViewProjection(cam, ortho);
  808. }
  809. /**
  810. * Draws the viewport but without notifying {@link SceneProcessor scene
  811. * processors} of any rendering events.
  812. *
  813. * @param vp The ViewPort to render
  814. *
  815. * @see #renderViewPort(com.jme3.renderer.ViewPort, float)
  816. */
  817. public void renderViewPortRaw(ViewPort vp) {
  818. setCamera(vp.getCamera(), false);
  819. List<Spatial> scenes = vp.getScenes();
  820. for (int i = scenes.size() - 1; i >= 0; i--) {
  821. renderScene(scenes.get(i), vp);
  822. }
  823. flushQueue(vp);
  824. }
  825. /**
  826. * Renders the {@link ViewPort}.
  827. * <p>
  828. * If the ViewPort is {@link ViewPort#isEnabled() disabled}, this method
  829. * returns immediately. Otherwise, the ViewPort is rendered by
  830. * the following process:<br>
  831. * <ul>
  832. * <li>All {@link SceneProcessor scene processors} that are attached
  833. * to the ViewPort are {@link SceneProcessor#initialize(com.jme3.renderer.RenderManager, com.jme3.renderer.ViewPort) initialized}.
  834. * </li>
  835. * <li>The SceneProcessors' {@link SceneProcessor#preFrame(float) } method
  836. * is called.</li>
  837. * <li>The ViewPort's {@link ViewPort#getOutputFrameBuffer() output framebuffer}
  838. * is set on the Renderer</li>
  839. * <li>The camera is set on the renderer, including its view port parameters.
  840. * (see {@link #setCamera(com.jme3.renderer.Camera, boolean) })</li>
  841. * <li>Any buffers that the ViewPort requests to be cleared are cleared
  842. * and the {@link ViewPort#getBackgroundColor() background color} is set</li>
  843. * <li>Every scene that is attached to the ViewPort is flattened into
  844. * the ViewPort's render queue
  845. * (see {@link #renderViewPortQueues(com.jme3.renderer.ViewPort, boolean) })
  846. * </li>
  847. * <li>The SceneProcessors' {@link SceneProcessor#postQueue(com.jme3.renderer.queue.RenderQueue) }
  848. * method is called.</li>
  849. * <li>The render queue is sorted and then flushed, sending
  850. * rendering commands to the underlying Renderer implementation.
  851. * (see {@link #flushQueue(com.jme3.renderer.ViewPort) })</li>
  852. * <li>The SceneProcessors' {@link SceneProcessor#postFrame(com.jme3.texture.FrameBuffer) }
  853. * method is called.</li>
  854. * <li>The translucent queue of the ViewPort is sorted and then flushed
  855. * (see {@link #renderTranslucentQueue(com.jme3.renderer.ViewPort) })</li>
  856. * <li>If any objects remained in the render queue, they are removed
  857. * from the queue. This is generally objects added to the
  858. * {@link RenderQueue#renderShadowQueue(com.jme3.renderer.queue.RenderQueue.ShadowMode, com.jme3.renderer.RenderManager, com.jme3.renderer.Camera, boolean)
  859. * shadow queue}
  860. * which were not rendered because of a missing shadow renderer.</li>
  861. * </ul>
  862. *
  863. * @param vp
  864. * @param tpf
  865. */
  866. public void renderViewPort(ViewPort vp, float tpf) {
  867. if (!vp.isEnabled()) {
  868. return;
  869. }
  870. List<SceneProcessor> processors = vp.getProcessors();
  871. if (processors.isEmpty()) {
  872. processors = null;
  873. }
  874. if (processors != null) {
  875. for (SceneProcessor proc : processors) {
  876. if (!proc.isInitialized()) {
  877. proc.initialize(this, vp);
  878. }
  879. proc.preFrame(tpf);
  880. }
  881. }
  882. renderer.setFrameBuffer(vp.getOutputFrameBuffer());
  883. setCamera(vp.getCamera(), false);
  884. if (vp.isClearDepth() || vp.isClearColor() || vp.isClearStencil()) {
  885. if (vp.isClearColor()) {
  886. renderer.setBackgroundColor(vp.getBackgroundColor());
  887. }
  888. renderer.clearBuffers(vp.isClearColor(),
  889. vp.isClearDepth(),
  890. vp.isClearStencil());
  891. }
  892. List<Spatial> scenes = vp.getScenes();
  893. for (int i = scenes.size() - 1; i >= 0; i--) {
  894. renderScene(scenes.get(i), vp);
  895. }
  896. if (processors != null) {
  897. for (SceneProcessor proc : processors) {
  898. proc.postQueue(vp.getQueue());
  899. }
  900. }
  901. flushQueue(vp);
  902. if (processors != null) {
  903. for (SceneProcessor proc : processors) {
  904. proc.postFrame(vp.getOutputFrameBuffer());
  905. }
  906. }
  907. //renders the translucent objects queue after processors have been rendered
  908. renderTranslucentQueue(vp);
  909. // clear any remaining spatials that were not rendered.
  910. clearQueue(vp);
  911. }
  912. /**
  913. * Called by the application to render any ViewPorts
  914. * added to this RenderManager.
  915. * <p>
  916. * Renders any viewports that were added using the following methods:
  917. * <ul>
  918. * <li>{@link #createPreView(java.lang.String, com.jme3.renderer.Camera) }</li>
  919. * <li>{@link #createMainView(java.lang.String, com.jme3.renderer.Camera) }</li>
  920. * <li>{@link #createPostView(java.lang.String, com.jme3.renderer.Camera) }</li>
  921. * </ul>
  922. *
  923. * @param tpf Time per frame value
  924. */
  925. public void render(float tpf, boolean mainFrameBufferActive) {
  926. if (renderer instanceof NullRenderer) {
  927. return;
  928. }
  929. this.shader = renderer.getCaps().contains(Caps.GLSL100);
  930. for (int i = 0; i < preViewPorts.size(); i++) {
  931. ViewPort vp = preViewPorts.get(i);
  932. if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
  933. renderViewPort(vp, tpf);
  934. }
  935. }
  936. for (int i = 0; i < viewPorts.size(); i++) {
  937. ViewPort vp = viewPorts.get(i);
  938. if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
  939. renderViewPort(vp, tpf);
  940. }
  941. }
  942. for (int i = 0; i < postViewPorts.size(); i++) {
  943. ViewPort vp = postViewPorts.get(i);
  944. if (vp.getOutputFrameBuffer() != null || mainFrameBufferActive){
  945. renderViewPort(vp, tpf);
  946. }
  947. }
  948. }
  949. }