// // sphere.js // interface // // Created by Andrzej Kapolka on 12/17/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // function strictIndexOf(array, element) { for (var i = 0; i < array.length; i++) { if (array[i] == element) { return i; } } return -1; } var colorIndex; var normalIndex; var visitor; var info; var MAX_DEPTH = 4; var sphereCenter = [ 0.5, 0.5, 0.5 ]; var sphereColor = 0xFFFF00FF; var sphereRadius = 0.25; var sphereRadiusSquared = sphereRadius * sphereRadius; function lengthSquared(x, y, z) { return x*x + y*y + z*z; } function setNormal(vector) { if (normalIndex != -1) { var length = Math.sqrt(lengthSquared(vector[0], vector[1], vector[2])); if (length == 0.0) { info.inputValues[normalIndex] = 0x007F00; } else { var scale = 127.0 / length; info.inputValues[normalIndex] = (Math.floor(vector[0] * scale) & 0xFF) << 16 | (Math.floor(vector[1] * scale) & 0xFF) << 8 | Math.floor(vector[2] * scale) & 0xFF; } } } function guide(minimum, size, depth) { info.minimum = minimum; info.size = size; // start with a relative fast bounding volume test to find most non-intersecting states var maximum = [ minimum[0] + size, minimum[1] + size, minimum[2] + size ]; if (minimum[0] >= sphereCenter[0] + sphereRadius || minimum[1] >= sphereCenter[1] + sphereRadius || minimum[2] >= sphereCenter[2] + sphereRadius || maximum[0] <= sphereCenter[0] - sphereRadius || maximum[1] <= sphereCenter[1] - sphereRadius || maximum[2] <= sphereCenter[2] - sphereRadius) { info.isLeaf = true; if (colorIndex != -1) { info.inputValues[colorIndex] = 0x0; } visitor.visit(info); return; } var halfSize = size / 2; var center = [ minimum[0] + halfSize, minimum[1] + halfSize, minimum[2] + halfSize ]; var vector = [ center[0] - sphereCenter[0], center[1] - sphereCenter[1], center[2] - sphereCenter[2] ]; // count the number of points inside the sphere var inside = 0; if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - minimum[2]) <= sphereRadiusSquared) { inside++; } if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - minimum[2]) <= sphereRadiusSquared) { inside++; } if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - minimum[2]) <= sphereRadiusSquared) { inside++; } if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - minimum[2]) <= sphereRadiusSquared) { inside++; } if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - maximum[2]) <= sphereRadiusSquared) { inside++; } if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - minimum[1], sphereCenter[2] - maximum[2]) <= sphereRadiusSquared) { inside++; } if (lengthSquared(sphereCenter[0] - minimum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - maximum[2]) <= sphereRadiusSquared) { inside++; } if (lengthSquared(sphereCenter[0] - maximum[0], sphereCenter[1] - maximum[1], sphereCenter[2] - maximum[2]) <= sphereRadiusSquared) { inside++; } // see if all points are in the sphere if (inside == 8) { info.isLeaf = true; if (colorIndex != -1) { info.inputValues[colorIndex] = sphereColor; } setNormal(vector); visitor.visit(info); return; } // if we've reached max depth, compute alpha using a volume estimate if (depth == MAX_DEPTH) { info.isLeaf = true; if (inside >= 3) { if (colorIndex != -1) { info.inputValues[colorIndex] = sphereColor; } setNormal(vector); } else { if (colorIndex != -1) { info.inputValues[colorIndex] = 0x0; } } visitor.visit(info); return; } // recurse info.isLeaf = false; if (!visitor.visit(info)) { return; } depth += 1; guide(minimum, halfSize, depth); guide([ center[0], minimum[1], minimum[2] ], halfSize, depth); guide([ minimum[0], center[1], minimum[2] ], halfSize, depth); guide([ center[0], center[1], minimum[2] ], halfSize, depth); guide([ minimum[0], minimum[1], center[2] ], halfSize, depth); guide([ center[0], minimum[1], center[2] ], halfSize, depth); guide([ minimum[0], center[1], center[2] ], halfSize, depth); guide([ center[0], center[1], center[2] ], halfSize, depth); } (function(visitation) { var inputs = visitation.visitor.getInputs(); colorIndex = strictIndexOf(inputs, AttributeRegistry.colorAttribute); normalIndex = strictIndexOf(inputs, AttributeRegistry.normalAttribute); visitor = visitation.visitor; info = { inputValues: new Array(inputs.length) }; // have the sphere orbit the center and pulse in size var time = new Date().getTime(); var ROTATE_PERIOD = 400.0; sphereCenter[0] = 0.5 + 0.25 * Math.cos(time / ROTATE_PERIOD); sphereCenter[2] = 0.5 + 0.25 * Math.sin(time / ROTATE_PERIOD); var PULSE_PERIOD = 300.0; sphereRadius = 0.25 + 0.0625 * Math.cos(time / PULSE_PERIOD); sphereRadiusSquared = sphereRadius * sphereRadius; guide(visitation.info.minimum, visitation.info.size, 0); })