summaryrefslogtreecommitdiffstats
path: root/o3d/samples
diff options
context:
space:
mode:
authorsimonrad@chromium.org <simonrad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-10 06:16:51 +0000
committersimonrad@chromium.org <simonrad@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-12-10 06:16:51 +0000
commit791d861fb0ee9fe2bdb0f62131a34c55a7f312bb (patch)
tree7bf6736c6c9d348eb5c876ffe23b10727e46e360 /o3d/samples
parent867125a08f77a22b770f197d90519a8672af83aa (diff)
downloadchromium_src-791d861fb0ee9fe2bdb0f62131a34c55a7f312bb.zip
chromium_src-791d861fb0ee9fe2bdb0f62131a34c55a7f312bb.tar.gz
chromium_src-791d861fb0ee9fe2bdb0f62131a34c55a7f312bb.tar.bz2
Add line stippling and add functionality to the CameraController.
- Added optional line stippling based on texCoords to the rotate1 line ring shader. - Redesigned the CameraController and added the ability to zoom, dolly, dolly-zoom, and pan using the mouse. BUG=none TEST=none Review URL: http://codereview.chromium.org/486003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@34235 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/samples')
-rw-r--r--o3d/samples/manipulators/rotate1.html67
-rw-r--r--o3d/samples/manipulators/translate1.html67
-rw-r--r--o3d/samples/manipulators/translate2.html67
-rw-r--r--o3d/samples/o3djs/cameracontroller.js205
-rw-r--r--o3d/samples/o3djs/lineprimitives.js13
-rw-r--r--o3d/samples/o3djs/manipulators.js159
6 files changed, 406 insertions, 172 deletions
diff --git a/o3d/samples/manipulators/rotate1.html b/o3d/samples/manipulators/rotate1.html
index 7f4f27d..cb78ef1 100644
--- a/o3d/samples/manipulators/rotate1.html
+++ b/o3d/samples/manipulators/rotate1.html
@@ -111,9 +111,22 @@ function main(clientElements) {
}
function onMouseDown(e) {
- if(e.button == 2) {
- g_cameraController.mousedown(e);
- } else {
+ if(e.button == 2 && !e.shiftKey && !e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.SPIN_ABOUT_CENTER, e.x, e.y);
+ } else if(e.button == 2 && e.shiftKey && !e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.ZOOM_IN_OUT, e.x, e.y);
+ } else if(e.button == 2 && !e.shiftKey && e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.DOLLY_IN_OUT, e.x, e.y);
+ } else if(e.button == 2 && e.shiftKey && e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.DOLLY_ZOOM, e.x, e.y);
+ } else if(e.button == 1) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.MOVE_CENTER_IN_VIEW_PLANE, e.x, e.y);
+ } else if(e.button == 0) {
g_manager.mousedown(e.x, e.y,
g_mainViewInfo.drawContext.view,
g_mainViewInfo.drawContext.projection,
@@ -123,8 +136,12 @@ function onMouseDown(e) {
}
function onMouseMove(e) {
- g_cameraController.mousemove(e);
- g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix();
+ g_cameraController.mouseMoved(e.x, e.y);
+
+ // You can call this function here, or pass it to the CameraController
+ // as the onChange callback.
+ //updateViewAndProjectionMatrices();
+
g_manager.mousemove(e.x, e.y,
g_mainViewInfo.drawContext.view,
g_mainViewInfo.drawContext.projection,
@@ -134,12 +151,11 @@ function onMouseMove(e) {
}
function onMouseUp(e) {
- if(e.button == 2) {
- g_cameraController.mouseup(e);
- } else {
- g_manager.mouseup();
- g_manager.updateInactiveManipulators();
- }
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.NONE, e.x, e.y);
+
+ g_manager.mouseup();
+ g_manager.updateInactiveManipulators();
}
/**
@@ -168,20 +184,27 @@ function initGlobals(clientElements) {
* Sets up reasonable view and projection matrices.
*/
function initContext() {
+ // Set up our CameraController.
+ g_cameraController = o3djs.cameracontroller.createCameraController(
+ [0, 2, 0], // centerPos
+ 23, // backpedal
+ 0, // heightAngle
+ 0, // rotationAngle
+ g_math.degToRad(15), // fieldOfViewAngle
+ updateViewAndProjectionMatrices); // opt_onChange
+
+ updateViewAndProjectionMatrices();
+}
+
+function updateViewAndProjectionMatrices() {
+ g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix();
+
// Set up a perspective transformation for the projection.
g_mainViewInfo.drawContext.projection = g_math.matrix4.perspective(
- g_math.degToRad(30), // 30 degree frustum.
+ g_cameraController.fieldOfViewAngle * 2, // Frustum angle.
g_o3dElement.clientWidth / g_o3dElement.clientHeight, // Aspect ratio.
- 1, // Near plane.
- 5000); // Far plane.
-
- // Set up our view transformation using our CameraController.
- g_cameraController = o3djs.cameracontroller.createCameraController(
- [0, 2, 0], // centerPos
- 23, // backpedal
- 0, // heightAngle
- 0); // rotationAngle
- g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix();
+ 1, // Near plane.
+ 5000); // Far plane.
}
/**
diff --git a/o3d/samples/manipulators/translate1.html b/o3d/samples/manipulators/translate1.html
index 06c7193..10b4df6 100644
--- a/o3d/samples/manipulators/translate1.html
+++ b/o3d/samples/manipulators/translate1.html
@@ -111,9 +111,22 @@ function main(clientElements) {
}
function onMouseDown(e) {
- if(e.button == 2) {
- g_cameraController.mousedown(e);
- } else {
+ if(e.button == 2 && !e.shiftKey && !e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.SPIN_ABOUT_CENTER, e.x, e.y);
+ } else if(e.button == 2 && e.shiftKey && !e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.ZOOM_IN_OUT, e.x, e.y);
+ } else if(e.button == 2 && !e.shiftKey && e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.DOLLY_IN_OUT, e.x, e.y);
+ } else if(e.button == 2 && e.shiftKey && e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.DOLLY_ZOOM, e.x, e.y);
+ } else if(e.button == 1) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.MOVE_CENTER_IN_VIEW_PLANE, e.x, e.y);
+ } else if(e.button == 0) {
g_manager.mousedown(e.x, e.y,
g_mainViewInfo.drawContext.view,
g_mainViewInfo.drawContext.projection,
@@ -123,8 +136,12 @@ function onMouseDown(e) {
}
function onMouseMove(e) {
- g_cameraController.mousemove(e);
- g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix();
+ g_cameraController.mouseMoved(e.x, e.y);
+
+ // You can call this function here, or pass it to the CameraController
+ // as the onChange callback.
+ //updateViewAndProjectionMatrices();
+
g_manager.mousemove(e.x, e.y,
g_mainViewInfo.drawContext.view,
g_mainViewInfo.drawContext.projection,
@@ -134,12 +151,11 @@ function onMouseMove(e) {
}
function onMouseUp(e) {
- if(e.button == 2) {
- g_cameraController.mouseup(e);
- } else {
- g_manager.mouseup();
- g_manager.updateInactiveManipulators();
- }
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.NONE, e.x, e.y);
+
+ g_manager.mouseup();
+ g_manager.updateInactiveManipulators();
}
/**
@@ -168,20 +184,27 @@ function initGlobals(clientElements) {
* Sets up reasonable view and projection matrices.
*/
function initContext() {
+ // Set up our CameraController.
+ g_cameraController = o3djs.cameracontroller.createCameraController(
+ [0, 2, 0], // centerPos
+ 23, // backpedal
+ 0, // heightAngle
+ 0, // rotationAngle
+ g_math.degToRad(15), // fieldOfViewAngle
+ updateViewAndProjectionMatrices); // opt_onChange
+
+ updateViewAndProjectionMatrices();
+}
+
+function updateViewAndProjectionMatrices() {
+ g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix();
+
// Set up a perspective transformation for the projection.
g_mainViewInfo.drawContext.projection = g_math.matrix4.perspective(
- g_math.degToRad(30), // 30 degree frustum.
+ g_cameraController.fieldOfViewAngle * 2, // Frustum angle.
g_o3dElement.clientWidth / g_o3dElement.clientHeight, // Aspect ratio.
- 1, // Near plane.
- 5000); // Far plane.
-
- // Set up our view transformation using our CameraController.
- g_cameraController = o3djs.cameracontroller.createCameraController(
- [0, 2, 0], // centerPos
- 23, // backpedal
- 0, // heightAngle
- 0); // rotationAngle
- g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix();
+ 1, // Near plane.
+ 5000); // Far plane.
}
/**
diff --git a/o3d/samples/manipulators/translate2.html b/o3d/samples/manipulators/translate2.html
index a284f89..48cc6ee 100644
--- a/o3d/samples/manipulators/translate2.html
+++ b/o3d/samples/manipulators/translate2.html
@@ -111,9 +111,22 @@ function main(clientElements) {
}
function onMouseDown(e) {
- if(e.button == 2) {
- g_cameraController.mousedown(e);
- } else {
+ if(e.button == 2 && !e.shiftKey && !e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.SPIN_ABOUT_CENTER, e.x, e.y);
+ } else if(e.button == 2 && e.shiftKey && !e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.ZOOM_IN_OUT, e.x, e.y);
+ } else if(e.button == 2 && !e.shiftKey && e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.DOLLY_IN_OUT, e.x, e.y);
+ } else if(e.button == 2 && e.shiftKey && e.ctrlKey) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.DOLLY_ZOOM, e.x, e.y);
+ } else if(e.button == 1) {
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.MOVE_CENTER_IN_VIEW_PLANE, e.x, e.y);
+ } else if(e.button == 0) {
g_manager.mousedown(e.x, e.y,
g_mainViewInfo.drawContext.view,
g_mainViewInfo.drawContext.projection,
@@ -123,8 +136,12 @@ function onMouseDown(e) {
}
function onMouseMove(e) {
- g_cameraController.mousemove(e);
- g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix();
+ g_cameraController.mouseMoved(e.x, e.y);
+
+ // You can call this function here, or pass it to the CameraController
+ // as the onChange callback.
+ //updateViewAndProjectionMatrices();
+
g_manager.mousemove(e.x, e.y,
g_mainViewInfo.drawContext.view,
g_mainViewInfo.drawContext.projection,
@@ -134,12 +151,11 @@ function onMouseMove(e) {
}
function onMouseUp(e) {
- if(e.button == 2) {
- g_cameraController.mouseup(e);
- } else {
- g_manager.mouseup();
- g_manager.updateInactiveManipulators();
- }
+ g_cameraController.setDragMode(
+ o3djs.cameracontroller.DragMode.NONE, e.x, e.y);
+
+ g_manager.mouseup();
+ g_manager.updateInactiveManipulators();
}
/**
@@ -168,20 +184,27 @@ function initGlobals(clientElements) {
* Sets up reasonable view and projection matrices.
*/
function initContext() {
+ // Set up our CameraController.
+ g_cameraController = o3djs.cameracontroller.createCameraController(
+ [0, 2, 0], // centerPos
+ 23, // backpedal
+ 0, // heightAngle
+ 0, // rotationAngle
+ g_math.degToRad(15), // fieldOfViewAngle
+ updateViewAndProjectionMatrices); // opt_onChange
+
+ updateViewAndProjectionMatrices();
+}
+
+function updateViewAndProjectionMatrices() {
+ g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix();
+
// Set up a perspective transformation for the projection.
g_mainViewInfo.drawContext.projection = g_math.matrix4.perspective(
- g_math.degToRad(30), // 30 degree frustum.
+ g_cameraController.fieldOfViewAngle * 2, // Frustum angle.
g_o3dElement.clientWidth / g_o3dElement.clientHeight, // Aspect ratio.
- 1, // Near plane.
- 5000); // Far plane.
-
- // Set up our view transformation using our CameraController.
- g_cameraController = o3djs.cameracontroller.createCameraController(
- [0, 2, 0], // centerPos
- 23, // backpedal
- 0, // heightAngle
- 0); // rotationAngle
- g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix();
+ 1, // Near plane.
+ 5000); // Far plane.
}
/**
diff --git a/o3d/samples/o3djs/cameracontroller.js b/o3d/samples/o3djs/cameracontroller.js
index 9dcb980..612e1cc 100644
--- a/o3d/samples/o3djs/cameracontroller.js
+++ b/o3d/samples/o3djs/cameracontroller.js
@@ -46,6 +46,46 @@ o3djs.require('o3djs.math');
o3djs.cameracontroller = o3djs.cameracontroller || {};
/**
+ * The possible modes that a CameraController can be in.
+ * One of these is usually set when a mouse button is pressed down,
+ * and then NONE is set when the mouse button is released.
+ * When the mouse is moved, the DragMode determines what effect the mouse move
+ * has on the camera parameters (such as position and orientation).
+ * If the DragMode is NONE, mouse moves have no effect.
+ * @enum {number}
+ */
+o3djs.cameracontroller.DragMode = {
+ /**
+ * Dragging the mouse has no effect.
+ */
+ NONE: 0,
+ /**
+ * Dragging left or right changes rotationAngle,
+ * dragging up or down changes heightAngle.
+ */
+ SPIN_ABOUT_CENTER: 1,
+ /**
+ * Dragging up or down changes the backpedal.
+ */
+ DOLLY_IN_OUT: 2,
+ /**
+ * Dragging up or down changes the fieldOfViewAngle.
+ */
+ ZOOM_IN_OUT: 3,
+ /**
+ * Dragging up or down changes the amount of perspective.
+ * Perspective is focused on the centerPos.
+ * If backpedal is negative or zero, there is no effect.
+ */
+ DOLLY_ZOOM: 4,
+ /**
+ * Dragging moves the centerPos around the plane perpendicular to
+ * the camera view direction.
+ */
+ MOVE_CENTER_IN_VIEW_PLANE: 5,
+};
+
+/**
* Creates a CameraController.
* @param {!o3djs.math.Vector3} centerPos The position that the camera is
* looking at and rotating around; or if backpedal is zero, the location
@@ -56,8 +96,12 @@ o3djs.cameracontroller = o3djs.cameracontroller || {};
* (about the x axis that passes through the centerPos). In radians.
* @param {number} rotationAngle The angle the camera rotates left or right
* (about the y axis that passes through the centerPos). In radians.
+ * @param {number} fieldOfViewAngle The vertical angle of the viewing frustum.
+ * In radians, between 0 and PI/2. This does not affect the view matrix,
+ * but it can still be useful to let the CameraController control the
+ * field of view.
* @param {function(!o3djs.cameracontroller.CameraController): void}
- * opt_onchange Pointer to a callback to call when the camera changes.
+ * opt_onChange Pointer to a callback to call when the camera changes.
* @return {!o3djs.cameracontroller.CameraController} The created
* CameraController.
*/
@@ -65,16 +109,27 @@ o3djs.cameracontroller.createCameraController = function(centerPos,
backpedal,
heightAngle,
rotationAngle,
- opt_onchange) {
+ fieldOfViewAngle,
+ opt_onChange) {
return new o3djs.cameracontroller.CameraController(centerPos,
backpedal,
heightAngle,
rotationAngle,
- opt_onchange);
+ fieldOfViewAngle,
+ opt_onChange);
};
/**
* Class to hold user-controlled camera information and handle user events.
+ * It can control and output a view matrix, and can also control some aspects
+ * of a projection matrix.
+ *
+ * Most of the parameters it controls affect the view matrix, and it can
+ * generate a view matrix based on its parameters.
+ * It can also control certain parameters that affect the projection matrix,
+ * such as field of view. Rather than deal with all the parameters needed for
+ * a projection matrix, this class leaves generation of the projection matrix
+ * up to the user code, and simply exposes the parameters it has.
* @constructor
* @param {!o3djs.math.Vector3} centerPos The position that the camera is
* looking at and rotating around; or if backpedal is zero, the location
@@ -85,14 +140,18 @@ o3djs.cameracontroller.createCameraController = function(centerPos,
* (about the x axis that passes through the centerPos). In radians.
* @param {number} rotationAngle The angle the camera rotates left or right
* (about the y axis that passes through the centerPos). In radians.
+ * @param {number} fieldOfViewAngle The vertical angle of the viewing frustum.
+ * In radians, between 0 and PI/2. This does not affect the view matrix,
+ * but it can still be useful to let this class control the field of view.
* @param {function(!o3djs.cameracontroller.CameraController): void}
- * opt_onchange Pointer to a callback to call when the camera changes.
+ * opt_onChange Pointer to a callback to call when the camera changes.
*/
o3djs.cameracontroller.CameraController = function(centerPos,
backpedal,
heightAngle,
rotationAngle,
- opt_onchange) {
+ fieldOfViewAngle,
+ opt_onChange) {
/**
* The position that the camera is looking at and rotating around.
* Or if backpedal is zero, the location of the camera. In world space.
@@ -118,19 +177,28 @@ o3djs.cameracontroller.CameraController = function(centerPos,
*/
this.rotationAngle = rotationAngle;
+ /**
+ * The vertical angle of the perspective viewing frustum.
+ * In radians, between 0 and PI/2. This does not affect the view matrix.
+ * The user code can access this value and use it to construct a
+ * projection matrix, or it can simply ignore it.
+ * @type {number}
+ */
+ this.fieldOfViewAngle = fieldOfViewAngle;
+
/**
* Points to a callback to call when the camera changes.
* @type {function(!o3djs.cameracontroller.CameraController): void}
*/
- this.onchange = opt_onchange || null;
+ this.onChange = opt_onChange || null;
/**
- * Whether the mouse is currently being dragged to control the camera.
+ * The current mouse-drag mode, ie what happens when you move the mouse.
* @private
- * @type {boolean}
+ * @type {o3djs.cameracontroller.DragMode}
*/
- this.dragging_ = false;
+ this.dragMode_ = o3djs.cameracontroller.DragMode.NONE;
/**
* The last X coordinate of the mouse.
@@ -146,18 +214,48 @@ o3djs.cameracontroller.CameraController = function(centerPos,
*/
this.mouseY_ = 0;
+
+ // Some variables to control how quickly the camera changes when you
+ // move the mouse a certain distance. Feel free to modify these.
+ // Mouse pixels are converted into arbitrary "units" (for lack of
+ // a better term), and then "units" are converted into an angle,
+ // or a distance, etc as the case may be.
+
+ /**
+ * Controls how quickly the mouse moves the camera (in general).
+ * Used to convert pixels into "units".
+ * @type {number}
+ */
+ this.pixelsPerUnit = 300.0;
+
+ /**
+ * Controls how quickly the mouse affects rotation angles.
+ * Used to convert "units" into radians.
+ * @type {number}
+ */
+ this.radiansPerUnit = 1.0;
+
+ /**
+ * Controls how quickly the mouse affects camera translation.
+ * Used to convert "units" into world space units of distance.
+ * @type {number}
+ */
+ this.distancePerUnit = 10.0;
+
/**
- * Controls how quickly the mouse moves the camera.
+ * Controls how quickly the mouse affects zooming.
+ * Used to convert "units" into zoom factor.
* @type {number}
*/
- this.dragScaleFactor = 300.0;
+ this.zoomPerUnit = 1.0;
};
/**
* Calculates the view matrix for this camera.
* @return {!o3djs.math.Matrix4} The view matrix.
*/
-o3djs.cameracontroller.CameraController.prototype.calculateViewMatrix = function() {
+o3djs.cameracontroller.CameraController.prototype.calculateViewMatrix =
+ function() {
var matrix4 = o3djs.math.matrix4;
var view = matrix4.translation(o3djs.math.negativeVector(this.centerPos));
view = matrix4.mul(view, matrix4.rotationY(this.rotationAngle));
@@ -167,42 +265,67 @@ o3djs.cameracontroller.CameraController.prototype.calculateViewMatrix = function
};
/**
- * Method which should be called by end user code upon receiving a
- * mouse-down event.
- * @param {!o3d.Event} ev The event.
- */
-o3djs.cameracontroller.CameraController.prototype.mousedown = function(ev) {
- this.dragging_ = true;
- this.mouseX_ = ev.x;
- this.mouseY_ = ev.y;
-};
-
-/**
- * Method which should be called by end user code upon receiving a
- * mouse-up event.
- * @param {!o3d.Event} ev The event.
+ * Change the current mouse-drag mode, ie what happens when you move the mouse.
+ * Usually you would set it to something when a mouse button is pressed down,
+ * and then set it to NONE when the button is released.
+ * @param {o3djs.cameracontroller.DragMode} dragMode The new DragMode.
+ * @param {number} x The current mouse X coordinate.
+ * @param {number} y The current mouse Y coordinate.
*/
-o3djs.cameracontroller.CameraController.prototype.mouseup = function(ev) {
- this.dragging_ = false;
+o3djs.cameracontroller.CameraController.prototype.setDragMode =
+ function(dragMode, x, y) {
+ this.dragMode_ = dragMode;
+ this.mouseX_ = x;
+ this.mouseY_ = y;
};
/**
* Method which should be called by end user code upon receiving a
* mouse-move event.
- * @param {!o3d.Event} ev The event.
+ * @param {number} x The new mouse X coordinate.
+ * @param {number} y The new mouse Y coordinate.
*/
-o3djs.cameracontroller.CameraController.prototype.mousemove = function(ev) {
- if (this.dragging_) {
- var curX = ev.x;
- var curY = ev.y;
- var deltaX = (curX - this.mouseX_) / this.dragScaleFactor;
- var deltaY = (curY - this.mouseY_) / this.dragScaleFactor;
- this.mouseX_ = curX;
- this.mouseY_ = curY;
- this.rotationAngle += deltaX;
- this.heightAngle += deltaY;
- if (this.onchange != null) {
- this.onchange(this);
+o3djs.cameracontroller.CameraController.prototype.mouseMoved = function(x, y) {
+ var deltaX = (x - this.mouseX_) / this.pixelsPerUnit;
+ var deltaY = (y - this.mouseY_) / this.pixelsPerUnit;
+ this.mouseX_ = x;
+ this.mouseY_ = y;
+
+ if (this.dragMode_ == o3djs.cameracontroller.DragMode.SPIN_ABOUT_CENTER) {
+ this.rotationAngle += deltaX * this.radiansPerUnit;
+ this.heightAngle += deltaY * this.radiansPerUnit;
+ }
+ if (this.dragMode_ == o3djs.cameracontroller.DragMode.DOLLY_IN_OUT) {
+ this.backpedal += deltaY * this.distancePerUnit;
+ }
+ if (this.dragMode_ == o3djs.cameracontroller.DragMode.ZOOM_IN_OUT) {
+ var width = Math.tan(this.fieldOfViewAngle);
+ width *= Math.pow(2, deltaY * this.zoomPerUnit);
+ this.fieldOfViewAngle = Math.atan(width);
+ }
+ if (this.dragMode_ == o3djs.cameracontroller.DragMode.DOLLY_ZOOM) {
+ if (this.backpedal > 0) {
+ var oldWidth = Math.tan(this.fieldOfViewAngle);
+ this.fieldOfViewAngle += deltaY * this.radiansPerUnit;
+ this.fieldOfViewAngle = Math.min(this.fieldOfViewAngle, 0.98 * Math.PI/2);
+ this.fieldOfViewAngle = Math.max(this.fieldOfViewAngle, 0.02 * Math.PI/2);
+ var newWidth = Math.tan(this.fieldOfViewAngle);
+ this.backpedal *= oldWidth / newWidth;
}
}
+ if (this.dragMode_ ==
+ o3djs.cameracontroller.DragMode.MOVE_CENTER_IN_VIEW_PLANE) {
+ var matrix4 = o3djs.math.matrix4;
+ var translationVector = [-deltaX * this.distancePerUnit,
+ deltaY * this.distancePerUnit, 0];
+ var inverseViewMatrix = matrix4.inverse(this.calculateViewMatrix());
+ translationVector = matrix4.transformDirection(
+ inverseViewMatrix, translationVector);
+ this.centerPos = o3djs.math.addVector(this.centerPos, translationVector);
+ }
+
+ if (this.onChange != null &&
+ this.dragMode_ != o3djs.cameracontroller.DragMode.NONE) {
+ this.onChange(this);
+ }
};
diff --git a/o3d/samples/o3djs/lineprimitives.js b/o3d/samples/o3djs/lineprimitives.js
index 8e4d923..4d7ae90 100644
--- a/o3d/samples/o3djs/lineprimitives.js
+++ b/o3d/samples/o3djs/lineprimitives.js
@@ -312,11 +312,14 @@ o3djs.lineprimitives.createLineSphere = function(
/**
* Creates ring vertices.
* The ring is a circle in the XZ plane, centered at the origin.
- * The created ring has a position stream and a normal stream.
+ * The created ring has position, normal, and 1-D texcoord streams.
* The normals point outwards from the center of the ring.
+ * The texture coordinates are based on angle about the center.
*
* @param {number} radius Radius of the ring.
* @param {number} subdivisions Number of steps around the ring.
+ * @param {number} maxTexCoord 1-D texture coordinates will range from 0 to
+ * this value, based on angle about the center.
* @param {!o3djs.math.Matrix4} opt_matrix A matrix by which to multiply all
* the vertices.
* @return {!o3djs.lineprimitives.LineVertexInfo} The created ring vertices.
@@ -324,6 +327,7 @@ o3djs.lineprimitives.createLineSphere = function(
o3djs.lineprimitives.createLineRingVertices = function(
radius,
subdivisions,
+ maxTexCoord,
opt_matrix) {
if (subdivisions < 3) {
throw Error('subdivisions must be >= 3');
@@ -334,18 +338,21 @@ o3djs.lineprimitives.createLineRingVertices = function(
3, o3djs.base.o3d.Stream.POSITION);
var normalStream = vertexInfo.addStream(
3, o3djs.base.o3d.Stream.NORMAL);
+ var texCoordStream = vertexInfo.addStream(
+ 1, o3djs.base.o3d.Stream.TEXCOORD, 0);
// Generate the individual vertices in our vertex buffer.
- for (var i = 0; i < subdivisions; i++) {
+ for (var i = 0; i <= subdivisions; i++) {
var theta = 2 * Math.PI * i / subdivisions;
positionStream.addElement(radius * Math.cos(theta), 0,
radius * Math.sin(theta));
normalStream.addElement(Math.cos(theta), 0, Math.sin(theta));
+ texCoordStream.addElement(maxTexCoord * i / subdivisions);
}
// Connect the vertices by simple lines.
for (var i = 0; i < subdivisions; i++) {
- vertexInfo.addLine(i, (i+1) % subdivisions);
+ vertexInfo.addLine(i, (i+1));
}
if (opt_matrix) {
diff --git a/o3d/samples/o3djs/manipulators.js b/o3d/samples/o3djs/manipulators.js
index f1ac3ae..1565dbe 100644
--- a/o3d/samples/o3djs/manipulators.js
+++ b/o3d/samples/o3djs/manipulators.js
@@ -477,6 +477,9 @@ o3djs.manipulators.Manager = function(pack,
var state = this.viewInfo.zOrderedState;
state.getStateParam('ZComparisonFunction').value =
o3djs.base.o3d.State.CMP_GREATER;
+ // Disable depth writing, otherwise the second pass will have a
+ // screwed up depth buffer, and will draw when it shouldn't.
+ state.getStateParam('ZWriteEnable').value = false;
// Swap the priorities of the DrawPasses so they get drawn in the
// opposite order
@@ -493,6 +496,13 @@ o3djs.manipulators.Manager = function(pack,
// obscured get drawn as normal. This allows the obscured parts
// of the manipulators to be rendered with a different material.
+ // POTENTIAL PROBLEM: Since we reverse the depth comparison function (and
+ // disable depth writing) for the obscured rendering pass, those objects will
+ // not have their proper faces showing. So they will look wrong unless we use
+ // a constant shader. One possible solution would be to set the stencil
+ // buffer to indicate obscured/unobscured, so that we are free to use the
+ // depth buffer normally.
+
/**
* The DrawList we use to render manipulators that are unobscured by the main
* scene.
@@ -607,7 +617,7 @@ o3djs.manipulators.Manager.prototype.createConstantMaterial_ =
* Gets the constant material used for manipulators.
* @return {!o3d.Material} A material.
*/
-o3djs.manipulators.Manager.prototype.getConstantMaterial = function() {
+o3djs.manipulators.Manager.prototype.getUnobscuredConstantMaterial = function() {
return this.constantMaterial_;
};
@@ -623,11 +633,12 @@ o3djs.manipulators.Manager.prototype.getObscuredConstantMaterial = function() {
* Gets the material used for the line ring manipulators.
* @return {!o3d.Material} A material.
*/
-o3djs.manipulators.Manager.prototype.getLineRingMaterial = function() {
+o3djs.manipulators.Manager.prototype.getUnobscuredLineRingMaterial =
+ function() {
if (!this.lineRingMaterial_) {
this.lineRingMaterial_ = o3djs.manipulators.createLineRingMaterial(
this.pack, this.unobscuredDrawList_,
- [1, 1, 1, 1], [1, 1, 1, 0.4]);
+ [1, 1, 1, 1], [1, 1, 1, 0.6], false);
}
return this.lineRingMaterial_;
};
@@ -640,7 +651,7 @@ o3djs.manipulators.Manager.prototype.getObscuredLineRingMaterial = function() {
if (!this.obscuredLineRingMaterial_) {
this.obscuredLineRingMaterial_ = o3djs.manipulators.createLineRingMaterial(
this.pack, this.obscuredDrawList_,
- [1, 0, 0, 1], [1, 1, 1, 0.4]); // TODO(gman): Pick a color.
+ [1, 1, 1, 0.5], [1, 1, 1, 0.3], true);
}
return this.obscuredLineRingMaterial_;
};
@@ -1279,7 +1290,7 @@ o3djs.manipulators.Translate1 = function(manager) {
o3djs.manipulators.Manip.call(this, manager);
var pack = manager.pack;
- var material = manager.getConstantMaterial();
+ var material = manager.getUnobscuredConstantMaterial();
var shape = manager.translate1Shape_;
if (!shape) {
@@ -1386,7 +1397,7 @@ o3djs.manipulators.Translate2 = function(manager) {
o3djs.manipulators.Manip.call(this, manager);
var pack = manager.pack;
- var material = manager.getConstantMaterial();
+ var material = manager.getUnobscuredConstantMaterial();
var shape = manager.Translate2Shape_;
if (!shape) {
@@ -1508,7 +1519,7 @@ o3djs.manipulators.Rotate1 = function(manager) {
16,
6,
o3djs.math.matrix4.rotationZ(Math.PI / 2));
- pickShape = verts.createShape(pack, manager.getConstantMaterial());
+ pickShape = verts.createShape(pack, manager.getUnobscuredConstantMaterial());
manager.Rotate1PickShape_ = pickShape;
}
@@ -1517,10 +1528,12 @@ o3djs.manipulators.Rotate1 = function(manager) {
// Create the line geometry for displaying the manipulator, which looks like
// a ring centered at the origin, with the X axis as its vertical axis.
var verts = o3djs.lineprimitives.createLineRingVertices(
- 1.0,
- 32,
- o3djs.math.matrix4.rotationZ(Math.PI / 2));
- visibleShape = verts.createShape(pack, manager.getLineRingMaterial());
+ 1.0, // radius
+ 32, // subdivisions
+ 120, // maxTexCoord (this determines the number of stipples)
+ o3djs.math.matrix4.rotationZ(Math.PI / 2)); // opt_matrix
+ visibleShape = verts.createShape(pack,
+ manager.getUnobscuredLineRingMaterial());
// Add a second DrawElement to this shape to draw it a second time
// with a different material when it's obscured.
visibleShape.createDrawElements(
@@ -1655,54 +1668,72 @@ o3djs.manipulators.Rotate1.prototype.drag = function(startPoint,
// TODO(simonrad): Find a better place for these?
/**
- * The name of the Rotate1 manipulator's line ring effect.
- * @type {string}
- */
-o3djs.manipulators.LINE_RING_EFFECT_NAME =
- 'o3djs.manipulators.lineRingEffect';
-
-/**
- * An effect string for the Rotate1 manipulator's line ring.
- * @type {string}
- */
-o3djs.manipulators.LINE_RING_FXSTRING = '' +
- 'float4x4 worldViewProjection : WORLDVIEWPROJECTION;\n' +
- 'float4x4 worldViewProjectionInverseTranspose :\n' +
- ' WORLDVIEWPROJECTIONINVERSETRANSPOSE;\n' +
- 'float4 color1;\n' +
- 'float4 color2;\n' +
- 'float4 emissive; // Used for highlighting.\n' +
- '\n' +
- 'struct VertexShaderInput {\n' +
- ' float4 position : POSITION;\n' +
- ' float4 normal : NORMAL;\n' +
- '};\n' +
- '\n' +
- 'struct PixelShaderInput {\n' +
- ' float4 position : POSITION;\n' +
- ' float3 normal : TEXCOORD0;\n' +
- '};\n' +
- '\n' +
- 'PixelShaderInput vertexShaderFunction(VertexShaderInput input) {\n' +
- ' PixelShaderInput output;\n' +
- '\n' +
- ' output.position = mul(input.position, worldViewProjection);\n' +
- ' output.normal = mul(input.normal,\n' +
- ' worldViewProjectionInverseTranspose).xyz;\n' +
- ' return output;\n' +
- '}\n' +
- '\n' +
- 'float4 pixelShaderFunction(PixelShaderInput input): COLOR {\n' +
- ' if (input.normal.z < 0) {\n' +
- ' return color1 * emissive;\n' +
- ' } else {\n' +
- ' return color2 * emissive;\n' +
- ' }\n' +
- '}\n' +
- '\n' +
- '// #o3d VertexShaderEntryPoint vertexShaderFunction\n' +
- '// #o3d PixelShaderEntryPoint pixelShaderFunction\n' +
- '// #o3d MatrixLoadOrder RowMajor\n';
+ * Returns an effect string for the Rotate1 manipulator's line ring.
+ * @private
+ * @param {boolean} enableStipple Whether line stippling should be enabled
+ * in the shader.
+ * @return {string} The created shader source / effect string.
+ */
+o3djs.manipulators.getLineRingFXString_ = function(enableStipple) {
+ var stippleCode = '';
+ if (enableStipple) {
+ stippleCode = '' +
+ ' // Use the texCoord to do stippling.\n' +
+ ' if (input.texCoord.x % 2 > 1) return float4(0, 0, 0, 0);\n';
+ }
+ return '' +
+ 'float4x4 worldViewProjection : WORLDVIEWPROJECTION;\n' +
+ '// NOTE: We transform the normals through the\n' +
+ '// worldViewProjectionInverseTranspose instead of the\n' +
+ '// worldViewInverseTranspose. The projection matrix warps the\n' +
+ '// normals in strange ways. One result of this is that the "front\n' +
+ '// face" color of the ring can extend around more than 50% of the\n' +
+ '// ring. This may be good or bad. If we dont include the projection\n' +
+ '// matrix, we always get a 50% split, but we do not account for\n' +
+ '// perspective. An alternative would be to get a little more\n' +
+ '// complicated, using the positions of the camera and the center\n' +
+ '// of the ring.\n' +
+ 'float4x4 worldViewProjectionInverseTranspose :\n' +
+ ' WORLDVIEWPROJECTIONINVERSETRANSPOSE;\n' +
+ 'float4 color1;\n' +
+ 'float4 color2;\n' +
+ 'float4 emissive; // Used for highlighting.\n' +
+ '\n' +
+ 'struct VertexShaderInput {\n' +
+ ' float4 position : POSITION;\n' +
+ ' float4 normal : NORMAL;\n' +
+ ' float1 texCoord : TEXCOORD0;\n' +
+ '};\n' +
+ '\n' +
+ 'struct PixelShaderInput {\n' +
+ ' float4 position : POSITION;\n' +
+ ' float3 normal : TEXCOORD0;\n' +
+ ' float1 texCoord : TEXCOORD1;\n' +
+ '};\n' +
+ '\n' +
+ 'PixelShaderInput vertexShaderFunction(VertexShaderInput input) {\n' +
+ ' PixelShaderInput output;\n' +
+ '\n' +
+ ' output.position = mul(input.position, worldViewProjection);\n' +
+ ' output.normal = mul(input.normal,\n' +
+ ' worldViewProjectionInverseTranspose).xyz;\n' +
+ ' output.texCoord = input.texCoord;\n' +
+ ' return output;\n' +
+ '}\n' +
+ '\n' +
+ 'float4 pixelShaderFunction(PixelShaderInput input): COLOR {\n' +
+ stippleCode +
+ ' if (input.normal.z < 0) {\n' +
+ ' return color1 * emissive; // Front face of the ring.\n' +
+ ' } else {\n' +
+ ' return color2 * emissive; // Back face of the ring.\n' +
+ ' }\n' +
+ '}\n' +
+ '\n' +
+ '// #o3d VertexShaderEntryPoint vertexShaderFunction\n' +
+ '// #o3d PixelShaderEntryPoint pixelShaderFunction\n' +
+ '// #o3d MatrixLoadOrder RowMajor\n';
+};
/**
* Creates the Rotate1 manipulator's line ring material.
@@ -1712,16 +1743,19 @@ o3djs.manipulators.LINE_RING_FXSTRING = '' +
* the material is created.
* @param {!o3djs.math.Vector4} color1 A color in the format [r, g, b, a].
* @param {!o3djs.math.Vector4} color2 A color in the format [r, g, b, a].
+ * @param {boolean} enableStipple Whether line stippling should be enabled
+ * in the shader.
* @return {!o3d.Material} The created material.
*/
o3djs.manipulators.createLineRingMaterial = function(pack,
drawList,
color1,
- color2) {
+ color2,
+ enableStipple) {
var material = pack.createObject('Material');
material.effect = pack.createObject('Effect');
- material.effect.loadFromFXString(o3djs.manipulators.LINE_RING_FXSTRING);
- material.effect.name = o3djs.manipulators.LINE_RING_EFFECT_NAME;
+ material.effect.loadFromFXString(
+ o3djs.manipulators.getLineRingFXString_(enableStipple));
material.drawList = drawList;
material.createParam('color1', 'ParamFloat4').value = color1;
material.createParam('color2', 'ParamFloat4').value = color2;
@@ -1736,6 +1770,7 @@ o3djs.manipulators.createLineRingMaterial = function(pack,
material.state.getStateParam('AlphaTestEnable').value = true;
material.state.getStateParam('AlphaComparisonFunction').value =
o3djs.base.o3d.State.CMP_GREATER;
+ material.state.getStateParam('AlphaReference').value = 0;
return material;
};