summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
Diffstat (limited to 'o3d')
-rw-r--r--o3d/samples/o3djs/element.js68
-rw-r--r--o3d/samples/o3djs/picking.js38
-rw-r--r--o3d/samples/picking.html57
3 files changed, 148 insertions, 15 deletions
diff --git a/o3d/samples/o3djs/element.js b/o3d/samples/o3djs/element.js
index aedcacb..0c4593b 100644
--- a/o3d/samples/o3djs/element.js
+++ b/o3d/samples/o3djs/element.js
@@ -141,4 +141,72 @@ o3djs.element.duplicateElement = function(pack, sourceElement) {
return newElement;
};
+/**
+ * Gets the normal for specific triangle in a Primitive in that Primitive's
+ * local space.
+ *
+ * NOTE: THIS FUNCTION IS SLOW! If you want to do collisions you should use a
+ * different solution.
+ *
+ * @param {!o3d.Primitive} primitive Primitive to get normal from. The
+ * primitive MUST be a TRIANGLELIST or a TRIANGLESTRIP and it must have a
+ * POSITION,0 stream.
+ * @param {number} index Index of triangle.
+ * @param {boolean} opt_winding The winding of the triangles of the
+ * Primitive. False = Clockwise, True = Counterclockwise. The default is
+ * false. This is only used for Primitives that have no normals.
+ * @return {!o3djs.math.Vector3} The normal for the triangle.
+ */
+o3djs.element.getNormalForTriangle = function(primitive, index, opt_winding) {
+ // Check that we can do this
+ var primitiveType = primitive.primitiveType;
+ if (primitiveType != o3djs.base.o3d.Primitive.TRIANGLELIST &&
+ primitiveType != o3djs.base.o3d.Primitive.TRIANGLESTRIP) {
+ throw 'primitive is not a TRIANGLELIST or TRIANGLESTRIP';
+ }
+
+ var indexBuffer = primitive.indexBuffer;
+ var vertexIndex = (primitiveType == o3djs.base.o3d.Primitive.TRIANGLELIST) ?
+ (index * 3) : (index + 2);
+ var vertexIndices;
+ if (indexBuffer) {
+ var indexField = indexBuffer.fields[0];
+ vertexIndices = indexField.getAt(vertexIndex, 3);
+ } else {
+ vertexIndices = [vertexIndex, vertexIndex + 1, vertexIndex + 2]
+ }
+
+ var normalStream = primitive.streamBank.getVertexStream(
+ o3djs.base.o3d.Stream.NORMAL, 0);
+ if (normalStream) {
+ var normalField = normalStream.field;
+ // Look up the 3 normals that make the triangle.
+ var summedNormal = [0, 0, 0];
+ for (var ii = 0; ii < 3; ++ii) {
+ var normal = normalField.getAt(vertexIndices[ii], 1);
+ summedNormal = o3djs.math.addVector(summedNormal, normal);
+ }
+ return o3djs.math.normalize(summedNormal);
+ } else {
+ var positionStream = primitive.streamBank.getVertexStream(
+ o3djs.base.o3d.Stream.POSITION, 0);
+ if (!positionStream) {
+ throw 'no POSITION,0 stream in primitive';
+ }
+ var positionField = positionStream.field;
+ // Lookup the 3 positions that make the triangle.
+ var positions = [];
+ for (var ii = 0; ii < 3; ++ii) {
+ positions[ii] = positionField.getAt(vertexIndices[ii], 1);
+ }
+
+ // Compute a face normal from the positions.
+ var v0 = o3djs.math.normalize(o3djs.math.subVector(positions[1],
+ positions[0]));
+ var v1 = o3djs.math.normalize(o3djs.math.subVector(positions[2],
+ positions[1]));
+ return opt_winding ? o3djs.math.cross(v1, v0) : o3djs.math.cross(v0, v1);
+ }
+};
+
diff --git a/o3d/samples/o3djs/picking.js b/o3d/samples/o3djs/picking.js
index a40eb5d..06e3765 100644
--- a/o3d/samples/o3djs/picking.js
+++ b/o3d/samples/o3djs/picking.js
@@ -70,18 +70,20 @@ o3djs.picking.Ray = goog.typedef;
/**
* Creates a new PickInfo.
- * @param {!o3djs.picking.ShapeInfo} shapeInfo The ShapeInfo that
- * was picked.
- * @param {!o3d.RayIntersectionInfo} rayIntersectionInfo Information
- * about the pick.
- * @param {!o3djs.math.Vector3} worldIntersectionPosition
- * world position of intersection.
+ * @param {!o3d.Element} element The Element that was picked.
+ * @param {!o3djs.picking.ShapeInfo} shapeInfo The ShapeInfo that was picked.
+ * @param {!o3d.RayIntersectionInfo} rayIntersectionInfo Information about the
+ * pick.
+ * @param {!o3djs.math.Vector3} worldIntersectionPosition world position of
+ * intersection.
* @return {!o3djs.picking.PickInfo} The new PickInfo.
*/
-o3djs.picking.createPickInfo = function(shapeInfo,
+o3djs.picking.createPickInfo = function(element,
+ shapeInfo,
rayIntersectionInfo,
worldIntersectionPosition) {
- return new o3djs.picking.PickInfo(shapeInfo,
+ return new o3djs.picking.PickInfo(element,
+ shapeInfo,
rayIntersectionInfo,
worldIntersectionPosition);
};
@@ -219,17 +221,24 @@ o3djs.picking.dumpRayIntersectionInfo = function(label,
/**
* Creates a new PickInfo. Used to return picking information.
* @constructor
- * @param {!o3djs.picking.ShapeInfo} shapeInfo The ShapeInfo that
- * was picked.
- * @param {!o3d.RayIntersectionInfo} rayIntersectionInfo Information
- * about the pick.
+ * @param {!o3d.Element} element The Element that was picked.
+ * @param {!o3djs.picking.ShapeInfo} shapeInfo The ShapeInfo that was picked.
+ * @param {!o3d.RayIntersectionInfo} rayIntersectionInfo Information about the
+ * pick.
* @param {!o3djs.math.Vector3} worldIntersectionPosition world position of
* intersection.
*/
-o3djs.picking.PickInfo = function(shapeInfo,
+o3djs.picking.PickInfo = function(element,
+ shapeInfo,
rayIntersectionInfo,
worldIntersectionPosition) {
/**
+ * The Element that was picked (Primitive).
+ * @type {!o3d.Element}
+ */
+ this.element = element;
+
+ /**
* The ShapeInfo that was picked.
* @type {!o3djs.picking.ShapeInfo}
*/
@@ -335,7 +344,8 @@ o3djs.picking.ShapeInfo.prototype.pick = function(worldRay) {
if (rayIntersectionInfo.intersected) {
var worldIntersectionPosition = o3djs.math.matrix4.transformPoint(
worldMatrix, rayIntersectionInfo.position);
- return o3djs.picking.createPickInfo(this,
+ return o3djs.picking.createPickInfo(element,
+ this,
rayIntersectionInfo,
worldIntersectionPosition);
}
diff --git a/o3d/samples/picking.html b/o3d/samples/picking.html
index cd9ddd1..ae62ebd 100644
--- a/o3d/samples/picking.html
+++ b/o3d/samples/picking.html
@@ -56,7 +56,7 @@ O3D Picking Example.
<!-- Include default javascript library functions-->
<script type="text/javascript" src="o3djs/base.js"></script>
<!-- Our javascript code -->
-<script type="text/javascript">
+<script type="text/javascript" id="o3d">
o3djs.require('o3djs.util');
o3djs.require('o3djs.math');
o3djs.require('o3djs.rendergraph');
@@ -64,6 +64,7 @@ o3djs.require('o3djs.pack');
o3djs.require('o3djs.camera');
o3djs.require('o3djs.picking');
o3djs.require('o3djs.scene');
+o3djs.require('o3djs.debug');
// Events
// init() once the page has finished loading.
@@ -71,6 +72,9 @@ o3djs.require('o3djs.scene');
window.onload = init;
window.onunload = unload;
+// constants
+var NORMAL_SCALE_FACTOR = 2.0;
+
// global variables
var g_o3d;
var g_math;
@@ -79,6 +83,9 @@ var g_pack;
var g_viewInfo;
var g_treeInfo; // information about the transform graph.
var g_pickInfoElem;
+var g_debugHelper;
+var g_debugLineGroup;
+var g_debugLine;
var g_selectedInfo = null;
var g_flashTimer = 0;
var g_highlightMaterial;
@@ -135,13 +142,53 @@ function pick(e) {
unSelectAll();
// Update the entire tree in case anything moved.
+ // NOTE: This function is very SLOW!
+ // If you really want to use picking you should manually update only those
+ // transforms and shapes that moved, were added, or deleted by writing your
+ // own picking library. You should also make sure that you are only
+ // considering things that are pickable. By that I mean if you have a scene of
+ // a meadow with trees, grass, bushes, and animals and the only thing the user
+ // can pick is the animals then put the animals on their own sub branch of the
+ // transform graph and only pick against that subgraph.
+ // Even better, make a separate transform graph with only cubes on it to
+ // represent the animals and use that instead of the actual animals.
g_treeInfo.update();
var pickInfo = g_treeInfo.pick(worldRay);
if (pickInfo) {
select(pickInfo);
g_pickInfoElem.innerHTML = pickInfo.shapeInfo.shape.name;
+
+ // Display the normal
+ // NOTE: Lookup the normal with this function is very SLOW!!
+ // If you need performance, for a game or something, you should consider
+ // other methods.
+ var normal = o3djs.element.getNormalForTriangle(
+ pickInfo.element,
+ pickInfo.rayIntersectionInfo.primitiveIndex);
+
+ // Convert the normal from local to world space.
+ normal = g_math.matrix4.transformNormal(
+ pickInfo.shapeInfo.parent.transform.worldMatrix,
+ normal);
+
+ // Remove the scale from the normal.
+ normal = g_math.normalize(normal);
+
+ // Get the world position of the collision.
+ var worldPosition = pickInfo.worldIntersectionPosition;
+
+ // Add the normal to it to get a point in space above it with some
+ // multiplier to scale it.
+ var normalSpot = g_math.addVector(
+ worldPosition,
+ g_math.mulVectorScalar(normal, NORMAL_SCALE_FACTOR));
+
+ // Move our debug line to show the normal
+ g_debugLine.setVisible(true);
+ g_debugLine.setEndPoints(worldPosition, normalSpot);
} else {
+ g_debugLine.setVisible(false);
g_pickInfoElem.innerHTML = '--nothing--';
}
}
@@ -238,6 +285,14 @@ function initStep2(clientElements) {
g_client.root,
g_client.renderGraphRoot);
+ // Use the debug library to create a line we can position to show
+ // the normal.
+ g_debugHelper = o3djs.debug.createDebugHelper(g_client.createPack(),
+ g_viewInfo);
+ g_debugLineGroup = g_debugHelper.createDebugLineGroup(g_client.root);
+ g_debugLine = g_debugLineGroup.addLine();
+ g_debugLine.setColor([0,1,0,1]);
+
// Create a material for highlighting.
g_highlightMaterial = g_pack.createObject('Material');
g_highlightMaterial.drawList = g_viewInfo.performanceDrawList;