diff options
author | luchen@google.com <luchen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-05 02:07:51 +0000 |
---|---|---|
committer | luchen@google.com <luchen@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-05 02:07:51 +0000 |
commit | e8f03e2b6ca119a31abdfeac549949f0ebcc66fb (patch) | |
tree | f5b53bd759f199bdd343c95732fad71dabc6a3a0 /o3d | |
parent | 97452c9788b026b810bd4fbd55cfd40711548e3d (diff) | |
download | chromium_src-e8f03e2b6ca119a31abdfeac549949f0ebcc66fb.zip chromium_src-e8f03e2b6ca119a31abdfeac549949f0ebcc66fb.tar.gz chromium_src-e8f03e2b6ca119a31abdfeac549949f0ebcc66fb.tar.bz2 |
o3d-webgl: Adding support for triangle fan/strip in picking.
TEST=picking-more.html demo
Review URL: http://codereview.chromium.org/2805101
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@55017 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/samples/o3d-webgl-samples/picking-more.html | 384 | ||||
-rw-r--r-- | o3d/samples/o3d-webgl/primitive.js | 64 |
2 files changed, 441 insertions, 7 deletions
diff --git a/o3d/samples/o3d-webgl-samples/picking-more.html b/o3d/samples/o3d-webgl-samples/picking-more.html new file mode 100644 index 0000000..b158603 --- /dev/null +++ b/o3d/samples/o3d-webgl-samples/picking-more.html @@ -0,0 +1,384 @@ +<!-- +Copyright 2010, 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. +--> +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> +<head> +<meta http-equiv="content-type" content="text/html; charset=UTF-8"> +<title> +Picking and IndexBuffers +</title> +<script type="text/javascript" src="../o3d-webgl/base.js"></script> +<script type="text/javascript" src="../o3djs/base.js"></script> +<script type="text/javascript" id="o3dscript"> +o3djs.base.o3d = o3d; +o3djs.require('o3djs.webgl'); +o3djs.require('o3djs.math'); +o3djs.require('o3djs.rendergraph'); +o3djs.require('o3djs.primitives'); +o3djs.require('o3djs.material'); +o3djs.require('o3djs.picking'); + +// global variables +var g_o3dElement; +var g_client; +var g_o3d; +var g_math; +var g_pack; +var g_viewInfo; +var g_eyePosition = [0, 0, 10]; +var g_dataroot; +var g_pickManager; + +/** + * Creates the client area. + */ +function initClient() { + window.g_finished = false; // for selenium testing. + o3djs.webgl.makeClients(main); +} + +/** + * Updates the span with the name of the shape that was picked, if anything. + * @param {event} e + */ +function pick(e) { + var worldRay = o3djs.picking.clientPositionToWorldRay( + e.x, + e.y, + g_viewInfo.drawContext, + g_client.width, + g_client.height); + var pickInfo = g_pickManager.pick(worldRay); + var picked = 'nothing'; + if (pickInfo) { + picked = pickInfo.shapeInfo.shape.name; + } + document.getElementById('picked').innerHTML = picked; +} + +/** + * Rotates the scene if key is one of 'wasd'. + * @param {event} event + */ +function rotateScene(event) { + // Ignore accelerator key messages. + if (event.metaKey) + return; + + var keyChar = String.fromCharCode(o3djs.event.getEventKeyChar(event)); + // Just in case they have capslock on. + keyChar = keyChar.toLowerCase(); + + var actionTaken = false; + var delta = 0.1; + switch(keyChar) { + case 'a': + g_dataroot.localMatrix = + g_math.matrix4.mul(g_dataroot.localMatrix, + g_math.matrix4.rotationY(-delta)); + actionTaken = true; + break; + case 'd': + g_dataroot.localMatrix = + g_math.matrix4.mul(g_dataroot.localMatrix, + g_math.matrix4.rotationY(delta)); + actionTaken = true; + break; + case 'w': + g_dataroot.localMatrix = + g_math.matrix4.mul(g_dataroot.localMatrix, + g_math.matrix4.rotationX(-delta)); + actionTaken = true; + break; + case 's': + g_dataroot.localMatrix = + g_math.matrix4.mul(g_dataroot.localMatrix, + g_math.matrix4.rotationX(delta)); + actionTaken = true; + break; + } + if (actionTaken) { + g_pickManager.update(); + } +} + +/** + * Initializes global variables, positions camera, draws shapes. + * @param {Array} clientElements Array of o3d object elements. + */ +function main(clientElements) { + // Init global variables. + initGlobals(clientElements); + + // Set up the view and projection transformations. + initContext(); + + // Add the shapes to the transform heirarchy. + createShapes(); + + o3djs.event.addEventListener(g_o3dElement, 'mousedown', pick); + o3djs.event.addEventListener(g_o3dElement, 'keypress', rotateScene); + + // Create the pick manager. + g_pickManager = o3djs.picking.createPickManager(g_client.root); + g_pickManager.update(); + + window.g_finished = true; // for selenium testing. +} + +/** + * Initializes global variables and libraries. + */ +function initGlobals(clientElements) { + g_o3dElement = clientElements[0]; + window.g_client = g_client = g_o3dElement.client; + g_o3d = g_o3dElement.o3d; + g_math = o3djs.math; + + // Create a pack to manage the objects created. + g_pack = g_client.createPack(); + + // Creates a transform to put our data on. + g_dataroot = g_pack.createObject('Transform'); + g_dataroot.parent = g_client.root; + g_dataroot.rotateY(-0.3); + + // Create the render graph for a view. + g_viewInfo = o3djs.rendergraph.createBasicView( + g_pack, + g_client.root, + g_client.renderGraphRoot); +} +/** + * Sets up reasonable view and projection matrices. + */ +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_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, 0, 0], // target + [0, 1, 0]); // up +} + +/** + * Creates shapes using the primitives utility library, and adds them to the + * transform graph at the root node. + */ +function createShapes() { + var triangleFan = createShape(g_o3d.Primitive.TRIANGLEFAN); + triangleFan.name = 'triangle-fan'; + var triangleStrip = createShape(g_o3d.Primitive.TRIANGLESTRIP); + triangleStrip.name = 'triangle-strip'; + var triangleList = createShape(g_o3d.Primitive.TRIANGLELIST); + triangleList.name = 'triangle-list'; + var noIndexBuffer = createShape(-1); + noIndexBuffer.name = 'bufferless'; + + // Add the shapes to the transforms. + var transformTable = [ + {shape: noIndexBuffer, translation: [-0.5, 1.25, 0]}, + {shape: triangleFan, translation: [-1.0, -1.0, 0]}, + {shape: triangleStrip, translation: [1.0, -1.0, 0]}, + {shape: triangleList, translation: [0, 0, 0]} + ]; + + for (var tt = 0; tt < transformTable.length; ++tt) { + var transform = g_pack.createObject('Transform'); + transform.addShape(transformTable[tt].shape); + transform.translate(transformTable[tt].translation); + transform.parent = g_dataroot; + } +} + +/** + * Creates a shape that uses the requested indexing type. + * @param {o3d.Primitive.Type} indexType + */ +function createShape(indexType) { + var material = g_pack.createObject('Material'); + var effect = g_pack.createObject('Effect'); + var shaderString = document.getElementById('shader').value; + effect.loadFromFXString(shaderString); + material.effect = effect; + material.drawList = g_viewInfo.performanceDrawList; + effect.createUniformParameters(material); + + var shape = g_pack.createObject('Shape'); + var primitive = g_pack.createObject('Primitive'); + var streamBank = g_pack.createObject('StreamBank'); + + primitive.material = material; + primitive.owner = shape; + primitive.streamBank = streamBank; + primitive.primitiveType = indexType; + primitive.createDrawElement(g_pack, null); + + var positionArray = []; + + switch (indexType) { + case g_o3d.Primitive.TRIANGLEFAN: + positionArray = [ + 0.5, 0.0, 0.5, // 0 + 0.5, 0.0, -0.5, // 1 + -0.5, 0.0, -0.5, // 2 + -0.5, 0.0, 0.5, // 3 + 0.0, -1.0, 0.0 // 4 + ]; + indices = [4, 3, 2, 1, 0, 3]; // Square pyramid w/o the bottom. + primitive.numberPrimitives = 4; + primitive.numberVertices = 5; + break; + case g_o3d.Primitive.TRIANGLESTRIP: + positionArray = [ + 0.0, 0.0, 0.0, // 0 + 1.0, 0.0, 0.0, // 1 + 0.5, 0.0, -0.866, // 2 + 0.5, 0.866, -0.433 // 3 + ]; + indices = [0, 1, 3, 2, 0, 1]; // Triangular pyramid sort of shape. + primitive.numberPrimitives = 4; + primitive.numberVertices = 4; + break; + case g_o3d.Primitive.TRIANGLELIST: + positionArray = [ + -0.5, -0.5, 0.5, // vertex 0 + 0.5, -0.5, 0.5, // vertex 1 + -0.5, 0.5, 0.5, // vertex 2 + 0.5, 0.5, 0.5, // vertex 3 + -0.5, 0.5, -0.5, // vertex 4 + 0.5, 0.5, -0.5, // vertex 5 + -0.5, -0.5, -0.5, // vertex 6 + 0.5, -0.5, -0.5 // vertex 7 + ]; + indices = [ + 0, 1, 2, // face 1 + 2, 1, 3, + 2, 3, 4, // face 2 + 4, 3, 5, + 4, 5, 6, // face 3 + 6, 5, 7, + 6, 7, 0, // face 4 + 0, 7, 1, + 1, 7, 3, // face 5 + 3, 7, 5, + 6, 0, 4, // face 6 + 4, 0, 2 + ]; + primitive.numberPrimitives = 12; + primitive.numberVertices = 8; + break; + default: + // No index buffer. Vertex data contains triples of triangles. + positionArray = [ + -0.5, -0.5, 0.5, + 0.5, -0.5, 0.5, + -0.5, 0.5, 0.5, + 0.5, -0.5, 0.5, + 1.5, -0.5, 0.5, // vertex 1 + 1.5, 0.5, 0.5 // vertex 3 + ]; + indices = null; + primitive.numberPrimitives = 2; + primitive.numberVertices = 6; + break; + } + + // Create buffers containing the vertex data. + var positionsBuffer = g_pack.createObject('VertexBuffer'); + var positionsField = positionsBuffer.createField('FloatField', 3); + positionsBuffer.set(positionArray); + + if (indices) { + var indexBuffer = g_pack.createObject('IndexBuffer'); + indexBuffer.set(indices); + primitive.indexBuffer = indexBuffer; + } + + // Associate the positions Buffer with the StreamBank. + streamBank.setVertexStream( + g_o3d.Stream.POSITION, // semantic: This stream stores vertex positions + 0, // semantic index: First (and only) position stream + positionsField, // field: the field this stream uses. + 0); // start_index: How many elements to skip in the + // field. + return shape; +} +</script> +</head> +<body onload="initClient()"> +<h1>More Picking</h1> +<p>This example demonstrates picking with custom shapes that use a variety of +index buffer formats. Back faces are culled (hidden) and cannot be picked.</p> +<p> + You picked: <span id="picked" style="color: red;">nothing</span> +</p> +<p>Rotate in the scene with WASD.</p> +<br/> +<!-- Start of O3D plugin --> +<div id="o3d" style="width: 600px; height: 600px;"></div> +<!-- End of O3D plugin --> + +<textarea id="shader" style="display: none;"> + attribute vec4 position; + uniform mat4 worldViewProjection; + varying vec4 pos; + + /** + * The vertex shader simply transforms the input vertices to screen space. + */ + void main() { + // Multiply the vertex positions by the worldViewProjection matrix to + // transform them to screen space. + gl_Position = worldViewProjection * position; + pos = position; + } + + // #o3d SplitMarker + varying vec4 pos; + + /** + * The fragment shader derives color based on the position. + */ + void main() { + gl_FragColor = vec4(pos.xyz, 1.0); + } +</textarea> +</body> +</html> diff --git a/o3d/samples/o3d-webgl/primitive.js b/o3d/samples/o3d-webgl/primitive.js index 17f483a..e1c02b4 100644 --- a/o3d/samples/o3d-webgl/primitive.js +++ b/o3d/samples/o3d-webgl/primitive.js @@ -333,6 +333,44 @@ o3d.Primitive.prototype.computeWireframeIndices_ = function() { } }; +/** + * Returns the three indices of the n-th triangle of this primitive. If the + * primitive has no index buffer, then the buffer is assumed to be [0 ... n-1]. + * These indices can then be used to reference the vertex buffer and get the + * triangle vertices' positions. + * + * @param {number} n The number of the triangle we want. Zero-indexed. + * @return {!Array.<Number>} Array containing three indices that correspond to + * the n-th triangle of this primitive. + * @private + */ +o3d.Primitive.prototype.computeTriangleIndices_ = function(n) { + var indices; + switch (this.primitiveType) { + case o3d.Primitive.TRIANGLESTRIP: + if (n % 2 == 0) { + indices = [n, n + 1, n + 2]; + } else { + indices = [n + 1, n, n + 2]; + } + break; + case o3d.Primitive.TRIANGLEFAN: + indices = [0, n + 1, n + 2]; + break; + case o3d.Primitive.TRIANGLELIST: + default: + indices = [3 * n, 3 * n + 1, 3 * n + 2]; + break; + } + if (this.indexBuffer) { + var buffer = this.indexBuffer.array_; + return [buffer[indices[0]], + buffer[indices[1]], + buffer[indices[2]]]; + } else { + return indices; + } +}; /** * Computes the intersection of a ray in the coordinate system of @@ -392,15 +430,27 @@ o3d.Primitive.prototype.intersectRay = // from the start the point with this variable. var min_distance = 0; - // Iterate through the indices three at a time. Each triple of indices - // defines a triangle. For each triangle, we test for intersection with + // Iterate through the indices and examine triples of indices that each + // define a triangle. For each triangle, we test for intersection with // the ray. We need to find the closest one to start, so we have to // check them all. - var a = indexBuffer.array_; - for (var i = 0; i < a.length / 3; ++i) { - // Indices of the triangle. - var t = 3 * i; - var indices = [a[t], a[t + 1], a[t + 2]]; + + var numIndices = indexBuffer ? indexBuffer.array_.length : numPoints; + switch (this.primitiveType) { + case o3d.Primitive.TRIANGLESTRIP: + numTriangles = numIndices - 2; + break; + case o3d.Primitive.TRIANGLEFAN: + numTriangles = numIndices - 2; + break; + case o3d.Primitive.TRIANGLELIST: + default: + numTriangles = numIndices / 3; + break; + } + + for (var i = 0; i < numTriangles; ++i) { + var indices = this.computeTriangleIndices_(i); // Check if the current triangle is too far to one side of the ray // to intersect at all. (This is what the orthogonal vectors are for) |