Ver Fonte

Editor: Added VR mode (WIP).

Mr.doob há 9 anos atrás
pai
commit
d868ce70b0

+ 49 - 1
editor/index.html

@@ -97,7 +97,8 @@
 		<script src="js/Menubar.Edit.js"></script>
 		<script src="js/Menubar.Add.js"></script>
 		<script src="js/Menubar.Play.js"></script>
-		<script src="js/Menubar.Examples.js"></script>
+		<script src="js/Menubar.View.js"></script>
+		<!-- <script src="js/Menubar.Examples.js"></script> -->
 		<script src="js/Menubar.Help.js"></script>
 		<script src="js/Menubar.Status.js"></script>
 		<script src="js/Sidebar.js"></script>
@@ -152,6 +153,8 @@
 
 		<!-- <script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="qyqgfqd9j8z890t"></script> -->
 
+		<script src="js/libs/html2canvas.js"></script>
+
 		<script>
 
 			window.URL = window.URL || window.webkitURL;
@@ -382,6 +385,51 @@
 			}, false );
 			*/
 
+			// VR
+
+			var groupVR;
+
+			// TODO: Use editor.signals.enteredVR (WebVR 1.0)
+
+			editor.signals.enterVR.add( function () {
+
+				if ( groupVR === undefined ) {
+
+					groupVR = new THREE.HTMLGroup( viewport.dom );
+					editor.sceneHelpers.add( groupVR );
+
+					var mesh = new THREE.HTMLMesh( sidebar.dom );
+					mesh.position.set( 15, 0, 15 );
+					mesh.rotation.y = - 0.5;
+					groupVR.add( mesh );
+
+					var signals = editor.signals;
+
+					function updateTexture() {
+
+						mesh.material.map.update();
+
+					}
+
+					signals.objectSelected.add( updateTexture );
+					signals.objectAdded.add( updateTexture );
+					signals.objectChanged.add( updateTexture );
+					signals.objectRemoved.add( updateTexture );
+					signals.sceneGraphChanged.add( updateTexture );
+					signals.historyChanged.add( updateTexture );
+
+				}
+
+				groupVR.visible = true;
+
+			} );
+
+			editor.signals.exitedVR.add( function () {
+
+				if ( groupVR !== undefined ) groupVR.visible = false;
+
+			} );
+
 		</script>
 	</body>
 </html>

+ 7 - 0
editor/js/Editor.js

@@ -22,6 +22,13 @@ var Editor = function () {
 		startPlayer: new Signal(),
 		stopPlayer: new Signal(),
 
+		// vr
+
+		enterVR: new Signal(),
+
+		enteredVR: new Signal(),
+		exitedVR: new Signal(),
+
 		// actions
 
 		showModal: new Signal(),

+ 41 - 0
editor/js/Menubar.View.js

@@ -0,0 +1,41 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+Menubar.View = function ( editor ) {
+
+	var container = new UI.Panel();
+	container.setClass( 'menu' );
+
+	var title = new UI.Panel();
+	title.setClass( 'title' );
+	title.setTextContent( 'View' );
+	container.add( title );
+
+	var options = new UI.Panel();
+	options.setClass( 'options' );
+	container.add( options );
+
+	// VR mode
+
+	var option = new UI.Row();
+	option.setClass( 'option' );
+	option.setTextContent( 'VR mode' );
+	option.onClick( function () {
+
+		if ( WEBVR.isAvailable() === true ) {
+
+			editor.signals.enterVR.dispatch();
+
+		} else {
+
+			alert( 'WebVR nor available' );
+
+		}
+
+	} );
+	options.add( option );
+
+	return container;
+
+};

+ 2 - 1
editor/js/Menubar.js

@@ -11,7 +11,8 @@ var Menubar = function ( editor ) {
 	container.add( new Menubar.Edit( editor ) );
 	container.add( new Menubar.Add( editor ) );
 	container.add( new Menubar.Play( editor ) );
-	container.add( new Menubar.Examples( editor ) );
+	container.add( new Menubar.View( editor ) );
+	// container.add( new Menubar.Examples( editor ) );
 	container.add( new Menubar.Help( editor ) );
 
 	container.add( new Menubar.Status( editor ) );

+ 62 - 16
editor/js/Viewport.js

@@ -12,11 +12,28 @@ var Viewport = function ( editor ) {
 
 	container.add( new Viewport.Info( editor ) );
 
+	//
+
+	var renderer = null;
+
+	var camera = editor.camera;
 	var scene = editor.scene;
 	var sceneHelpers = editor.sceneHelpers;
 
 	var objects = [];
 
+	//
+
+	var vrEffect, vrControls;
+
+	if ( WEBVR.isAvailable() === true ) {
+
+		var vrCamera = new THREE.PerspectiveCamera();
+		vrCamera.projectionMatrix = camera.projectionMatrix;
+		camera.add( vrCamera );
+
+	}
+
 	// helpers
 
 	var grid = new THREE.GridHelper( 30, 60 );
@@ -24,10 +41,6 @@ var Viewport = function ( editor ) {
 
 	//
 
-	var camera = editor.camera;
-
-	//
-
 	var box = new THREE.Box3();
 
 	var selectionBox = new THREE.BoxHelper();
@@ -278,6 +291,12 @@ var Viewport = function ( editor ) {
 
 	} );
 
+	signals.enterVR.add( function () {
+
+		vrEffect.isPresenting ? vrEffect.exitPresent() : vrEffect.requestPresent();
+
+	} );
+
 	var clearColor;
 
 	signals.themeChanged.add( function ( value ) {
@@ -341,6 +360,19 @@ var Viewport = function ( editor ) {
 
 		container.dom.appendChild( renderer.domElement );
 
+		if ( WEBVR.isAvailable() === true ) {
+
+			vrControls = new THREE.VRControls( vrCamera );
+			vrEffect = new THREE.VREffect( renderer );
+
+			window.addEventListener( 'vrdisplaypresentchange', function ( event ) {
+
+				effect.isPresenting ? signals.enteredVR.dispatch() : signals.exitedVR.dispatch();
+
+			}, false );
+
+		}
+
 		render();
 
 	} );
@@ -537,12 +569,6 @@ var Viewport = function ( editor ) {
 
 	//
 
-	var renderer = null;
-
-	animate();
-
-	//
-
 	function updateFog( root ) {
 
 		if ( root.fog ) {
@@ -581,12 +607,15 @@ var Viewport = function ( editor ) {
 
 			}
 
+		}
+		*/
+
+		if ( vrEffect && vrEffect.isPresenting ) {
+
 			render();
 
 		}
 
-		*/
-
 	}
 
 	function render() {
@@ -594,17 +623,34 @@ var Viewport = function ( editor ) {
 		sceneHelpers.updateMatrixWorld();
 		scene.updateMatrixWorld();
 
-		renderer.clear();
-		renderer.render( scene, camera );
+		if ( vrEffect && vrEffect.isPresenting ) {
+
+			vrControls.update();
+
+			camera.updateMatrixWorld();
+			renderer.clear();
+
+			vrEffect.render( scene, vrCamera );
+			vrEffect.render( sceneHelpers, vrCamera );
+
+		} else {
 
-		if ( renderer instanceof THREE.RaytracingRenderer === false ) {
+			renderer.clear();
+			renderer.render( scene, camera );
 
-			renderer.render( sceneHelpers, camera );
+			if ( renderer instanceof THREE.RaytracingRenderer === false ) {
+
+				renderer.render( sceneHelpers, camera );
+
+			}
 
 		}
 
+
 	}
 
+	requestAnimationFrame( animate );
+
 	return container;
 
 };

+ 263 - 0
editor/js/libs/html2canvas.js

@@ -0,0 +1,263 @@
+/**
+ * @author mrdoob / http://mrdoob.com/
+ */
+
+function html2canvas( element ) {
+
+	var range = document.createRange();
+
+	function Clipper( context ) {
+
+		var clips = [];
+		var isClipping = false;
+
+		function doClip() {
+
+			if ( isClipping ) {
+
+				isClipping = false;
+				context.restore();
+
+			}
+
+			if ( clips.length === 0 ) return;
+
+			var minX = - Infinity, minY = - Infinity;
+			var maxX = Infinity, maxY = Infinity;
+
+			for ( var i = 0; i < clips.length; i ++ ) {
+
+				var clip = clips[ i ];
+
+				minX = Math.max( minX, clip.x );
+				minY = Math.max( minY, clip.y );
+				maxX = Math.min( maxX, clip.x + clip.width );
+				maxY = Math.min( maxY, clip.y + clip.height );
+
+			}
+
+			context.save();
+			context.beginPath();
+			context.rect( minX, minY, maxX - minX, maxY - minY );
+			context.clip();
+
+			isClipping = true;
+
+		}
+
+		return {
+			add: function ( clip ) {
+				clips.push( clip );
+				doClip();
+			},
+			remove: function () {
+				clips.pop();
+				doClip();
+			}
+		};
+
+	}
+
+	function drawText( style, x, y, string ) {
+
+		if ( string !== '' ) {
+
+			context.font = style.fontSize + ' ' + style.fontFamily;
+			context.textBaseline = 'top';
+			context.fillStyle = style.color;
+			context.fillText( string, x, y );
+
+		}
+
+	}
+
+	function drawBorder( style, which, x, y, width, height ) {
+
+		var borderWidth = style[ which + 'Width' ];
+		var borderStyle = style[ which + 'Style' ];
+		var borderColor = style[ which + 'Color' ];
+
+		if ( borderWidth !== '0px' && borderStyle !== 'none' && borderColor !== 'transparent' && borderColor !== 'rgba(0, 0, 0, 0)' ) {
+
+			context.strokeStyle = borderColor;
+			context.beginPath();
+			context.moveTo( x, y );
+			context.lineTo( x + width, y + height );
+			context.stroke();
+
+		}
+
+	}
+
+	function drawElement( element, style ) {
+
+		var x = 0, y = 0, width = 0, height = 0;
+
+		if ( element.nodeType === 3 ) {
+
+			// text
+
+			range.selectNode( element );
+
+			var rect = range.getBoundingClientRect();
+
+			x = rect.left - offset.left - 0.5;
+			y = rect.top - offset.top - 0.5;
+			width = rect.width;
+			height = rect.height;
+
+			drawText( style, x, y, element.nodeValue.trim() );
+
+		} else {
+
+			if ( element.style.display === 'none' ) return;
+
+			var rect = element.getBoundingClientRect();
+
+			x = rect.left - offset.left - 0.5;
+			y = rect.top - offset.top - 0.5;
+			width = rect.width;
+			height = rect.height;
+
+			style = window.getComputedStyle( element );
+
+			var backgroundColor = style.backgroundColor;
+
+			if ( backgroundColor !== 'transparent' && backgroundColor !== 'rgba(0, 0, 0, 0)' ) {
+
+				context.fillStyle = backgroundColor;
+				context.fillRect( x, y, width, height );
+
+			}
+
+			drawBorder( style, 'borderTop', x, y, width, 0 );
+			drawBorder( style, 'borderLeft', x, y, 0, height );
+			drawBorder( style, 'borderBottom', x, y + height, width, 0 );
+			drawBorder( style, 'borderRight', x + width, y, 0, height );
+
+			if ( element.type === 'color' || element.type === 'text' ) {
+
+				clipper.add( { x: x, y: y, width: width, height: height } );
+
+				drawText( style, x + parseInt( style.paddingLeft ), y + parseInt( style.paddingTop ), element.value );
+
+				clipper.remove();
+
+			}
+
+		}
+
+		/*
+		// debug
+
+		context.strokeStyle = '#' + Math.random().toString( 16 ).slice( - 3 );
+		context.strokeRect( x - 0.5, y - 0.5, width + 1, height + 1 );
+		*/
+
+		var isClipping = style.overflow === 'auto' || style.overflow === 'hidden';
+
+		if ( isClipping ) clipper.add( { x: x, y: y, width: width, height: height } );
+
+		for ( var i = 0; i < element.childNodes.length; i ++ ) {
+
+			drawElement( element.childNodes[ i ], style );
+
+		}
+
+		if ( isClipping ) clipper.remove();
+
+	}
+
+	var offset = element.getBoundingClientRect();
+
+	var canvas = document.createElement( 'canvas' );
+	canvas.width = offset.width;
+	canvas.height = offset.height;
+
+	var context = canvas.getContext( '2d'/*, { alpha: false }*/ );
+
+	var clipper = new Clipper( context );
+
+	console.time( 'drawElement' );
+
+	drawElement( element );
+
+	console.timeEnd( 'drawElement' );
+
+	return canvas;
+
+}
+
+//
+
+THREE.HTMLGroup = function ( dom ) {
+
+	THREE.Group.call( this );
+
+	this.type = 'HTMLGroup';
+
+	/*
+	dom.addEventListener( 'mousemove', function ( event ) {
+
+		console.log( 'mousemove' );
+
+	} );
+
+	dom.addEventListener( 'click', function ( event ) {
+
+		console.log( 'click' );
+
+	} );
+	*/
+
+};
+
+THREE.HTMLGroup.prototype = Object.assign( Object.create( THREE.Group.prototype ), {
+
+	constructor: THREE.HTMLGroup
+
+} );
+
+THREE.HTMLMesh = function ( dom ) {
+
+	var texture = new THREE.HTMLTexture( dom );
+
+	var geometry = new THREE.PlaneGeometry( texture.image.width * 0.05, texture.image.height * 0.05 );
+	var material = new THREE.MeshBasicMaterial( { map: texture } );
+
+	THREE.Mesh.call( this, geometry, material );
+
+	this.type = 'HTMLMesh';
+
+};
+
+THREE.HTMLMesh.prototype = Object.assign( Object.create( THREE.Mesh.prototype ), {
+
+	constructor: THREE.HTMLMesh
+
+} );
+
+THREE.HTMLTexture = function ( dom ) {
+
+	THREE.CanvasTexture.call( this, html2canvas( dom ) );
+
+	this.dom = dom;
+
+	this.anisotropy = 16;
+
+};
+
+THREE.HTMLTexture.prototype = Object.assign( Object.create( THREE.CanvasTexture.prototype ), {
+
+	constructor: THREE.HTMLTexture,
+
+	update: function () {
+
+		console.log( 'yo!', this, this.dom );
+
+		this.image = html2canvas( this.dom );
+		this.needsUpdate = true;
+
+	}
+
+} );