diff --git a/dependencies/VRControls.js b/dependencies/VRControls.js new file mode 100644 index 0000000000000000000000000000000000000000..8829c06266e0474e0f5ab607803b63b411bc8355 --- /dev/null +++ b/dependencies/VRControls.js @@ -0,0 +1,149 @@ +/** + * @author dmarcos / https://github.com/dmarcos + * @author mrdoob / http://mrdoob.com + */ + +THREE.VRControls = function ( object, onError ) { + + var scope = this; + + var vrDisplay, vrDisplays; + + var standingMatrix = new THREE.Matrix4(); + + var frameData = null; + + if ( 'VRFrameData' in window ) { + + frameData = new VRFrameData(); + + } + + function gotVRDisplays( displays ) { + + vrDisplays = displays; + + if ( displays.length > 0 ) { + + vrDisplay = displays[ 0 ]; + + } else { + + if ( onError ) onError( 'VR input not available.' ); + + } + + } + + if ( navigator.getVRDisplays ) { + + navigator.getVRDisplays().then( gotVRDisplays ).catch( function () { + + console.warn( 'THREE.VRControls: Unable to get VR Displays' ); + + } ); + + } + + // the Rift SDK returns the position in meters + // this scale factor allows the user to define how meters + // are converted to scene units. + + this.scale = 1; + + // If true will use "standing space" coordinate system where y=0 is the + // floor and x=0, z=0 is the center of the room. + this.standing = false; + + // Distance from the users eyes to the floor in meters. Used when + // standing=true but the VRDisplay doesn't provide stageParameters. + this.userHeight = 1.6; + + this.getVRDisplay = function () { + + return vrDisplay; + + }; + + this.setVRDisplay = function ( value ) { + + vrDisplay = value; + + }; + + this.getVRDisplays = function () { + + console.warn( 'THREE.VRControls: getVRDisplays() is being deprecated.' ); + return vrDisplays; + + }; + + this.getStandingMatrix = function () { + + return standingMatrix; + + }; + + this.update = function () { + + if ( vrDisplay ) { + + var pose; + + if ( vrDisplay.getFrameData ) { + + vrDisplay.getFrameData( frameData ); + pose = frameData.pose; + + } else if ( vrDisplay.getPose ) { + + pose = vrDisplay.getPose(); + + } + + if ( pose.orientation !== null ) { + + object.quaternion.fromArray( pose.orientation ); + + } + + if ( pose.position !== null ) { + + object.position.fromArray( pose.position ); + + } else { + + object.position.set( 0, 0, 0 ); + + } + + if ( this.standing ) { + + if ( vrDisplay.stageParameters ) { + + object.updateMatrix(); + + standingMatrix.fromArray( vrDisplay.stageParameters.sittingToStandingTransform ); + object.applyMatrix( standingMatrix ); + + } else { + + object.position.setY( object.position.y + this.userHeight ); + + } + + } + + object.position.multiplyScalar( scope.scale ); + + } + + }; + + this.dispose = function () { + + vrDisplay = null; + + }; + +}; diff --git a/dependencies/VREffect.js b/dependencies/VREffect.js new file mode 100644 index 0000000000000000000000000000000000000000..19bcba51359f8933045745ad230168712399b295 --- /dev/null +++ b/dependencies/VREffect.js @@ -0,0 +1,476 @@ +/** + * @author dmarcos / https://github.com/dmarcos + * @author mrdoob / http://mrdoob.com + * + * WebVR Spec: http://mozvr.github.io/webvr-spec/webvr.html + * + * Firefox: http://mozvr.com/downloads/ + * Chromium: https://webvr.info/get-chrome + */ + +THREE.VREffect = function ( renderer, onError ) { + + var vrDisplay, vrDisplays; + var eyeTranslationL = new THREE.Vector3(); + var eyeTranslationR = new THREE.Vector3(); + var renderRectL, renderRectR; + + var frameData = null; + + if ( 'VRFrameData' in window ) { + + frameData = new window.VRFrameData(); + + } + + function gotVRDisplays( displays ) { + + vrDisplays = displays; + + if ( displays.length > 0 ) { + + vrDisplay = displays[ 0 ]; + + } else { + + if ( onError ) onError( 'HMD not available' ); + + } + + } + + if ( navigator.getVRDisplays ) { + + navigator.getVRDisplays().then( gotVRDisplays ).catch( function () { + + console.warn( 'THREE.VREffect: Unable to get VR Displays' ); + + } ); + + } + + // + + this.isPresenting = false; + + var scope = this; + + var rendererSize = renderer.getSize(); + var rendererUpdateStyle = false; + var rendererPixelRatio = renderer.getPixelRatio(); + + this.getVRDisplay = function () { + + return vrDisplay; + + }; + + this.setVRDisplay = function ( value ) { + + vrDisplay = value; + + }; + + this.getVRDisplays = function () { + + console.warn( 'THREE.VREffect: getVRDisplays() is being deprecated.' ); + return vrDisplays; + + }; + + this.setSize = function ( width, height, updateStyle ) { + + rendererSize = { width: width, height: height }; + rendererUpdateStyle = updateStyle; + + if ( scope.isPresenting ) { + + var eyeParamsL = vrDisplay.getEyeParameters( 'left' ); + renderer.setPixelRatio( 1 ); + renderer.setSize( eyeParamsL.renderWidth * 2, eyeParamsL.renderHeight, false ); + + } else { + + renderer.setPixelRatio( rendererPixelRatio ); + renderer.setSize( width, height, updateStyle ); + + } + + }; + + // VR presentation + + var canvas = renderer.domElement; + var defaultLeftBounds = [ 0.0, 0.0, 0.5, 1.0 ]; + var defaultRightBounds = [ 0.5, 0.0, 0.5, 1.0 ]; + + function onVRDisplayPresentChange() { + + var wasPresenting = scope.isPresenting; + scope.isPresenting = vrDisplay !== undefined && vrDisplay.isPresenting; + + if ( scope.isPresenting ) { + + var eyeParamsL = vrDisplay.getEyeParameters( 'left' ); + var eyeWidth = eyeParamsL.renderWidth; + var eyeHeight = eyeParamsL.renderHeight; + + if ( ! wasPresenting ) { + + rendererPixelRatio = renderer.getPixelRatio(); + rendererSize = renderer.getSize(); + + renderer.setPixelRatio( 1 ); + renderer.setSize( eyeWidth * 2, eyeHeight, false ); + + } + + } else if ( wasPresenting ) { + + renderer.setPixelRatio( rendererPixelRatio ); + renderer.setSize( rendererSize.width, rendererSize.height, rendererUpdateStyle ); + + } + + } + + window.addEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false ); + + this.setFullScreen = function ( boolean ) { + + return new Promise( function ( resolve, reject ) { + + if ( vrDisplay === undefined ) { + + reject( new Error( 'No VR hardware found.' ) ); + return; + + } + + if ( scope.isPresenting === boolean ) { + + resolve(); + return; + + } + + if ( boolean ) { + + resolve( vrDisplay.requestPresent( [ { source: canvas } ] ) ); + + } else { + + resolve( vrDisplay.exitPresent() ); + + } + + } ); + + }; + + this.requestPresent = function () { + + return this.setFullScreen( true ); + + }; + + this.exitPresent = function () { + + return this.setFullScreen( false ); + + }; + + this.requestAnimationFrame = function ( f ) { + + if ( vrDisplay !== undefined ) { + + return vrDisplay.requestAnimationFrame( f ); + + } else { + + return window.requestAnimationFrame( f ); + + } + + }; + + this.cancelAnimationFrame = function ( h ) { + + if ( vrDisplay !== undefined ) { + + vrDisplay.cancelAnimationFrame( h ); + + } else { + + window.cancelAnimationFrame( h ); + + } + + }; + + this.submitFrame = function () { + + if ( vrDisplay !== undefined && scope.isPresenting ) { + + vrDisplay.submitFrame(); + + } + + }; + + this.autoSubmitFrame = true; + + // render + + var cameraL = new THREE.PerspectiveCamera(); + cameraL.layers.enable( 1 ); + + var cameraR = new THREE.PerspectiveCamera(); + cameraR.layers.enable( 2 ); + + this.render = function ( scene, camera, renderTarget, forceClear ) { + + if ( vrDisplay && scope.isPresenting ) { + + var autoUpdate = scene.autoUpdate; + + if ( autoUpdate ) { + + scene.updateMatrixWorld(); + scene.autoUpdate = false; + + } + + var eyeParamsL = vrDisplay.getEyeParameters( 'left' ); + var eyeParamsR = vrDisplay.getEyeParameters( 'right' ); + + eyeTranslationL.fromArray( eyeParamsL.offset ); + eyeTranslationR.fromArray( eyeParamsR.offset ); + + if ( Array.isArray( scene ) ) { + + console.warn( 'THREE.VREffect.render() no longer supports arrays. Use object.layers instead.' ); + scene = scene[ 0 ]; + + } + + // When rendering we don't care what the recommended size is, only what the actual size + // of the backbuffer is. + var size = renderer.getSize(); + var layers = vrDisplay.getLayers(); + var leftBounds; + var rightBounds; + + if ( layers.length ) { + + var layer = layers[ 0 ]; + + leftBounds = layer.leftBounds !== null && layer.leftBounds.length === 4 ? layer.leftBounds : defaultLeftBounds; + rightBounds = layer.rightBounds !== null && layer.rightBounds.length === 4 ? layer.rightBounds : defaultRightBounds; + + } else { + + leftBounds = defaultLeftBounds; + rightBounds = defaultRightBounds; + + } + + renderRectL = { + x: Math.round( size.width * leftBounds[ 0 ] ), + y: Math.round( size.height * leftBounds[ 1 ] ), + width: Math.round( size.width * leftBounds[ 2 ] ), + height: Math.round( size.height * leftBounds[ 3 ] ) + }; + renderRectR = { + x: Math.round( size.width * rightBounds[ 0 ] ), + y: Math.round( size.height * rightBounds[ 1 ] ), + width: Math.round( size.width * rightBounds[ 2 ] ), + height: Math.round( size.height * rightBounds[ 3 ] ) + }; + + if ( renderTarget ) { + + renderer.setRenderTarget( renderTarget ); + renderTarget.scissorTest = true; + + } else { + + renderer.setRenderTarget( null ); + renderer.setScissorTest( true ); + + } + + if ( renderer.autoClear || forceClear ) renderer.clear(); + + if ( camera.parent === null ) camera.updateMatrixWorld(); + + camera.matrixWorld.decompose( cameraL.position, cameraL.quaternion, cameraL.scale ); + + cameraR.position.copy( cameraL.position ); + cameraR.quaternion.copy( cameraL.quaternion ); + cameraR.scale.copy( cameraL.scale ); + + cameraL.translateOnAxis( eyeTranslationL, cameraL.scale.x ); + cameraR.translateOnAxis( eyeTranslationR, cameraR.scale.x ); + + if ( vrDisplay.getFrameData ) { + + vrDisplay.depthNear = camera.near; + vrDisplay.depthFar = camera.far; + + vrDisplay.getFrameData( frameData ); + + cameraL.projectionMatrix.elements = frameData.leftProjectionMatrix; + cameraR.projectionMatrix.elements = frameData.rightProjectionMatrix; + + } else { + + cameraL.projectionMatrix = fovToProjection( eyeParamsL.fieldOfView, true, camera.near, camera.far ); + cameraR.projectionMatrix = fovToProjection( eyeParamsR.fieldOfView, true, camera.near, camera.far ); + + } + + // render left eye + if ( renderTarget ) { + + renderTarget.viewport.set( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height ); + renderTarget.scissor.set( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height ); + + } else { + + renderer.setViewport( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height ); + renderer.setScissor( renderRectL.x, renderRectL.y, renderRectL.width, renderRectL.height ); + + } + renderer.render( scene, cameraL, renderTarget, forceClear ); + + // render right eye + if ( renderTarget ) { + + renderTarget.viewport.set( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height ); + renderTarget.scissor.set( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height ); + + } else { + + renderer.setViewport( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height ); + renderer.setScissor( renderRectR.x, renderRectR.y, renderRectR.width, renderRectR.height ); + + } + renderer.render( scene, cameraR, renderTarget, forceClear ); + + if ( renderTarget ) { + + renderTarget.viewport.set( 0, 0, size.width, size.height ); + renderTarget.scissor.set( 0, 0, size.width, size.height ); + renderTarget.scissorTest = false; + renderer.setRenderTarget( null ); + + } else { + + renderer.setViewport( 0, 0, size.width, size.height ); + renderer.setScissorTest( false ); + + } + + if ( autoUpdate ) { + + scene.autoUpdate = true; + + } + + if ( scope.autoSubmitFrame ) { + + scope.submitFrame(); + + } + + return; + + } + + // Regular render mode if not HMD + + renderer.render( scene, camera, renderTarget, forceClear ); + + }; + + this.dispose = function () { + + window.removeEventListener( 'vrdisplaypresentchange', onVRDisplayPresentChange, false ); + + }; + + // + + function fovToNDCScaleOffset( fov ) { + + var pxscale = 2.0 / ( fov.leftTan + fov.rightTan ); + var pxoffset = ( fov.leftTan - fov.rightTan ) * pxscale * 0.5; + var pyscale = 2.0 / ( fov.upTan + fov.downTan ); + var pyoffset = ( fov.upTan - fov.downTan ) * pyscale * 0.5; + return { scale: [ pxscale, pyscale ], offset: [ pxoffset, pyoffset ] }; + + } + + function fovPortToProjection( fov, rightHanded, zNear, zFar ) { + + rightHanded = rightHanded === undefined ? true : rightHanded; + zNear = zNear === undefined ? 0.01 : zNear; + zFar = zFar === undefined ? 10000.0 : zFar; + + var handednessScale = rightHanded ? - 1.0 : 1.0; + + // start with an identity matrix + var mobj = new THREE.Matrix4(); + var m = mobj.elements; + + // and with scale/offset info for normalized device coords + var scaleAndOffset = fovToNDCScaleOffset( fov ); + + // X result, map clip edges to [-w,+w] + m[ 0 * 4 + 0 ] = scaleAndOffset.scale[ 0 ]; + m[ 0 * 4 + 1 ] = 0.0; + m[ 0 * 4 + 2 ] = scaleAndOffset.offset[ 0 ] * handednessScale; + m[ 0 * 4 + 3 ] = 0.0; + + // Y result, map clip edges to [-w,+w] + // Y offset is negated because this proj matrix transforms from world coords with Y=up, + // but the NDC scaling has Y=down (thanks D3D?) + m[ 1 * 4 + 0 ] = 0.0; + m[ 1 * 4 + 1 ] = scaleAndOffset.scale[ 1 ]; + m[ 1 * 4 + 2 ] = - scaleAndOffset.offset[ 1 ] * handednessScale; + m[ 1 * 4 + 3 ] = 0.0; + + // Z result (up to the app) + m[ 2 * 4 + 0 ] = 0.0; + m[ 2 * 4 + 1 ] = 0.0; + m[ 2 * 4 + 2 ] = zFar / ( zNear - zFar ) * - handednessScale; + m[ 2 * 4 + 3 ] = ( zFar * zNear ) / ( zNear - zFar ); + + // W result (= Z in) + m[ 3 * 4 + 0 ] = 0.0; + m[ 3 * 4 + 1 ] = 0.0; + m[ 3 * 4 + 2 ] = handednessScale; + m[ 3 * 4 + 3 ] = 0.0; + + mobj.transpose(); + return mobj; + + } + + function fovToProjection( fov, rightHanded, zNear, zFar ) { + + var DEG2RAD = Math.PI / 180.0; + + var fovPort = { + upTan: Math.tan( fov.upDegrees * DEG2RAD ), + downTan: Math.tan( fov.downDegrees * DEG2RAD ), + leftTan: Math.tan( fov.leftDegrees * DEG2RAD ), + rightTan: Math.tan( fov.rightDegrees * DEG2RAD ) + }; + + return fovPortToProjection( fovPort, rightHanded, zNear, zFar ); + + } + +}; diff --git a/dependencies/ViveController.js b/dependencies/ViveController.js new file mode 100644 index 0000000000000000000000000000000000000000..7d70e73be0f98db83c47d02ae2249cb8c507248f --- /dev/null +++ b/dependencies/ViveController.js @@ -0,0 +1,128 @@ +/** + * @author mrdoob / http://mrdoob.com + * @author stewdio / http://stewd.io + */ + +THREE.ViveController = function ( id ) { + + THREE.Object3D.call( this ); + + var scope = this; + var gamepad; + + var axes = [ 0, 0 ]; + var thumbpadIsPressed = false; + var triggerIsPressed = false; + var gripsArePressed = false; + var menuIsPressed = false; + + function findGamepad( id ) { + + // Iterate across gamepads as Vive Controllers may not be + // in position 0 and 1. + + var gamepads = navigator.getGamepads(); + + for ( var i = 0, j = 0; i < 4; i ++ ) { + + var gamepad = gamepads[ i ]; + + if ( gamepad && ( gamepad.id === 'OpenVR Gamepad' || gamepad.id === 'Oculus Touch (Left)' || gamepad.id === 'Oculus Touch (Right)' ) ) { + + if ( j === id ) return gamepad; + + j ++; + + } + + } + + } + + this.matrixAutoUpdate = false; + this.standingMatrix = new THREE.Matrix4(); + + this.getGamepad = function () { + + return gamepad; + + }; + + this.getButtonState = function ( button ) { + + if ( button === 'thumbpad' ) return thumbpadIsPressed; + if ( button === 'trigger' ) return triggerIsPressed; + if ( button === 'grips' ) return gripsArePressed; + if ( button === 'menu' ) return menuIsPressed; + + }; + + this.update = function () { + + gamepad = findGamepad( id ); + + if ( gamepad !== undefined && gamepad.pose !== undefined ) { + + if ( gamepad.pose === null ) return; // No user action yet + + // Position and orientation. + + var pose = gamepad.pose; + + if ( pose.position !== null ) scope.position.fromArray( pose.position ); + if ( pose.orientation !== null ) scope.quaternion.fromArray( pose.orientation ); + scope.matrix.compose( scope.position, scope.quaternion, scope.scale ); + scope.matrix.multiplyMatrices( scope.standingMatrix, scope.matrix ); + scope.matrixWorldNeedsUpdate = true; + scope.visible = true; + + // Thumbpad and Buttons. + + if ( axes[ 0 ] !== gamepad.axes[ 0 ] || axes[ 1 ] !== gamepad.axes[ 1 ] ) { + + axes[ 0 ] = gamepad.axes[ 0 ]; // X axis: -1 = Left, +1 = Right. + axes[ 1 ] = gamepad.axes[ 1 ]; // Y axis: -1 = Bottom, +1 = Top. + scope.dispatchEvent( { type: 'axischanged', axes: axes } ); + + } + + if ( thumbpadIsPressed !== gamepad.buttons[ 0 ].pressed ) { + + thumbpadIsPressed = gamepad.buttons[ 0 ].pressed; + scope.dispatchEvent( { type: thumbpadIsPressed ? 'thumbpaddown' : 'thumbpadup' } ); + + } + + if ( triggerIsPressed !== gamepad.buttons[ 1 ].pressed ) { + + triggerIsPressed = gamepad.buttons[ 1 ].pressed; + scope.dispatchEvent( { type: triggerIsPressed ? 'triggerdown' : 'triggerup' } ); + + } + + if ( gripsArePressed !== gamepad.buttons[ 2 ].pressed ) { + + gripsArePressed = gamepad.buttons[ 2 ].pressed; + scope.dispatchEvent( { type: gripsArePressed ? 'gripsdown' : 'gripsup' } ); + + } + + if ( menuIsPressed !== gamepad.buttons[ 3 ].pressed ) { + + menuIsPressed = gamepad.buttons[ 3 ].pressed; + scope.dispatchEvent( { type: menuIsPressed ? 'menudown' : 'menuup' } ); + + } + + } else { + + scope.visible = false; + + } + + }; + +}; + +THREE.ViveController.prototype = Object.create( THREE.Object3D.prototype ); +THREE.ViveController.prototype.constructor = THREE.ViveController; diff --git a/dependencies/WebVR.js b/dependencies/WebVR.js new file mode 100644 index 0000000000000000000000000000000000000000..80b3243c6c0d9ceed0bbb47e7bd651344adc2587 --- /dev/null +++ b/dependencies/WebVR.js @@ -0,0 +1,131 @@ +/** + * @author mrdoob / http://mrdoob.com + * Based on @tojiro's vr-samples-utils.js + */ + +var WEBVR = { + + isLatestAvailable: function () { + + console.warn( 'WEBVR: isLatestAvailable() is being deprecated. Use .isAvailable() instead.' ); + return this.isAvailable(); + + }, + + isAvailable: function () { + + return navigator.getVRDisplays !== undefined; + + }, + + getVRDisplay: function ( onDisplay ) { + + if ( 'getVRDisplays' in navigator ) { + + navigator.getVRDisplays() + .then( function ( displays ) { + onDisplay( displays[ 0 ] ); + } ); + + } + + }, + + getMessage: function () { + + var message; + + if ( navigator.getVRDisplays ) { + + navigator.getVRDisplays().then( function ( displays ) { + + if ( displays.length === 0 ) message = 'WebVR supported, but no VRDisplays found.'; + + } ); + + } else { + + message = 'Your browser does not support WebVR. See <a href="http://webvr.info">webvr.info</a> for assistance.'; + + } + + if ( message !== undefined ) { + + var container = document.createElement( 'div' ); + container.style.position = 'absolute'; + container.style.left = '0'; + container.style.top = '0'; + container.style.right = '0'; + container.style.zIndex = '999'; + container.align = 'center'; + + var error = document.createElement( 'div' ); + error.style.fontFamily = 'sans-serif'; + error.style.fontSize = '16px'; + error.style.fontStyle = 'normal'; + error.style.lineHeight = '26px'; + error.style.backgroundColor = '#fff'; + error.style.color = '#000'; + error.style.padding = '10px 20px'; + error.style.margin = '50px'; + error.style.display = 'inline-block'; + error.innerHTML = message; + container.appendChild( error ); + + return container; + + } + + }, + + getButton: function ( display, canvas ) { + + if ( 'VREffect' in THREE && display instanceof THREE.VREffect ) { + + console.error( 'WebVR.getButton() now expects a VRDisplay.' ); + return document.createElement( 'button' ); + + } + + var button = document.createElement( 'button' ); + button.style.position = 'absolute'; + button.style.left = 'calc(50% - 50px)'; + button.style.bottom = '20px'; + button.style.width = '100px'; + button.style.border = '0'; + button.style.padding = '8px'; + button.style.cursor = 'pointer'; + button.style.backgroundColor = '#000'; + button.style.color = '#fff'; + button.style.fontFamily = 'sans-serif'; + button.style.fontSize = '13px'; + button.style.fontStyle = 'normal'; + button.style.textAlign = 'center'; + button.style.zIndex = '999'; + + if ( display ) { + + button.textContent = 'ENTER VR'; + button.onclick = function () { + + display.isPresenting ? display.exitPresent() : display.requestPresent( [ { source: canvas } ] ); + + }; + + window.addEventListener( 'vrdisplaypresentchange', function () { + + button.textContent = display.isPresenting ? 'EXIT VR' : 'ENTER VR'; + + }, false ); + + } else { + + button.textContent = 'NO VR DISPLAY'; + + } + + return button; + + } + +}; diff --git a/index.html b/index.html index 9f3d182746f9d2e027595463c799bd53583c5ccd..64b80141cef501e89a0d642b5fa4ae03c6dc6ddc 100644 --- a/index.html +++ b/index.html @@ -284,7 +284,6 @@ float dotNormals = dot(normal1, normal2);//normals are already normalized, no need to divide by length if (dotNormals < -1.0) dotNormals = -1.0; else if (dotNormals > 1.0) dotNormals = 1.0; - //float theta = acos(dotNormals); vec2 creaseVectorIndices = texture2D(u_creaseVectors, scaledFragCoord).xy; vec2 creaseNodeIndex = vec2(mod(creaseVectorIndices[0], u_textureDim.x)+0.5, floor(creaseVectorIndices[0]/u_textureDim.x)+0.5); @@ -301,10 +300,7 @@ float theta = atan(y, x); - //float sign = dot(cross(normal1, normal2), creaseVector); - //if (sign < 0.0) theta *= -1.0; float diff = theta-lastTheta[0]; - float projectedTheta = lastTheta[0] + lastTheta[1]*u_dt; if (diff < -5.0) { diff += TWO_PI; theta = lastTheta[0] + diff; @@ -312,7 +308,7 @@ diff -= TWO_PI; theta = lastTheta[0] + diff; } - gl_FragColor = vec4(theta, creaseVectorIndices[1], lastTheta[2], lastTheta[3]);//[theta, w, normal1Index, normal2Index] + gl_FragColor = vec4(theta, theta, lastTheta[2], lastTheta[3]);//[theta, w, normal1Index, normal2Index] } </script> @@ -345,7 +341,9 @@ scaledNodeIndex = nodeIndex/u_textureDim; vec3 c = texture2D(u_lastPosition, scaledNodeIndex).xyz + texture2D(u_originalPosition, scaledNodeIndex).xyz; - gl_FragColor = vec4(normalize(cross(b-a, c-a)), 0.0); + vec3 normal = normalize(cross(b-a, c-a)); + + gl_FragColor = vec4(normal, 0.0); } </script> @@ -372,6 +370,11 @@ <script type="text/javascript" src="dependencies/Detector.js"></script> <script type="text/javascript" src="dependencies/RenderPass.js"></script> + <script type="text/javascript" src="dependencies/WebVR.js"></script> + <script type="text/javascript" src="dependencies/VREffect.js"></script> + <script type="text/javascript" src="dependencies/ViveController.js"></script> + <script type="text/javascript" src="dependencies/VRControls.js"></script> + <script type="text/javascript" src="js/dynamic/GLBoilerplate.js"></script> <script type="text/javascript" src="js/dynamic/GPUMath.js"></script> <script type="text/javascript" src="js/controls.js"></script> @@ -388,7 +391,7 @@ <script type="text/javascript" src="js/saveSTL.js"></script> <script type="text/javascript" src="js/saveFOLD.js"></script> <script type="text/javascript" src="js/importer.js"></script> - + <script type="text/javascript" src="js/ViveInterface.js"></script> <script type="text/javascript" src="js/main.js"></script> </head> @@ -605,7 +608,7 @@ <!--</div>--> VR: <div class="indent smallTxt"> - Status: <span id="VRstatus">No device connected</span> + Status: <span id="VRstatus"></span> <a class="about floatRight" href="#" id="aboutVR"><span class="fui-question-circle"></span></a><br/> <div id="VRoptions"> <label class="checkbox" for="vrEnabled"> diff --git a/js/ViveInterface.js b/js/ViveInterface.js new file mode 100644 index 0000000000000000000000000000000000000000..96e57b4aac906af501ca2863f2591552bca3c05f --- /dev/null +++ b/js/ViveInterface.js @@ -0,0 +1,65 @@ +/** + * Created by amandaghassaei on 5/10/17. + */ + + +function initViveInterface(globals){ + + var $status = $("#VRstatus"); + + if ( WEBVR.isAvailable() === false ) { + $status.html("WebVR not supported by this browser<br/>see <a href='https://webvr.info/' target='_blank'>webvr.info</a> for more info."); + $("#VRoptions").hide(); + return; + } + + var controls, controller1, controller2, effect; + + var mesh = new THREE.Mesh(new THREE.CubeGeometry(1, 1,1 ), new THREE.MeshLambertMaterial({color:0xff0000})); + + function setup(){ + + controls = new THREE.VRControls(globals.threeView.camera); + controls.standing = true; + + // controllers + controller1 = new THREE.ViveController( 0 ); + controller1.standingMatrix = controls.getStandingMatrix(); + globals.threeView.scene.add( controller1 ); + + controller2 = new THREE.ViveController( 1 ); + controller2.standingMatrix = controls.getStandingMatrix(); + globals.threeView.scene.add( controller2 ); + + controller1.add(mesh.clone()); + controller2.add(mesh.clone()); + + effect = new THREE.VREffect(globals.threeView.renderer); + + } + + function connect(){ + WEBVR.getVRDisplay( function ( display ) { + + document.body.appendChild( WEBVR.getButton( display, renderer.domElement ) ); + + } ); + } + + function disconnect(){ + + } + + function render(){ + controller1.update(); + controller2.update(); + controls.update(); + effect.render( globals.threeView.scene, globals.threeView.camera ); + } + + return { + effect: effect, + render: render + } + +} \ No newline at end of file diff --git a/js/dynamic/dynamicSolver.js b/js/dynamic/dynamicSolver.js index d03df827f73f90c1057f10141f6ca41ba78d1ad5..6f8c2e4a43dd5056991b73416b04c7440db370ca 100644 --- a/js/dynamic/dynamicSolver.js +++ b/js/dynamic/dynamicSolver.js @@ -61,6 +61,7 @@ function initDynamicSolver(globals){ globals.gpuMath.step("zeroTexture", [], "u_lastPosition"); globals.gpuMath.step("zeroTexture", [], "u_velocity"); globals.gpuMath.step("zeroTexture", [], "u_lastVelocity"); + //todo reset theta render(); } @@ -172,7 +173,9 @@ function initDynamicSolver(globals){ // var pixels = new Uint8Array(height*textureDimCreases*4*vectorLength); // globals.gpuMath.readPixels(0, 0, textureDimCreases * vectorLength, height, pixels); // var parsedPixels = new Float32Array(pixels.buffer); - // console.log(parsedPixels); + // for (var i=0;i<parsedPixels.length;i+=2){ + // if (Math.abs(parsedPixels[i+1])>3.0) console.log(parsedPixels[i+1]); + // } // } else { // console.log("here"); // } diff --git a/js/main.js b/js/main.js index 09439897673632812b5b36f3cb0bd960b0b876c0..7b9142077e7a17e2a35d67251ef685711b89a975 100644 --- a/js/main.js +++ b/js/main.js @@ -17,5 +17,6 @@ $(function() { globals.staticSolver = initStaticSolver(globals); globals.dynamicSolver = initDynamicSolver(globals); globals.pattern = initPattern(globals); + globals.vive = initViveInterface(globals); $(".demo[data-url='Tessellations/waterbomb.svg']").click(); }); \ No newline at end of file diff --git a/js/threeView.js b/js/threeView.js index 3aa5f49effbfd0b6f736ff829af3eee451093393..5ddfd4834f6f54575b0fd0e91537ff943836329b 100644 --- a/js/threeView.js +++ b/js/threeView.js @@ -122,6 +122,10 @@ function initThreeView(globals) { } function _render(){ + if (globals.vrEnabled){ + globals.vive.render(); + return; + } if (globals.ambientOcclusion) { // Render depth into depthRenderTarget scene.overrideMaterial = depthMaterial; @@ -129,13 +133,19 @@ function initThreeView(globals) { // Render renderPass and SSAO shaderPass scene.overrideMaterial = null; effectComposer.render(); - } else { - renderer.render(scene, camera); + return; } + renderer.render(scene, camera); } function _loop(callback){ callback(); + if (globals.vrEnabled){ + globals.vive.effect.requestAnimationFrame(function(){ + _loop(callback); + }); + return; + } requestAnimationFrame(function(){ if (pauseFlag) { pauseFlag = false; @@ -231,6 +241,7 @@ function initThreeView(globals) { enableControls: enableControls, scene: scene, camera: camera, + renderer: renderer, running: running, setScale:setScale, saveSVG: saveSVG