From 87e33397918d1148684210c93fe2692feb04e07f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Jan 2015 12:28:05 -0800 Subject: [PATCH 01/11] Fix for normal selection with degenerate triangles. --- interface/src/MetavoxelSystem.cpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index eeb1c84a4e..ea4941ee33 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1498,6 +1498,17 @@ const NormalIndex& IndexVector::get(int y) const { return (relative >= 0 && relative < size()) ? at(relative) : invalidIndex; } +static inline glm::vec3 getNormal(const QVector& vertices, const NormalIndex& i0, + const NormalIndex& i1, const NormalIndex& i2, const NormalIndex& i3) { + // check both triangles in case one is degenerate + const glm::vec3& v0 = vertices.at(i0.indices[0]).vertex; + glm::vec3 normal = glm::cross(vertices.at(i1.indices[0]).vertex - v0, vertices.at(i2.indices[0]).vertex - v0); + if (glm::length(normal) > EPSILON) { + return normal; + } + return glm::cross(vertices.at(i2.indices[0]).vertex - v0, vertices.at(i3.indices[0]).vertex - v0); +} + void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, bool cursor) { if (!node->getHeight()) { @@ -2174,10 +2185,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g quadIndices.insert(qRgb(reclampedX, y - 1, reclampedZ - 1), indices.size()); quadIndices.insert(qRgb(reclampedX, y, reclampedZ - 1), indices.size()); } - const glm::vec3& first = vertices.at(index.indices[0]).vertex; - glm::vec3 normal = glm::cross(vertices.at(index1.indices[0]).vertex - first, - vertices.at(index3.indices[0]).vertex - first); - + glm::vec3 normal = getNormal(vertices, index, index1, index2, index3); if (alpha0 == 0) { // quad faces negative x indices.append(index3.getClosestIndex(normal = -normal, vertices)); indices.append(index2.getClosestIndex(normal, vertices)); @@ -2206,10 +2214,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g if (reclampedZ > 0) { quadIndices.insert(qRgb(reclampedX, y, reclampedZ - 1), indices.size()); } - const glm::vec3& first = vertices.at(index.indices[0]).vertex; - glm::vec3 normal = glm::cross(vertices.at(index3.indices[0]).vertex - first, - vertices.at(index1.indices[0]).vertex - first); - + glm::vec3 normal = getNormal(vertices, index, index3, index2, index1); if (alpha0 == 0) { // quad faces negative y indices.append(index3.getClosestIndex(normal, vertices)); indices.append(index2.getClosestIndex(normal, vertices)); @@ -2235,10 +2240,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } quadIndices.insert(qRgb(reclampedX, y - 1, reclampedZ), indices.size()); - const glm::vec3& first = vertices.at(index.indices[0]).vertex; - glm::vec3 normal = glm::cross(vertices.at(index1.indices[0]).vertex - first, - vertices.at(index3.indices[0]).vertex - first); - + glm::vec3 normal = getNormal(vertices, index, index1, index2, index3); if (alpha0 == 0) { // quad faces negative z indices.append(index1.getClosestIndex(normal, vertices)); indices.append(index2.getClosestIndex(normal, vertices)); From 8636f0c48e80374ea3614789a8a9e3f5c6d951f4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Jan 2015 12:57:24 -0800 Subject: [PATCH 02/11] Simplification. --- interface/src/MetavoxelSystem.cpp | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index ea4941ee33..719326f628 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1857,11 +1857,8 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g if (!(corners & (1 << i))) { continue; } - int offsetX = (i & X_MAXIMUM_FLAG) ? 1 : 0; - int offsetZ = (i & Y_MAXIMUM_FLAG) ? 1 : 0; - const quint16* height = heightLineSrc + offsetZ * width + offsetX; - float heightValue = *height * voxelScale; - if (heightValue >= y && heightValue < y + 1) { + const EdgeCrossing& cornerCrossing = cornerCrossings[i]; + if (cornerCrossing.point.y >= y && cornerCrossing.point.y < y + 1) { crossedCorners |= (1 << i); } } @@ -1901,30 +1898,24 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g if (!(corners & (1 << i))) { continue; } - int offsetX = (i & X_MAXIMUM_FLAG) ? 1 : 0; - int offsetZ = (i & Y_MAXIMUM_FLAG) ? 1 : 0; - const quint16* height = heightLineSrc + offsetZ * width + offsetX; - float heightValue = *height * voxelScale; int nextIndex = NEXT_CORNERS[i]; if (!(corners & (1 << nextIndex))) { continue; } - int nextOffsetX = (nextIndex & X_MAXIMUM_FLAG) ? 1 : 0; - int nextOffsetZ = (nextIndex & Y_MAXIMUM_FLAG) ? 1 : 0; - const quint16* nextHeight = heightLineSrc + nextOffsetZ * width + nextOffsetX; - float nextHeightValue = *nextHeight * voxelScale; - float divisor = (nextHeightValue - heightValue); + const EdgeCrossing& cornerCrossing = cornerCrossings[i]; + const EdgeCrossing& nextCornerCrossing = cornerCrossings[nextIndex]; + float divisor = (nextCornerCrossing.point.y - cornerCrossing.point.y); if (divisor == 0.0f) { continue; } - float t1 = (y - heightValue) / divisor; - float t2 = (y + 1 - heightValue) / divisor; + float t1 = (y - cornerCrossing.point.y) / divisor; + float t2 = (y + 1 - cornerCrossing.point.y) / divisor; if (t1 >= 0.0f && t1 <= 1.0f) { - crossings[crossingCount++].mix(cornerCrossings[i], cornerCrossings[nextIndex], t1); + crossings[crossingCount++].mix(cornerCrossing, nextCornerCrossing, t1); crossings[crossingCount - 1].point.y -= y; } if (t2 >= 0.0f && t2 <= 1.0f) { - crossings[crossingCount++].mix(cornerCrossings[i], cornerCrossings[nextIndex], t2); + crossings[crossingCount++].mix(cornerCrossing, nextCornerCrossing, t2); crossings[crossingCount - 1].point.y -= y; } } From 8bd944e32e038738a95690e8af63ae630a0680f5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Jan 2015 16:10:00 -0800 Subject: [PATCH 03/11] Incremental improvement to stitching. --- interface/src/MetavoxelSystem.cpp | 49 +++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 719326f628..a0d6a8d72e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1427,6 +1427,8 @@ public: void setColorMaterial(const StackArray::Entry& entry) { color = entry.color; material = entry.material; } void mix(const EdgeCrossing& first, const EdgeCrossing& second, float t); + + VoxelPoint createPoint(int clampedX, int clampedZ, float step) const; }; void EdgeCrossing::mix(const EdgeCrossing& first, const EdgeCrossing& second, float t) { @@ -1437,6 +1439,16 @@ void EdgeCrossing::mix(const EdgeCrossing& first, const EdgeCrossing& second, fl material = (t < 0.5f) ? first.material : second.material; } +VoxelPoint EdgeCrossing::createPoint(int clampedX, int clampedZ, float step) const { + VoxelPoint voxelPoint = { glm::vec3(clampedX + point.x, point.y, clampedZ + point.z) * step, + { (quint8)qRed(color), (quint8)qGreen(color), (quint8)qBlue(color) }, + { (char)(normal.x * numeric_limits::max()), (char)(normal.y * numeric_limits::max()), + (char)(normal.z * numeric_limits::max()) }, + { (quint8)material, 0, 0, 0 }, + { numeric_limits::max(), 0, 0, 0 } }; + return voxelPoint; +} + const int MAX_NORMALS_PER_VERTEX = 4; class NormalIndex { @@ -1509,6 +1521,19 @@ static inline glm::vec3 getNormal(const QVector& vertices, const Nor return glm::cross(vertices.at(i2.indices[0]).vertex - v0, vertices.at(i3.indices[0]).vertex - v0); } +static inline void appendTriangle(const EdgeCrossing& e0, const EdgeCrossing& e1, const EdgeCrossing& e2, + int clampedX, int clampedZ, float step, QVector& vertices, QVector& indices, + QMultiHash& quadIndices) { + int firstIndex = vertices.size(); + vertices.append(e0.createPoint(clampedX, clampedZ, step)); + vertices.append(e1.createPoint(clampedX, clampedZ, step)); + vertices.append(e2.createPoint(clampedX, clampedZ, step)); + indices.append(firstIndex); + indices.append(firstIndex + 1); + indices.append(firstIndex + 2); + indices.append(firstIndex + 2); +} + void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, bool cursor) { if (!node->getHeight()) { @@ -1865,7 +1890,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g switch (crossedCorners) { case UPPER_LEFT_CORNER: case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER: - case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: + case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER | UPPER_LEFT_CORNER: case UPPER_LEFT_CORNER | LOWER_RIGHT_CORNER: crossings[crossingCount++] = cornerCrossings[0]; crossings[crossingCount - 1].point.y -= y; @@ -1873,22 +1898,34 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g case UPPER_RIGHT_CORNER: case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: - case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[1]; crossings[crossingCount - 1].point.y -= y; break; - + + case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: + crossings[crossingCount++] = cornerCrossings[1]; + crossings[crossingCount - 1].point.y -= y; + appendTriangle(cornerCrossings[1], cornerCrossings[0], cornerCrossings[2], + clampedX, clampedZ, step, vertices, indices, quadIndices); + break; + case LOWER_LEFT_CORNER: case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: - case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER | UPPER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[2]; crossings[crossingCount - 1].point.y -= y; break; - + + case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: + crossings[crossingCount++] = cornerCrossings[2]; + crossings[crossingCount - 1].point.y -= y; + appendTriangle(cornerCrossings[2], cornerCrossings[3], cornerCrossings[1], + clampedX, clampedZ, step, vertices, indices, quadIndices); + break; + case LOWER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: - case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: + case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: crossings[crossingCount++] = cornerCrossings[3]; crossings[crossingCount - 1].point.y -= y; break; From 0d8380a28839d846c5146e9c76f404802d4114c5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 21 Jan 2015 17:47:13 -0800 Subject: [PATCH 04/11] Put the indices for our extra triangles into the spatial hash. --- interface/src/MetavoxelSystem.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index a0d6a8d72e..2161887b91 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1532,6 +1532,12 @@ static inline void appendTriangle(const EdgeCrossing& e0, const EdgeCrossing& e1 indices.append(firstIndex + 1); indices.append(firstIndex + 2); indices.append(firstIndex + 2); + + int minimumY = qMin((int)e0.point.y, qMin((int)e1.point.y, (int)e2.point.y)); + int maximumY = qMax((int)e0.point.y, qMax((int)e1.point.y, (int)e2.point.y)); + for (int y = minimumY; y <= maximumY; y++) { + quadIndices.insert(qRgb(clampedX, y, clampedZ), firstIndex); + } } void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, @@ -1895,7 +1901,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g crossings[crossingCount++] = cornerCrossings[0]; crossings[crossingCount - 1].point.y -= y; break; - + case UPPER_RIGHT_CORNER: case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER: @@ -1909,7 +1915,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g appendTriangle(cornerCrossings[1], cornerCrossings[0], cornerCrossings[2], clampedX, clampedZ, step, vertices, indices, quadIndices); break; - + case LOWER_LEFT_CORNER: case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[2]; @@ -1922,7 +1928,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g appendTriangle(cornerCrossings[2], cornerCrossings[3], cornerCrossings[1], clampedX, clampedZ, step, vertices, indices, quadIndices); break; - + case LOWER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER: From 45a84895e10a0ef649ddcdaed5297356a2e93b96 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 22 Jan 2015 12:44:07 -0800 Subject: [PATCH 05/11] Paddle ball game, first version --- examples/controllers/hydra/paddleBall.js | 164 +++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 examples/controllers/hydra/paddleBall.js diff --git a/examples/controllers/hydra/paddleBall.js b/examples/controllers/hydra/paddleBall.js new file mode 100644 index 0000000000..e5d409bd8a --- /dev/null +++ b/examples/controllers/hydra/paddleBall.js @@ -0,0 +1,164 @@ +// PaddleBall.js +// +// Created by Philip Rosedale on January 21, 2015 +// Copyright 2014 High Fidelity, Inc. +// +// Move your hand with the hydra controller, and hit the ball with the paddle. +// Click 'X' button to turn off this script. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var BALL_SIZE = 0.08; +var PADDLE_SIZE = 0.20; +var PADDLE_THICKNESS = 0.06; +var PADDLE_COLOR = { red: 184, green: 134, blue: 11 }; +var BALL_COLOR = { red: 255, green: 0, blue: 0 }; +var LINE_COLOR = { red: 255, green: 255, blue: 0 }; +var PADDLE_OFFSET = { x: 0.05, y: 0.0, z: 0.0 }; +var GRAVITY = 0.0; +var SPRING_FORCE = 15.0; +var lastSoundTime = 0; +var controllerID = 1; +var gameOn = false; + +HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +hitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav"); + +var screenSize = Controller.getViewportDimensions(); +var offButton = Overlays.addOverlay("image", { + x: screenSize.x - 48, + y: 96, + width: 32, + height: 32, + imageURL: HIFI_PUBLIC_BUCKET + "images/close.png", + color: { red: 255, green: 255, blue: 255}, + alpha: 1 + }); + +var ball, paddle, paddleModel, line; + +function createEntities() { + ball = Entities.addEntity( + { type: "Sphere", + position: Controller.getSpatialControlPosition(controllerID), + dimensions: { x: BALL_SIZE, y: BALL_SIZE, z: BALL_SIZE }, + color: BALL_COLOR, + gravity: { x: 0, y: GRAVITY, z: 0 }, + ignoreCollisions: false, + damping: 0.50, + collisionsWillMove: true }); + + paddle = Entities.addEntity( + { type: "Box", + position: Controller.getSpatialControlPosition(controllerID), + dimensions: { x: PADDLE_SIZE, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 0.80 }, + color: PADDLE_COLOR, + gravity: { x: 0, y: 0, z: 0 }, + ignoreCollisions: false, + damping: 0.10, + visible: false, + rotation: Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), + collisionsWillMove: false }); + + modelURL = "http://public.highfidelity.io/models/attachments/pong_paddle.fbx"; + paddleModel = Entities.addEntity( + { type: "Model", + position: Vec3.sum(Controller.getSpatialControlPosition(controllerID), PADDLE_OFFSET), + dimensions: { x: PADDLE_SIZE * 1.5, y: PADDLE_THICKNESS, z: PADDLE_SIZE * 1.25 }, + color: PADDLE_COLOR, + gravity: { x: 0, y: 0, z: 0 }, + ignoreCollisions: true, + modelURL: modelURL, + damping: 0.10, + rotation: Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)), + collisionsWillMove: false }); + + line = Overlays.addOverlay("line3d", { + start: { x: 0, y: 0, z: 0 }, + end: { x: 0, y: 0, z: 0 }, + color: LINE_COLOR, + alpha: 1, + visible: true, + lineWidth: 2 }); +} + +function deleteEntities() { + Entities.deleteEntity(ball); + Entities.deleteEntity(paddle); + Entities.deleteEntity(paddleModel); + Overlays.deleteOverlay(line); +} + +function update(deltaTime) { + var palmPosition = Controller.getSpatialControlPosition(controllerID); + var controllerActive = (Vec3.length(palmPosition) > 0); + + if (!gameOn && controllerActive) { + createEntities(); + gameOn = true; + } else if (gameOn && !controllerActive) { + deleteEntities(); + gameOn = false; + } + if (!gameOn || !controllerActive) { + return; + } + + if (!paddle.isKnownID) { + paddle = Entities.identifyEntity(paddle); + } + if (!ball.isKnownID) { + ball = Entities.identifyEntity(ball); + } else { + var props = Entities.getEntityProperties(ball); + var spring = Vec3.subtract(palmPosition, props.position); + var paddleWorldOrientation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(controllerID)); + var springLength = Vec3.length(spring); + spring = Vec3.normalize(spring); + var ballVelocity = Vec3.sum(props.velocity, Vec3.multiply(springLength * SPRING_FORCE * deltaTime, spring)); + Entities.editEntity(ball, { velocity: ballVelocity }); + Overlays.editOverlay(line, { start: props.position, end: palmPosition }); + Entities.editEntity(paddle, { position: palmPosition, + velocity: Controller.getSpatialControlVelocity(controllerID), + rotation: paddleWorldOrientation }); + Entities.editEntity(paddleModel, { position: Vec3.sum(palmPosition, Vec3.multiplyQbyV(paddleWorldOrientation, PADDLE_OFFSET)), + velocity: Controller.getSpatialControlVelocity(controllerID), + rotation: paddleWorldOrientation }); + } +} + +function entityCollisionWithEntity(entity1, entity2, collision) { + if ((entity1.id == ball.id) || (entity2.id ==ball.id)) { + var props1 = Entities.getEntityProperties(entity1); + var props2 = Entities.getEntityProperties(entity2); + var dVel = Vec3.length(Vec3.subtract(props1.velocity, props2.velocity)); + var currentTime = new Date().getTime(); + var MIN_MSECS_BETWEEN_BOUNCE_SOUNDS = 100; + var MIN_VELOCITY_FOR_SOUND_IMPACT = 0.25; + if ((dVel > MIN_VELOCITY_FOR_SOUND_IMPACT) && (currentTime - lastSoundTime) > MIN_MSECS_BETWEEN_BOUNCE_SOUNDS) { + Audio.playSound(hitSound, { position: props1.position, volume: Math.min(dVel, 1.0) }); + lastSoundTime = new Date().getTime(); + } + } +} + +function mousePressEvent(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y}); + if (clickedOverlay == offButton) { + Script.stop(); + } +} + +function scriptEnding() { + if (gameOn) { + deleteEntities(); + } + Overlays.deleteOverlay(offButton); +} + +Entities.entityCollisionWithEntity.connect(entityCollisionWithEntity); +Controller.mousePressEvent.connect(mousePressEvent); +Script.scriptEnding.connect(scriptEnding); +Script.update.connect(update); From 59f79fd4368bba983f120d076d63ab4baadede8a Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 22 Jan 2015 13:42:19 -0800 Subject: [PATCH 06/11] Add handedness choice, default to right handed --- examples/controllers/hydra/paddleBall.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/examples/controllers/hydra/paddleBall.js b/examples/controllers/hydra/paddleBall.js index e5d409bd8a..85b025e4cd 100644 --- a/examples/controllers/hydra/paddleBall.js +++ b/examples/controllers/hydra/paddleBall.js @@ -20,8 +20,16 @@ var PADDLE_OFFSET = { x: 0.05, y: 0.0, z: 0.0 }; var GRAVITY = 0.0; var SPRING_FORCE = 15.0; var lastSoundTime = 0; -var controllerID = 1; var gameOn = false; +var leftHanded = false; +var controllerID; + +if (leftHanded) { + controllerID = 1; +} else { + controllerID = 3; +} + HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; hitSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav"); From 805d5ace13cf8d5411689776071b734edc8be27a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 22 Jan 2015 14:55:14 -0800 Subject: [PATCH 07/11] Another slight stitching improvement. --- interface/src/MetavoxelSystem.cpp | 87 ++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 2161887b91..e91ff89270 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1540,6 +1540,50 @@ static inline void appendTriangle(const EdgeCrossing& e0, const EdgeCrossing& e1 } } +const int CORNER_COUNT = 4; + +static inline StackArray::Entry getEntry(const StackArray* lineSrc, int stackWidth, int y, float heightfieldHeight, + EdgeCrossing cornerCrossings[CORNER_COUNT], int cornerIndex) { + const EdgeCrossing& cornerCrossing = cornerCrossings[cornerIndex]; + if (cornerCrossing.point.y == 0.0f) { + int offsetX = (cornerIndex & X_MAXIMUM_FLAG) ? 1 : 0; + int offsetZ = (cornerIndex & Y_MAXIMUM_FLAG) ? 1 : 0; + return lineSrc[offsetZ * stackWidth + offsetX].getEntry(y, heightfieldHeight); + } + StackArray::Entry entry; + bool set = false; + if (cornerCrossing.point.y >= y) { + entry.color = cornerCrossing.color; + entry.material = cornerCrossing.material; + set = true; + + if (cornerCrossing.point.y < y + 1) { + entry.setHermiteY(cornerCrossing.normal, cornerCrossing.point.y - y); + } + } else { + entry.material = entry.color = 0; + } + if (!(cornerIndex & X_MAXIMUM_FLAG)) { + const EdgeCrossing& nextCornerCrossingX = cornerCrossings[cornerIndex | X_MAXIMUM_FLAG]; + if (nextCornerCrossingX.point.y != 0.0f && (nextCornerCrossingX.point.y >= y) != set) { + float t = (y - cornerCrossing.point.y) / (nextCornerCrossingX.point.y - cornerCrossing.point.y); + if (t >= 0.0f && t <= 1.0f) { + entry.setHermiteX(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingX.normal, t)), t); + } + } + } + if (!(cornerIndex & Y_MAXIMUM_FLAG)) { + const EdgeCrossing& nextCornerCrossingZ = cornerCrossings[cornerIndex | Y_MAXIMUM_FLAG]; + if (nextCornerCrossingZ.point.y != 0.0f && (nextCornerCrossingZ.point.y >= y) != set) { + float t = (y - cornerCrossing.point.y) / (nextCornerCrossingZ.point.y - cornerCrossing.point.y); + if (t >= 0.0f && t <= 1.0f) { + entry.setHermiteZ(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingZ.normal, t)), t); + } + } + } + return entry; +} + void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const glm::vec3& translation, const glm::quat& rotation, const glm::vec3& scale, bool cursor) { if (!node->getHeight()) { @@ -1748,7 +1792,6 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g const int LOWER_RIGHT_CORNER = 8; const int NO_CORNERS = 0; const int ALL_CORNERS = UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER | LOWER_RIGHT_CORNER; - const int CORNER_COUNT = 4; const int NEXT_CORNERS[] = { 1, 3, 0, 2 }; int corners = NO_CORNERS; if (heightfieldHeight != 0.0f) { @@ -1823,7 +1866,7 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g indicesZ[x].position = position; indicesZ[x].resize(count); for (int y = position, end = position + count; y < end; y++) { - const StackArray::Entry& entry = lineSrc->getEntry(y, heightfieldHeight); + StackArray::Entry entry = getEntry(lineSrc, stackWidth, y, heightfieldHeight, cornerCrossings, 0); if (displayHermite && x != 0 && z != 0 && !lineSrc->isEmpty() && y >= lineSrc->getPosition()) { glm::vec3 normal; if (entry.hermiteX != 0) { @@ -1969,10 +2012,13 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g // the terrifying conditional code that follows checks each cube edge for a crossing, gathering // its properties (color, material, normal) if one is present; as before, boundary edges are excluded if (crossingCount == 0) { - const StackArray::Entry& nextEntryY = lineSrc->getEntry(y + 1, heightfieldHeight); + StackArray::Entry nextEntryY = getEntry(lineSrc, stackWidth, y + 1, + heightfieldHeight, cornerCrossings, 0); if (middleX) { - const StackArray::Entry& nextEntryX = lineSrc[1].getEntry(y, nextHeightfieldHeightX); - const StackArray::Entry& nextEntryXY = lineSrc[1].getEntry(y + 1, nextHeightfieldHeightX); + StackArray::Entry nextEntryX = getEntry(lineSrc, stackWidth, y, nextHeightfieldHeightX, + cornerCrossings, 1); + StackArray::Entry nextEntryXY = getEntry(lineSrc, stackWidth, y + 1, nextHeightfieldHeightX, + cornerCrossings, 1); if (alpha0 != alpha1) { EdgeCrossing& crossing = crossings[crossingCount++]; crossing.point = glm::vec3(entry.getHermiteX(crossing.normal), 0.0f, 0.0f); @@ -1989,12 +2035,12 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g crossing.setColorMaterial(alpha2 == 0 ? nextEntryXY : nextEntryY); } if (middleZ) { - const StackArray::Entry& nextEntryZ = lineSrc[stackWidth].getEntry(y, - nextHeightfieldHeightZ); - const StackArray::Entry& nextEntryXZ = lineSrc[stackWidth + 1].getEntry( - y, nextHeightfieldHeightXZ); - const StackArray::Entry& nextEntryXYZ = lineSrc[stackWidth + 1].getEntry( - y + 1, nextHeightfieldHeightXZ); + StackArray::Entry nextEntryZ = getEntry(lineSrc, stackWidth, y, nextHeightfieldHeightZ, + cornerCrossings, 2); + StackArray::Entry nextEntryXZ = getEntry(lineSrc, stackWidth, y, nextHeightfieldHeightXZ, + cornerCrossings, 3); + StackArray::Entry nextEntryXYZ = getEntry(lineSrc, stackWidth, y + 1, + nextHeightfieldHeightXZ, cornerCrossings, 3); if (alpha1 != alpha5) { EdgeCrossing& crossing = crossings[crossingCount++]; crossing.point = glm::vec3(1.0f, 0.0f, nextEntryX.getHermiteZ(crossing.normal)); @@ -2002,8 +2048,8 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } if (alpha3 != alpha7) { EdgeCrossing& crossing = crossings[crossingCount++]; - const StackArray::Entry& nextEntryXY = lineSrc[1].getEntry(y + 1, - nextHeightfieldHeightX); + StackArray::Entry nextEntryXY = getEntry(lineSrc, stackWidth, y + 1, + nextHeightfieldHeightX, cornerCrossings, 1); crossing.point = glm::vec3(1.0f, 1.0f, nextEntryXY.getHermiteZ(crossing.normal)); crossing.setColorMaterial(alpha3 == 0 ? nextEntryXYZ : nextEntryXY); } @@ -2014,15 +2060,15 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } if (alpha5 != alpha7) { EdgeCrossing& crossing = crossings[crossingCount++]; - const StackArray::Entry& nextEntryXZ = lineSrc[stackWidth + 1].getEntry( - y, nextHeightfieldHeightXZ); + StackArray::Entry nextEntryXZ = getEntry(lineSrc, stackWidth, y, + nextHeightfieldHeightXZ, cornerCrossings, 3); crossing.point = glm::vec3(1.0f, nextEntryXZ.getHermiteY(crossing.normal), 1.0f); crossing.setColorMaterial(alpha5 == 0 ? nextEntryXYZ : nextEntryXZ); } if (alpha6 != alpha7) { EdgeCrossing& crossing = crossings[crossingCount++]; - const StackArray::Entry& nextEntryYZ = lineSrc[stackWidth].getEntry( - y + 1, nextHeightfieldHeightZ); + StackArray::Entry nextEntryYZ = getEntry(lineSrc, stackWidth, y + 1, + nextHeightfieldHeightZ, cornerCrossings, 2); crossing.point = glm::vec3(nextEntryYZ.getHermiteX(crossing.normal), 1.0f, 1.0f); crossing.setColorMaterial(alpha6 == 0 ? nextEntryXYZ : nextEntryYZ); } @@ -2034,9 +2080,10 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g crossing.setColorMaterial(alpha0 == 0 ? nextEntryY : entry); } if (middleZ) { - const StackArray::Entry& nextEntryZ = lineSrc[stackWidth].getEntry(y, nextHeightfieldHeightZ); - const StackArray::Entry& nextEntryYZ = lineSrc[stackWidth].getEntry(y + 1, - nextHeightfieldHeightZ); + StackArray::Entry nextEntryZ = getEntry(lineSrc, stackWidth, y, + nextHeightfieldHeightZ, cornerCrossings, 2); + StackArray::Entry nextEntryYZ = getEntry(lineSrc, stackWidth, y + 1, + nextHeightfieldHeightZ, cornerCrossings, 2); if (alpha0 != alpha4) { EdgeCrossing& crossing = crossings[crossingCount++]; crossing.point = glm::vec3(0.0f, 0.0f, entry.getHermiteZ(crossing.normal)); From 0e6f2d7252f8943897ae1032457a9a45b27494a8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 22 Jan 2015 16:22:36 -0800 Subject: [PATCH 08/11] Update runningScriptsWidgets px -> pt --- interface/ui/runningScriptsWidget.ui | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/ui/runningScriptsWidget.ui b/interface/ui/runningScriptsWidget.ui index 3d7db5064a..ec078681e3 100644 --- a/interface/ui/runningScriptsWidget.ui +++ b/interface/ui/runningScriptsWidget.ui @@ -70,7 +70,7 @@ Helvetica,Arial,sans-serif - -1 + 16 75 false true @@ -78,7 +78,7 @@ color: #0e7077; -font: bold 16px; +font: bold 16pt; @@ -192,7 +192,7 @@ font: bold 16px; - font: 14px; color: #5f5f5f; margin: 2px; + font: 14pt; color: #5f5f5f; margin: 2px; There are no scripts running. @@ -245,8 +245,8 @@ font: bold 16px; 0 0 - 334 - 20 + 328 + 18 @@ -259,7 +259,7 @@ font: bold 16px; Qt::LeftToRight - font-size: 14px; + font-size: 14pt; @@ -301,7 +301,7 @@ font: bold 16px; - font: 14px; color: #5f5f5f; margin: 2px; + font: 14pt; color: #5f5f5f; margin: 2px; Tip @@ -370,7 +370,7 @@ font: bold 16px; color: #0e7077; -font: bold 16px; +font: bold 16pt; Load Scripts From e65090bab917d781637b2fad748914d759288928 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 22 Jan 2015 21:08:48 -0800 Subject: [PATCH 09/11] Another slight stitching improvement. --- interface/src/MetavoxelSystem.cpp | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index e91ff89270..7edabb0beb 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1857,6 +1857,15 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g } minimumY = qMin(minimumY, cornerMinimumY); maximumY = qMax(maximumY, cornerMaximumY); + + if (corners == (LOWER_LEFT_CORNER | UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER)) { + appendTriangle(cornerCrossings[1], cornerCrossings[0], cornerCrossings[2], + clampedX, clampedZ, step, vertices, indices, quadIndices); + + } else if (corners == (UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER)) { + appendTriangle(cornerCrossings[2], cornerCrossings[3], cornerCrossings[1], + clampedX, clampedZ, step, vertices, indices, quadIndices); + } } int position = minimumY; int count = maximumY - minimumY + 1; @@ -1948,28 +1957,16 @@ void HeightfieldNodeRenderer::render(const HeightfieldNodePointer& node, const g case UPPER_RIGHT_CORNER: case UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: case UPPER_RIGHT_CORNER | LOWER_LEFT_CORNER: - crossings[crossingCount++] = cornerCrossings[1]; - crossings[crossingCount - 1].point.y -= y; - break; - case LOWER_LEFT_CORNER | UPPER_LEFT_CORNER | UPPER_RIGHT_CORNER: crossings[crossingCount++] = cornerCrossings[1]; crossings[crossingCount - 1].point.y -= y; - appendTriangle(cornerCrossings[1], cornerCrossings[0], cornerCrossings[2], - clampedX, clampedZ, step, vertices, indices, quadIndices); break; case LOWER_LEFT_CORNER: case LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: - crossings[crossingCount++] = cornerCrossings[2]; - crossings[crossingCount - 1].point.y -= y; - break; - case UPPER_RIGHT_CORNER | LOWER_RIGHT_CORNER | LOWER_LEFT_CORNER: crossings[crossingCount++] = cornerCrossings[2]; crossings[crossingCount - 1].point.y -= y; - appendTriangle(cornerCrossings[2], cornerCrossings[3], cornerCrossings[1], - clampedX, clampedZ, step, vertices, indices, quadIndices); break; case LOWER_RIGHT_CORNER: From c124dffd6ab1f3f3988decc684c1457ab3974dbb Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 22 Jan 2015 21:26:08 -0800 Subject: [PATCH 10/11] Another slight improvement. --- interface/src/MetavoxelSystem.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 7edabb0beb..1d2caa6c2c 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1556,29 +1556,25 @@ static inline StackArray::Entry getEntry(const StackArray* lineSrc, int stackWid entry.color = cornerCrossing.color; entry.material = cornerCrossing.material; set = true; + entry.setHermiteY(cornerCrossing.normal, glm::clamp(cornerCrossing.point.y - y, 0.0f, 1.0f)); - if (cornerCrossing.point.y < y + 1) { - entry.setHermiteY(cornerCrossing.normal, cornerCrossing.point.y - y); - } } else { entry.material = entry.color = 0; } if (!(cornerIndex & X_MAXIMUM_FLAG)) { const EdgeCrossing& nextCornerCrossingX = cornerCrossings[cornerIndex | X_MAXIMUM_FLAG]; if (nextCornerCrossingX.point.y != 0.0f && (nextCornerCrossingX.point.y >= y) != set) { - float t = (y - cornerCrossing.point.y) / (nextCornerCrossingX.point.y - cornerCrossing.point.y); - if (t >= 0.0f && t <= 1.0f) { - entry.setHermiteX(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingX.normal, t)), t); - } + float t = glm::clamp((y - cornerCrossing.point.y) / + (nextCornerCrossingX.point.y - cornerCrossing.point.y), 0.0f, 1.0f); + entry.setHermiteX(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingX.normal, t)), t); } } if (!(cornerIndex & Y_MAXIMUM_FLAG)) { const EdgeCrossing& nextCornerCrossingZ = cornerCrossings[cornerIndex | Y_MAXIMUM_FLAG]; if (nextCornerCrossingZ.point.y != 0.0f && (nextCornerCrossingZ.point.y >= y) != set) { - float t = (y - cornerCrossing.point.y) / (nextCornerCrossingZ.point.y - cornerCrossing.point.y); - if (t >= 0.0f && t <= 1.0f) { - entry.setHermiteZ(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingZ.normal, t)), t); - } + float t = glm::clamp((y - cornerCrossing.point.y) / + (nextCornerCrossingZ.point.y - cornerCrossing.point.y), 0.0f, 1.0f); + entry.setHermiteZ(glm::normalize(glm::mix(cornerCrossing.normal, nextCornerCrossingZ.normal, t)), t); } } return entry; From b8a15f0726c90943f07bbc521ab7c37a1fa0bb24 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 22 Jan 2015 22:04:10 -0800 Subject: [PATCH 11/11] Another tweak. --- interface/src/MetavoxelSystem.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 1d2caa6c2c..80c7c3f41f 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1542,13 +1542,21 @@ static inline void appendTriangle(const EdgeCrossing& e0, const EdgeCrossing& e1 const int CORNER_COUNT = 4; -static inline StackArray::Entry getEntry(const StackArray* lineSrc, int stackWidth, int y, float heightfieldHeight, +static StackArray::Entry getEntry(const StackArray* lineSrc, int stackWidth, int y, float heightfieldHeight, EdgeCrossing cornerCrossings[CORNER_COUNT], int cornerIndex) { + int offsetX = (cornerIndex & X_MAXIMUM_FLAG) ? 1 : 0; + int offsetZ = (cornerIndex & Y_MAXIMUM_FLAG) ? 1 : 0; + const StackArray& src = lineSrc[offsetZ * stackWidth + offsetX]; + int count = src.getEntryCount(); + if (count > 0) { + int relative = y - src.getPosition(); + if (relative < count && (relative >= 0 || heightfieldHeight == 0.0f)) { + return src.getEntry(y, heightfieldHeight); + } + } const EdgeCrossing& cornerCrossing = cornerCrossings[cornerIndex]; if (cornerCrossing.point.y == 0.0f) { - int offsetX = (cornerIndex & X_MAXIMUM_FLAG) ? 1 : 0; - int offsetZ = (cornerIndex & Y_MAXIMUM_FLAG) ? 1 : 0; - return lineSrc[offsetZ * stackWidth + offsetX].getEntry(y, heightfieldHeight); + return src.getEntry(y, heightfieldHeight); } StackArray::Entry entry; bool set = false;