/** * Copyright 2014 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list * of conditions and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of JogAmp Community. */ package com.jogamp.opengl.util.stereo; import com.jogamp.opengl.math.FloatUtil; import com.jogamp.opengl.math.Quaternion; import com.jogamp.opengl.math.VectorUtil; import com.jogamp.opengl.util.CustomGLEventListener; import com.jogamp.opengl.util.stereo.StereoDeviceRenderer.Eye; public class StereoUtil { /** * Return the vertical pupil center from the screen top in the range [0..1]. * @param screenHeightInMeters * @param pupilCenterFromScreenTopInMeters */ public static float getVertPupilCenterFromTop(final float screenHeightInMeters, final float pupilCenterFromScreenTopInMeters) { return pupilCenterFromScreenTopInMeters / screenHeightInMeters; } /** * Return the horizontal pupil center from the left side for both eyes in the range [0..1]. * <pre> <-------------left eye------------->| |<-----------right eye--------------> <------------------------------------screenSizeInMeters.Width-----------------------------------> <------interpupillaryDistanceInMeters------> <--centerFromLeftInMeters-> ^ center of pupil * </pre> * * @param screenWidthInMeters * @param interpupillaryDistanceInMeters */ public static float[] getHorizPupilCenterFromLeft(final float screenWidthInMeters, final float interpupillaryDistanceInMeters) { final float visibleWidthOfOneEye = 0.5f * screenWidthInMeters; final float leftPupilCenterFromLeftInMeters = ( screenWidthInMeters - interpupillaryDistanceInMeters ) * 0.5f; final float rightPupilCenterFromMiddleInMeters = leftPupilCenterFromLeftInMeters + interpupillaryDistanceInMeters - visibleWidthOfOneEye; return new float[] { leftPupilCenterFromLeftInMeters / visibleWidthOfOneEye, rightPupilCenterFromMiddleInMeters / visibleWidthOfOneEye }; } /** See {@link StereoDeviceRenderer#getDistortionBits()}. */ public static boolean usesBarrelDistortion(final int distortionBits) { return 0 != ( distortionBits & StereoDeviceRenderer.DISTORTION_BARREL ) ; } /** See {@link StereoDeviceRenderer#getDistortionBits()}. */ public static boolean usesTimewarpDistortion(final int distortionBits) { return 0 != ( distortionBits & StereoDeviceRenderer.DISTORTION_TIMEWARP ) ; } /** See {@link StereoDeviceRenderer#getDistortionBits()}. */ public static boolean usesChromaticDistortion(final int distortionBits) { return 0 != ( distortionBits & StereoDeviceRenderer.DISTORTION_CHROMATIC ) ; } /** See {@link StereoDeviceRenderer#getDistortionBits()}. */ public static boolean usesVignetteDistortion(final int distortionBits) { return 0 != ( distortionBits & StereoDeviceRenderer.DISTORTION_VIGNETTE ) ; } /** See {@link StereoDeviceRenderer#getDistortionBits()}. */ public static String distortionBitsToString(final int distortionBits) { boolean appendComma = false; final StringBuilder sb = new StringBuilder(); if( usesBarrelDistortion(distortionBits) ) { if( appendComma ) { sb.append(", "); }; sb.append("barrel"); appendComma=true; } if( usesVignetteDistortion(distortionBits) ) { if( appendComma ) { sb.append(", "); }; sb.append("vignette"); appendComma=true; } if( usesChromaticDistortion(distortionBits) ) { if( appendComma ) { sb.append(", "); }; sb.append("chroma"); appendComma=true; } if( usesTimewarpDistortion(distortionBits) ) { if( appendComma ) { sb.append(", "); }; sb.append("timewarp"); appendComma=true; } return sb.toString(); } /** See {@link StereoDevice#getSupportedSensorBits()} and {@link StereoDevice#getEnabledSensorBits()}. */ public static boolean usesOrientationSensor(final int sensorBits) { return 0 != ( sensorBits & StereoDevice.SENSOR_ORIENTATION ) ; } /** See {@link StereoDevice#getSupportedSensorBits()} and {@link StereoDevice#getEnabledSensorBits()}. */ public static boolean usesYawCorrectionSensor(final int sensorBits) { return 0 != ( sensorBits & StereoDevice.SENSOR_YAW_CORRECTION ) ; } /** See {@link StereoDevice#getSupportedSensorBits()} and {@link StereoDevice#getEnabledSensorBits()}. */ public static boolean usesPositionSensor(final int sensorBits) { return 0 != ( sensorBits & StereoDevice.SENSOR_POSITION ) ; } /** See {@link StereoDevice#getSupportedSensorBits()} and {@link StereoDevice#getEnabledSensorBits()}. */ public static String sensorBitsToString(final int sensorBits) { boolean appendComma = false; final StringBuilder sb = new StringBuilder(); if( usesOrientationSensor(sensorBits) ) { if( appendComma ) { sb.append(", "); }; sb.append("orientation"); appendComma=true; } if( usesYawCorrectionSensor(sensorBits) ) { if( appendComma ) { sb.append(", "); }; sb.append("yaw-corr"); appendComma=true; } if( usesPositionSensor(sensorBits) ) { if( appendComma ) { sb.append(", "); }; sb.append("position"); appendComma=true; } return sb.toString(); } /** * Calculates the <i>Side By Side</i>, SBS, projection- and modelview matrix for one eye. * <p> * {@link #updateViewerPose(int)} must be called upfront. * </p> * <p> * This method merely exist as an example implementation to compute the matrices, * which shall be adopted by the * {@link CustomGLEventListener#reshape(com.jogamp.opengl.GLAutoDrawable, int, int, int, int, EyeParameter, ViewerPose) upstream client code}. * </p> * @param viewerPose * @param eye * @param zNear frustum near value * @param zFar frustum far value * @param mat4Projection float[16] projection matrix result * @param mat4Modelview float[16] modelview matrix result */ public static void getSBSUpstreamPMV(final ViewerPose viewerPose, final Eye eye, final float zNear, final float zFar, final float[] mat4Projection, final float[] mat4Modelview) { final float[] mat4Tmp1 = new float[16]; final float[] mat4Tmp2 = new float[16]; final float[] vec3Tmp1 = new float[3]; final float[] vec3Tmp2 = new float[3]; final float[] vec3Tmp3 = new float[3]; final EyeParameter eyeParam = eye.getEyeParameter(); // // Projection // FloatUtil.makePerspective(mat4Projection, 0, true, eyeParam.fovhv, zNear, zFar); // // Modelview // final Quaternion rollPitchYaw = new Quaternion(); // private final float eyeYaw = FloatUtil.PI; // 180 degrees in radians // rollPitchYaw.rotateByAngleY(eyeYaw); final float[] shiftedEyePos = rollPitchYaw.rotateVector(vec3Tmp1, 0, viewerPose.position, 0); VectorUtil.addVec3(shiftedEyePos, shiftedEyePos, eyeParam.positionOffset); rollPitchYaw.mult(viewerPose.orientation); final float[] up = rollPitchYaw.rotateVector(vec3Tmp2, 0, VectorUtil.VEC3_UNIT_Y, 0); final float[] forward = rollPitchYaw.rotateVector(vec3Tmp3, 0, VectorUtil.VEC3_UNIT_Z_NEG, 0); final float[] center = VectorUtil.addVec3(forward, shiftedEyePos, forward); final float[] mLookAt = FloatUtil.makeLookAt(mat4Tmp2, 0, shiftedEyePos, 0, center, 0, up, 0, mat4Tmp1); final float[] mViewAdjust = FloatUtil.makeTranslation(mat4Modelview, true, eyeParam.distNoseToPupilX, eyeParam.distMiddleToPupilY, eyeParam.eyeReliefZ); /* mat4Modelview = */ FloatUtil.multMatrix(mViewAdjust, mLookAt); } }