Skip to content

Instantly share code, notes, and snippets.

@ThomasGaubert
Created April 17, 2016 05:11
Show Gist options
  • Save ThomasGaubert/1035973df8a4802525a25dcaefbb5b0d to your computer and use it in GitHub Desktop.
Save ThomasGaubert/1035973df8a4802525a25dcaefbb5b0d to your computer and use it in GitHub Desktop.
SteamVR Controller Experiments
package jmevr;
import com.jme3.scene.Geometry;
import jmevr.input.VRInput;
public class DefaultInput implements Input {
public InputMode getInputMode() {
return InputMode.DEFAULT;
}
public void handleInput(int controllerIndex, Geometry geo) {
if(VRInput.isButtonDown(controllerIndex, VRInput.VRINPUT_TYPE.ViveTriggerAxis)) {
System.out.println("Trigger");
}
if(VRInput.isButtonDown(controllerIndex, VRInput.VRINPUT_TYPE.ViveGripButton)) {
System.out.println("Grip");
}
if(VRInput.isButtonDown(controllerIndex, VRInput.VRINPUT_TYPE.ViveTouchpadAxis)) {
System.out.println("Touchpad");
}
}
public void printHelp() {
System.out.println("Default Input");
System.out.println("Press buttons to see name. Press menu button to switch input mode.");
}
}
package jmevr;
import com.jme3.scene.Geometry;
interface Input {
public abstract InputMode getInputMode();
public abstract void handleInput(int controllerIndex, Geometry geo);
public abstract void printHelp();
}
package jmevr;
public enum InputMode {
DEFAULT(new DefaultInput()),
JOYSTICK(new JoystickInput()),
JOYSTICK_INVERTED(new InvertedJoystickInput()),
TRACKING_TEST(new TrackingTestInput());
private Input input;
InputMode(Input input) {
this.input = input;
}
public Input getInput() {
return input;
}
}
package jmevr;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import jmevr.input.VRInput;
import jopenvr.VRControllerAxis_t;
import java.awt.*;
import java.awt.event.InputEvent;
public class InvertedJoystickInput implements Input {
public InputMode getInputMode() {
return InputMode.JOYSTICK_INVERTED;
}
public void handleInput(int controllerIndex, Geometry geo) {
// vibrate when holding down trigger
if( VRInput.getAxis(controllerIndex, VRInput.VRINPUT_TYPE.ViveTriggerAxis).x >= 1f) {
VRInput.triggerHapticPulse(controllerIndex, 0.5f);
}
// Vibrate if moving fast
Vector3f vel = VRInput.getVelocity(controllerIndex);
if(vel.getX() > 1 || vel.getY() > 1 || vel.getZ() > 1) {
VRInput.triggerHapticPulse(controllerIndex, 0.5f);
}
VRControllerAxis_t cs = VRInput.getRawControllerState(controllerIndex).rAxis[0];
float padX = cs.x;
float padY = cs.y;
double distFromOrigin = Math.sqrt(((0 - cs.x) * (0 - cs.x)) + ((0 - cs.y) * (0 - cs.y)));
VRInput.triggerHapticPulse(controllerIndex, (float) distFromOrigin / 4);
try {
Robot robot = new Robot();
if(VRInput.isButtonDown(controllerIndex, VRInput.VRINPUT_TYPE.ViveTriggerAxis)) {
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
} else if(VRInput.isButtonDown(controllerIndex, VRInput.VRINPUT_TYPE.ViveGripButton)) {
robot.mousePress(InputEvent.BUTTON3_MASK);
robot.mouseRelease(InputEvent.BUTTON3_MASK);
} else {
PointerInfo a = MouseInfo.getPointerInfo();
Point mousePos = a.getLocation();
if(distFromOrigin > 0) {
robot.mouseMove((int) (mousePos.getX() + 5 * padX), (int) (mousePos.getY() + 5 * padY));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void printHelp() {
System.out.println("Inverted Joystick Input");
System.out.println("Use touchpad to move mouse like a joystick. y-axis is inverted.");
System.out.println("Trigger - left click");
System.out.println("Grip - right click");
}
}
package jmevr;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import jmevr.input.VRInput;
import jopenvr.VRControllerAxis_t;
import java.awt.*;
import java.awt.event.InputEvent;
public class JoystickInput implements Input {
public InputMode getInputMode() {
return InputMode.JOYSTICK;
}
public void handleInput(int controllerIndex, Geometry geo) {
// vibrate when holding down trigger
if( VRInput.getAxis(controllerIndex, VRInput.VRINPUT_TYPE.ViveTriggerAxis).x >= 1f) {
VRInput.triggerHapticPulse(controllerIndex, 0.5f);
}
// Vibrate if moving fast
Vector3f vel = VRInput.getVelocity(controllerIndex);
if(vel.getX() > 1 || vel.getY() > 1 || vel.getZ() > 1) {
VRInput.triggerHapticPulse(controllerIndex, 0.5f);
}
VRControllerAxis_t cs = VRInput.getRawControllerState(controllerIndex).rAxis[0];
float padX = cs.x;
float padY = cs.y;
double distFromOrigin = Math.sqrt(((0 - cs.x) * (0 - cs.x)) + ((0 - cs.y) * (0 - cs.y)));
VRInput.triggerHapticPulse(controllerIndex, (float) distFromOrigin / 4);
try {
Robot robot = new Robot();
if(VRInput.isButtonDown(controllerIndex, VRInput.VRINPUT_TYPE.ViveTriggerAxis)) {
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
} else if(VRInput.isButtonDown(controllerIndex, VRInput.VRINPUT_TYPE.ViveGripButton)) {
robot.mousePress(InputEvent.BUTTON3_MASK);
robot.mouseRelease(InputEvent.BUTTON3_MASK);
} else {
PointerInfo a = MouseInfo.getPointerInfo();
Point mousePos = a.getLocation();
if(distFromOrigin > 0) {
robot.mouseMove((int) (mousePos.getX() + 5 * padX), (int) (mousePos.getY() + 5 * -padY));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void printHelp() {
System.out.println("Joystick Input");
System.out.println("Use touchpad to move mouse like a joystick.");
System.out.println("Trigger - left click");
System.out.println("Grip - right click");
}
}
/*
VR Instancing Progress:
- igByGeom gets huge, and updateInstances still happens on it,
even if the associated geometry is no longer in the scene
- track which InstanceGeometry to add or remove inside the Geometry?
- have list of instances to render maintained somewhere else?
*/
package jmevr;
import com.jme3.material.Material;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.Spatial.CullHint;
import com.jogamp.newt.Display;
import jmevr.app.VRApplication;
import jmevr.input.VRInput;
import jmevr.input.VRInput.VRINPUT_TYPE;
public class TestOpenVR extends VRApplication {
private static InputMode[] inputModes = {InputMode.DEFAULT, InputMode.JOYSTICK};
private static int inputMode = 0;
private static boolean seenController = false;
// set some VR settings & start the app
public static void main(String[] args){
TestOpenVR test = new TestOpenVR();
//test.preconfigureVRApp(PRECONFIG_PARAMETER.USE_STEAMVR_COMPOSITOR, false); // disable the SteamVR compositor (kinda needed at the moment)
test.preconfigureVRApp(PRECONFIG_PARAMETER.USE_CUSTOM_DISTORTION, false); // use full screen distortion, maximum FOV, possibly quicker (not compatible with instancing)
test.preconfigureVRApp(PRECONFIG_PARAMETER.ENABLE_MIRROR_WINDOW, true); // runs faster when set to false, but will allow mirroring
test.preconfigureVRApp(PRECONFIG_PARAMETER.FORCE_VR_MODE, false); // render two eyes, regardless of SteamVR
test.preconfigureVRApp(PRECONFIG_PARAMETER.SET_GUI_CURVED_SURFACE, true);
test.preconfigureVRApp(PRECONFIG_PARAMETER.FLIP_EYES, false);
test.preconfigureVRApp(PRECONFIG_PARAMETER.SET_GUI_OVERDRAW, true); // show gui even if it is behind things
test.preconfigureVRApp(PRECONFIG_PARAMETER.INSTANCE_VR_RENDERING, true); // faster VR rendering, requires some vertex shader changes (see jmevr/shaders/Unshaded.j3md)
test.preconfigureVRApp(PRECONFIG_PARAMETER.NO_GUI, true);
test.preconfigureFrustrumNearFar(0.1f, 512f); // set frustum distances here before app starts
//test.preconfigureResolutionMultiplier(0.666f); // you can downsample for performance reasons
test.start();
}
// general objects for scene management
Spatial observer;
Material mat;
Geometry leftHand, rightHand;
@Override
public void simpleInitApp() {
initTestScene();
if(VRApplication.getVRHardware() != null) {
System.out.println("Attached device: " + VRApplication.getVRHardware().getType());
}
}
private void initTestScene(){
observer = new Node("observer");
// Setup controllers
leftHand = (Geometry)getAssetManager().loadModel("Models/vive_controller.j3o");
rightHand = leftHand.clone();
Material handMat = new Material(getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");
handMat.setTexture("ColorMap", getAssetManager().loadTexture("Textures/vive_controller.png"));
leftHand.setMaterial(handMat);
rightHand.setMaterial(handMat);
rootNode.attachChild(rightHand);
rootNode.attachChild(leftHand);
observer.setLocalTranslation(new Vector3f(0.0f, 0.0f, 0.0f));
//VRApplication.setObserver(observer);
//rootNode.attachChild(observer);
getInputManager().setCursorVisible(true);
}
@Override
public void simpleUpdate(float tpf){
if(VRInput.isInputDeviceTracking(0) && !seenController) {
seenController = true;
System.out.println("==============================================");
System.out.println("Input mode: " + inputModes[inputMode]);
inputModes[inputMode].getInput().printHelp();
System.out.println("==============================================");
} else if(!VRInput.isInputDeviceTracking(0)) {
seenController = false;
}
handleWandInput(0, leftHand);
handleWandInput(1, rightHand);
}
private void handleWandInput(int index, Geometry geo) {
Quaternion q = VRInput.getFinalObserverRotation(index);
Vector3f v = VRInput.getFinalObserverPosition(index);
if( q != null && v != null ) {
geo.setCullHint(CullHint.Dynamic); // make sure we see it
geo.setLocalTranslation(v);
geo.setLocalRotation(q);
// Handle switching input modes
if(VRInput.isButtonDown(index, VRINPUT_TYPE.ViveThumbButton)) {
VRInput.triggerHapticPulse(index, 0.7f);
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
VRInput.triggerHapticPulse(index, 0.7f);
if(inputMode == inputModes.length - 1) {
inputMode = 0;
try {
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
VRInput.triggerHapticPulse(index, 0.7f);
} else {
inputMode++;
}
System.out.println("==============================================");
System.out.println("Input mode now: " + inputModes[inputMode]);
inputModes[inputMode].getInput().printHelp();
System.out.println("==============================================");
}
inputModes[inputMode].getInput().handleInput(index, geo);
} else {
geo.setCullHint(CullHint.Always); // hide it
}
}
}
package jmevr;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import jmevr.input.VRInput;
public class TrackingTestInput implements Input {
private Vector3f[] screen = new Vector3f[4];
private int screenPos = 0;
private int count;
private float xRunning, yRunning, zRunning;
public InputMode getInputMode() {
return InputMode.TRACKING_TEST;
}
public void handleInput(int controllerIndex, Geometry geo) {
if(VRInput.isButtonDown(controllerIndex, VRInput.VRINPUT_TYPE.ViveGripButton)) {
System.out.println(geo.getLocalTranslation());
xRunning += geo.getLocalTranslation().getX();
yRunning += geo.getLocalTranslation().getY();
zRunning += geo.getLocalTranslation().getZ();
count++;
} else {
if(count > 0) {
System.out.println("After " + count + " iterations, averages are:");
System.out.println("x: " + xRunning / count);
System.out.println("y: " + yRunning / count);
System.out.println("z: " + zRunning / count);
screen[screenPos] = new Vector3f(xRunning / count, yRunning / count, zRunning / count);
if(screenPos < screen.length - 1) {
screenPos++;
} else {
screenPos = 0;
System.out.println("Screen set! Retrain to set new screen...");
for(int x = 0; x < screen.length; x++) {
System.out.println(screen[x]);
}
}
count = 0;
xRunning = yRunning = zRunning = 0;
}
}
}
public void printHelp() {
System.out.println("Tracking Test Input");
System.out.println("Move the controller to see tracking information.");
System.out.println("You may need to hold menu button to switch input modes.");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment