parent
f781760a45
commit
103e404dd9
@ -0,0 +1,2 @@ |
||||
{ |
||||
} |
@ -0,0 +1,19 @@ |
||||
AFRAME.registerComponent('drag-controls', { |
||||
schema: {objects: {type: 'string', default: 'a-entity'}}, |
||||
|
||||
init: function () { |
||||
var objects = []; |
||||
var el = this.el; |
||||
var els; |
||||
var dragControls; |
||||
els = el.sceneEl.querySelectorAll(this.data.objects); |
||||
for (var i = 0; i < els.length; i++) { |
||||
console.log(i); |
||||
objects.push(els[i].object3D); |
||||
} |
||||
|
||||
el.sceneEl.addEventListener('renderstart', function () { |
||||
dragControls = new THREE.DragControls(objects, el.sceneEl.camera, el.sceneEl.renderer.domElement); |
||||
}); |
||||
} |
||||
}); |
@ -0,0 +1,89 @@ |
||||
/* global AFRAME, THREE */ |
||||
|
||||
/** |
||||
* Handles events coming from the hand-controls. |
||||
* Determines if the entity is grabbed or released. |
||||
* Updates its position to move along the controller. |
||||
*/ |
||||
AFRAME.registerComponent('grab', { |
||||
init: function () { |
||||
this.GRABBED_STATE = 'grabbed'; |
||||
// Bind event handlers
|
||||
this.onHit = this.onHit.bind(this); |
||||
this.onGripOpen = this.onGripOpen.bind(this); |
||||
this.onGripClose = this.onGripClose.bind(this); |
||||
this.currentPosition = new THREE.Vector3(); |
||||
}, |
||||
|
||||
play: function () { |
||||
var el = this.el; |
||||
el.addEventListener('hit', this.onHit); |
||||
el.addEventListener('buttondown', this.onGripClose); |
||||
el.addEventListener('buttonup', this.onGripOpen); |
||||
}, |
||||
|
||||
pause: function () { |
||||
var el = this.el; |
||||
el.removeEventListener('hit', this.onHit); |
||||
el.addEventListener('buttondown', this.onGripClose); |
||||
el.addEventListener('buttonup', this.onGripOpen); |
||||
}, |
||||
|
||||
onGripClose: function (evt) { |
||||
if (this.grabbing) { return; } |
||||
this.grabbing = true; |
||||
this.pressedButtonId = evt.detail.id; |
||||
delete this.previousPosition; |
||||
}, |
||||
|
||||
onGripOpen: function (evt) { |
||||
var hitEl = this.hitEl; |
||||
if (this.pressedButtonId !== evt.detail.id) { return; } |
||||
this.grabbing = false; |
||||
if (!hitEl) { return; } |
||||
hitEl.removeState(this.GRABBED_STATE); |
||||
hitEl.emit('grabend'); |
||||
this.hitEl = undefined; |
||||
}, |
||||
|
||||
onHit: function (evt) { |
||||
var hitEl = evt.detail.el; |
||||
// If the element is already grabbed (it could be grabbed by another controller).
|
||||
// If the hand is not grabbing the element does not stick.
|
||||
// If we're already grabbing something you can't grab again.
|
||||
if (!hitEl || hitEl.is(this.GRABBED_STATE) || !this.grabbing || this.hitEl) { return; } |
||||
hitEl.addState(this.GRABBED_STATE); |
||||
this.hitEl = hitEl; |
||||
}, |
||||
|
||||
tick: function () { |
||||
var hitEl = this.hitEl; |
||||
var position; |
||||
if (!hitEl) { return; } |
||||
this.updateDelta(); |
||||
position = hitEl.getAttribute('position'); |
||||
hitEl.setAttribute('position', { |
||||
x: position.x + this.deltaPosition.x, |
||||
y: position.y + this.deltaPosition.y, |
||||
z: position.z + this.deltaPosition.z |
||||
}); |
||||
}, |
||||
|
||||
updateDelta: function () { |
||||
var currentPosition = this.currentPosition; |
||||
this.el.object3D.updateMatrixWorld(); |
||||
currentPosition.setFromMatrixPosition(this.el.object3D.matrixWorld); |
||||
if (!this.previousPosition) { |
||||
this.previousPosition = new THREE.Vector3(); |
||||
this.previousPosition.copy(currentPosition); |
||||
} |
||||
var previousPosition = this.previousPosition; |
||||
var deltaPosition = { |
||||
x: currentPosition.x - previousPosition.x, |
||||
y: currentPosition.y - previousPosition.y, |
||||
z: currentPosition.z - previousPosition.z |
||||
}; |
||||
this.previousPosition.copy(currentPosition); |
||||
this.deltaPosition = deltaPosition; |
||||
} |
||||
}); |
@ -1,6 +1,26 @@ |
||||
<a-scene background="color: #FAFAFA" vr-mode-ui="enterVRButton: #vrButton"> |
||||
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" shadow></a-box> |
||||
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E" shadow></a-sphere> |
||||
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D" shadow></a-cylinder> |
||||
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow></a-plane> |
||||
<a-scene drag-controls="objects: .cube" background="color: #FAFAFA" vr-mode-ui="enterVRButton: #vrButton"> |
||||
<a-assets> |
||||
<a-mixin id="cube" |
||||
event-set__grab="material.color: #FFEF4F" |
||||
event-set__grabend="material.color: #F2E646" |
||||
event-set__hit="material.color: #F2E646" |
||||
event-set__hitend="material.color: #EF2D5E" |
||||
event-set__mousedown="material.color: #FFEF4F" |
||||
event-set__mouseenter="material.color: #F2E646" |
||||
event-set__mouseleave="material.color: #EF2D5E" |
||||
event-set__mouseup="material.color: #F2E646" |
||||
geometry="primitive: box; height: 0.30; width: 0.30; depth: 0.30" |
||||
material="color: #EF2D5E;"> |
||||
</a-mixin> |
||||
</a-assets> |
||||
|
||||
<a-entity class="cube" mixin="cube" position="0.30 1.65 0"></a-entity> |
||||
<a-entity class="cube" mixin="cube" position="0 1.95 0"></a-entity> |
||||
<a-entity class="cube" mixin="cube" position="-0.30 1.65 0"></a-entity> |
||||
|
||||
<a-entity environment="preset: forest;"></a-entity> |
||||
<a-entity hand-controls="left" aabb-collider="objects: .cube;" grab></a-entity> |
||||
<a-entity hand-controls="right" aabb-collider="objects: .cube;" grab></a-entity> |
||||
<a-entity position="0 1.6 2" camera look-controls wasd-controls></a-entity> |
||||
|
||||
</a-scene> |
@ -0,0 +1,282 @@ |
||||
/* |
||||
* @author zz85 / https://github.com/zz85
|
||||
* @author mrdoob / http://mrdoob.com
|
||||
* Running this will allow you to drag three.js objects around the screen. |
||||
*/ |
||||
|
||||
THREE.DragControls = function ( _objects, _camera, _domElement ) { |
||||
|
||||
if ( _objects instanceof THREE.Camera ) { |
||||
|
||||
console.warn( 'THREE.DragControls: Constructor now expects ( objects, camera, domElement )' ); |
||||
var temp = _objects; _objects = _camera; _camera = temp; |
||||
|
||||
} |
||||
|
||||
var _plane = new THREE.Plane(); |
||||
var _raycaster = new THREE.Raycaster(); |
||||
|
||||
var _mouse = new THREE.Vector2(); |
||||
var _offset = new THREE.Vector3(); |
||||
var _intersection = new THREE.Vector3(); |
||||
|
||||
var _selected = null, _hovered = null; |
||||
|
||||
//
|
||||
|
||||
var scope = this; |
||||
|
||||
function activate() { |
||||
|
||||
_domElement.addEventListener( 'mousemove', onDocumentMouseMove, false ); |
||||
_domElement.addEventListener( 'mousedown', onDocumentMouseDown, false ); |
||||
_domElement.addEventListener( 'mouseup', onDocumentMouseCancel, false ); |
||||
_domElement.addEventListener( 'mouseleave', onDocumentMouseCancel, false ); |
||||
_domElement.addEventListener( 'touchmove', onDocumentTouchMove, false ); |
||||
_domElement.addEventListener( 'touchstart', onDocumentTouchStart, false ); |
||||
_domElement.addEventListener( 'touchend', onDocumentTouchEnd, false ); |
||||
|
||||
} |
||||
|
||||
function deactivate() { |
||||
|
||||
_domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false ); |
||||
_domElement.removeEventListener( 'mousedown', onDocumentMouseDown, false ); |
||||
_domElement.removeEventListener( 'mouseup', onDocumentMouseCancel, false ); |
||||
_domElement.removeEventListener( 'mouseleave', onDocumentMouseCancel, false ); |
||||
_domElement.removeEventListener( 'touchmove', onDocumentTouchMove, false ); |
||||
_domElement.removeEventListener( 'touchstart', onDocumentTouchStart, false ); |
||||
_domElement.removeEventListener( 'touchend', onDocumentTouchEnd, false ); |
||||
|
||||
} |
||||
|
||||
function dispose() { |
||||
|
||||
deactivate(); |
||||
|
||||
} |
||||
|
||||
function onDocumentMouseMove( event ) { |
||||
|
||||
event.preventDefault(); |
||||
|
||||
var rect = _domElement.getBoundingClientRect(); |
||||
|
||||
_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; |
||||
_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; |
||||
|
||||
_raycaster.setFromCamera( _mouse, _camera ); |
||||
|
||||
if ( _selected && scope.enabled ) { |
||||
|
||||
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
||||
|
||||
_selected.position.copy( _intersection.sub( _offset ) ); |
||||
|
||||
} |
||||
|
||||
scope.dispatchEvent( { type: 'drag', object: _selected } ); |
||||
|
||||
return; |
||||
|
||||
} |
||||
|
||||
_raycaster.setFromCamera( _mouse, _camera ); |
||||
|
||||
var intersects = _raycaster.intersectObjects( _objects, true ); |
||||
|
||||
if ( intersects.length > 0 ) { |
||||
|
||||
var object = intersects[ 0 ].object.parent; |
||||
|
||||
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), object.position ); |
||||
|
||||
if ( _hovered !== object ) { |
||||
|
||||
scope.dispatchEvent( { type: 'hoveron', object: object } ); |
||||
|
||||
_domElement.style.cursor = 'pointer'; |
||||
_hovered = object; |
||||
|
||||
} |
||||
|
||||
} else { |
||||
|
||||
if ( _hovered !== null ) { |
||||
|
||||
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); |
||||
|
||||
_domElement.style.cursor = 'auto'; |
||||
_hovered = null; |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
function onDocumentMouseDown( event ) { |
||||
|
||||
event.preventDefault(); |
||||
|
||||
_raycaster.setFromCamera( _mouse, _camera ); |
||||
|
||||
var intersects = _raycaster.intersectObjects( _objects, true ); |
||||
|
||||
if ( intersects.length > 0 ) { |
||||
|
||||
_selected = intersects[ 0 ].object.parent; |
||||
|
||||
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
||||
|
||||
_offset.copy( _intersection ).sub( _selected.position ); |
||||
|
||||
} |
||||
|
||||
_domElement.style.cursor = 'move'; |
||||
|
||||
scope.dispatchEvent( { type: 'dragstart', object: _selected } ); |
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
function onDocumentMouseCancel( event ) { |
||||
|
||||
event.preventDefault(); |
||||
|
||||
if ( _selected ) { |
||||
|
||||
scope.dispatchEvent( { type: 'dragend', object: _selected } ); |
||||
|
||||
_selected = null; |
||||
|
||||
} |
||||
|
||||
_domElement.style.cursor = 'auto'; |
||||
|
||||
} |
||||
|
||||
function onDocumentTouchMove( event ) { |
||||
|
||||
event.preventDefault(); |
||||
event = event.changedTouches[ 0 ]; |
||||
|
||||
var rect = _domElement.getBoundingClientRect(); |
||||
|
||||
_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; |
||||
_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; |
||||
|
||||
_raycaster.setFromCamera( _mouse, _camera ); |
||||
|
||||
if ( _selected && scope.enabled ) { |
||||
|
||||
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
||||
|
||||
_selected.position.copy( _intersection.sub( _offset ) ); |
||||
|
||||
} |
||||
|
||||
scope.dispatchEvent( { type: 'drag', object: _selected } ); |
||||
|
||||
return; |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
function onDocumentTouchStart( event ) { |
||||
|
||||
event.preventDefault(); |
||||
event = event.changedTouches[ 0 ]; |
||||
|
||||
var rect = _domElement.getBoundingClientRect(); |
||||
|
||||
_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; |
||||
_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; |
||||
|
||||
_raycaster.setFromCamera( _mouse, _camera ); |
||||
|
||||
var intersects = _raycaster.intersectObjects( _objects, true ); |
||||
|
||||
if ( intersects.length > 0 ) { |
||||
|
||||
_selected = intersects[ 0 ].object.parent; |
||||
|
||||
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _selected.position ); |
||||
|
||||
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
||||
|
||||
_offset.copy( _intersection ).sub( _selected.position ); |
||||
|
||||
} |
||||
|
||||
_domElement.style.cursor = 'move'; |
||||
|
||||
scope.dispatchEvent( { type: 'dragstart', object: _selected } ); |
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
function onDocumentTouchEnd( event ) { |
||||
|
||||
event.preventDefault(); |
||||
|
||||
if ( _selected ) { |
||||
|
||||
scope.dispatchEvent( { type: 'dragend', object: _selected } ); |
||||
|
||||
_selected = null; |
||||
|
||||
} |
||||
|
||||
_domElement.style.cursor = 'auto'; |
||||
|
||||
} |
||||
|
||||
activate(); |
||||
|
||||
// API
|
||||
|
||||
this.enabled = true; |
||||
|
||||
this.activate = activate; |
||||
this.deactivate = deactivate; |
||||
this.dispose = dispose; |
||||
|
||||
// Backward compatibility
|
||||
|
||||
this.setObjects = function () { |
||||
|
||||
console.error( 'THREE.DragControls: setObjects() has been removed.' ); |
||||
|
||||
}; |
||||
|
||||
this.on = function ( type, listener ) { |
||||
|
||||
console.warn( 'THREE.DragControls: on() has been deprecated. Use addEventListener() instead.' ); |
||||
scope.addEventListener( type, listener ); |
||||
|
||||
}; |
||||
|
||||
this.off = function ( type, listener ) { |
||||
|
||||
console.warn( 'THREE.DragControls: off() has been deprecated. Use removeEventListener() instead.' ); |
||||
scope.removeEventListener( type, listener ); |
||||
|
||||
}; |
||||
|
||||
this.notify = function ( type ) { |
||||
|
||||
console.error( 'THREE.DragControls: notify() has been deprecated. Use dispatchEvent() instead.' ); |
||||
scope.dispatchEvent( { type: type } ); |
||||
|
||||
}; |
||||
|
||||
}; |
||||
|
||||
THREE.DragControls.prototype = Object.create( THREE.EventDispatcher.prototype ); |
||||
THREE.DragControls.prototype.constructor = THREE.DragControls; |
Loading…
Reference in new issue