All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jme3.input.vr.osvr.OSVRViewManager Maven / Gradle / Ivy

There is a newer version: 3.7.0-stable
Show newest version
package com.jme3.input.vr.osvr;

import java.awt.GraphicsEnvironment;
import java.util.Iterator;
import java.util.logging.Logger;

import com.jme3.app.VREnvironment;
import com.jme3.input.vr.AbstractVRViewManager;
import com.jme3.input.vr.VRAPI;
import com.jme3.input.vr.openvr.OpenVRViewManager;
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.jme3.util.VRGUIPositioningMode;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.PointerByReference;

/**
 *
 * @author Julien Seinturier - COMEX SA - http://www.seinturier.fr
 *
 */
public class OSVRViewManager extends AbstractVRViewManager{
    private static final Logger logger = Logger.getLogger(OpenVRViewManager.class.getName());

    // 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 Texture2D dualEyeTex;

    private final PointerByReference grabRBS = new PointerByReference();

    //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 OSVRViewManager(VREnvironment environment){
        this.environment = environment;
    }

    /**
     * Get the identifier of the left eye texture.
     * @return the identifier of the left eye texture.
     * @see #getRightTexId()
     * @see #getFullTexId()
     */
    protected int getLeftTexId() {
        return 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 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 dualEyeTex.getImage().getId();
    }

    /**
     * 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.
     */
    @Override
    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.
     */
    @Override
    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();
                    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 *= getResolutionMuliplier();
            size.y *= getResolutionMuliplier();

            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 with the distortion mesh as the main camera's scene.
     */
    private void setupVRScene(){
        if (environment != null){
            if (environment.getApplication() != null){
                // no special scene to set up 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) getLeftViewPort().getOutputFrameBuffer().getColorBuffer().getTexture();
                rightEyeTexture = (Texture2D)getRightViewPort().getOutputFrameBuffer().getColorBuffer().getTexture();
                leftEyeDepth    = (Texture2D) getLeftViewPort().getOutputFrameBuffer().getDepthBuffer().getTexture();
                rightEyeDepth   = (Texture2D)getRightViewPort().getOutputFrameBuffer().getDepthBuffer().getTexture();

                // main viewport is either going to be a distortion scene or nothing
                // mirroring is handled by copying framebuffers
                Iterator 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 VR application and should not be called manually.
     * @param tpf the time per frame.
     */
    @Override
    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().isWantsReposition() || 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 += getHeightAdjustment();
        cam.setFrame(finalPosition, finalRotation);
    }

    /**
     * Handles moving filters from the main view to each eye
     */
    @Override
    public void moveScreenProcessingToEyes() {
        if( getRightViewPort() == 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.
     */
    @Override
    public void syncScreenProcessing(ViewPort sourceViewport) {
        if( getRightViewPort() == null ){
            return;
        }

        if (environment != null){
            if (environment.getApplication() != null){
                // set up 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();
                getLeftViewPort().clearProcessors();
                getRightViewPort().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
                getLeftViewPort().addProcessor(leftPostProcessor);
                getRightViewPort().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, light scattering 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());
                        getRightViewPort().getProcessors().add(0, dlsrRight);
                        getLeftViewPort().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 frustum 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 frustum 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, getLeftViewPort(), getRightViewPort());

                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 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.");
        }
    }

    /**
     * Set up 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 set up 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;
  }

    @Override
    public void render() {
        // TODO Auto-generated method stub
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy