diff options
Diffstat (limited to 'o3d/samples')
-rw-r--r-- | o3d/samples/manipulators/rotate1.html | 40 | ||||
-rw-r--r-- | o3d/samples/manipulators/translate1.html | 133 | ||||
-rw-r--r-- | o3d/samples/manipulators/translate2.html | 133 | ||||
-rw-r--r-- | o3d/samples/o3djs/cameracontroller.js | 208 | ||||
-rw-r--r-- | o3d/samples/o3djs/lineprimitives.js | 100 | ||||
-rw-r--r-- | o3d/samples/o3djs/manipulators.js | 219 |
6 files changed, 675 insertions, 158 deletions
diff --git a/o3d/samples/manipulators/rotate1.html b/o3d/samples/manipulators/rotate1.html index 49f56f3..0b418db 100644 --- a/o3d/samples/manipulators/rotate1.html +++ b/o3d/samples/manipulators/rotate1.html @@ -52,6 +52,7 @@ o3djs.require('o3djs.rendergraph'); o3djs.require('o3djs.primitives'); o3djs.require('o3djs.manipulators'); o3djs.require('o3djs.effect'); +o3djs.require('o3djs.cameracontroller'); // global variables var g_o3dElement; @@ -62,10 +63,10 @@ var g_mainPack; var g_mainViewInfo; var g_mainRoot; var g_lightPosition = [5, 5, 7]; -var g_eyePosition = [1, 5, 23]; var g_lastCubeTransform; var g_primitives = []; var g_manager; +var g_cameraController; /** * Creates the client area. @@ -110,14 +111,20 @@ function main(clientElements) { } function onMouseDown(e) { - g_manager.mousedown(e.x, e.y, - g_mainViewInfo.drawContext.view, - g_mainViewInfo.drawContext.projection, - g_client.width, - g_client.height); + if(e.button == 2) { + g_cameraController.mousedown(e); + } else { + g_manager.mousedown(e.x, e.y, + g_mainViewInfo.drawContext.view, + g_mainViewInfo.drawContext.projection, + g_client.width, + g_client.height); + } } function onMouseMove(e) { + g_cameraController.mousemove(e); + g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix(); g_manager.mousemove(e.x, e.y, g_mainViewInfo.drawContext.view, g_mainViewInfo.drawContext.projection, @@ -127,8 +134,12 @@ function onMouseMove(e) { } function onMouseUp(e) { - g_manager.mouseup(); - g_manager.updateInactiveManipulators(); + if(e.button == 2) { + g_cameraController.mouseup(e); + } else { + g_manager.mouseup(); + g_manager.updateInactiveManipulators(); + } } /** @@ -164,12 +175,13 @@ function initContext() { 1, // Near plane. 5000); // Far plane. - // Set up our view transformation to look towards the world origin where the - // primitives are located. - g_mainViewInfo.drawContext.view = g_math.matrix4.lookAt( - g_eyePosition, // eye - [0, 2, 0], // target - [0, 1, 0]); // up + // 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(); } /** diff --git a/o3d/samples/manipulators/translate1.html b/o3d/samples/manipulators/translate1.html index 7debeae..c8eb98e 100644 --- a/o3d/samples/manipulators/translate1.html +++ b/o3d/samples/manipulators/translate1.html @@ -52,20 +52,21 @@ o3djs.require('o3djs.rendergraph'); o3djs.require('o3djs.primitives'); o3djs.require('o3djs.manipulators'); o3djs.require('o3djs.effect'); +o3djs.require('o3djs.cameracontroller'); // global variables var g_o3dElement; var g_client; var g_o3d; var g_math; -var g_pack; -var g_viewInfo; - +var g_mainPack; +var g_mainViewInfo; +var g_mainRoot; var g_lightPosition = [5, 5, 7]; -var g_eyePosition = [1, 5, 23]; - +var g_lastCubeTransform; var g_primitives = []; var g_manager; +var g_cameraController; /** * Creates the client area. @@ -92,15 +93,15 @@ function main(clientElements) { // Init global variables. initGlobals(clientElements); - // Set up the view and projection transformations. - initContext(); - // Add the shapes to the transform heirarchy. createShapes(); // Add the manipulators to the transform hierarchy. createManipulators(); + // Set up the view and projection transformations. + initContext(); + // Start picking; it won't do anything until the scene finishes loading. o3djs.event.addEventListener(o3dElement, 'mousedown', onMouseDown); o3djs.event.addEventListener(o3dElement, 'mousemove', onMouseMove); @@ -110,25 +111,35 @@ function main(clientElements) { } function onMouseDown(e) { - g_manager.mousedown(e.x, e.y, - g_viewInfo.drawContext.view, - g_viewInfo.drawContext.projection, - g_client.width, - g_client.height); + if(e.button == 2) { + g_cameraController.mousedown(e); + } else { + g_manager.mousedown(e.x, e.y, + g_mainViewInfo.drawContext.view, + g_mainViewInfo.drawContext.projection, + g_client.width, + g_client.height); + } } function onMouseMove(e) { + g_cameraController.mousemove(e); + g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix(); g_manager.mousemove(e.x, e.y, - g_viewInfo.drawContext.view, - g_viewInfo.drawContext.projection, + g_mainViewInfo.drawContext.view, + g_mainViewInfo.drawContext.projection, g_client.width, g_client.height); g_manager.updateInactiveManipulators(); } function onMouseUp(e) { - g_manager.mouseup(); - g_manager.updateInactiveManipulators(); + if(e.button == 2) { + g_cameraController.mouseup(e); + } else { + g_manager.mouseup(); + g_manager.updateInactiveManipulators(); + } } /** @@ -141,12 +152,15 @@ function initGlobals(clientElements) { g_math = o3djs.math; // Create a pack to manage the objects created. - g_pack = g_client.createPack(); + g_mainPack = g_client.createPack(); + + // Make a root transform for our scene. + g_mainRoot = g_mainPack.createObject('Transform'); - // Create the render graph for a view. - g_viewInfo = o3djs.rendergraph.createBasicView( - g_pack, - g_client.root, + // Create the render graph for the scene view. + g_mainViewInfo = o3djs.rendergraph.createBasicView( + g_mainPack, + g_mainRoot, g_client.renderGraphRoot); } @@ -155,18 +169,19 @@ function initGlobals(clientElements) { */ function initContext() { // Set up a perspective transformation for the projection. - g_viewInfo.drawContext.projection = g_math.matrix4.perspective( - g_math.degToRad(30), // 30 degree frustum. + g_mainViewInfo.drawContext.projection = g_math.matrix4.perspective( + g_math.degToRad(30), // 30 degree frustum. g_o3dElement.clientWidth / g_o3dElement.clientHeight, // Aspect ratio. - 1, // Near plane. - 5000); // Far plane. - - // Set up our view transformation to look towards the world origin where the - // primitives are located. - g_viewInfo.drawContext.view = g_math.matrix4.lookAt( - g_eyePosition, // eye - [0, 2, 0], // target - [0, 1, 0]); // up + 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(); } /** @@ -175,7 +190,8 @@ function initContext() { */ function createShapes() { // Create a little tree-like hierarchy of cubes - createCubeTree(2, 1.5, [0, 0, 0], g_client.root); + createCubeTree(2, 1.5, [0, 0, 0], g_mainRoot); + g_lastCubeTransform.scale(3, 1, 1); } /** @@ -210,13 +226,14 @@ function createCubeTree(depth, edgeLength, translation, parent) { */ function createCube(edgeLength, opt_translation, opt_parent) { var cube = o3djs.primitives.createCube( - g_pack, + g_mainPack, // A green phong-shaded material. - o3djs.material.createBasicMaterial(g_pack, - g_viewInfo, + o3djs.material.createBasicMaterial(g_mainPack, + g_mainViewInfo, [0, 1, 0, 1]), edgeLength); - var transform = g_pack.createObject('Transform'); + var transform = g_mainPack.createObject('Transform'); + g_lastCubeTransform = transform; transform.addShape(cube); if (opt_translation) { transform.translate(opt_translation); @@ -224,7 +241,7 @@ function createCube(edgeLength, opt_translation, opt_parent) { if (opt_parent) { transform.parent = opt_parent; } else { - transform.parent = g_client.root; + transform.parent = g_mainRoot; } g_primitives.push(transform); return transform; @@ -234,11 +251,39 @@ function createCube(edgeLength, opt_translation, opt_parent) { * Creates manipulators attached to the objects we've just created. */ function createManipulators() { - g_manager = o3djs.manipulators.createManager(g_pack, - g_viewInfo.performanceDrawList, - g_client.root, - null, - 0); + // Create a separate pack for the manipulators so they don't get mixed in + // with the main scene's objects. + var pack = g_client.createPack(); + + // Create a root transform for the manipulators so they are 100% separate + // from the scene's transforms. + var manipulatorRoot = pack.createObject('Transform'); + + // Create the render graph for the manipulators view that uses the same + // DrawContext as the main view. + var manipulatorViewInfo = o3djs.rendergraph.createView( + pack, + manipulatorRoot, + g_client.renderGraphRoot, + undefined, // clearColor + undefined, // priority + undefined, // viewport + undefined, // performanceDrawList + undefined, // zOrderedDrawList + g_mainViewInfo.drawContext); + + // Make sure the manipulators gets drawn after the scene. + manipulatorViewInfo.root.priority = g_mainViewInfo.root.priority + 1; + + // Turn off clearing the color for the manipulators. + manipulatorViewInfo.clearBuffer.clearColorFlag = false; + + g_manager = o3djs.manipulators.createManager( + pack, + manipulatorViewInfo.performanceDrawList, + manipulatorRoot, + null, + 0); var jj = 2; for (var ii = 0; ii < g_primitives.length; ii++) { var manip = g_manager.createTranslate1(); diff --git a/o3d/samples/manipulators/translate2.html b/o3d/samples/manipulators/translate2.html index f9cbff7..3946d74 100644 --- a/o3d/samples/manipulators/translate2.html +++ b/o3d/samples/manipulators/translate2.html @@ -52,20 +52,21 @@ o3djs.require('o3djs.rendergraph'); o3djs.require('o3djs.primitives'); o3djs.require('o3djs.manipulators'); o3djs.require('o3djs.effect'); +o3djs.require('o3djs.cameracontroller'); // global variables var g_o3dElement; var g_client; var g_o3d; var g_math; -var g_pack; -var g_viewInfo; - +var g_mainPack; +var g_mainViewInfo; +var g_mainRoot; var g_lightPosition = [5, 5, 7]; -var g_eyePosition = [1, 5, 23]; - +var g_lastCubeTransform; var g_primitives = []; var g_manager; +var g_cameraController; /** * Creates the client area. @@ -92,15 +93,15 @@ function main(clientElements) { // Init global variables. initGlobals(clientElements); - // Set up the view and projection transformations. - initContext(); - // Add the shapes to the transform heirarchy. createShapes(); // Add the manipulators to the transform hierarchy. createManipulators(); + // Set up the view and projection transformations. + initContext(); + // Start picking; it won't do anything until the scene finishes loading. o3djs.event.addEventListener(o3dElement, 'mousedown', onMouseDown); o3djs.event.addEventListener(o3dElement, 'mousemove', onMouseMove); @@ -110,25 +111,35 @@ function main(clientElements) { } function onMouseDown(e) { - g_manager.mousedown(e.x, e.y, - g_viewInfo.drawContext.view, - g_viewInfo.drawContext.projection, - g_client.width, - g_client.height); + if(e.button == 2) { + g_cameraController.mousedown(e); + } else { + g_manager.mousedown(e.x, e.y, + g_mainViewInfo.drawContext.view, + g_mainViewInfo.drawContext.projection, + g_client.width, + g_client.height); + } } function onMouseMove(e) { + g_cameraController.mousemove(e); + g_mainViewInfo.drawContext.view = g_cameraController.calculateViewMatrix(); g_manager.mousemove(e.x, e.y, - g_viewInfo.drawContext.view, - g_viewInfo.drawContext.projection, + g_mainViewInfo.drawContext.view, + g_mainViewInfo.drawContext.projection, g_client.width, g_client.height); g_manager.updateInactiveManipulators(); } function onMouseUp(e) { - g_manager.mouseup(); - g_manager.updateInactiveManipulators(); + if(e.button == 2) { + g_cameraController.mouseup(e); + } else { + g_manager.mouseup(); + g_manager.updateInactiveManipulators(); + } } /** @@ -141,12 +152,15 @@ function initGlobals(clientElements) { g_math = o3djs.math; // Create a pack to manage the objects created. - g_pack = g_client.createPack(); + g_mainPack = g_client.createPack(); + + // Make a root transform for our scene. + g_mainRoot = g_mainPack.createObject('Transform'); - // Create the render graph for a view. - g_viewInfo = o3djs.rendergraph.createBasicView( - g_pack, - g_client.root, + // Create the render graph for the scene view. + g_mainViewInfo = o3djs.rendergraph.createBasicView( + g_mainPack, + g_mainRoot, g_client.renderGraphRoot); } @@ -155,18 +169,19 @@ function initGlobals(clientElements) { */ function initContext() { // Set up a perspective transformation for the projection. - g_viewInfo.drawContext.projection = g_math.matrix4.perspective( - g_math.degToRad(30), // 30 degree frustum. + g_mainViewInfo.drawContext.projection = g_math.matrix4.perspective( + g_math.degToRad(30), // 30 degree frustum. g_o3dElement.clientWidth / g_o3dElement.clientHeight, // Aspect ratio. - 1, // Near plane. - 5000); // Far plane. - - // Set up our view transformation to look towards the world origin where the - // primitives are located. - g_viewInfo.drawContext.view = g_math.matrix4.lookAt( - g_eyePosition, // eye - [0, 2, 0], // target - [0, 1, 0]); // up + 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(); } /** @@ -175,7 +190,8 @@ function initContext() { */ function createShapes() { // Create a little tree-like hierarchy of cubes - createCubeTree(2, 1.5, [0, 0, 0], g_client.root); + createCubeTree(2, 1.5, [0, 0, 0], g_mainRoot); + g_lastCubeTransform.scale(3, 1, 1); } /** @@ -210,13 +226,14 @@ function createCubeTree(depth, edgeLength, translation, parent) { */ function createCube(edgeLength, opt_translation, opt_parent) { var cube = o3djs.primitives.createCube( - g_pack, + g_mainPack, // A green phong-shaded material. - o3djs.material.createBasicMaterial(g_pack, - g_viewInfo, + o3djs.material.createBasicMaterial(g_mainPack, + g_mainViewInfo, [0, 1, 0, 1]), edgeLength); - var transform = g_pack.createObject('Transform'); + var transform = g_mainPack.createObject('Transform'); + g_lastCubeTransform = transform; transform.addShape(cube); if (opt_translation) { transform.translate(opt_translation); @@ -224,7 +241,7 @@ function createCube(edgeLength, opt_translation, opt_parent) { if (opt_parent) { transform.parent = opt_parent; } else { - transform.parent = g_client.root; + transform.parent = g_mainRoot; } g_primitives.push(transform); return transform; @@ -234,11 +251,39 @@ function createCube(edgeLength, opt_translation, opt_parent) { * Creates manipulators attached to the objects we've just created. */ function createManipulators() { - g_manager = o3djs.manipulators.createManager(g_pack, - g_viewInfo.performanceDrawList, - g_client.root, - null, - 0); + // Create a separate pack for the manipulators so they don't get mixed in + // with the main scene's objects. + var pack = g_client.createPack(); + + // Create a root transform for the manipulators so they are 100% separate + // from the scene's transforms. + var manipulatorRoot = pack.createObject('Transform'); + + // Create the render graph for the manipulators view that uses the same + // DrawContext as the main view. + var manipulatorViewInfo = o3djs.rendergraph.createView( + pack, + manipulatorRoot, + g_client.renderGraphRoot, + undefined, // clearColor + undefined, // priority + undefined, // viewport + undefined, // performanceDrawList + undefined, // zOrderedDrawList + g_mainViewInfo.drawContext); + + // Make sure the manipulators gets drawn after the scene. + manipulatorViewInfo.root.priority = g_mainViewInfo.root.priority + 1; + + // Turn off clearing the color for the manipulators. + manipulatorViewInfo.clearBuffer.clearColorFlag = false; + + g_manager = o3djs.manipulators.createManager( + pack, + manipulatorViewInfo.performanceDrawList, + manipulatorRoot, + null, + 0); var jj = 2; for (var ii = 0; ii < g_primitives.length; ii++) { var manip = g_manager.createTranslate2(); diff --git a/o3d/samples/o3djs/cameracontroller.js b/o3d/samples/o3djs/cameracontroller.js new file mode 100644 index 0000000..9dcb980 --- /dev/null +++ b/o3d/samples/o3djs/cameracontroller.js @@ -0,0 +1,208 @@ +/* + * Copyright 2009, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +/** + * @fileoverview This file contains sample code for controlling the camera + * (ie view matrix) using the mouse and keyboard. + */ + +o3djs.provide('o3djs.cameracontroller'); + +o3djs.require('o3djs.math'); + +/** + * A Module for user control of the camera / view matrix. + * @namespace + */ +o3djs.cameracontroller = o3djs.cameracontroller || {}; + +/** + * 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 + * of the camera. In world space. + * @param {number} backpedal The distance the camera moves back from the + * centerPos. + * @param {number} heightAngle The angle the camera rotates up or down + * (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 {function(!o3djs.cameracontroller.CameraController): void} + * opt_onchange Pointer to a callback to call when the camera changes. + * @return {!o3djs.cameracontroller.CameraController} The created + * CameraController. + */ +o3djs.cameracontroller.createCameraController = function(centerPos, + backpedal, + heightAngle, + rotationAngle, + opt_onchange) { + return new o3djs.cameracontroller.CameraController(centerPos, + backpedal, + heightAngle, + rotationAngle, + opt_onchange); +}; + +/** + * Class to hold user-controlled camera information and handle user events. + * @constructor + * @param {!o3djs.math.Vector3} centerPos The position that the camera is + * looking at and rotating around; or if backpedal is zero, the location + * of the camera. In world space. + * @param {number} backpedal The distance the camera moves back from the + * centerPos. + * @param {number} heightAngle The angle the camera rotates up or down + * (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 {function(!o3djs.cameracontroller.CameraController): void} + * opt_onchange Pointer to a callback to call when the camera changes. + */ +o3djs.cameracontroller.CameraController = function(centerPos, + backpedal, + heightAngle, + rotationAngle, + 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. + * @type {!o3djs.math.Vector3} + */ + this.centerPos = centerPos; + + /** + * The distance the camera moves back from the centerPos. + * @type {number} + */ + this.backpedal = backpedal; + + /** + * The angle the camera rotates up or down. + * @type {number} + */ + this.heightAngle = heightAngle; + + /** + * The angle the camera rotates left or right. + * @type {number} + */ + this.rotationAngle = rotationAngle; + + + /** + * Points to a callback to call when the camera changes. + * @type {function(!o3djs.cameracontroller.CameraController): void} + */ + this.onchange = opt_onchange || null; + + /** + * Whether the mouse is currently being dragged to control the camera. + * @private + * @type {boolean} + */ + this.dragging_ = false; + + /** + * The last X coordinate of the mouse. + * @private + * @type {number} + */ + this.mouseX_ = 0; + + /** + * The last Y coordinate of the mouse. + * @private + * @type {number} + */ + this.mouseY_ = 0; + + /** + * Controls how quickly the mouse moves the camera. + * @type {number} + */ + this.dragScaleFactor = 300.0; +}; + +/** + * Calculates the view matrix for this camera. + * @return {!o3djs.math.Matrix4} The view matrix. + */ +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)); + view = matrix4.mul(view, matrix4.rotationX(this.heightAngle)); + view = matrix4.mul(view, matrix4.translation([0, 0, -this.backpedal])); + return view; +}; + +/** + * 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. + */ +o3djs.cameracontroller.CameraController.prototype.mouseup = function(ev) { + this.dragging_ = false; +}; + +/** + * Method which should be called by end user code upon receiving a + * mouse-move event. + * @param {!o3d.Event} ev The event. + */ +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); + } + } +}; diff --git a/o3d/samples/o3djs/lineprimitives.js b/o3d/samples/o3djs/lineprimitives.js index 8a5d1d6..8e4d923 100644 --- a/o3d/samples/o3djs/lineprimitives.js +++ b/o3d/samples/o3djs/lineprimitives.js @@ -129,10 +129,10 @@ o3djs.lineprimitives.createLineVertexInfo = function() { }; /** - * Creates the vertices and indices for a cube of lines. The - * cube will be created around the origin. (-size / 2, size / 2) + * Creates the vertices and indices for a cube of lines. + * The cube will be created around the origin (-size / 2, size / 2). * The created cube has a position stream only and can therefore only be used - * with shaders that support those a position stream. + * with appropriate shaders. * * @param {number} size Width, height and depth of the cube. * @param {!o3djs.math.Matrix4} opt_matrix A matrix by which to multiply all @@ -188,8 +188,12 @@ o3djs.lineprimitives.createLineCubeVertices = function(size, opt_matrix) { /** * Creates a cube of lines. - * @param {!o3d.Pack} pack Pack to create sphere elements in. - * @param {!o3d.Material} material to use. + * The cube will be created around the origin (-size / 2, size / 2). + * The created cube has a position stream only and can therefore only be used + * with appropriate shaders. + * + * @param {!o3d.Pack} pack Pack to create cube elements in. + * @param {!o3d.Material} material Material to use. * @param {number} size Width, height and depth of the cube. * @param {!o3djs.math.Matrix4} opt_matrix A matrix by which to multiply all * the vertices. @@ -208,11 +212,11 @@ o3djs.lineprimitives.createLineCube = function( /** * Creates sphere vertices. * The created sphere has a position stream only and can therefore only be - * used with shaders that support those a position stream. + * used with appropriate shaders. * * @param {number} radius radius of the sphere. * @param {number} subdivisionsAxis number of steps around the sphere. - * @param {number} subdivisionsHeight number of vertically on the sphere. + * @param {number} subdivisionsHeight number of steps vertically on the sphere. * @param {!o3djs.math.Matrix4} opt_matrix A matrix by which to multiply all * the vertices. * @return {!o3djs.lineprimitives.LineVertexInfo} The created sphere vertices. @@ -274,15 +278,14 @@ o3djs.lineprimitives.createLineSphereVertices = function( /** * Creates a sphere. - * The created sphere has position, normal, uv and vertex color streams only - * and can therefore only be used with shaders that support those 4 - * streams. + * The created sphere has a position stream only and can therefore only be + * used with appropriate shaders. * * @param {!o3d.Pack} pack Pack to create sphere elements in. - * @param {!o3d.Material} material to use. + * @param {!o3d.Material} material Material to use. * @param {number} radius radius of the sphere. * @param {number} subdivisionsAxis number of steps around the sphere. - * @param {number} subdivisionsHeight number of vertically on the sphere. + * @param {number} subdivisionsHeight number of steps vertically on the sphere. * @param {!o3djs.math.Matrix4} opt_matrix A matrix by which to multiply all * the vertices. * @return {!o3d.Shape} The created sphere. @@ -306,3 +309,76 @@ o3djs.lineprimitives.createLineSphere = function( return vertexInfo.createShape(pack, material); }; +/** + * 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 normals point outwards from the center of the ring. + * + * @param {number} radius Radius of the ring. + * @param {number} subdivisions Number of steps around the ring. + * @param {!o3djs.math.Matrix4} opt_matrix A matrix by which to multiply all + * the vertices. + * @return {!o3djs.lineprimitives.LineVertexInfo} The created ring vertices. + */ +o3djs.lineprimitives.createLineRingVertices = function( + radius, + subdivisions, + opt_matrix) { + if (subdivisions < 3) { + throw Error('subdivisions must be >= 3'); + } + + var vertexInfo = o3djs.lineprimitives.createLineVertexInfo(); + var positionStream = vertexInfo.addStream( + 3, o3djs.base.o3d.Stream.POSITION); + var normalStream = vertexInfo.addStream( + 3, o3djs.base.o3d.Stream.NORMAL); + + // Generate the individual vertices in our vertex buffer. + 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)); + } + + // Connect the vertices by simple lines. + for (var i = 0; i < subdivisions; i++) { + vertexInfo.addLine(i, (i+1) % subdivisions); + } + + if (opt_matrix) { + vertexInfo.reorient(opt_matrix); + } + return vertexInfo; +}; + +/** + * Creates a ring. + * The ring is a circle in the XZ plane, centered at the origin. + * The created ring has a position stream only and can therefore only be + * used with appropriate shaders. + * + * @param {!o3d.Pack} pack Pack to create ring elements in. + * @param {!o3d.Material} material Material to use. + * @param {number} radius Radius of the ring. + * @param {number} subdivisions Number of steps around the ring. + * @param {!o3djs.math.Matrix4} opt_matrix A matrix by which to multiply all + * the vertices. + * @return {!o3d.Shape} The created ring. + */ +o3djs.lineprimitives.createLineRing = function( + pack, + material, + radius, + subdivisions, + opt_matrix) { + var vertexInfo = o3djs.lineprimitives.createLineRingVertices( + radius, + subdivisions, + opt_matrix); + + return vertexInfo.createShape(pack, material); +}; + diff --git a/o3d/samples/o3djs/manipulators.js b/o3d/samples/o3djs/manipulators.js index 85fb611..76db16c 100644 --- a/o3d/samples/o3djs/manipulators.js +++ b/o3d/samples/o3djs/manipulators.js @@ -37,6 +37,8 @@ o3djs.provide('o3djs.manipulators'); +o3djs.require('o3djs.lineprimitives'); + o3djs.require('o3djs.material'); o3djs.require('o3djs.math'); @@ -491,18 +493,17 @@ o3djs.manipulators.Manager = function(pack, this.lightPosition = [10, 10, 10]; /** - * The default material for manipulators (used when not highlighted). + * A constant-shaded material, useful for line geometry in some manipulators. + * + * TODO(simonrad): This is currently used for Translate1+2 polygon geometry. + * We should change polygon geometry back to using phong shader. We should + * use this constant shader for Translate1+2 line geometry, if we add it. + * Rotate1 line geometry uses a different, special shader. + * * @type {!o3d.Material} */ - this.defaultMaterial = - this.createMaterial_(o3djs.manipulators.DEFAULT_COLOR); - /** - * The material used for manipulators when they are highlighted. - * (TODO(simonrad): This is not currently used; only defaultMaterial is used. Remove this?) - * @type {!o3d.Material} - */ - this.highlightedMaterial = - this.createMaterial_(o3djs.manipulators.HIGHLIGHTED_COLOR); + this.constantMaterial = + this.createConstantMaterial_(o3djs.manipulators.DEFAULT_COLOR); /** * A map from the manip's parent Transform clientId to the manip. @@ -512,10 +513,9 @@ o3djs.manipulators.Manager = function(pack, /** * A PickManager to manage picking for the manipulators. - * @type {!o3djs.picking.TransformInfo} + * @type {!o3djs.picking.PickManager} */ - this.pickManager = - o3djs.picking.createPickManager(this.parentTransform); + this.pickManager = o3djs.picking.createPickManager(this.parentTransform); /** * The currently-highlighted manipulator. @@ -532,19 +532,24 @@ o3djs.manipulators.Manager = function(pack, } /** - * Creates a material based on the given single color. + * Creates a constant-shaded material based on the given single color. * @private * @param {!o3djs.math.Vector4} baseColor A vector with 4 entries, the * R,G,B, and A components of a color. - * @return {!o3d.Material} A phong material whose overall pigment is baseColor. + * @return {!o3d.Material} A constant material whose overall pigment is baseColor. */ -o3djs.manipulators.Manager.prototype.createMaterial_ = +o3djs.manipulators.Manager.prototype.createConstantMaterial_ = function(baseColor) { - // Create a new, empty Material object. return o3djs.material.createConstantMaterialEx( this.pack, this.drawList, baseColor); } +// TODO(simonrad): Add phong shader back in. We need it for the solid cones +// of the Translate1+2 manipulators. Note that for highlighting, the phong +// shader uses diffuse param and the constant shader uses emissive param, so +// we'll need to either change that or split them onto separate transforms. +// Probably the former would be better. + /** * Creates a new Translate1 manipulator. A Translate1 moves along the * X axis in its local coordinate system. @@ -586,8 +591,6 @@ o3djs.manipulators.Manager.prototype.createRotate1 = function() { o3djs.manipulators.Manager.prototype.add_ = function(manip) { // Generate draw elements for the manipulator's transform manip.getTransform().createDrawElements(this.pack, null); - // Add the manipulator's transform to the parent transform - manip.getBaseTransform_().parent = this.parentTransform; // Add the manipulator into our managed list this.manipsByClientId[manip.getTransform().clientId] = manip; } @@ -628,8 +631,13 @@ o3djs.manipulators.Manager.prototype.handleMouse_ = function(x, // Find which manipulator we picked. // NOTE this assumes some things about the transform graph // structure of the manipulators. + // We may need to index by the parent-parent transform instead, since the + // shape could be attached to the manip's invisibleTransform_, which is a + // child of the localTransform_. var manip = - this.manipsByClientId[pickResult.shapeInfo.parent.transform.clientId]; + this.manipsByClientId[pickResult.shapeInfo.parent.transform.clientId] || + this.manipsByClientId[ + pickResult.shapeInfo.parent.parent.transform.clientId]; func(this, pickResult, manip); } else { func(this, null, null); @@ -808,9 +816,28 @@ o3djs.manipulators.Manip = function(manager) { */ this.baseTransform_ = pack.createObject('Transform'); + /** + * This child transform is used only to hold any invisible shapes + * we may want. Invisible shapes can be useful for picking. Visibility is + * controlled by the transform, which is why we need this transform. + * The local matrix of this transform should only be the identity matrix. + * @private + * @type {!o3d.Transform} + */ + this.invisibleTransform_ = pack.createObject('Transform'); + this.invisibleTransform_.visible = false; + // Hook up these transforms + this.invisibleTransform_.parent = this.localTransform_; this.localTransform_.parent = this.offsetTransform_; this.offsetTransform_.parent = this.baseTransform_; + this.baseTransform_.parent = manager.parentTransform; + + // Make the invisible transform pickable even though it's invisible + manager.pickManager.update(); + var invisibleTransformInfo = manager.pickManager.getTransformInfo( + this.invisibleTransform_); + invisibleTransformInfo.pickableEvenIfInvisible = true; /** * This is the transform in the scene graph to which this @@ -833,10 +860,19 @@ o3djs.manipulators.Manip = function(manager) { * Adds shapes to the internal transform of this manipulator. * @private * @param {!Array.<!o3d.Shape>} shapes Array of shapes to add. + * @param {boolean} opt_visible Whether the added shapes should be visible. + * Default = true. Invisible geometry can be useful for picking. */ -o3djs.manipulators.Manip.prototype.addShapes_ = function(shapes) { +o3djs.manipulators.Manip.prototype.addShapes_ = function(shapes, opt_visible) { + if (opt_visible == undefined) { + opt_visible = true; + } for (var ii = 0; ii < shapes.length; ii++) { - this.localTransform_.addShape(shapes[ii]); + if(opt_visible) { + this.localTransform_.addShape(shapes[ii]); + } else { + this.invisibleTransform_.addShape(shapes[ii]); + } } } @@ -1145,7 +1181,7 @@ o3djs.manipulators.Translate1 = function(manager) { o3djs.manipulators.Manip.call(this, manager); var pack = manager.pack; - var material = manager.defaultMaterial; + var material = manager.constantMaterial; var shape = manager.translate1Shape_; if (!shape) { @@ -1159,10 +1195,6 @@ o3djs.manipulators.Translate1 = function(manager) { this.addShapes_([ shape ]); - this.transformInfo = manager.pickManager.createTransformInfo( - this.getTransform(), - manager.transformInfo); - /** * A parameter added to our transform to be able to change the * material's color for highlighting. @@ -1254,7 +1286,7 @@ o3djs.manipulators.Translate2 = function(manager) { o3djs.manipulators.Manip.call(this, manager); var pack = manager.pack; - var material = manager.defaultMaterial; + var material = manager.constantMaterial; var shape = manager.Translate2Shape_; if (!shape) { @@ -1271,10 +1303,6 @@ o3djs.manipulators.Translate2 = function(manager) { this.addShapes_([ shape ]); - this.transformInfo = manager.pickManager.createTransformInfo( - this.getTransform(), - manager.transformInfo); - /** * A parameter added to our transform to be able to change the * material's color for highlighting. @@ -1367,27 +1395,40 @@ o3djs.manipulators.Rotate1 = function(manager) { o3djs.manipulators.Manip.call(this, manager); var pack = manager.pack; - var material = manager.defaultMaterial; - var shape = manager.Rotate1Shape_; - if (!shape) { - // Create the geometry for the manipulator, which looks like + if (!manager.lineRingMaterial) { + manager.lineRingMaterial = o3djs.manipulators.createLineRingMaterial( + pack, manager.drawList, [1, 1, 1, 1], [1, 1, 1, 0.4]); + } + + var pickShape = manager.Rotate1PickShape_; + if (!pickShape) { + // Create the polygon geometry for picking the manipulator, which looks like // a torus centered at the origin, with the X axis as its vertical axis. var verts = o3djs.primitives.createTorusVertices( 1.0, 0.1, - 32, - 8, + 16, + 6, o3djs.math.matrix4.rotationZ(Math.PI / 2)); - shape = verts.createShape(pack, material); - manager.Rotate1Shape_ = shape; + pickShape = verts.createShape(pack, manager.constantMaterial); + manager.Rotate1PickShape_ = pickShape; } - this.addShapes_([ shape ]); + var visibleShape = manager.Rotate1VisibleShape_; + if (!visibleShape) { + // 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.lineRingMaterial); + manager.Rotate1VisibleShape_ = visibleShape; + } - this.transformInfo = manager.pickManager.createTransformInfo( - this.getTransform(), - manager.transformInfo); + this.addShapes_([ pickShape ], false); // Invisible + this.addShapes_([ visibleShape ]); /** * A parameter added to our transform to be able to change the @@ -1508,3 +1549,93 @@ o3djs.manipulators.Rotate1.prototype.drag = function(startPoint, this.getTransform().localMatrix = o3djs.math.matrix4.rotationX(-angle); this.updateAttachedTransformFromLocalTransform_(); } + + +// The shader and material for the Rotate1 manipulator's line ring. +// 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'; + +/** + * Creates the Rotate1 manipulator's line ring material. + * + * @param {!o3d.Pack} pack The pack to create the effect and material in. + * @param {!o3d.DrawList} drawList The draw list against which + * 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]. + * @return {!o3d.Material} The created material. + */ +o3djs.manipulators.createLineRingMaterial = function(pack, + drawList, + color1, + color2) { + 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.drawList = drawList; + material.createParam('color1', 'ParamFloat4').value = color1; + material.createParam('color2', 'ParamFloat4').value = color2; + + // Set up the state to allow alpha blending + material.state = pack.createObject('State'); + material.state.getStateParam('AlphaBlendEnable').value = true; + material.state.getStateParam('SourceBlendFunction').value = + o3djs.base.o3d.State.BLENDFUNC_SOURCE_ALPHA; + material.state.getStateParam('DestinationBlendFunction').value = + o3djs.base.o3d.State.BLENDFUNC_INVERSE_SOURCE_ALPHA; + material.state.getStateParam('AlphaTestEnable').value = true; + material.state.getStateParam('AlphaComparisonFunction').value = + o3djs.base.o3d.State.CMP_GREATER; + + return material; +}; |