summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authorluchen@google.com <luchen@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-05 02:07:51 +0000
committerluchen@google.com <luchen@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-08-05 02:07:51 +0000
commite8f03e2b6ca119a31abdfeac549949f0ebcc66fb (patch)
treef5b53bd759f199bdd343c95732fad71dabc6a3a0 /o3d
parent97452c9788b026b810bd4fbd55cfd40711548e3d (diff)
downloadchromium_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.html384
-rw-r--r--o3d/samples/o3d-webgl/primitive.js64
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)