VRViewManagerOpenVR.java 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. /*
  2. * To change this template, choose Tools | Templates
  3. * and open the template in the editor.
  4. */
  5. package com.jme3.util;
  6. import com.jme3.app.VREnvironment;
  7. import com.jme3.input.vr.OpenVR;
  8. import com.jme3.input.vr.VRAPI;
  9. import com.jme3.input.vr.VRTrackedController;
  10. import com.jme3.material.Material;
  11. import com.jme3.math.ColorRGBA;
  12. import com.jme3.math.Quaternion;
  13. import com.jme3.math.Vector2f;
  14. import com.jme3.math.Vector3f;
  15. import com.jme3.renderer.Camera;
  16. import com.jme3.renderer.ViewPort;
  17. import com.jme3.renderer.queue.RenderQueue.Bucket;
  18. import com.jme3.scene.Geometry;
  19. import com.jme3.scene.Mesh;
  20. import com.jme3.scene.Node;
  21. import com.jme3.scene.Spatial;
  22. import com.jme3.scene.VertexBuffer;
  23. import com.jme3.system.jopenvr.DistortionCoordinates_t;
  24. import com.jme3.system.jopenvr.JOpenVRLibrary;
  25. import com.jme3.system.jopenvr.OpenVRUtil;
  26. import com.jme3.system.jopenvr.Texture_t;
  27. import com.jme3.system.jopenvr.VRTextureBounds_t;
  28. import com.jme3.system.jopenvr.VR_IVRSystem_FnTable;
  29. import com.jme3.texture.FrameBuffer;
  30. import com.jme3.texture.Image;
  31. import com.jme3.texture.Texture;
  32. import com.jme3.texture.Texture2D;
  33. import com.jme3.ui.Picture;
  34. import java.util.Iterator;
  35. import java.util.logging.Logger;
  36. /**
  37. * A VR view manager based on OpenVR. This class enable to submit 3D views to the VR compositor.
  38. * @author reden - phr00t - https://github.com/phr00t
  39. * @author Julien Seinturier - (c) 2016 - JOrigin project - <a href="http://www.jorigin.org">http:/www.jorigin.org</a>
  40. */
  41. public class VRViewManagerOpenVR extends AbstractVRViewManager {
  42. private static final Logger logger = Logger.getLogger(VRViewManagerOpenVR.class.getName());
  43. // OpenVR values
  44. private VRTextureBounds_t leftTextureBounds;
  45. private Texture_t leftTextureType;
  46. private VRTextureBounds_t rightTextureBounds;
  47. private Texture_t rightTextureType;
  48. private Texture2D dualEyeTex;
  49. //final & temp values for camera calculations
  50. private final Vector3f finalPosition = new Vector3f();
  51. private final Quaternion finalRotation = new Quaternion();
  52. private final Vector3f hmdPos = new Vector3f();
  53. private final Quaternion hmdRot = new Quaternion();
  54. /**
  55. * Create a new VR view manager attached to the given {@link VREnvironment VR environment}.
  56. * @param environment the {@link VREnvironment VR environment} to which this view manager is attached.
  57. */
  58. public VRViewManagerOpenVR(VREnvironment environment){
  59. this.environment = environment;
  60. }
  61. /**
  62. * Get the identifier of the left eye texture.
  63. * @return the identifier of the left eye texture.
  64. * @see #getRightTexId()
  65. * @see #getFullTexId()
  66. */
  67. protected int getLeftTexId() {
  68. return (int)getLeftTexture().getImage().getId();
  69. }
  70. /**
  71. * Get the identifier of the right eye texture.
  72. * @return the identifier of the right eye texture.
  73. * @see #getLeftTexId()
  74. * @see #getFullTexId()
  75. */
  76. protected int getRightTexId() {
  77. return (int)getRightTexture().getImage().getId();
  78. }
  79. /**
  80. * Get the identifier of the full (dual eye) texture.
  81. * @return the identifier of the full (dual eye) texture.
  82. * @see #getLeftTexId()
  83. * @see #getRightTexId()
  84. */
  85. private int getFullTexId() {
  86. return (int)dualEyeTex.getImage().getId();
  87. }
  88. /**
  89. * Initialize the system binds of the textures.
  90. */
  91. private void initTextureSubmitStructs() {
  92. leftTextureType = new Texture_t();
  93. rightTextureType = new Texture_t();
  94. if (environment != null){
  95. if( environment.getVRHardware() instanceof OpenVR ) {
  96. leftTextureBounds = new VRTextureBounds_t();
  97. rightTextureBounds = new VRTextureBounds_t();
  98. // left eye
  99. leftTextureBounds.uMax = 0.5f;
  100. leftTextureBounds.uMin = 0f;
  101. leftTextureBounds.vMax = 1f;
  102. leftTextureBounds.vMin = 0f;
  103. leftTextureBounds.setAutoSynch(false);
  104. leftTextureBounds.setAutoRead(false);
  105. leftTextureBounds.setAutoWrite(false);
  106. leftTextureBounds.write();
  107. // right eye
  108. rightTextureBounds.uMax = 1f;
  109. rightTextureBounds.uMin = 0.5f;
  110. rightTextureBounds.vMax = 1f;
  111. rightTextureBounds.vMin = 0f;
  112. rightTextureBounds.setAutoSynch(false);
  113. rightTextureBounds.setAutoRead(false);
  114. rightTextureBounds.setAutoWrite(false);
  115. rightTextureBounds.write();
  116. // texture type
  117. leftTextureType.eColorSpace = JOpenVRLibrary.EColorSpace.EColorSpace_ColorSpace_Gamma;
  118. leftTextureType.eType = JOpenVRLibrary.ETextureType.ETextureType_TextureType_OpenGL;
  119. leftTextureType.setAutoSynch(false);
  120. leftTextureType.setAutoRead(false);
  121. leftTextureType.setAutoWrite(false);
  122. leftTextureType.handle = -1;
  123. rightTextureType.eColorSpace = JOpenVRLibrary.EColorSpace.EColorSpace_ColorSpace_Gamma;
  124. rightTextureType.eType = JOpenVRLibrary.ETextureType.ETextureType_TextureType_OpenGL;
  125. rightTextureType.setAutoSynch(false);
  126. rightTextureType.setAutoRead(false);
  127. rightTextureType.setAutoWrite(false);
  128. rightTextureType.handle = -1;
  129. logger.config("Init eyes native texture binds");
  130. logger.config(" Left eye texture");
  131. logger.config(" address: "+leftTextureType.getPointer());
  132. logger.config(" size: "+leftTextureType.size()+" bytes");
  133. logger.config(" color space: "+OpenVRUtil.getEColorSpaceString(leftTextureType.eColorSpace));
  134. logger.config(" type: "+OpenVRUtil.getETextureTypeString(leftTextureType.eType));
  135. logger.config(" auto read: "+leftTextureType.getAutoRead());
  136. logger.config(" auto write: "+leftTextureType.getAutoWrite());
  137. logger.config(" handle address: "+leftTextureType.handle);
  138. logger.config(" handle value: "+leftTextureType.handle);
  139. logger.config("");
  140. logger.config(" Right eye texture");
  141. logger.config(" address: "+rightTextureType.getPointer());
  142. logger.config(" size: "+rightTextureType.size()+" bytes");
  143. logger.config(" color space: "+OpenVRUtil.getEColorSpaceString(rightTextureType.eColorSpace));
  144. logger.config(" type: "+OpenVRUtil.getETextureTypeString(rightTextureType.eType));
  145. logger.config(" auto read: "+rightTextureType.getAutoRead());
  146. logger.config(" auto write: "+rightTextureType.getAutoWrite());
  147. logger.config(" handle address: "+rightTextureType.handle);
  148. logger.config(" handle value: "+rightTextureType.handle);
  149. }
  150. } else {
  151. throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
  152. }
  153. }
  154. @Override
  155. public void postRender() {
  156. if (environment != null){
  157. if( environment.isInVR() ) {
  158. VRAPI api = environment.getVRHardware();
  159. if( api.getCompositor() != null ) {
  160. // using the compositor...
  161. int errl = 0, errr = 0;
  162. if( environment.isInstanceRendering() ) {
  163. if( leftTextureType.handle == -1 || leftTextureType.handle != getFullTexId() ) {
  164. leftTextureType.handle = getFullTexId();
  165. if( leftTextureType.handle != -1 ) {
  166. leftTextureType.write();
  167. }
  168. } else {
  169. if( api instanceof OpenVR ) {
  170. int submitFlag = JOpenVRLibrary.EVRSubmitFlags.EVRSubmitFlags_Submit_Default;
  171. errr = ((OpenVR)api).getCompositor().Submit.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Right, leftTextureType, rightTextureBounds, submitFlag);
  172. errl = ((OpenVR)api).getCompositor().Submit.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Left, leftTextureType, leftTextureBounds, submitFlag);
  173. }
  174. }
  175. } else if( leftTextureType.handle == -1 || rightTextureType.handle == -1 ||
  176. leftTextureType.handle != getLeftTexId() || rightTextureType.handle != getRightTexId() ) {
  177. leftTextureType.handle = getLeftTexId();
  178. if( leftTextureType.handle != -1 ) {
  179. logger.fine("Writing Left texture to native memory at " + leftTextureType.getPointer());
  180. leftTextureType.write();
  181. }
  182. rightTextureType.handle = getRightTexId();
  183. if( rightTextureType.handle != -1 ) {
  184. logger.fine("Writing Right texture to native memory at " + leftTextureType.getPointer());
  185. rightTextureType.write();
  186. }
  187. } else {
  188. if( api instanceof OpenVR ) {
  189. errl = ((OpenVR)api).getCompositor().Submit.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Left, leftTextureType, null,
  190. JOpenVRLibrary.EVRSubmitFlags.EVRSubmitFlags_Submit_Default);
  191. errr = ((OpenVR)api).getCompositor().Submit.apply(JOpenVRLibrary.EVREye.EVREye_Eye_Right, rightTextureType, null,
  192. JOpenVRLibrary.EVRSubmitFlags.EVRSubmitFlags_Submit_Default);
  193. } else {
  194. }
  195. }
  196. if( errl != 0 ){
  197. logger.severe("Submit to left compositor error: " + OpenVRUtil.getEVRCompositorErrorString(errl)+" ("+Integer.toString(errl)+")");
  198. logger.severe(" Texture color space: "+OpenVRUtil.getEColorSpaceString(leftTextureType.eColorSpace));
  199. logger.severe(" Texture type: "+OpenVRUtil.getETextureTypeString(leftTextureType.eType));
  200. logger.severe(" Texture handle: "+leftTextureType.handle);
  201. logger.severe(" Left eye texture "+leftEyeTexture.getName()+" ("+leftEyeTexture.getImage().getId()+")");
  202. logger.severe(" Type: "+leftEyeTexture.getType());
  203. logger.severe(" Size: "+leftEyeTexture.getImage().getWidth()+"x"+leftEyeTexture.getImage().getHeight());
  204. logger.severe(" Image depth: "+leftEyeTexture.getImage().getDepth());
  205. logger.severe(" Image format: "+leftEyeTexture.getImage().getFormat());
  206. logger.severe(" Image color space: "+leftEyeTexture.getImage().getColorSpace());
  207. }
  208. if( errr != 0 ){
  209. logger.severe("Submit to right compositor error: " + OpenVRUtil.getEVRCompositorErrorString(errl)+" ("+Integer.toString(errl)+")");
  210. logger.severe(" Texture color space: "+OpenVRUtil.getEColorSpaceString(rightTextureType.eColorSpace));
  211. logger.severe(" Texture type: "+OpenVRUtil.getETextureTypeString(rightTextureType.eType));
  212. logger.severe(" Texture handle: "+rightTextureType.handle);
  213. logger.severe(" Right eye texture "+rightEyeTexture.getName()+" ("+rightEyeTexture.getImage().getId()+")");
  214. logger.severe(" Type: "+rightEyeTexture.getType());
  215. logger.severe(" Size: "+rightEyeTexture.getImage().getWidth()+"x"+rightEyeTexture.getImage().getHeight());
  216. logger.severe(" Image depth: "+rightEyeTexture.getImage().getDepth());
  217. logger.severe(" Image format: "+rightEyeTexture.getImage().getFormat());
  218. logger.severe(" Image color space: "+rightEyeTexture.getImage().getColorSpace());
  219. }
  220. }
  221. }
  222. } else {
  223. throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
  224. }
  225. }
  226. @Override
  227. public void initialize() {
  228. logger.config("Initializing VR view manager.");
  229. if (environment != null){
  230. initTextureSubmitStructs();
  231. setupCamerasAndViews();
  232. setupVRScene();
  233. moveScreenProcessingToEyes();
  234. if( environment.hasTraditionalGUIOverlay() ) {
  235. environment.getVRMouseManager().initialize();
  236. // update the pose to position the gui correctly on start
  237. update(0f);
  238. environment.getVRGUIManager().positionGui();
  239. }
  240. logger.config("Initialized VR view manager [SUCCESS]");
  241. } else {
  242. throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
  243. }
  244. }
  245. /**
  246. * Prepare the size of the given {@link Camera camera} to adapt it to the underlying rendering context.
  247. * @param cam the {@link Camera camera} to prepare.
  248. * @param xMult the camera width multiplier.
  249. */
  250. private void prepareCameraSize(Camera cam, float xMult) {
  251. if (environment != null){
  252. if (environment.getApplication() != null){
  253. Vector2f size = new Vector2f();
  254. VRAPI vrhmd = environment.getVRHardware();
  255. if( vrhmd == null ) {
  256. size.x = 1280f;
  257. size.y = 720f;
  258. } else {
  259. vrhmd.getRenderSize(size);
  260. }
  261. if( size.x < environment.getApplication().getContext().getSettings().getWidth() ) {
  262. size.x = environment.getApplication().getContext().getSettings().getWidth();
  263. }
  264. if( size.y < environment.getApplication().getContext().getSettings().getHeight() ) {
  265. size.y = environment.getApplication().getContext().getSettings().getHeight();
  266. }
  267. if( environment.isInstanceRendering() ){
  268. size.x *= 2f;
  269. }
  270. // other adjustments
  271. size.x *= xMult;
  272. size.x *= getResolutionMuliplier();
  273. size.y *= getResolutionMuliplier();
  274. if( cam.getWidth() != size.x || cam.getHeight() != size.y ){
  275. cam.resize((int)size.x, (int)size.y, false);
  276. }
  277. } else {
  278. throw new IllegalStateException("This VR environment is not attached to any application.");
  279. }
  280. } else {
  281. throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
  282. }
  283. }
  284. /**
  285. * Replaces rootNode as the main cameras scene with the distortion mesh
  286. */
  287. private void setupVRScene(){
  288. if (environment != null){
  289. if (environment.getApplication() != null){
  290. // no special scene to setup if we are doing instancing
  291. if( environment.isInstanceRendering() ) {
  292. // distortion has to be done with compositor here... we want only one pass on our end!
  293. if( environment.getApplication().getContext().getSettings().isSwapBuffers() ) {
  294. setupMirrorBuffers(environment.getCamera(), dualEyeTex, true);
  295. }
  296. return;
  297. }
  298. leftEyeTexture = (Texture2D) getLeftViewPort().getOutputFrameBuffer().getColorBuffer().getTexture();
  299. rightEyeTexture = (Texture2D)getRightViewPort().getOutputFrameBuffer().getColorBuffer().getTexture();
  300. leftEyeDepth = (Texture2D) getLeftViewPort().getOutputFrameBuffer().getDepthBuffer().getTexture();
  301. rightEyeDepth = (Texture2D)getRightViewPort().getOutputFrameBuffer().getDepthBuffer().getTexture();
  302. // main viewport is either going to be a distortion scene or nothing
  303. // mirroring is handled by copying framebuffers
  304. Iterator<Spatial> spatialIter = environment.getApplication().getViewPort().getScenes().iterator();
  305. while(spatialIter.hasNext()){
  306. environment.getApplication().getViewPort().detachScene(spatialIter.next());
  307. }
  308. spatialIter = environment.getApplication().getGuiViewPort().getScenes().iterator();
  309. while(spatialIter.hasNext()){
  310. environment.getApplication().getGuiViewPort().detachScene(spatialIter.next());
  311. }
  312. // only setup distortion scene if compositor isn't running (or using custom mesh distortion option)
  313. if( environment.getVRHardware().getCompositor() == null ) {
  314. Node distortionScene = new Node();
  315. Material leftMat = new Material(environment.getApplication().getAssetManager(), "Common/MatDefs/VR/OpenVR.j3md");
  316. leftMat.setTexture("Texture", leftEyeTexture);
  317. Geometry leftEye = new Geometry("box", setupDistortionMesh(JOpenVRLibrary.EVREye.EVREye_Eye_Left, environment.getVRHardware()));
  318. leftEye.setMaterial(leftMat);
  319. distortionScene.attachChild(leftEye);
  320. Material rightMat = new Material(environment.getApplication().getAssetManager(), "Common/MatDefs/VR/OpenVR.j3md");
  321. rightMat.setTexture("Texture", rightEyeTexture);
  322. Geometry rightEye = new Geometry("box", setupDistortionMesh(JOpenVRLibrary.EVREye.EVREye_Eye_Right, environment.getVRHardware()));
  323. rightEye.setMaterial(rightMat);
  324. distortionScene.attachChild(rightEye);
  325. distortionScene.updateGeometricState();
  326. environment.getApplication().getViewPort().attachScene(distortionScene);
  327. //if( useCustomDistortion ) setupFinalFullTexture(app.getViewPort().getCamera());
  328. }
  329. if( environment.getApplication().getContext().getSettings().isSwapBuffers() ) {
  330. setupMirrorBuffers(environment.getCamera(), leftEyeTexture, false);
  331. }
  332. } else {
  333. throw new IllegalStateException("This VR environment is not attached to any application.");
  334. }
  335. } else {
  336. throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
  337. }
  338. }
  339. @Override
  340. public void update(float tpf) {
  341. if (environment != null){
  342. // grab the observer
  343. Object obs = environment.getObserver();
  344. Quaternion objRot;
  345. Vector3f objPos;
  346. if( obs instanceof Camera ) {
  347. objRot = ((Camera)obs).getRotation();
  348. objPos = ((Camera)obs).getLocation();
  349. } else {
  350. objRot = ((Spatial)obs).getWorldRotation();
  351. objPos = ((Spatial)obs).getWorldTranslation();
  352. }
  353. // grab the hardware handle
  354. VRAPI dev = environment.getVRHardware();
  355. if( dev != null ) {
  356. // update the HMD's position & orientation
  357. dev.updatePose();
  358. dev.getPositionAndOrientation(hmdPos, hmdRot);
  359. /*
  360. // TOREMOVE
  361. Vector3f v = dev.getVRinput().getTrackedController(0).getPosition();
  362. Quaternion q = dev.getVRinput().getTrackedController(0).getOrientation();
  363. if ((v != null)&&(q != null)){
  364. hmdPos.set(v);
  365. hmdRot.set(q);
  366. }
  367. logger.severe("HMD controller ");
  368. logger.severe(" Position "+hmdPos);
  369. logger.severe(" Orientation "+hmdRot);
  370. VRTrackedController tc = null;
  371. for(int i = 0; i < dev.getVRinput().getTrackedControllerCount(); i++){
  372. tc = dev.getVRinput().getTrackedController(i);
  373. logger.severe("Tracked controller "+i+": "+tc.getControllerName());
  374. logger.severe(" Position "+tc.getPosition());
  375. logger.severe(" Orientation "+tc.getOrientation());
  376. logger.severe("");
  377. }
  378. */
  379. // TOREMOVE
  380. if( obs != null ) {
  381. // update hmdPos based on obs rotation
  382. finalRotation.set(objRot);
  383. finalRotation.mult(hmdPos, hmdPos);
  384. finalRotation.multLocal(hmdRot);
  385. }
  386. finalizeCamera(dev.getHMDVectorPoseLeftEye(), objPos, getLeftCamera());
  387. finalizeCamera(dev.getHMDVectorPoseRightEye(), objPos, getRightCamera());
  388. } else {
  389. getLeftCamera().setFrame(objPos, objRot);
  390. getRightCamera().setFrame(objPos, objRot);
  391. }
  392. if( environment.hasTraditionalGUIOverlay() ) {
  393. // update the mouse?
  394. environment.getVRMouseManager().update(tpf);
  395. // update GUI position?
  396. if( environment.getVRGUIManager().wantsReposition || environment.getVRGUIManager().getPositioningMode() != VRGUIPositioningMode.MANUAL ) {
  397. environment.getVRGUIManager().positionGuiNow(tpf);
  398. environment.getVRGUIManager().updateGuiQuadGeometricState();
  399. }
  400. }
  401. } else {
  402. throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
  403. }
  404. }
  405. /**
  406. * Place the camera within the scene.
  407. * @param eyePos the eye position.
  408. * @param obsPosition the observer position.
  409. * @param cam the camera to place.
  410. */
  411. private void finalizeCamera(Vector3f eyePos, Vector3f obsPosition, Camera cam) {
  412. finalRotation.mult(eyePos, finalPosition);
  413. finalPosition.addLocal(hmdPos);
  414. if( obsPosition != null ) finalPosition.addLocal(obsPosition);
  415. finalPosition.y += getHeightAdjustment();
  416. cam.setFrame(finalPosition, finalRotation);
  417. }
  418. private void setupCamerasAndViews() {
  419. if (environment != null){
  420. // get desired frustrum from original camera
  421. Camera origCam = environment.getCamera();
  422. float fFar = origCam.getFrustumFar();
  423. float fNear = origCam.getFrustumNear();
  424. // restore frustrum on distortion scene cam, if needed
  425. if( environment.isInstanceRendering() ) {
  426. leftCamera = origCam;
  427. } else if( environment.compositorAllowed() == false ) {
  428. origCam.setFrustumFar(100f);
  429. origCam.setFrustumNear(1f);
  430. leftCamera = origCam.clone();
  431. prepareCameraSize(origCam, 2f);
  432. } else {
  433. leftCamera = origCam.clone();
  434. }
  435. getLeftCamera().setFrustumPerspective(environment.getDefaultFOV(), environment.getDefaultAspect(), fNear, fFar);
  436. prepareCameraSize(getLeftCamera(), 1f);
  437. if( environment.getVRHardware() != null ) {
  438. getLeftCamera().setProjectionMatrix(environment.getVRHardware().getHMDMatrixProjectionLeftEye(getLeftCamera()));
  439. }
  440. //org.lwjgl.opengl.GL11.glEnable(org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_SRGB);
  441. if( !environment.isInstanceRendering()) {
  442. leftViewPort = setupViewBuffers(getLeftCamera(), LEFT_VIEW_NAME);
  443. rightCamera = getLeftCamera().clone();
  444. if( environment.getVRHardware() != null ){
  445. getRightCamera().setProjectionMatrix(environment.getVRHardware().getHMDMatrixProjectionRightEye(getRightCamera()));
  446. }
  447. rightViewPort = setupViewBuffers(getRightCamera(), RIGHT_VIEW_NAME);
  448. } else {
  449. if (environment.getApplication() != null){
  450. logger.severe("THIS CODE NEED CHANGES !!!");
  451. leftViewPort = environment.getApplication().getViewPort();
  452. //leftViewport.attachScene(app.getRootNode());
  453. rightCamera = getLeftCamera().clone();
  454. if( environment.getVRHardware() != null ){
  455. getRightCamera().setProjectionMatrix(environment.getVRHardware().getHMDMatrixProjectionRightEye(getRightCamera()));
  456. }
  457. org.lwjgl.opengl.GL11.glEnable(org.lwjgl.opengl.GL30.GL_CLIP_DISTANCE0);
  458. //FIXME: [jme-vr] Fix with JMonkey next release
  459. //RenderManager._VRInstancing_RightCamProjection = camRight.getViewProjectionMatrix();
  460. setupFinalFullTexture(environment.getApplication().getViewPort().getCamera());
  461. } else {
  462. throw new IllegalStateException("This VR environment is not attached to any application.");
  463. }
  464. }
  465. // setup gui
  466. environment.getVRGUIManager().setupGui(getLeftCamera(), getRightCamera(), getLeftViewPort(), getRightViewPort());
  467. if( environment.getVRHardware() != null ) {
  468. // call these to cache the results internally
  469. environment.getVRHardware().getHMDMatrixPoseLeftEye();
  470. environment.getVRHardware().getHMDMatrixPoseRightEye();
  471. }
  472. } else {
  473. throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
  474. }
  475. }
  476. private ViewPort setupMirrorBuffers(Camera cam, Texture tex, boolean expand) {
  477. if (environment != null){
  478. if (environment.getApplication() != null){
  479. Camera clonecam = cam.clone();
  480. ViewPort viewPort = environment.getApplication().getRenderManager().createPostView("MirrorView", clonecam);
  481. clonecam.setParallelProjection(true);
  482. viewPort.setClearFlags(true, true, true);
  483. viewPort.setBackgroundColor(ColorRGBA.Black);
  484. Picture pic = new Picture("fullscene");
  485. pic.setLocalTranslation(-0.75f, -0.5f, 0f);
  486. if( expand ) {
  487. pic.setLocalScale(3f, 1f, 1f);
  488. } else {
  489. pic.setLocalScale(1.5f, 1f, 1f);
  490. }
  491. pic.setQueueBucket(Bucket.Opaque);
  492. pic.setTexture(environment.getApplication().getAssetManager(), (Texture2D)tex, false);
  493. viewPort.attachScene(pic);
  494. viewPort.setOutputFrameBuffer(null);
  495. pic.updateGeometricState();
  496. return viewPort;
  497. } else {
  498. throw new IllegalStateException("This VR environment is not attached to any application.");
  499. }
  500. } else {
  501. throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
  502. }
  503. }
  504. private void setupFinalFullTexture(Camera cam) {
  505. if (environment != null){
  506. if (environment.getApplication() != null){
  507. // create offscreen framebuffer
  508. FrameBuffer out = new FrameBuffer(cam.getWidth(), cam.getHeight(), 1);
  509. //offBuffer.setSrgb(true);
  510. //setup framebuffer's texture
  511. dualEyeTex = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8);
  512. dualEyeTex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
  513. dualEyeTex.setMagFilter(Texture.MagFilter.Bilinear);
  514. logger.config("Dual eye texture "+dualEyeTex.getName()+" ("+dualEyeTex.getImage().getId()+")");
  515. logger.config(" Type: "+dualEyeTex.getType());
  516. logger.config(" Size: "+dualEyeTex.getImage().getWidth()+"x"+dualEyeTex.getImage().getHeight());
  517. logger.config(" Image depth: "+dualEyeTex.getImage().getDepth());
  518. logger.config(" Image format: "+dualEyeTex.getImage().getFormat());
  519. logger.config(" Image color space: "+dualEyeTex.getImage().getColorSpace());
  520. //setup framebuffer to use texture
  521. out.setDepthBuffer(Image.Format.Depth);
  522. out.setColorTexture(dualEyeTex);
  523. ViewPort viewPort = environment.getApplication().getViewPort();
  524. viewPort.setClearFlags(true, true, true);
  525. viewPort.setBackgroundColor(ColorRGBA.Black);
  526. viewPort.setOutputFrameBuffer(out);
  527. } else {
  528. throw new IllegalStateException("This VR environment is not attached to any application.");
  529. }
  530. } else {
  531. throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
  532. }
  533. }
  534. private ViewPort setupViewBuffers(Camera cam, String viewName){
  535. if (environment != null){
  536. if (environment.getApplication() != null){
  537. // create offscreen framebuffer
  538. FrameBuffer offBufferLeft = new FrameBuffer(cam.getWidth(), cam.getHeight(), 1);
  539. //offBufferLeft.setSrgb(true);
  540. //setup framebuffer's texture
  541. Texture2D offTex = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8);
  542. offTex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
  543. offTex.setMagFilter(Texture.MagFilter.Bilinear);
  544. //setup framebuffer to use texture
  545. offBufferLeft.setDepthBuffer(Image.Format.Depth);
  546. offBufferLeft.setColorTexture(offTex);
  547. ViewPort viewPort = environment.getApplication().getRenderManager().createPreView(viewName, cam);
  548. viewPort.setClearFlags(true, true, true);
  549. viewPort.setBackgroundColor(ColorRGBA.Black);
  550. Iterator<Spatial> spatialIter = environment.getApplication().getViewPort().getScenes().iterator();
  551. while(spatialIter.hasNext()){
  552. viewPort.attachScene(spatialIter.next());
  553. }
  554. //set viewport to render to offscreen framebuffer
  555. viewPort.setOutputFrameBuffer(offBufferLeft);
  556. return viewPort;
  557. } else {
  558. throw new IllegalStateException("This VR environment is not attached to any application.");
  559. }
  560. } else {
  561. throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
  562. }
  563. }
  564. /**
  565. * Setup a distortion mesh for the stereo view.
  566. * @param eye the eye to apply.
  567. * @param api the underlying VR api
  568. * @return the distorted mesh.
  569. */
  570. public static Mesh setupDistortionMesh(int eye, VRAPI api) {
  571. Mesh distortionMesh = new Mesh();
  572. float m_iLensGridSegmentCountH = 43, m_iLensGridSegmentCountV = 43;
  573. float w = 1f / (m_iLensGridSegmentCountH - 1f);
  574. float h = 1f / (m_iLensGridSegmentCountV - 1f);
  575. float u, v;
  576. float verts[] = new float[(int) (m_iLensGridSegmentCountV * m_iLensGridSegmentCountH) * 3];
  577. float texcoordR[] = new float[(int) (m_iLensGridSegmentCountV * m_iLensGridSegmentCountH) * 2];
  578. float texcoordG[] = new float[(int) (m_iLensGridSegmentCountV * m_iLensGridSegmentCountH) * 2];
  579. float texcoordB[] = new float[(int) (m_iLensGridSegmentCountV * m_iLensGridSegmentCountH) * 2];
  580. int vertPos = 0, coordPos = 0;
  581. float Xoffset = eye == JOpenVRLibrary.EVREye.EVREye_Eye_Left ? -1f : 0;
  582. for (int y = 0; y < m_iLensGridSegmentCountV; y++) {
  583. for (int x = 0; x < m_iLensGridSegmentCountH; x++) {
  584. u = x * w;
  585. v = 1 - y * h;
  586. verts[vertPos] = Xoffset + u; // x
  587. verts[vertPos + 1] = -1 + 2 * y * h; // y
  588. verts[vertPos + 2] = 0f; // z
  589. vertPos += 3;
  590. DistortionCoordinates_t dc0 = new DistortionCoordinates_t();
  591. if( api.getVRSystem() == null ) {
  592. // default to no distortion
  593. texcoordR[coordPos] = u;
  594. texcoordR[coordPos + 1] = 1 - v;
  595. texcoordG[coordPos] = u;
  596. texcoordG[coordPos + 1] = 1 - v;
  597. texcoordB[coordPos] = u;
  598. texcoordB[coordPos + 1] = 1 - v;
  599. } else {
  600. ((VR_IVRSystem_FnTable)api.getVRSystem()).ComputeDistortion.apply(eye, u, v, dc0);
  601. texcoordR[coordPos] = dc0.rfRed[0];
  602. texcoordR[coordPos + 1] = 1 - dc0.rfRed[1];
  603. texcoordG[coordPos] = dc0.rfGreen[0];
  604. texcoordG[coordPos + 1] = 1 - dc0.rfGreen[1];
  605. texcoordB[coordPos] = dc0.rfBlue[0];
  606. texcoordB[coordPos + 1] = 1 - dc0.rfBlue[1];
  607. }
  608. coordPos += 2;
  609. }
  610. }
  611. // have UV coordinates & positions, now to setup indices
  612. int[] indices = new int[(int) ((m_iLensGridSegmentCountV - 1) * (m_iLensGridSegmentCountH - 1)) * 6];
  613. int indexPos = 0;
  614. int a, b, c, d;
  615. int offset = 0;
  616. for (int y = 0; y < m_iLensGridSegmentCountV - 1; y++) {
  617. for (int x = 0; x < m_iLensGridSegmentCountH - 1; x++) {
  618. a = (int) (m_iLensGridSegmentCountH * y + x + offset);
  619. b = (int) (m_iLensGridSegmentCountH * y + x + 1 + offset);
  620. c = (int) ((y + 1) * m_iLensGridSegmentCountH + x + 1 + offset);
  621. d = (int) ((y + 1) * m_iLensGridSegmentCountH + x + offset);
  622. indices[indexPos] = a;
  623. indices[indexPos + 1] = b;
  624. indices[indexPos + 2] = c;
  625. indices[indexPos + 3] = a;
  626. indices[indexPos + 4] = c;
  627. indices[indexPos + 5] = d;
  628. indexPos += 6;
  629. }
  630. }
  631. // OK, create the mesh
  632. distortionMesh.setBuffer(VertexBuffer.Type.Position, 3, verts);
  633. distortionMesh.setBuffer(VertexBuffer.Type.Index, 1, indices);
  634. distortionMesh.setBuffer(VertexBuffer.Type.TexCoord, 2, texcoordR);
  635. distortionMesh.setBuffer(VertexBuffer.Type.TexCoord2, 2, texcoordG);
  636. distortionMesh.setBuffer(VertexBuffer.Type.TexCoord3, 2, texcoordB);
  637. distortionMesh.setStatic();
  638. return distortionMesh;
  639. }
  640. }