|
|
|
package com.jme3.util;
|
|
|
|
|
|
|
|
import java.awt.GraphicsEnvironment;
|
|
|
|
import java.util.Iterator;
|
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
|
|
|
import com.jme3.app.VREnvironment;
|
|
|
|
import com.jme3.input.vr.OSVR;
|
|
|
|
import com.jme3.input.vr.VRAPI;
|
|
|
|
import com.jme3.material.Material;
|
|
|
|
import com.jme3.math.ColorRGBA;
|
|
|
|
import com.jme3.math.Quaternion;
|
|
|
|
import com.jme3.math.Vector2f;
|
|
|
|
import com.jme3.math.Vector3f;
|
|
|
|
import com.jme3.post.CartoonSSAO;
|
|
|
|
import com.jme3.post.Filter;
|
|
|
|
import com.jme3.post.FilterPostProcessor;
|
|
|
|
import com.jme3.post.FilterUtil;
|
|
|
|
import com.jme3.post.SceneProcessor;
|
|
|
|
import com.jme3.post.filters.FogFilter;
|
|
|
|
import com.jme3.post.filters.TranslucentBucketFilter;
|
|
|
|
import com.jme3.post.ssao.SSAOFilter;
|
|
|
|
import com.jme3.renderer.Camera;
|
|
|
|
import com.jme3.renderer.ViewPort;
|
|
|
|
import com.jme3.renderer.queue.RenderQueue.Bucket;
|
|
|
|
import com.jme3.scene.Geometry;
|
|
|
|
import com.jme3.scene.Mesh;
|
|
|
|
import com.jme3.scene.Node;
|
|
|
|
import com.jme3.scene.Spatial;
|
|
|
|
import com.jme3.scene.VertexBuffer;
|
|
|
|
import com.jme3.shadow.DirectionalLightShadowFilter;
|
|
|
|
import com.jme3.shadow.VRDirectionalLightShadowRenderer;
|
|
|
|
import com.jme3.system.jopenvr.DistortionCoordinates_t;
|
|
|
|
import com.jme3.system.jopenvr.JOpenVRLibrary;
|
|
|
|
import com.jme3.system.jopenvr.OpenVRUtil;
|
|
|
|
import com.jme3.system.jopenvr.Texture_t;
|
|
|
|
import com.jme3.system.jopenvr.VR_IVRSystem_FnTable;
|
|
|
|
import com.jme3.system.lwjgl.LwjglWindow;
|
|
|
|
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_RenderBufferOpenGL;
|
|
|
|
import com.jme3.system.osvr.osvrrendermanageropengl.OSVR_ViewportDescription;
|
|
|
|
import com.jme3.system.osvr.osvrrendermanageropengl.OsvrRenderManagerOpenGLLibrary;
|
|
|
|
import com.jme3.texture.FrameBuffer;
|
|
|
|
import com.jme3.texture.Image;
|
|
|
|
import com.jme3.texture.Texture;
|
|
|
|
import com.jme3.texture.Texture2D;
|
|
|
|
import com.jme3.ui.Picture;
|
|
|
|
import com.sun.jna.Pointer;
|
|
|
|
import com.sun.jna.ptr.PointerByReference;
|
|
|
|
|
|
|
|
public class VRViewManagerOSVR extends AbstractVRViewManager{
|
|
|
|
private static final Logger logger = Logger.getLogger(VRViewManagerOpenVR.class.getName());
|
|
|
|
|
|
|
|
private Camera leftCamera;
|
|
|
|
private ViewPort leftViewport;
|
|
|
|
private FilterPostProcessor leftPostProcessor;
|
|
|
|
private Texture2D leftEyeTexture;
|
|
|
|
private Texture2D leftEyeDepth;
|
|
|
|
|
|
|
|
private Camera rightCamera;
|
|
|
|
private ViewPort rightViewport;
|
|
|
|
private FilterPostProcessor rightPostProcessor;
|
|
|
|
private Texture2D rightEyeTexture;
|
|
|
|
private Texture2D rightEyeDepth;
|
|
|
|
|
|
|
|
// OpenVR values
|
|
|
|
private Texture_t leftTextureType;
|
|
|
|
private Texture_t rightTextureType;
|
|
|
|
|
|
|
|
// OSVR values
|
|
|
|
OSVR_RenderBufferOpenGL.ByValue[] osvr_renderBuffer;
|
|
|
|
OSVR_ViewportDescription.ByValue osvr_viewDescFull;
|
|
|
|
OSVR_ViewportDescription.ByValue osvr_viewDescLeft;
|
|
|
|
OSVR_ViewportDescription.ByValue osvr_viewDescRight;
|
|
|
|
Pointer osvr_rmBufferState;
|
|
|
|
|
|
|
|
//private static boolean useCustomDistortion;
|
|
|
|
private float heightAdjustment;
|
|
|
|
|
|
|
|
private Texture2D dualEyeTex;
|
|
|
|
|
|
|
|
private final PointerByReference grabRBS = new PointerByReference();
|
|
|
|
|
|
|
|
private float resMult = 1f;
|
|
|
|
|
|
|
|
//final & temp values for camera calculations
|
|
|
|
private final Vector3f finalPosition = new Vector3f();
|
|
|
|
private final Quaternion finalRotation = new Quaternion();
|
|
|
|
private final Vector3f hmdPos = new Vector3f();
|
|
|
|
private final Quaternion hmdRot = new Quaternion();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new VR view manager attached to the given {@link VREnvironment VR environment}.
|
|
|
|
* @param environment the {@link VREnvironment VR environment} to which this view manager is attached.
|
|
|
|
*/
|
|
|
|
public VRViewManagerOSVR(VREnvironment environment){
|
|
|
|
this.environment = environment;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the {@link Camera camera} attached to the left eye.
|
|
|
|
* @return the {@link Camera camera} attached to the left eye.
|
|
|
|
* @see #getRightCamera()
|
|
|
|
*/
|
|
|
|
public Camera getLeftCamera() {
|
|
|
|
return leftCamera;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the {@link Camera camera} attached to the right eye.
|
|
|
|
* @return the {@link Camera camera} attached to the right eye.
|
|
|
|
* @see #getLeftCamera()
|
|
|
|
*/
|
|
|
|
public Camera getRightCamera() {
|
|
|
|
return rightCamera;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the {@link ViewPort viewport} attached to the left eye.
|
|
|
|
* @return the {@link ViewPort viewport} attached to the left eye.
|
|
|
|
* @see #getRightViewPort()
|
|
|
|
*/
|
|
|
|
public ViewPort getLeftViewPort() {
|
|
|
|
return leftViewport;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the {@link ViewPort viewport} attached to the right eye.
|
|
|
|
* @return the {@link ViewPort viewport} attached to the right eye.
|
|
|
|
* @see #getLeftViewPort()
|
|
|
|
*/
|
|
|
|
public ViewPort getRightViewPort() {
|
|
|
|
return rightViewport;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the identifier of the left eye texture.
|
|
|
|
* @return the identifier of the left eye texture.
|
|
|
|
* @see #getRightTexId()
|
|
|
|
* @see #getFullTexId()
|
|
|
|
*/
|
|
|
|
protected int getLeftTexId() {
|
|
|
|
return (int)leftEyeTexture.getImage().getId();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the identifier of the right eye texture.
|
|
|
|
* @return the identifier of the right eye texture.
|
|
|
|
* @see #getLeftTexId()
|
|
|
|
* @see #getFullTexId()
|
|
|
|
*/
|
|
|
|
protected int getRightTexId() {
|
|
|
|
return (int)rightEyeTexture.getImage().getId();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the identifier of the full (dual eye) texture.
|
|
|
|
* @return the identifier of the full (dual eye) texture.
|
|
|
|
* @see #getLeftTexId()
|
|
|
|
* @see #getRightTexId()
|
|
|
|
*/
|
|
|
|
private int getFullTexId() {
|
|
|
|
return (int)dualEyeTex.getImage().getId();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the height adjustment to apply to the cameras before rendering.
|
|
|
|
* @return the height adjustment to apply to the cameras before rendering.
|
|
|
|
* @see #setHeightAdjustment(float)
|
|
|
|
*/
|
|
|
|
public float getHeightAdjustment() {
|
|
|
|
return heightAdjustment;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the height adjustment to apply to the cameras before rendering.
|
|
|
|
* @param amount the height adjustment to apply to the cameras before rendering.
|
|
|
|
* @see #getHeightAdjustment()
|
|
|
|
*/
|
|
|
|
public void setHeightAdjustment(float amount) {
|
|
|
|
heightAdjustment = amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the resolution multiplier.
|
|
|
|
* @return the resolution multiplier.
|
|
|
|
* @see #setResolutionMultiplier(float)
|
|
|
|
*/
|
|
|
|
public float getResolutionMuliplier() {
|
|
|
|
return resMult;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the resolution multiplier.
|
|
|
|
* @param resMult the resolution multiplier.
|
|
|
|
* @see #getResolutionMuliplier()
|
|
|
|
*/
|
|
|
|
public void setResolutionMultiplier(float resMult) {
|
|
|
|
this.resMult = resMult;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the system binds of the textures.
|
|
|
|
*/
|
|
|
|
private void initTextureSubmitStructs() {
|
|
|
|
leftTextureType = new Texture_t();
|
|
|
|
rightTextureType = new Texture_t();
|
|
|
|
|
|
|
|
// must be OSVR
|
|
|
|
osvr_renderBuffer = new OSVR_RenderBufferOpenGL.ByValue[2];
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT] = new OSVR_RenderBufferOpenGL.ByValue();
|
|
|
|
osvr_renderBuffer[OSVR.EYE_RIGHT] = new OSVR_RenderBufferOpenGL.ByValue();
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT].setAutoSynch(false);
|
|
|
|
osvr_renderBuffer[OSVR.EYE_RIGHT].setAutoSynch(false);
|
|
|
|
osvr_viewDescFull = new OSVR_ViewportDescription.ByValue();
|
|
|
|
osvr_viewDescFull.setAutoSynch(false);
|
|
|
|
osvr_viewDescFull.left = osvr_viewDescFull.lower = 0.0;
|
|
|
|
osvr_viewDescFull.width = osvr_viewDescFull.height = 1.0;
|
|
|
|
osvr_viewDescLeft = new OSVR_ViewportDescription.ByValue();
|
|
|
|
osvr_viewDescLeft.setAutoSynch(false);
|
|
|
|
osvr_viewDescLeft.left = osvr_viewDescLeft.lower = 0.0;
|
|
|
|
osvr_viewDescLeft.width = 0.5;
|
|
|
|
osvr_viewDescLeft.height = 1.0;
|
|
|
|
osvr_viewDescRight = new OSVR_ViewportDescription.ByValue();
|
|
|
|
osvr_viewDescRight.setAutoSynch(false);
|
|
|
|
osvr_viewDescRight.left = 0.5;
|
|
|
|
osvr_viewDescRight.lower = 0.0;
|
|
|
|
osvr_viewDescRight.width = 0.5;
|
|
|
|
osvr_viewDescRight.height = 1.0;
|
|
|
|
osvr_viewDescRight.write();
|
|
|
|
osvr_viewDescLeft.write();
|
|
|
|
osvr_viewDescFull.write();
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT].depthStencilBufferName = -1;
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT].colorBufferName = -1;
|
|
|
|
osvr_renderBuffer[OSVR.EYE_RIGHT].depthStencilBufferName = -1;
|
|
|
|
osvr_renderBuffer[OSVR.EYE_RIGHT].colorBufferName = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Register the OSVR OpenGL buffer.
|
|
|
|
* @param buf the OSVR OpenGL buffer.
|
|
|
|
*/
|
|
|
|
private void registerOSVRBuffer(OSVR_RenderBufferOpenGL.ByValue buf) {
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerStartRegisterRenderBuffers(grabRBS);
|
|
|
|
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerRegisterRenderBufferOpenGL(grabRBS.getValue(), buf);
|
|
|
|
OsvrRenderManagerOpenGLLibrary.osvrRenderManagerFinishRegisterRenderBuffers(((OSVR)environment.getVRHardware()).getCompositor(), grabRBS.getValue(), (byte)0);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send the textures to the two eyes.
|
|
|
|
*/
|
|
|
|
public void postRender() {
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
if( environment.isInVR() ) {
|
|
|
|
VRAPI api = environment.getVRHardware();
|
|
|
|
if( api.getCompositor() != null ) {
|
|
|
|
// using the compositor...
|
|
|
|
int errl = 0, errr = 0;
|
|
|
|
if( environment.isInstanceRendering() ) {
|
|
|
|
if( leftTextureType.handle == -1 || leftTextureType.handle != getFullTexId() ) {
|
|
|
|
leftTextureType.handle = getFullTexId();
|
|
|
|
if( leftTextureType.handle != -1 ) {
|
|
|
|
leftTextureType.write();
|
|
|
|
if( api instanceof OSVR ) {
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT].colorBufferName = leftTextureType.handle;
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT].depthStencilBufferName = dualEyeTex.getImage().getId();
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT].write();
|
|
|
|
registerOSVRBuffer(osvr_renderBuffer[OSVR.EYE_LEFT]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if( api instanceof OSVR ) {
|
|
|
|
((OSVR)api).handleRenderBufferPresent(osvr_viewDescLeft, osvr_viewDescRight,
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT], osvr_renderBuffer[OSVR.EYE_LEFT]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if( leftTextureType.handle == -1 || rightTextureType.handle == -1 ||
|
|
|
|
leftTextureType.handle != getLeftTexId() || rightTextureType.handle != getRightTexId() ) {
|
|
|
|
leftTextureType.handle = getLeftTexId();
|
|
|
|
if( leftTextureType.handle != -1 ) {
|
|
|
|
logger.fine("Writing Left texture to native memory at " + leftTextureType.getPointer());
|
|
|
|
leftTextureType.write();
|
|
|
|
if( api instanceof OSVR ) {
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT].colorBufferName = leftTextureType.handle;
|
|
|
|
if( leftEyeDepth != null ) osvr_renderBuffer[OSVR.EYE_LEFT].depthStencilBufferName = leftEyeDepth.getImage().getId();
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT].write();
|
|
|
|
registerOSVRBuffer(osvr_renderBuffer[OSVR.EYE_LEFT]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
rightTextureType.handle = getRightTexId();
|
|
|
|
if( rightTextureType.handle != -1 ) {
|
|
|
|
logger.fine("Writing Right texture to native memory at " + leftTextureType.getPointer());
|
|
|
|
rightTextureType.write();
|
|
|
|
if( api instanceof OSVR ) {
|
|
|
|
osvr_renderBuffer[OSVR.EYE_RIGHT].colorBufferName = rightTextureType.handle;
|
|
|
|
if( rightEyeDepth != null ) osvr_renderBuffer[OSVR.EYE_RIGHT].depthStencilBufferName = rightEyeDepth.getImage().getId();
|
|
|
|
osvr_renderBuffer[OSVR.EYE_RIGHT].write();
|
|
|
|
registerOSVRBuffer(osvr_renderBuffer[OSVR.EYE_RIGHT]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if( api instanceof OSVR ) {
|
|
|
|
((OSVR)api).handleRenderBufferPresent(osvr_viewDescFull, osvr_viewDescFull,
|
|
|
|
osvr_renderBuffer[OSVR.EYE_LEFT], osvr_renderBuffer[OSVR.EYE_RIGHT]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( errl != 0 ){
|
|
|
|
logger.severe("Submit to left compositor error: " + OpenVRUtil.getEVRCompositorErrorString(errl)+" ("+Integer.toString(errl)+")");
|
|
|
|
logger.severe(" Texture color space: "+OpenVRUtil.getEColorSpaceString(leftTextureType.eColorSpace));
|
|
|
|
logger.severe(" Texture type: "+OpenVRUtil.getETextureTypeString(leftTextureType.eType));
|
|
|
|
logger.severe(" Texture handle: "+leftTextureType.handle);
|
|
|
|
|
|
|
|
logger.severe(" Left eye texture "+leftEyeTexture.getName()+" ("+leftEyeTexture.getImage().getId()+")");
|
|
|
|
logger.severe(" Type: "+leftEyeTexture.getType());
|
|
|
|
logger.severe(" Size: "+leftEyeTexture.getImage().getWidth()+"x"+leftEyeTexture.getImage().getHeight());
|
|
|
|
logger.severe(" Image depth: "+leftEyeTexture.getImage().getDepth());
|
|
|
|
logger.severe(" Image format: "+leftEyeTexture.getImage().getFormat());
|
|
|
|
logger.severe(" Image color space: "+leftEyeTexture.getImage().getColorSpace());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if( errr != 0 ){
|
|
|
|
logger.severe("Submit to right compositor error: " + OpenVRUtil.getEVRCompositorErrorString(errl)+" ("+Integer.toString(errl)+")");
|
|
|
|
logger.severe(" Texture color space: "+OpenVRUtil.getEColorSpaceString(rightTextureType.eColorSpace));
|
|
|
|
logger.severe(" Texture type: "+OpenVRUtil.getETextureTypeString(rightTextureType.eType));
|
|
|
|
logger.severe(" Texture handle: "+rightTextureType.handle);
|
|
|
|
|
|
|
|
logger.severe(" Right eye texture "+rightEyeTexture.getName()+" ("+rightEyeTexture.getImage().getId()+")");
|
|
|
|
logger.severe(" Type: "+rightEyeTexture.getType());
|
|
|
|
logger.severe(" Size: "+rightEyeTexture.getImage().getWidth()+"x"+rightEyeTexture.getImage().getHeight());
|
|
|
|
logger.severe(" Image depth: "+rightEyeTexture.getImage().getDepth());
|
|
|
|
logger.severe(" Image format: "+rightEyeTexture.getImage().getFormat());
|
|
|
|
logger.severe(" Image color space: "+rightEyeTexture.getImage().getColorSpace());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the VR view manager.
|
|
|
|
*/
|
|
|
|
public void initialize() {
|
|
|
|
|
|
|
|
logger.config("Initializing VR view manager.");
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
initTextureSubmitStructs();
|
|
|
|
setupCamerasAndViews();
|
|
|
|
setupVRScene();
|
|
|
|
moveScreenProcessingToEyes();
|
|
|
|
if( environment.hasTraditionalGUIOverlay() ) {
|
|
|
|
|
|
|
|
environment.getVRMouseManager().initialize();
|
|
|
|
|
|
|
|
// update the pose to position the gui correctly on start
|
|
|
|
update(0f);
|
|
|
|
environment.getVRGUIManager().positionGui();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (environment.getApplication() != null){
|
|
|
|
// if we are OSVR, our primary mirror window needs to be the same size as the render manager's output...
|
|
|
|
if( environment.getVRHardware() instanceof OSVR ) {
|
|
|
|
int origWidth = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode().getWidth();
|
|
|
|
int origHeight = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDisplayMode().getHeight();
|
|
|
|
long window = ((LwjglWindow)environment.getApplication().getContext()).getWindowHandle();
|
|
|
|
Vector2f windowSize = new Vector2f();
|
|
|
|
((OSVR)environment.getVRHardware()).getRenderSize(windowSize);
|
|
|
|
windowSize.x = Math.max(windowSize.x * 2f, leftCamera.getWidth());
|
|
|
|
org.lwjgl.glfw.GLFW.glfwSetWindowSize(window, (int)windowSize.x, (int)windowSize.y);
|
|
|
|
environment.getApplication().getContext().getSettings().setResolution((int)windowSize.x, (int)windowSize.y);
|
|
|
|
|
|
|
|
if (environment.getApplication().getRenderManager() != null) {
|
|
|
|
environment.getApplication().getRenderManager().notifyReshape((int)windowSize.x, (int)windowSize.y);
|
|
|
|
}
|
|
|
|
|
|
|
|
org.lwjgl.glfw.GLFW.glfwSetWindowPos(window, origWidth - (int)windowSize.x, 32);
|
|
|
|
|
|
|
|
org.lwjgl.glfw.GLFW.glfwFocusWindow(window);
|
|
|
|
|
|
|
|
org.lwjgl.glfw.GLFW.glfwSetCursorPos(window, origWidth / 2.0, origHeight / 2.0);
|
|
|
|
|
|
|
|
logger.config("Initialized VR view manager [SUCCESS]");
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("Underlying VR hardware should be "+OSVR.class.getSimpleName());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR environment is not attached to any application.");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prepare the size of the given {@link Camera camera} to adapt it to the underlying rendering context.
|
|
|
|
* @param cam the {@link Camera camera} to prepare.
|
|
|
|
* @param xMult the camera width multiplier.
|
|
|
|
*/
|
|
|
|
private void prepareCameraSize(Camera cam, float xMult) {
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
|
|
|
|
if (environment.getApplication() != null){
|
|
|
|
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR environment is not attached to any application.");
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector2f size = new Vector2f();
|
|
|
|
VRAPI vrhmd = environment.getVRHardware();
|
|
|
|
|
|
|
|
if( vrhmd == null ) {
|
|
|
|
size.x = 1280f;
|
|
|
|
size.y = 720f;
|
|
|
|
} else {
|
|
|
|
vrhmd.getRenderSize(size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( size.x < environment.getApplication().getContext().getSettings().getWidth() ) {
|
|
|
|
size.x = environment.getApplication().getContext().getSettings().getWidth();
|
|
|
|
}
|
|
|
|
if( size.y < environment.getApplication().getContext().getSettings().getHeight() ) {
|
|
|
|
size.y = environment.getApplication().getContext().getSettings().getHeight();
|
|
|
|
}
|
|
|
|
|
|
|
|
if( environment.isInstanceRendering() ){
|
|
|
|
size.x *= 2f;
|
|
|
|
}
|
|
|
|
|
|
|
|
// other adjustments
|
|
|
|
size.x *= xMult;
|
|
|
|
size.x *= resMult;
|
|
|
|
size.y *= resMult;
|
|
|
|
|
|
|
|
if( cam.getWidth() != size.x || cam.getHeight() != size.y ){
|
|
|
|
cam.resize((int)size.x, (int)size.y, false);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Replaces rootNode as the main cameras scene with the distortion mesh
|
|
|
|
*/
|
|
|
|
private void setupVRScene(){
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
if (environment.getApplication() != null){
|
|
|
|
// no special scene to setup if we are doing instancing
|
|
|
|
if( environment.isInstanceRendering() ) {
|
|
|
|
// distortion has to be done with compositor here... we want only one pass on our end!
|
|
|
|
if( environment.getApplication().getContext().getSettings().isSwapBuffers() ) {
|
|
|
|
setupMirrorBuffers(environment.getCamera(), dualEyeTex, true);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
leftEyeTexture = (Texture2D) leftViewport.getOutputFrameBuffer().getColorBuffer().getTexture();
|
|
|
|
rightEyeTexture = (Texture2D)rightViewport.getOutputFrameBuffer().getColorBuffer().getTexture();
|
|
|
|
leftEyeDepth = (Texture2D) leftViewport.getOutputFrameBuffer().getDepthBuffer().getTexture();
|
|
|
|
rightEyeDepth = (Texture2D)rightViewport.getOutputFrameBuffer().getDepthBuffer().getTexture();
|
|
|
|
|
|
|
|
// main viewport is either going to be a distortion scene or nothing
|
|
|
|
// mirroring is handled by copying framebuffers
|
|
|
|
Iterator<Spatial> spatialIter = environment.getApplication().getViewPort().getScenes().iterator();
|
|
|
|
while(spatialIter.hasNext()){
|
|
|
|
environment.getApplication().getViewPort().detachScene(spatialIter.next());
|
|
|
|
}
|
|
|
|
|
|
|
|
spatialIter = environment.getApplication().getGuiViewPort().getScenes().iterator();
|
|
|
|
while(spatialIter.hasNext()){
|
|
|
|
environment.getApplication().getGuiViewPort().detachScene(spatialIter.next());
|
|
|
|
}
|
|
|
|
|
|
|
|
// only setup distortion scene if compositor isn't running (or using custom mesh distortion option)
|
|
|
|
if( environment.getVRHardware().getCompositor() == null ) {
|
|
|
|
Node distortionScene = new Node();
|
|
|
|
Material leftMat = new Material(environment.getApplication().getAssetManager(), "Common/MatDefs/VR/OpenVR.j3md");
|
|
|
|
leftMat.setTexture("Texture", leftEyeTexture);
|
|
|
|
Geometry leftEye = new Geometry("box", setupDistortionMesh(JOpenVRLibrary.EVREye.EVREye_Eye_Left, environment.getVRHardware()));
|
|
|
|
leftEye.setMaterial(leftMat);
|
|
|
|
distortionScene.attachChild(leftEye);
|
|
|
|
|
|
|
|
Material rightMat = new Material(environment.getApplication().getAssetManager(), "Common/MatDefs/VR/OpenVR.j3md");
|
|
|
|
rightMat.setTexture("Texture", rightEyeTexture);
|
|
|
|
Geometry rightEye = new Geometry("box", setupDistortionMesh(JOpenVRLibrary.EVREye.EVREye_Eye_Right, environment.getVRHardware()));
|
|
|
|
rightEye.setMaterial(rightMat);
|
|
|
|
distortionScene.attachChild(rightEye);
|
|
|
|
|
|
|
|
distortionScene.updateGeometricState();
|
|
|
|
|
|
|
|
environment.getApplication().getViewPort().attachScene(distortionScene);
|
|
|
|
|
|
|
|
//if( useCustomDistortion ) setupFinalFullTexture(app.getViewPort().getCamera());
|
|
|
|
}
|
|
|
|
|
|
|
|
if( environment.getApplication().getContext().getSettings().isSwapBuffers() ) {
|
|
|
|
setupMirrorBuffers(environment.getCamera(), leftEyeTexture, false);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR environment is not attached to any application.");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update the VR view manager.
|
|
|
|
* This method is called by the attached {@link VRApplication VR application} and should not be called manually.
|
|
|
|
* @param tpf the time per frame.
|
|
|
|
*/
|
|
|
|
public void update(float tpf) {
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
// grab the observer
|
|
|
|
Object obs = environment.getObserver();
|
|
|
|
Quaternion objRot;
|
|
|
|
Vector3f objPos;
|
|
|
|
if( obs instanceof Camera ) {
|
|
|
|
objRot = ((Camera)obs).getRotation();
|
|
|
|
objPos = ((Camera)obs).getLocation();
|
|
|
|
} else {
|
|
|
|
objRot = ((Spatial)obs).getWorldRotation();
|
|
|
|
objPos = ((Spatial)obs).getWorldTranslation();
|
|
|
|
}
|
|
|
|
// grab the hardware handle
|
|
|
|
VRAPI dev = environment.getVRHardware();
|
|
|
|
if( dev != null ) {
|
|
|
|
// update the HMD's position & orientation
|
|
|
|
dev.updatePose();
|
|
|
|
dev.getPositionAndOrientation(hmdPos, hmdRot);
|
|
|
|
if( obs != null ) {
|
|
|
|
// update hmdPos based on obs rotation
|
|
|
|
finalRotation.set(objRot);
|
|
|
|
finalRotation.mult(hmdPos, hmdPos);
|
|
|
|
finalRotation.multLocal(hmdRot);
|
|
|
|
}
|
|
|
|
|
|
|
|
finalizeCamera(dev.getHMDVectorPoseLeftEye(), objPos, leftCamera);
|
|
|
|
finalizeCamera(dev.getHMDVectorPoseRightEye(), objPos, rightCamera);
|
|
|
|
} else {
|
|
|
|
leftCamera.setFrame(objPos, objRot);
|
|
|
|
rightCamera.setFrame(objPos, objRot);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( environment.hasTraditionalGUIOverlay() ) {
|
|
|
|
// update the mouse?
|
|
|
|
environment.getVRMouseManager().update(tpf);
|
|
|
|
|
|
|
|
// update GUI position?
|
|
|
|
if( environment.getVRGUIManager().wantsReposition || environment.getVRGUIManager().getPositioningMode() != VRGUIPositioningMode.MANUAL ) {
|
|
|
|
environment.getVRGUIManager().positionGuiNow(tpf);
|
|
|
|
environment.getVRGUIManager().updateGuiQuadGeometricState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Place the camera within the scene.
|
|
|
|
* @param eyePos the eye position.
|
|
|
|
* @param obsPosition the observer position.
|
|
|
|
* @param cam the camera to place.
|
|
|
|
*/
|
|
|
|
private void finalizeCamera(Vector3f eyePos, Vector3f obsPosition, Camera cam) {
|
|
|
|
finalRotation.mult(eyePos, finalPosition);
|
|
|
|
finalPosition.addLocal(hmdPos);
|
|
|
|
if( obsPosition != null ){
|
|
|
|
finalPosition.addLocal(obsPosition);
|
|
|
|
}
|
|
|
|
finalPosition.y += heightAdjustment;
|
|
|
|
cam.setFrame(finalPosition, finalRotation);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handles moving filters from the main view to each eye
|
|
|
|
*/
|
|
|
|
public void moveScreenProcessingToEyes() {
|
|
|
|
if( rightViewport == null ){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
if (environment.getApplication() != null){
|
|
|
|
|
|
|
|
syncScreenProcessing(environment.getApplication().getViewPort());
|
|
|
|
environment.getApplication().getViewPort().clearProcessors();
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR environment is not attached to any application.");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the two views to use the list of {@link SceneProcessor processors}.
|
|
|
|
* @param sourceViewport the {@link ViewPort viewport} that contains the processors to use.
|
|
|
|
*/
|
|
|
|
public void syncScreenProcessing(ViewPort sourceViewport) {
|
|
|
|
if( rightViewport == null ){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
if (environment.getApplication() != null){
|
|
|
|
// setup post processing filters
|
|
|
|
if( rightPostProcessor == null ) {
|
|
|
|
rightPostProcessor = new FilterPostProcessor(environment.getApplication().getAssetManager());
|
|
|
|
leftPostProcessor = new FilterPostProcessor(environment.getApplication().getAssetManager());
|
|
|
|
}
|
|
|
|
// clear out all filters & processors, to start from scratch
|
|
|
|
rightPostProcessor.removeAllFilters();
|
|
|
|
leftPostProcessor.removeAllFilters();
|
|
|
|
leftViewport.clearProcessors();
|
|
|
|
rightViewport.clearProcessors();
|
|
|
|
// if we have no processors to sync, don't add the FilterPostProcessor
|
|
|
|
if( sourceViewport.getProcessors().isEmpty() ) return;
|
|
|
|
// add post processors we just made, which are empty
|
|
|
|
leftViewport.addProcessor(leftPostProcessor);
|
|
|
|
rightViewport.addProcessor(rightPostProcessor);
|
|
|
|
// go through all of the filters in the processors list
|
|
|
|
// add them to the left viewport processor & clone them to the right
|
|
|
|
for(SceneProcessor sceneProcessor : sourceViewport.getProcessors()) {
|
|
|
|
if (sceneProcessor instanceof FilterPostProcessor) {
|
|
|
|
for(Filter f : ((FilterPostProcessor)sceneProcessor).getFilterList() ) {
|
|
|
|
if( f instanceof TranslucentBucketFilter ) {
|
|
|
|
// just remove this filter, we will add it at the end manually
|
|
|
|
((FilterPostProcessor)sceneProcessor).removeFilter(f);
|
|
|
|
} else {
|
|
|
|
leftPostProcessor.addFilter(f);
|
|
|
|
// clone to the right
|
|
|
|
Filter f2;
|
|
|
|
if(f instanceof FogFilter){
|
|
|
|
f2 = FilterUtil.cloneFogFilter((FogFilter)f);
|
|
|
|
} else if (f instanceof CartoonSSAO ) {
|
|
|
|
f2 = new CartoonSSAO((CartoonSSAO)f);
|
|
|
|
} else if (f instanceof SSAOFilter){
|
|
|
|
f2 = FilterUtil.cloneSSAOFilter((SSAOFilter)f);
|
|
|
|
} else if (f instanceof DirectionalLightShadowFilter){
|
|
|
|
f2 = FilterUtil.cloneDirectionalLightShadowFilter(environment.getApplication().getAssetManager(), (DirectionalLightShadowFilter)f);
|
|
|
|
} else {
|
|
|
|
f2 = f; // dof, bloom, lightscattering etc.
|
|
|
|
}
|
|
|
|
rightPostProcessor.addFilter(f2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (sceneProcessor instanceof VRDirectionalLightShadowRenderer) {
|
|
|
|
// shadow processing
|
|
|
|
// TODO: make right shadow processor use same left shadow maps for performance
|
|
|
|
VRDirectionalLightShadowRenderer dlsr = (VRDirectionalLightShadowRenderer) sceneProcessor;
|
|
|
|
VRDirectionalLightShadowRenderer dlsrRight = dlsr.clone();
|
|
|
|
dlsrRight.setLight(dlsr.getLight());
|
|
|
|
rightViewport.getProcessors().add(0, dlsrRight);
|
|
|
|
leftViewport.getProcessors().add(0, sceneProcessor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// make sure each has a translucent filter renderer
|
|
|
|
leftPostProcessor.addFilter(new TranslucentBucketFilter());
|
|
|
|
rightPostProcessor.addFilter(new TranslucentBucketFilter());
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR environment is not attached to any application.");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setupCamerasAndViews() {
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
if (environment.getApplication() != null){
|
|
|
|
// get desired frustrum from original camera
|
|
|
|
Camera origCam = environment.getCamera();
|
|
|
|
float fFar = origCam.getFrustumFar();
|
|
|
|
float fNear = origCam.getFrustumNear();
|
|
|
|
|
|
|
|
// if we are using OSVR get the eye info here
|
|
|
|
if( environment.getVRHardware() instanceof OSVR ) {
|
|
|
|
((OSVR)environment.getVRHardware()).getEyeInfo();
|
|
|
|
}
|
|
|
|
|
|
|
|
// restore frustrum on distortion scene cam, if needed
|
|
|
|
if( environment.isInstanceRendering() ) {
|
|
|
|
leftCamera = origCam;
|
|
|
|
} else if( environment.compositorAllowed() == false ) {
|
|
|
|
origCam.setFrustumFar(100f);
|
|
|
|
origCam.setFrustumNear(1f);
|
|
|
|
leftCamera = origCam.clone();
|
|
|
|
prepareCameraSize(origCam, 2f);
|
|
|
|
} else {
|
|
|
|
leftCamera = origCam.clone();
|
|
|
|
}
|
|
|
|
|
|
|
|
leftCamera.setFrustumPerspective(environment.getDefaultFOV(), environment.getDefaultAspect(), fNear, fFar);
|
|
|
|
|
|
|
|
prepareCameraSize(leftCamera, 1f);
|
|
|
|
if( environment.getVRHardware() != null ) leftCamera.setProjectionMatrix(environment.getVRHardware().getHMDMatrixProjectionLeftEye(leftCamera));
|
|
|
|
//org.lwjgl.opengl.GL11.glEnable(org.lwjgl.opengl.GL30.GL_FRAMEBUFFER_SRGB);
|
|
|
|
|
|
|
|
if( !environment.isInstanceRendering()) {
|
|
|
|
leftViewport = setupViewBuffers(leftCamera, LEFT_VIEW_NAME);
|
|
|
|
rightCamera = leftCamera.clone();
|
|
|
|
if( environment.getVRHardware() != null ){
|
|
|
|
rightCamera.setProjectionMatrix(environment.getVRHardware().getHMDMatrixProjectionRightEye(rightCamera));
|
|
|
|
}
|
|
|
|
rightViewport = setupViewBuffers(rightCamera, RIGHT_VIEW_NAME);
|
|
|
|
} else {
|
|
|
|
|
|
|
|
System.err.println("[VRViewManager] THIS CODE NEED CHANGES !!!");
|
|
|
|
leftViewport = environment.getApplication().getViewPort();
|
|
|
|
//leftViewport.attachScene(app.getRootNode());
|
|
|
|
rightCamera = leftCamera.clone();
|
|
|
|
if( environment.getVRHardware() != null ){
|
|
|
|
rightCamera.setProjectionMatrix(environment.getVRHardware().getHMDMatrixProjectionRightEye(rightCamera));
|
|
|
|
}
|
|
|
|
|
|
|
|
org.lwjgl.opengl.GL11.glEnable(org.lwjgl.opengl.GL30.GL_CLIP_DISTANCE0);
|
|
|
|
|
|
|
|
//FIXME: [jme-vr] Fix with JMonkey next release
|
|
|
|
//RenderManager._VRInstancing_RightCamProjection = camRight.getViewProjectionMatrix();
|
|
|
|
setupFinalFullTexture(environment.getApplication().getViewPort().getCamera());
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup gui
|
|
|
|
environment.getVRGUIManager().setupGui(leftCamera, rightCamera, leftViewport, rightViewport);
|
|
|
|
|
|
|
|
if( environment.getVRHardware() != null ) {
|
|
|
|
// call these to cache the results internally
|
|
|
|
environment.getVRHardware().getHMDMatrixPoseLeftEye();
|
|
|
|
environment.getVRHardware().getHMDMatrixPoseRightEye();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR environment is not attached to any application.");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private ViewPort setupMirrorBuffers(Camera cam, Texture tex, boolean expand) {
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
if (environment.getApplication() != null){
|
|
|
|
Camera clonecam = cam.clone();
|
|
|
|
ViewPort viewPort = environment.getApplication().getRenderManager().createPostView("MirrorView", clonecam);
|
|
|
|
clonecam.setParallelProjection(true);
|
|
|
|
viewPort.setClearFlags(true, true, true);
|
|
|
|
viewPort.setBackgroundColor(ColorRGBA.Black);
|
|
|
|
Picture pic = new Picture("fullscene");
|
|
|
|
pic.setLocalTranslation(-0.75f, -0.5f, 0f);
|
|
|
|
if( expand ) {
|
|
|
|
pic.setLocalScale(3f, 1f, 1f);
|
|
|
|
} else {
|
|
|
|
pic.setLocalScale(1.5f, 1f, 1f);
|
|
|
|
}
|
|
|
|
pic.setQueueBucket(Bucket.Opaque);
|
|
|
|
pic.setTexture(environment.getApplication().getAssetManager(), (Texture2D)tex, false);
|
|
|
|
viewPort.attachScene(pic);
|
|
|
|
viewPort.setOutputFrameBuffer(null);
|
|
|
|
|
|
|
|
pic.updateGeometricState();
|
|
|
|
|
|
|
|
return viewPort;
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR environment is not attached to any application.");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setupFinalFullTexture(Camera cam) {
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
if (environment.getApplication() != null){
|
|
|
|
// create offscreen framebuffer
|
|
|
|
FrameBuffer out = new FrameBuffer(cam.getWidth(), cam.getHeight(), 1);
|
|
|
|
//offBuffer.setSrgb(true);
|
|
|
|
|
|
|
|
//setup framebuffer's texture
|
|
|
|
dualEyeTex = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8);
|
|
|
|
dualEyeTex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
|
|
|
|
dualEyeTex.setMagFilter(Texture.MagFilter.Bilinear);
|
|
|
|
|
|
|
|
logger.config("Dual eye texture "+dualEyeTex.getName()+" ("+dualEyeTex.getImage().getId()+")");
|
|
|
|
logger.config(" Type: "+dualEyeTex.getType());
|
|
|
|
logger.config(" Size: "+dualEyeTex.getImage().getWidth()+"x"+dualEyeTex.getImage().getHeight());
|
|
|
|
logger.config(" Image depth: "+dualEyeTex.getImage().getDepth());
|
|
|
|
logger.config(" Image format: "+dualEyeTex.getImage().getFormat());
|
|
|
|
logger.config(" Image color space: "+dualEyeTex.getImage().getColorSpace());
|
|
|
|
|
|
|
|
//setup framebuffer to use texture
|
|
|
|
out.setDepthBuffer(Image.Format.Depth);
|
|
|
|
out.setColorTexture(dualEyeTex);
|
|
|
|
|
|
|
|
ViewPort viewPort = environment.getApplication().getViewPort();
|
|
|
|
viewPort.setClearFlags(true, true, true);
|
|
|
|
viewPort.setBackgroundColor(ColorRGBA.Black);
|
|
|
|
viewPort.setOutputFrameBuffer(out);
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR environment is not attached to any application.");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private ViewPort setupViewBuffers(Camera cam, String viewName){
|
|
|
|
|
|
|
|
if (environment != null){
|
|
|
|
if (environment.getApplication() != null){
|
|
|
|
// create offscreen framebuffer
|
|
|
|
FrameBuffer offBufferLeft = new FrameBuffer(cam.getWidth(), cam.getHeight(), 1);
|
|
|
|
//offBufferLeft.setSrgb(true);
|
|
|
|
|
|
|
|
//setup framebuffer's texture
|
|
|
|
Texture2D offTex = new Texture2D(cam.getWidth(), cam.getHeight(), Image.Format.RGBA8);
|
|
|
|
offTex.setMinFilter(Texture.MinFilter.BilinearNoMipMaps);
|
|
|
|
offTex.setMagFilter(Texture.MagFilter.Bilinear);
|
|
|
|
|
|
|
|
//setup framebuffer to use texture
|
|
|
|
offBufferLeft.setDepthBuffer(Image.Format.Depth);
|
|
|
|
offBufferLeft.setColorTexture(offTex);
|
|
|
|
|
|
|
|
ViewPort viewPort = environment.getApplication().getRenderManager().createPreView(viewName, cam);
|
|
|
|
viewPort.setClearFlags(true, true, true);
|
|
|
|
viewPort.setBackgroundColor(ColorRGBA.Black);
|
|
|
|
|
|
|
|
Iterator<Spatial> spatialIter = environment.getApplication().getViewPort().getScenes().iterator();
|
|
|
|
while(spatialIter.hasNext()){
|
|
|
|
viewPort.attachScene(spatialIter.next());
|
|
|
|
}
|
|
|
|
|
|
|
|
//set viewport to render to offscreen framebuffer
|
|
|
|
viewPort.setOutputFrameBuffer(offBufferLeft);
|
|
|
|
return viewPort;
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR environment is not attached to any application.");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
throw new IllegalStateException("This VR view manager is not attached to any VR environment.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Setup a distortion mesh for the stereo view.
|
|
|
|
* @param eye the eye to apply.
|
|
|
|
* @param api the underlying VR api
|
|
|
|
* @return the distorted mesh.
|
|
|
|
*/
|
|
|
|
public static Mesh setupDistortionMesh(int eye, VRAPI api) {
|
|
|
|
Mesh distortionMesh = new Mesh();
|
|
|
|
float m_iLensGridSegmentCountH = 43, m_iLensGridSegmentCountV = 43;
|
|
|
|
|
|
|
|
float w = 1f / (m_iLensGridSegmentCountH - 1f);
|
|
|
|
float h = 1f / (m_iLensGridSegmentCountV - 1f);
|
|
|
|
|
|
|
|
float u, v;
|
|
|
|
|
|
|
|
float verts[] = new float[(int) (m_iLensGridSegmentCountV * m_iLensGridSegmentCountH) * 3];
|
|
|
|
|
|
|
|
float texcoordR[] = new float[(int) (m_iLensGridSegmentCountV * m_iLensGridSegmentCountH) * 2];
|
|
|
|
float texcoordG[] = new float[(int) (m_iLensGridSegmentCountV * m_iLensGridSegmentCountH) * 2];
|
|
|
|
float texcoordB[] = new float[(int) (m_iLensGridSegmentCountV * m_iLensGridSegmentCountH) * 2];
|
|
|
|
|
|
|
|
int vertPos = 0, coordPos = 0;
|
|
|
|
|
|
|
|
float Xoffset = eye == JOpenVRLibrary.EVREye.EVREye_Eye_Left ? -1f : 0;
|
|
|
|
for (int y = 0; y < m_iLensGridSegmentCountV; y++) {
|
|
|
|
for (int x = 0; x < m_iLensGridSegmentCountH; x++) {
|
|
|
|
u = x * w;
|
|
|
|
v = 1 - y * h;
|
|
|
|
verts[vertPos] = Xoffset + u; // x
|
|
|
|
verts[vertPos + 1] = -1 + 2 * y * h; // y
|
|
|
|
verts[vertPos + 2] = 0f; // z
|
|
|
|
vertPos += 3;
|
|
|
|
|
|
|
|
DistortionCoordinates_t dc0 = new DistortionCoordinates_t();
|
|
|
|
if( api.getVRSystem() == null ) {
|
|
|
|
// default to no distortion
|
|
|
|
texcoordR[coordPos] = u;
|
|
|
|
texcoordR[coordPos + 1] = 1 - v;
|
|
|
|
texcoordG[coordPos] = u;
|
|
|
|
texcoordG[coordPos + 1] = 1 - v;
|
|
|
|
texcoordB[coordPos] = u;
|
|
|
|
texcoordB[coordPos + 1] = 1 - v;
|
|
|
|
} else {
|
|
|
|
((VR_IVRSystem_FnTable)api.getVRSystem()).ComputeDistortion.apply(eye, u, v, dc0);
|
|
|
|
|
|
|
|
texcoordR[coordPos] = dc0.rfRed[0];
|
|
|
|
texcoordR[coordPos + 1] = 1 - dc0.rfRed[1];
|
|
|
|
texcoordG[coordPos] = dc0.rfGreen[0];
|
|
|
|
texcoordG[coordPos + 1] = 1 - dc0.rfGreen[1];
|
|
|
|
texcoordB[coordPos] = dc0.rfBlue[0];
|
|
|
|
texcoordB[coordPos + 1] = 1 - dc0.rfBlue[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
coordPos += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// have UV coordinates & positions, now to setup indices
|
|
|
|
|
|
|
|
int[] indices = new int[(int) ((m_iLensGridSegmentCountV - 1) * (m_iLensGridSegmentCountH - 1)) * 6];
|
|
|
|
int indexPos = 0;
|
|
|
|
int a, b, c, d;
|
|
|
|
|
|
|
|
int offset = 0;
|
|
|
|
for (int y = 0; y < m_iLensGridSegmentCountV - 1; y++) {
|
|
|
|
for (int x = 0; x < m_iLensGridSegmentCountH - 1; x++) {
|
|
|
|
a = (int) (m_iLensGridSegmentCountH * y + x + offset);
|
|
|
|
b = (int) (m_iLensGridSegmentCountH * y + x + 1 + offset);
|
|
|
|
c = (int) ((y + 1) * m_iLensGridSegmentCountH + x + 1 + offset);
|
|
|
|
d = (int) ((y + 1) * m_iLensGridSegmentCountH + x + offset);
|
|
|
|
|
|
|
|
indices[indexPos] = a;
|
|
|
|
indices[indexPos + 1] = b;
|
|
|
|
indices[indexPos + 2] = c;
|
|
|
|
|
|
|
|
indices[indexPos + 3] = a;
|
|
|
|
indices[indexPos + 4] = c;
|
|
|
|
indices[indexPos + 5] = d;
|
|
|
|
|
|
|
|
indexPos += 6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// OK, create the mesh
|
|
|
|
distortionMesh.setBuffer(VertexBuffer.Type.Position, 3, verts);
|
|
|
|
distortionMesh.setBuffer(VertexBuffer.Type.Index, 1, indices);
|
|
|
|
distortionMesh.setBuffer(VertexBuffer.Type.TexCoord, 2, texcoordR);
|
|
|
|
distortionMesh.setBuffer(VertexBuffer.Type.TexCoord2, 2, texcoordG);
|
|
|
|
distortionMesh.setBuffer(VertexBuffer.Type.TexCoord3, 2, texcoordB);
|
|
|
|
distortionMesh.setStatic();
|
|
|
|
return distortionMesh;
|
|
|
|
}
|
|
|
|
}
|