summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authorsimonrad@chromium.org <simonrad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-24 19:45:57 +0000
committersimonrad@chromium.org <simonrad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-11-24 19:45:57 +0000
commitf06e54d0eccbb4df6ea4f0e13f95565760e54ce0 (patch)
tree354f77d3c666f32b94967077f8e80226eecafac0 /o3d
parentdfeb5959aca20ddf51428ce4b2db17e172404b89 (diff)
downloadchromium_src-f06e54d0eccbb4df6ea4f0e13f95565760e54ce0.zip
chromium_src-f06e54d0eccbb4df6ea4f0e13f95565760e54ce0.tar.gz
chromium_src-f06e54d0eccbb4df6ea4f0e13f95565760e54ce0.tar.bz2
Added new way of dragging the Rotate1 manipulator (linear mapping in screen space).
BUG=none TEST=none Review URL: http://codereview.chromium.org/413007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@32958 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r--o3d/samples/manipulators/rotate1.html10
-rw-r--r--o3d/samples/o3djs/manipulators.js169
2 files changed, 119 insertions, 60 deletions
diff --git a/o3d/samples/manipulators/rotate1.html b/o3d/samples/manipulators/rotate1.html
index 226001e..e7c95d4 100644
--- a/o3d/samples/manipulators/rotate1.html
+++ b/o3d/samples/manipulators/rotate1.html
@@ -30,9 +30,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->
<!--
-Translate2 manipulator
+Rotate1 manipulator
-This sample shows how to use the o3djs.manipulators.Translate2 class
+This sample shows how to use the o3djs.manipulators.Rotate1 class
to interactively drag objects around the scene.
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
@@ -41,7 +41,7 @@ to interactively drag objects around the scene.
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>
-Translate2 Manipulator
+Rotate1 Manipulator
</title>
<script type="text/javascript" src="../o3djs/base.js"></script>
<script type="text/javascript" id="o3dscript">
@@ -271,9 +271,9 @@ function unload() {
</script>
</head>
<body onload="initClient()" onunload="unload()">
-<h1>Translate2 Manipulator Sample</h1>
+<h1>Rotate1 Manipulator Sample</h1>
This example shows how to move objects around the scene using the
-Translate2 manipulator.
+Rotate1 manipulator.
<br/>
<!-- Start of O3D plugin -->
<div id="o3d" style="width: 600px; height: 600px;"></div>
diff --git a/o3d/samples/o3djs/manipulators.js b/o3d/samples/o3djs/manipulators.js
index db44344..74cc79e 100644
--- a/o3d/samples/o3djs/manipulators.js
+++ b/o3d/samples/o3djs/manipulators.js
@@ -736,7 +736,8 @@ o3djs.manipulators.Manager.prototype.mousemove = function(x,
o3djs.picking.clientPositionToWorldRayEx(x, y,
view, projection,
width, height);
- this.draggedManip_.drag(worldRay.near, worldRay.far);
+ this.draggedManip_.drag(worldRay.near, worldRay.far,
+ x, y, view, projection, width, height);
} else {
this.handleMouse_(x, y, view, projection, width, height,
o3djs.manipulators.hoverCallback_);
@@ -988,16 +989,29 @@ o3djs.manipulators.Manip.prototype.makeInactive = function() {
/**
* Drags this manipulator according to the world-space ray specified
- * by startPoint and endPoint. makeActive must already have been
+ * by startPoint and endPoint, or alternatively the screen space mouse
+ * coordinate specified by x and y. makeActive must already have been
* called with the initial pick result causing this manipulator to
* become active.
* @param {!o3djs.math.Vector3} startPoint Start point of the
* world-space ray through the current mouse position.
* @param {!o3djs.math.Vector3} endPoint End point of the world-space
* ray through the current mouse position.
+ * @param {number} x The x coordinate of the current mouse position.
+ * @param {number} y The y coordinate of the current mouse position.
+ * @param {!o3djs.math.Matrix4} view The current view matrix.
+ * @param {!o3djs.math.Matrix4} projection The current projection matrix.
+ * @param {number} width The width of the viewport.
+ * @param {number} height The height of the viewport.
*/
o3djs.manipulators.Manip.prototype.drag = function(startPoint,
- endPoint) {
+ endPoint,
+ x,
+ y,
+ view,
+ projection,
+ width,
+ height) {
}
/**
@@ -1195,10 +1209,10 @@ o3djs.manipulators.Translate1.prototype.clearHighlight = function() {
o3djs.manipulators.Translate1.prototype.makeActive = function(pickResult) {
o3djs.manipulators.Manip.prototype.makeActive.call(this, pickResult);
this.highlight(pickResult);
- var worldMatrix = this.getTransform().worldMatrix;
+ var localToWorld = this.getTransform().worldMatrix;
this.dragLine_.setDirection(
- o3djs.math.matrix4.transformDirection(worldMatrix,
- o3djs.manipulators.X_AXIS));
+ o3djs.math.matrix4.transformDirection(localToWorld,
+ o3djs.manipulators.X_AXIS));
this.dragLine_.setPoint(pickResult.worldIntersectionPosition);
}
@@ -1210,7 +1224,13 @@ o3djs.manipulators.Translate1.prototype.makeInactive = function() {
}
o3djs.manipulators.Translate1.prototype.drag = function(startPoint,
- endPoint) {
+ endPoint,
+ x,
+ y,
+ view,
+ projection,
+ width,
+ height) {
// Algorithm: Find closest point of ray to dragLine_. Subtract this
// point from the line's point to find difference vector; transform
// from world to local coordinates to find new local offset of
@@ -1300,10 +1320,10 @@ o3djs.manipulators.Translate2.prototype.clearHighlight = function() {
o3djs.manipulators.Translate2.prototype.makeActive = function(pickResult) {
o3djs.manipulators.Manip.prototype.makeActive.call(this, pickResult);
this.highlight(pickResult);
- var worldMatrix = this.getTransform().worldMatrix;
+ var localToWorld = this.getTransform().worldMatrix;
this.dragPlane_.setNormal(
- o3djs.math.matrix4.transformDirection(worldMatrix,
- o3djs.manipulators.Z_AXIS));
+ o3djs.math.matrix4.transformDirection(localToWorld,
+ o3djs.manipulators.Z_AXIS));
this.dragPlane_.setPoint(pickResult.worldIntersectionPosition);
}
@@ -1315,7 +1335,13 @@ o3djs.manipulators.Translate2.prototype.makeInactive = function() {
}
o3djs.manipulators.Translate2.prototype.drag = function(startPoint,
- endPoint) {
+ endPoint,
+ x,
+ y,
+ view,
+ projection,
+ width,
+ height) {
// Algorithm: Find intersection of ray with dragPlane_. Subtract this
// point from the plane's point to find difference vector; transform
// from world to local coordinates to find new local offset of
@@ -1384,11 +1410,12 @@ o3djs.manipulators.Rotate1 = function(manager) {
this.clearHighlight();
/**
- * Plane around which we are dragging.
+ * Line along which we are dragging.
+ * We just use this to store the point and direction, not to do any math.
* @private
- * @type {!o3djs.manipulators.Plane_}
+ * @type {!o3djs.manipulators.Line_}
*/
- this.dragPlane_ = new o3djs.manipulators.Plane_();
+ this.dragLine_ = new o3djs.manipulators.Line_();
}
o3djs.base.inherit(o3djs.manipulators.Rotate1, o3djs.manipulators.Manip);
@@ -1407,11 +1434,25 @@ o3djs.manipulators.Rotate1.prototype.clearHighlight = function() {
o3djs.manipulators.Rotate1.prototype.makeActive = function(pickResult) {
o3djs.manipulators.Manip.prototype.makeActive.call(this, pickResult);
this.highlight(pickResult);
- var worldMatrix = this.getTransform().worldMatrix;
- this.dragPlane_.setNormal(
- o3djs.math.matrix4.transformDirection(worldMatrix,
- o3djs.manipulators.X_AXIS));
- this.dragPlane_.setPoint(pickResult.worldIntersectionPosition);
+ var localToWorld = this.getTransform().worldMatrix;
+ var worldToLocal = o3djs.math.matrix4.inverse(localToWorld);
+
+ // Set up the line. The line is tangent to the circle of rotation
+ // and passes through the initial pickResult.
+ // Do the math in local space.
+ // The rotation axis is the X axis, centered at the origin.
+ var localIntersectionPosition =
+ o3djs.math.matrix4.transformPoint(worldToLocal,
+ pickResult.worldIntersectionPosition);
+ var localLineDirection = o3djs.math.cross(localIntersectionPosition,
+ o3djs.manipulators.X_AXIS);
+ this.dragLine_.setDirection(
+ o3djs.math.matrix4.transformDirection(localToWorld,
+ localLineDirection));
+ this.dragLine_.setPoint(pickResult.worldIntersectionPosition);
+
+ // TODO(simonrad): It would be nice to draw an arrow on the screen
+ // at the click position, indicating the direction of the line.
}
o3djs.manipulators.Rotate1.prototype.makeInactive = function() {
@@ -1421,42 +1462,60 @@ o3djs.manipulators.Rotate1.prototype.makeInactive = function() {
this.updateBaseTransformFromAttachedTransform_();
}
-o3djs.manipulators.Rotate1.prototype.drag = function(startPoint,
- endPoint) {
- // Algorithm: Find intersection of ray with dragPlane_. Transform
- // everything from world to local coordinates. Find angle of the
- // initial and final plane intersection points about the rotation
- // axis. Subtract these to find the rotation angle.
- var worldIntersectPoint = this.dragPlane_.intersectRay(startPoint,
- o3djs.math.subVector(endPoint, startPoint));
- if (worldIntersectPoint == null) {
- // Drag plane is parallel to ray. Punt.
- return;
- }
-
- // We don't want the current drag state to affect our world-to-local
- // transform, since we are calculating the drag from scratch.
- this.getTransform().localMatrix = o3djs.math.matrix4.identity();
-
- // Need to do a world-to-local transformation on all the points.
- var worldToLocal =
- o3djs.math.matrix4.inverse(this.getTransform().worldMatrix);
-
- // All of these are in local space.
- var dragStart = o3djs.math.matrix4.transformPoint(worldToLocal,
- this.dragPlane_.getPoint());
- var dragEnd = o3djs.math.matrix4.transformPoint(worldToLocal,
- worldIntersectPoint);
- // Since this should all be happening in a YZ plane, we can discard
- // the X components.
- dragStart[0] = 0;
- dragEnd[0] = 0;
-
- // The point that we are rotating around is the origin (in local space).
-
- var diffAngle = Math.atan2(dragEnd[1], dragEnd[2]) -
- Math.atan2(dragStart[1], dragStart[2]);
+/**
+ * Convert the specified frustum-space position into
+ * client coordinates (ie pixels).
+ * @private
+ * @param {!o3djs.math.Vector3} frustumPoint The point in frustum coordinates
+ * to transform.
+ * @param {number} width The width of the viewport.
+ * @param {number} height The height of the viewport.
+ * @return {!o3djs.math.Vector2} The location of frustumPoint on the screen,
+ * in client coordinates.
+ */
+o3djs.manipulators.frustumPositionToClientPosition_ = function(frustumPoint,
+ width,
+ height) {
+ return [(frustumPoint[0] + 1) * width / 2,
+ (-frustumPoint[1] + 1) * height / 2];
+}
- this.getTransform().localMatrix = o3djs.math.matrix4.rotationX(-diffAngle);
+o3djs.manipulators.Rotate1.prototype.drag = function(startPoint,
+ endPoint,
+ x,
+ y,
+ view,
+ projection,
+ width,
+ height) {
+ // Use a simple linear mouse mapping based on distance along the tangent line.
+ // Do the dragging in client (screen space) coordinates. This eliminates any
+ // degenerate cases involved with a 3D line.
+
+ // Compute the position and direction of the line in screen coordinates.
+ var viewProjectionMatrix = o3djs.math.matrix4.mul(view, projection);
+ var linePoint1 = o3djs.manipulators.frustumPositionToClientPosition_(
+ o3djs.math.matrix4.transformPoint(viewProjectionMatrix,
+ this.dragLine_.getPoint()),
+ width, height);
+ var linePoint2 = o3djs.manipulators.frustumPositionToClientPosition_(
+ o3djs.math.matrix4.transformPoint(viewProjectionMatrix,
+ o3djs.math.addVector(
+ this.dragLine_.getPoint(),
+ this.dragLine_.getDirection()
+ )),
+ width, height);
+ var lineDirection = o3djs.math.normalize(o3djs.math.subVector(linePoint2,
+ linePoint1));
+ var mousePoint = [x, y];
+
+ // The distance *along the line* that we have dragged, in pixels.
+ var dragDistance = o3djs.math.dot(lineDirection, mousePoint) -
+ o3djs.math.dot(lineDirection, linePoint1);
+
+ // Determine rotation angle based on drag distance relative to
+ // the size of the client area.
+ var angle = (dragDistance / Math.max(width, height)) * 2 * Math.PI;
+ this.getTransform().localMatrix = o3djs.math.matrix4.rotationX(-angle);
this.updateAttachedTransformFromLocalTransform_();
}