diff --git a/examples/example/soundToys.js b/examples/example/soundToys.js new file mode 100644 index 0000000000..9d8c824b90 --- /dev/null +++ b/examples/example/soundToys.js @@ -0,0 +1,66 @@ +"use strict"; +// Creates some objects that each play a sound when they are hit (or when they hit something else). +// +// Created by Howard Stearns on June 3, 2015 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +var Camera, Vec3, Quat, Entities, Script; // Globals defined by HiFi, var'ed here to keep jslint happy. +var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; +var SOUND_BUCKET = "http://public.highfidelity.io/sounds/Collisions-hitsandslaps/"; +var MAX_ANGULAR_SPEED = Math.PI; +var N_EACH_OBJECTS = 3; + +var ourToys = []; +function deleteAll() { + ourToys.forEach(Entities.deleteEntity); +} +function makeAll() { + var currentPosition = Vec3.sum(Camera.getPosition(), Vec3.multiply(4, Quat.getFront(Camera.getOrientation()))), + right = Vec3.multiply(0.6, Quat.getRight(Camera.getOrientation())), + currentDimensions, + data = [ + ["models/props/Dice/goldDie.fbx", HIFI_PUBLIC_BUCKET + "sounds/dice/diceCollide.wav"], + ["models/props/Pool/ball_8.fbx", HIFI_PUBLIC_BUCKET + "sounds/Collisions-ballhitsandcatches/billiards/collision1.wav"], + ["eric/models/woodFloor.fbx", SOUND_BUCKET + "67LCollision05.wav"] + ]; + currentPosition = Vec3.sum(currentPosition, Vec3.multiply(-1 * data.length * N_EACH_OBJECTS / 2, right)); + function makeOne(model, sound) { + var thisEntity; + function dropOnce() { // Once gravity is added, it will work if picked up and again dropped. + Entities.editEntity(thisEntity, {gravity: {x: 0, y: -9.8, z: 0}}); + Script.removeEventHandler(thisEntity, 'clickDownOnEntity', dropOnce); + } + thisEntity = Entities.addEntity({ + type: "Model", + modelURL: HIFI_PUBLIC_BUCKET + model, + collisionSoundURL: sound, + collisionsWillMove: true, + shapeType: "box", + restitution: 0.8, + dimensions: currentDimensions, + position: currentPosition, + angularVelocity: { + x: Math.random() * MAX_ANGULAR_SPEED, + y: Math.random() * MAX_ANGULAR_SPEED, + z: Math.random() * MAX_ANGULAR_SPEED + } + }); + ourToys.push(thisEntity); + Script.addEventHandler(thisEntity, 'clickDownOnEntity', dropOnce); + currentDimensions = Vec3.multiply(currentDimensions, 2); + currentPosition = Vec3.sum(currentPosition, right); + } + function makeThree(modelSound) { + var i, model = modelSound[0], sound = modelSound[1]; + currentDimensions = {x: 0.1, y: 0.1, z: 0.1}; + for (i = 0; i < N_EACH_OBJECTS; i++) { + makeOne(model, sound); + } + } + data.forEach(makeThree); +} +makeAll(); +Script.scriptEnding.connect(deleteAll); diff --git a/examples/lineRider.js b/examples/lineRider.js new file mode 100644 index 0000000000..21a690fc63 --- /dev/null +++ b/examples/lineRider.js @@ -0,0 +1,117 @@ +// +// lineRider.js +// examples +// +// Created by Eric Levin on 6/4/15. +// Copyright 2014 High Fidelity, Inc. +// +// Takes the avatar on a line ride. Meant to be used in conjunction with paint.js +// Paint a line and then click on roller coaster icon to start! +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +LineRider = function() { + HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + var screenSize = Controller.getViewportDimensions(); + + var BUTTON_SIZE = 32; + var PADDING = 3; + + this.buttonOffColor = { + red: 250, + green: 10, + blue: 10 + }; + this.buttonOnColor = { + red: 10, + green: 200, + blue: 100 + }; + this.riding = false; + + this.startButton = Overlays.addOverlay("image", { + x: screenSize.x / 2 - BUTTON_SIZE + PADDING * 2, + y: screenSize.y - (BUTTON_SIZE + PADDING), + width: BUTTON_SIZE, + height: BUTTON_SIZE, + imageURL: HIFI_PUBLIC_BUCKET + "images/coaster.png?v2", + color: this.buttonOffColor, + alpha: 1 + }); + + this.currentPoint = 0; + this.shouldUpdate = false; + this.moveIntervalTime = 50; + +} + + +LineRider.prototype.move = function() { + if (!this.shouldMove) { + return; + } + MyAvatar.position = this.points[this.currentPoint++]; + + if (this.currentPoint === this.points.length) { + this.currentPoint = 0; + } + var self = this; + Script.setTimeout(function() { + self.move(); + }, this.moveIntervalTime); +} + +LineRider.prototype.setPath = function(points) { + this.points = points; +} + +LineRider.prototype.addStartHandler = function(callback) { + this.onStart = callback; +} + + +LineRider.prototype.mousePressEvent = function(event) { + var clickedOverlay = Overlays.getOverlayAtPoint({ + x: event.x, + y: event.y + }); + if (clickedOverlay == this.startButton) { + this.toggleRide(); + + } + +} + +LineRider.prototype.toggleRide = function() { + this.riding = !this.riding; + if (this.riding === true) { + Overlays.editOverlay(this.startButton, { + color: this.buttonOnColor + }); + if (this.onStart) { + this.onStart(); + //make sure we actually have a path + if (this.points.length > 2) { + this.shouldMove = true; + } + var self = this; + Script.setTimeout(function() { + self.move(); + }, this.moveIntervalTime); + } + } else { + Overlays.editOverlay(this.startButton, { + color: this.buttonOffColor + }) + this.shouldMove = false; + } + +} +LineRider.prototype.startRide = function() { + this.shouldUpdate = true; + +} + +LineRider.prototype.cleanup = function() { + Overlays.deleteOverlay(this.startButton); +} \ No newline at end of file diff --git a/examples/paint.js b/examples/paint.js new file mode 100644 index 0000000000..6e4438d2ea --- /dev/null +++ b/examples/paint.js @@ -0,0 +1,495 @@ +// +// paint.js +// examples +// +// Created by Eric Levin on 6/4/15. +// Copyright 2014 High Fidelity, Inc. +// +// This script allows you to paint with the hydra or mouse! +// +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +Script.include('lineRider.js') +var MAX_POINTS_PER_LINE = 30; + + +var colorPalette = [{ + red: 236, + green: 208, + blue: 120 +}, { + red: 217, + green: 91, + blue: 67 +}, { + red: 192, + green: 41, + blue: 66 +}, { + red: 84, + green: 36, + blue: 55 +}, { + red: 83, + green: 119, + blue: 122 +}]; + +var currentColorIndex = 0; +var currentColor = colorPalette[currentColorIndex]; + + + +if (hydraCheck() === true) { + HydraPaint(); +} else { + MousePaint(); +} + + +function cycleColor() { + currentColor = colorPalette[++currentColorIndex]; + if (currentColorIndex === colorPalette.length - 1) { + currentColorIndex = -1; + } + +} + +function hydraCheck() { + var numberOfButtons = Controller.getNumberOfButtons(); + var numberOfTriggers = Controller.getNumberOfTriggers(); + var numberOfSpatialControls = Controller.getNumberOfSpatialControls(); + var controllersPerTrigger = numberOfSpatialControls / numberOfTriggers; + hydrasConnected = (numberOfButtons == 12 && numberOfTriggers == 2 && controllersPerTrigger == 2); + return hydrasConnected; //hydrasConnected; +} + +//************ Mouse Paint ************************** + +function MousePaint() { + var DRAWING_DISTANCE = 2; + var lines = []; + var deletedLines = []; + var isDrawing = false; + var path = []; + + var lineRider = new LineRider(); + lineRider.addStartHandler(function() { + var points = []; + //create points array from list of all points in path + path.forEach(function(point) { + points.push(point); + }); + lineRider.setPath(points); + }); + + + + var LINE_WIDTH = 7; + var line; + var points = []; + + + var BRUSH_SIZE = 0.02; + + var brush = Entities.addEntity({ + type: 'Sphere', + position: { + x: 0, + y: 0, + z: 0 + }, + color: currentColor, + dimensions: { + x: BRUSH_SIZE, + y: BRUSH_SIZE, + z: BRUSH_SIZE + } + }); + + + function newLine(point) { + line = Entities.addEntity({ + position: MyAvatar.position, + type: "Line", + color: currentColor, + dimensions: { + x: 10, + y: 10, + z: 10 + }, + lineWidth: LINE_WIDTH + }); + points = []; + if (point) { + points.push(point); + path.push(point); + } + lines.push(line); + } + + + function mouseMoveEvent(event) { + + + var pickRay = Camera.computePickRay(event.x, event.y); + var addVector = Vec3.multiply(Vec3.normalize(pickRay.direction), DRAWING_DISTANCE); + var point = Vec3.sum(Camera.getPosition(), addVector); + Entities.editEntity(line, { + linePoints: points + }); + Entities.editEntity(brush, { + position: point + }); + if (!isDrawing) { + return; + } + + points.push(point); + path.push(point); + + if (points.length === MAX_POINTS_PER_LINE) { + //We need to start a new line! + newLine(point); + } + } + + function undoStroke() { + var deletedLine = lines.pop(); + var deletedLineProps = Entities.getEntityProperties(deletedLine); + deletedLines.push(deletedLineProps); + Entities.deleteEntity(deletedLine); + } + + function redoStroke() { + var restoredLine = Entities.addEntity(deletedLines.pop()); + Entities.addEntity(restoredLine); + lines.push(restoredLine); + } + + function mousePressEvent(event) { + if(!event.isLeftButton) { + isDrawing = false; + return; + } + lineRider.mousePressEvent(event); + path = []; + newLine(); + isDrawing = true; + + + } + + function mouseReleaseEvent() { + isDrawing = false; + } + + function keyPressEvent(event) { + if (event.text === "SPACE") { + cycleColor(); + Entities.editEntity(brush, { + color: currentColor + }); + } + if (event.text === "z") { + undoStroke(); + } + if(event.text === "x") { + redoStroke(); + } + } + + function cleanup() { + lines.forEach(function(line) { + Entities.deleteEntity(line); + }); + Entities.deleteEntity(brush); + lineRider.cleanup(); + + } + + + Controller.mousePressEvent.connect(mousePressEvent); + Controller.mouseReleaseEvent.connect(mouseReleaseEvent); + Controller.mouseMoveEvent.connect(mouseMoveEvent); + Script.scriptEnding.connect(cleanup); + + Controller.keyPressEvent.connect(keyPressEvent); +} + + + +//*****************HYDRA PAINT ******************************************* + + + +function HydraPaint() { + + + + var lineRider = new LineRider(); + lineRider.addStartHandler(function() { + var points = []; + //create points array from list of all points in path + rightController.path.forEach(function(point) { + points.push(point); + }); + lineRider.setPath(points); + }); + + var LEFT = 0; + var RIGHT = 1; + + var currentTime = 0; + + + var minBrushSize = .02; + var maxBrushSize = .04 + + + var minLineWidth = 5; + var maxLineWidth = 10; + var currentLineWidth = minLineWidth; + var MIN_PAINT_TRIGGER_THRESHOLD = .01; + var LINE_LIFETIME = 20; + var COLOR_CHANGE_TIME_FACTOR = 0.1; + + var RIGHT_BUTTON_1 = 7 + var RIGHT_BUTTON_2 = 8 + var RIGHT_BUTTON_3 = 9; + var RIGHT_BUTTON_4 = 10 + + var LEFT_BUTTON_1 = 1; + var LEFT_BUTTON_2 = 2; + var LEFT_BUTTON_3 = 3; + var LEFT_BUTTON_4 = 4; + + var STROKE_SMOOTH_FACTOR = 1; + + var MIN_DRAW_DISTANCE = 0.2; + var MAX_DRAW_DISTANCE = 0.4; + + function controller(side, undoButton, redoButton, cycleColorButton, startRideButton) { + this.triggerHeld = false; + this.triggerThreshold = 0.9; + this.side = side; + this.palm = 2 * side; + this.tip = 2 * side + 1; + this.trigger = side; + this.lines = []; + this.deletedLines = [] //just an array of properties objects + this.isPainting = false; + + this.undoButton = undoButton; + this.undoButtonPressed = false; + this.prevUndoButtonPressed = false; + + this.redoButton = redoButton; + this.redoButtonPressed = false; + this.prevRedoButtonPressed = false; + + this.cycleColorButton = cycleColorButton; + this.cycleColorButtonPressed = false; + this.prevColorCycleButtonPressed = false; + + this.startRideButton = startRideButton; + this.startRideButtonPressed = false; + this.prevStartRideButtonPressed = false; + + this.strokeCount = 0; + this.currentBrushSize = minBrushSize; + this.points = []; + this.path = []; + + this.brush = Entities.addEntity({ + type: 'Sphere', + position: { + x: 0, + y: 0, + z: 0 + }, + color: currentColor, + dimensions: { + x: minBrushSize, + y: minBrushSize, + z: minBrushSize + } + }); + + + this.newLine = function(point) { + this.line = Entities.addEntity({ + position: MyAvatar.position, + type: "Line", + color: currentColor, + dimensions: { + x: 10, + y: 10, + z: 10 + }, + lineWidth: 5, + // lifetime: LINE_LIFETIME + }); + this.points = []; + if (point) { + this.points.push(point); + this.path.push(point); + } + this.lines.push(this.line); + } + + this.update = function(deltaTime) { + this.updateControllerState(); + this.avatarPalmOffset = Vec3.subtract(this.palmPosition, MyAvatar.position); + this.projectedForwardDistance = Vec3.dot(Quat.getFront(Camera.getOrientation()), this.avatarPalmOffset); + this.mappedPalmOffset = map(this.projectedForwardDistance, -.5, .5, MIN_DRAW_DISTANCE, MAX_DRAW_DISTANCE); + this.tipDirection = Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)); + this.offsetVector = Vec3.multiply(this.mappedPalmOffset, this.tipDirection); + this.drawPoint = Vec3.sum(this.palmPosition, this.offsetVector); + this.currentBrushSize = map(this.triggerValue, 0, 1, minBrushSize, maxBrushSize); + Entities.editEntity(this.brush, { + position: this.drawPoint, + dimensions: { + x: this.currentBrushSize, + y: this.currentBrushSize, + z: this.currentBrushSize + }, + color: currentColor + }); + if (this.triggerValue > MIN_PAINT_TRIGGER_THRESHOLD) { + if (!this.isPainting) { + this.isPainting = true; + this.newLine(); + this.path = []; + } + if (this.strokeCount % STROKE_SMOOTH_FACTOR === 0) { + this.paint(this.drawPoint); + } + this.strokeCount++; + } else if (this.triggerValue < MIN_PAINT_TRIGGER_THRESHOLD && this.isPainting) { + this.releaseTrigger(); + } + + this.oldPalmPosition = this.palmPosition; + this.oldTipPosition = this.tipPosition; + } + + this.releaseTrigger = function() { + this.isPainting = false; + + } + + + this.updateControllerState = function() { + this.undoButtonPressed = Controller.isButtonPressed(this.undoButton); + this.redoButtonPressed = Controller.isButtonPressed(this.redoButton); + this.cycleColorButtonPressed = Controller.isButtonPressed(this.cycleColorButton); + this.startRideButtonPressed = Controller.isButtonPressed(this.startRideButton); + + //This logic gives us button release + if (this.prevUndoButtonPressed === true && this.undoButtonPressed === false) { + //User released undo button, so undo + this.undoStroke(); + } + if (this.prevRedoButtonPressed === true && this.redoButtonPressed === false) { + this.redoStroke(); + } + + if (this.prevCycleColorButtonPressed === true && this.cycleColorButtonPressed === false) { + cycleColor(); + Entities.editEntity(this.brush, { + color: currentColor + }); + } + if (this.prevStartRideButtonPressed === true && this.startRideButtonPressed === false) { + lineRider.toggleRide(); + } + this.prevRedoButtonPressed = this.redoButtonPressed; + this.prevUndoButtonPressed = this.undoButtonPressed; + this.prevCycleColorButtonPressed = this.cycleColorButtonPressed; + this.prevStartRideButtonPressed = this.startRideButtonPressed; + + this.palmPosition = Controller.getSpatialControlPosition(this.palm); + this.tipPosition = Controller.getSpatialControlPosition(this.tip); + this.triggerValue = Controller.getTriggerValue(this.trigger); + } + + this.undoStroke = function() { + var deletedLine = this.lines.pop(); + var deletedLineProps = Entities.getEntityProperties(deletedLine); + this.deletedLines.push(deletedLineProps); + Entities.deleteEntity(deletedLine); + } + + this.redoStroke = function() { + var restoredLine = Entities.addEntity(this.deletedLines.pop()); + Entities.addEntity(restoredLine); + this.lines.push(restoredLine); + } + + this.paint = function(point) { + + currentLineWidth = map(this.triggerValue, 0, 1, minLineWidth, maxLineWidth); + this.points.push(point); + this.path.push(point); + Entities.editEntity(this.line, { + linePoints: this.points, + lineWidth: currentLineWidth, + }); + if (this.points.length > MAX_POINTS_PER_LINE) { + this.newLine(point); + } + } + + this.cleanup = function() { + Entities.deleteEntity(this.brush); + this.lines.forEach(function(line) { + Entities.deleteEntity(line); + }); + } + } + + function update(deltaTime) { + rightController.update(deltaTime); + leftController.update(deltaTime); + currentTime += deltaTime; + } + + function cleanup() { + rightController.cleanup(); + leftController.cleanup(); + lineRider.cleanup(); + } + + function mousePressEvent(event) { + lineRider.mousePressEvent(event); + } + + function vectorIsZero(v) { + return v.x === 0 && v.y === 0 && v.z === 0; + } + + + var rightController = new controller(RIGHT, RIGHT_BUTTON_3, RIGHT_BUTTON_4, RIGHT_BUTTON_1, RIGHT_BUTTON_2); + var leftController = new controller(LEFT, LEFT_BUTTON_3, LEFT_BUTTON_4, LEFT_BUTTON_1, LEFT_BUTTON_2); + + Script.update.connect(update); + Script.scriptEnding.connect(cleanup); + Controller.mousePressEvent.connect(mousePressEvent); + +} + +function randFloat(low, high) { + return low + Math.random() * (high - low); +} + + +function randInt(low, high) { + return Math.floor(randFloat(low, high)); +} + +function map(value, min1, max1, min2, max2) { + return min2 + (max2 - min2) * ((value - min1) / (max1 - min1)); +} \ No newline at end of file diff --git a/examples/pointer.js b/examples/pointer.js index 32698209a4..cca46709ee 100644 --- a/examples/pointer.js +++ b/examples/pointer.js @@ -1,30 +1,17 @@ // pointer.js // examples // -// Created by Eric Levin on May 26, 2015 +// Created by Seth Alves on May 15th +// Modified by Eric Levin on June 4 // Copyright 2015 High Fidelity, Inc. // // Provides a pointer with option to draw on surfaces // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// var lineEntityID = null; var lineIsRezzed = false; -var altHeld = false; -var lineCreated = false; -var position, positionOffset, prevPosition; -var nearLinePosition; -var strokes = []; -var STROKE_ADJUST = 0.005; -var DISTANCE_DRAW_THRESHOLD = .02; -var drawDistance = 0; - -var LINE_WIDTH = 20; - -var userCanPoint = false; -var userCanDraw = false; var BUTTON_SIZE = 32; var PADDING = 3; @@ -43,16 +30,7 @@ var buttonOnColor = { HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var screenSize = Controller.getViewportDimensions(); -var drawButton = Overlays.addOverlay("image", { - x: screenSize.x / 2 - BUTTON_SIZE + PADDING * 2, - y: screenSize.y - (BUTTON_SIZE + PADDING), - width: BUTTON_SIZE, - height: BUTTON_SIZE, - imageURL: HIFI_PUBLIC_BUCKET + "images/pencil.png?v2", - color: buttonOffColor, - alpha: 1 -}); - +var userCanPoint = false; var pointerButton = Overlays.addOverlay("image", { x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING, y: screenSize.y - (BUTTON_SIZE + PADDING), @@ -61,14 +39,12 @@ var pointerButton = Overlays.addOverlay("image", { imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png", color: buttonOffColor, alpha: 1 -}) +}); -var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2.0, Quat.getFront(Camera.getOrientation()))); -center.y += 0.5; -function calculateNearLinePosition(targetPosition) { +function nearLinePoint(targetPosition) { var handPosition = MyAvatar.getRightPalmPosition(); var along = Vec3.subtract(targetPosition, handPosition); along = Vec3.normalize(along); @@ -87,39 +63,40 @@ function removeLine() { function createOrUpdateLine(event) { - if (!userCanPoint) { - return; - } var pickRay = Camera.computePickRay(event.x, event.y); var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking var props = Entities.getEntityProperties(intersection.entityID); - if (intersection.intersects) { - startPosition = intersection.intersection; - var subtractVec = Vec3.multiply(Vec3.normalize(pickRay.direction), STROKE_ADJUST); - startPosition = Vec3.subtract(startPosition, subtractVec); - nearLinePosition = calculateNearLinePosition(intersection.intersection); - positionOffset = Vec3.subtract(startPosition, nearLinePosition); + if (intersection.intersects && userCanPoint) { + var points = [nearLinePoint(intersection.intersection), intersection.intersection] if (lineIsRezzed) { Entities.editEntity(lineEntityID, { - position: nearLinePosition, - dimensions: positionOffset, + position: nearLinePoint(intersection.intersection), + linePoints: points, + dimensions: { + x: 1, + y: 1, + z: 1 + }, + lifetime: 15 + props.lifespan // renew lifetime }); - if (userCanDraw) { - draw(); - } } else { lineIsRezzed = true; - prevPosition = startPosition; lineEntityID = Entities.addEntity({ type: "Line", - position: nearLinePosition, - dimensions: positionOffset, + position: nearLinePoint(intersection.intersection), + linePoints: points, + dimensions: { + x: 1, + y: 1, + z: 1 + }, color: { red: 255, green: 255, blue: 255 }, + lifetime: 15 // if someone crashes while pointing, don't leave the line there forever. }); } } else { @@ -127,120 +104,50 @@ function createOrUpdateLine(event) { } } -function draw() { - //We only want to draw line if distance between starting and previous point is large enough - drawDistance = Vec3.distance(startPosition, prevPosition); - if (drawDistance < DISTANCE_DRAW_THRESHOLD) { +function mousePressEvent(event) { + if (!event.isLeftButton) { return; } - var offset = Vec3.subtract(startPosition, prevPosition); - strokes.push(Entities.addEntity({ - type: "Line", - position: prevPosition, - dimensions: offset, - color: { - red: 200, - green: 40, - blue: 200 - }, - lineWidth: LINE_WIDTH - })); - prevPosition = startPosition; -} - -function mousePressEvent(event) { - var clickedOverlay = Overlays.getOverlayAtPoint({ + createOrUpdateLine(event); + var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - if (clickedOverlay == drawButton) { - userCanDraw = !userCanDraw; - if (userCanDraw === true) { - Overlays.editOverlay(drawButton, { - color: buttonOnColor - }); - } else { - Overlays.editOverlay(drawButton, { - color: buttonOffColor - }); - } - } - if (clickedOverlay == pointerButton) { userCanPoint = !userCanPoint; if (userCanPoint === true) { Overlays.editOverlay(pointerButton, { color: buttonOnColor }); - if (userCanDraw === true) { - - Overlays.editOverlay(drawButton, { - color: buttonOnColor - }); - } } else { Overlays.editOverlay(pointerButton, { color: buttonOffColor }); - Overlays.editOverlay(drawButton, { - color: buttonOffColor - }); } } - - if (!event.isLeftButton || altHeld) { - return; - } - Controller.mouseMoveEvent.connect(mouseMoveEvent); - createOrUpdateLine(event); - lineCreated = true; } - function mouseMoveEvent(event) { createOrUpdateLine(event); } - function mouseReleaseEvent(event) { - if (!lineCreated) { + if (!event.isLeftButton) { return; } - Controller.mouseMoveEvent.disconnect(mouseMoveEvent); removeLine(); - lineCreated = false; -} - -function keyPressEvent(event) { - if (event.text == "ALT") { - altHeld = true; - } -} - -function keyReleaseEvent(event) { - if (event.text == "ALT") { - altHeld = false; - } - } function cleanup() { - for (var i = 0; i < strokes.length; i++) { - Entities.deleteEntity(strokes[i]); - } - - Overlays.deleteOverlay(drawButton); Overlays.deleteOverlay(pointerButton); } - Script.scriptEnding.connect(cleanup); -Controller.mousePressEvent.connect(mousePressEvent); -Controller.mouseReleaseEvent.connect(mouseReleaseEvent); -Controller.keyPressEvent.connect(keyPressEvent); -Controller.keyReleaseEvent.connect(keyReleaseEvent); \ No newline at end of file +Controller.mouseMoveEvent.connect(mouseMoveEvent); +Controller.mousePressEvent.connect(mousePressEvent); +Controller.mouseReleaseEvent.connect(mouseReleaseEvent); \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a4ef5579f0..c58b10880c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -969,6 +969,7 @@ void Application::paintGL() { OculusManager::endFrameTiming(); } _frameCount++; + Stats::getInstance()->setRenderDetails(renderArgs._details); } void Application::runTests() { @@ -3095,8 +3096,11 @@ PickRay Application::computePickRay(float x, float y) const { if (isHMDMode()) { getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction); } else { - auto frustum = activeRenderingThread ? getDisplayViewFrustum() : getViewFrustum(); - frustum->computePickRay(x, y, result.origin, result.direction); + if (QThread::currentThread() == activeRenderingThread) { + getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction); + } else { + getViewFrustum()->computePickRay(x, y, result.origin, result.direction); + } } return result; } @@ -3294,7 +3298,7 @@ namespace render { skybox = skyStage->getSkybox(); if (skybox) { gpu::Batch batch; - model::Skybox::render(batch, *(args->_viewFrustum), *skybox); + model::Skybox::render(batch, *(Application::getInstance()->getDisplayViewFrustum()), *skybox); gpu::GLBackend::renderBatch(batch, true); glUseProgram(0); @@ -3486,7 +3490,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se _main3DScene->processPendingChangesQueue(); } - // FOr now every frame pass the renderCOntext + // For now every frame pass the renderContext { PerformanceTimer perfTimer("EngineRun"); render::RenderContext renderContext; @@ -3523,7 +3527,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems); sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems); - + } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 9656fa45fd..095a939036 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -74,7 +74,6 @@ namespace render { if (avatarPtr->isInitialized() && args) { avatarPtr->render(args, Application::getInstance()->getCamera()->getPosition()); - args->_elementsTouched++; } } } diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 530225b319..06da384a94 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -10,6 +10,7 @@ // #include +#include #include "Avatar.h" #include "AvatarMotionState.h" @@ -151,6 +152,11 @@ QUuid AvatarMotionState::getSimulatorID() const { void AvatarMotionState::bump() { } +// virtual +int16_t AvatarMotionState::computeCollisionGroup() { + return COLLISION_GROUP_OTHER_AVATAR; +} + // virtual void AvatarMotionState::clearObjectBackPointer() { ObjectMotionState::clearObjectBackPointer(); diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 68c687d65b..79a4d23179 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -61,6 +61,8 @@ public: void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; } + virtual int16_t computeCollisionGroup(); + friend class AvatarManager; protected: diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 722f998f86..1501c52de5 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -39,7 +39,8 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) { setPupilDilation(_owningHead->getPupilDilation()); setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients()); - invalidCalculatedMeshBoxes(); + // FIXME - this is very expensive, we shouldn't do it if we don't have to + //invalidCalculatedMeshBoxes(); if (isActive()) { setOffset(-_geometry->getFBXGeometry().neckPivot); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index c49208c835..32df75c46d 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -467,31 +467,30 @@ void Stats::display( horizontalOffset += 5; // Model/Entity render details - EntityTreeRenderer* entities = Application::getInstance()->getEntities(); octreeStats.str(""); - octreeStats << "Entity Items rendered: " << entities->getItemsRendered() - << " / Out of view:" << entities->getItemsOutOfView() - << " / Too small:" << entities->getItemsTooSmall(); + octreeStats << "Triangles: " << _renderDetails._trianglesRendered + << " / Quads:" << _renderDetails._quadsRendered + << " / Material Switches:" << _renderDetails._materialSwitches; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); if (_expanded) { octreeStats.str(""); - octreeStats << " Meshes rendered: " << entities->getMeshesRendered() - << " / Out of view:" << entities->getMeshesOutOfView() - << " / Too small:" << entities->getMeshesTooSmall(); + octreeStats << " Mesh Parts Rendered Opaque: " << _renderDetails._opaque._rendered + << " / Translucent:" << _renderDetails._translucent._rendered; verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); - + octreeStats.str(""); - octreeStats << " Triangles: " << entities->getTrianglesRendered() - << " / Quads:" << entities->getQuadsRendered() - << " / Material Switches:" << entities->getMaterialSwitches(); + octreeStats << " Opaque considered: " << _renderDetails._opaque._considered + << " / Out of view:" << _renderDetails._opaque._outOfView + << " / Too small:" << _renderDetails._opaque._tooSmall; verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); - + octreeStats.str(""); - octreeStats << " Mesh Parts Rendered Opaque: " << entities->getOpaqueMeshPartsRendered() - << " / Translucent:" << entities->getTranslucentMeshPartsRendered(); + octreeStats << " Translucent considered: " << _renderDetails._translucent._considered + << " / Out of view:" << _renderDetails._translucent._outOfView + << " / Too small:" << _renderDetails._translucent._tooSmall; verticalOffset += STATS_PELS_PER_LINE; drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color); } diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index 00c1650b71..4c6d6ede4e 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -14,7 +14,7 @@ #include -#include +#include class Stats: public QObject { Q_OBJECT @@ -35,6 +35,8 @@ public: int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess); bool includeTimingRecord(const QString& name); + void setRenderDetails(const RenderDetails& details) { _renderDetails = details; } + private: static Stats* _sharedInstance; @@ -51,6 +53,7 @@ private: int _lastHorizontalOffset; + RenderDetails _renderDetails; }; #endif // hifi_Stats_h diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index b4be515a46..cf3262d05c 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -55,8 +55,6 @@ namespace render { } template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) { if (args) { - args->_elementsTouched++; - glPushMatrix(); if (overlay->getAnchor() == Overlay::MY_AVATAR) { MyAvatar* avatar = DependencyManager::get()->getMyAvatar(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 213a8de9a0..98cbc1f845 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -508,24 +508,6 @@ void EntityTreeRenderer::render(RenderArgs* renderArgs) { applyZonePropertiesToScene(_bestZone); _tree->unlock(); - - // stats... - _meshesConsidered = renderArgs->_meshesConsidered; - _meshesRendered = renderArgs->_meshesRendered; - _meshesOutOfView = renderArgs->_meshesOutOfView; - _meshesTooSmall = renderArgs->_meshesTooSmall; - - _elementsTouched = renderArgs->_elementsTouched; - _itemsRendered = renderArgs->_itemsRendered; - _itemsOutOfView = renderArgs->_itemsOutOfView; - _itemsTooSmall = renderArgs->_itemsTooSmall; - - _materialSwitches = renderArgs->_materialSwitches; - _trianglesRendered = renderArgs->_trianglesRendered; - _quadsRendered = renderArgs->_quadsRendered; - - _translucentMeshPartsRendered = renderArgs->_translucentMeshPartsRendered; - _opaqueMeshPartsRendered = renderArgs->_opaqueMeshPartsRendered; } deleteReleasedModels(); // seems like as good as any other place to do some memory cleanup } @@ -649,7 +631,6 @@ void EntityTreeRenderer::renderProxies(EntityItemPointer entity, RenderArgs* arg } void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) { - args->_elementsTouched++; // actually render it here... // we need to iterate the actual entityItems of the element EntityTreeElement* entityTreeElement = static_cast(element); @@ -1019,13 +1000,12 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) { _entityScripts.remove(entityID); // here's where we remove the entity payload from the scene - auto entity = static_cast(_tree)->findEntityByID(entityID); - if (entity && _entitiesInScene.contains(entity)) { + if (_entitiesInScene.contains(entityID)) { + auto entity = _entitiesInScene.take(entityID); render::PendingChanges pendingChanges; auto scene = _viewState->getMain3DScene(); entity->removeFromScene(entity, scene, pendingChanges); scene->enqueuePendingChanges(pendingChanges); - _entitiesInScene.remove(entity); } } @@ -1040,7 +1020,7 @@ void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) { render::PendingChanges pendingChanges; auto scene = _viewState->getMain3DScene(); if (entity->addToScene(entity, scene, pendingChanges)) { - _entitiesInScene.insert(entity); + _entitiesInScene.insert(entity->getEntityItemID(), entity); } scene->enqueuePendingChanges(pendingChanges); } @@ -1100,11 +1080,18 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT return; } const float mass = entity->computeMass(); - const float COLLISION_PENTRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity() - const float linearVelocity = glm::length(collision.penetration) * COLLISION_PENTRATION_TO_VELOCITY; + const float COLLISION_PENETRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity() + // The collision.penetration is a pretty good indicator of changed velocity AFTER the initial contact, + // but that first contact depends on exactly where we hit in the physics step. + // We can get a more consistent initial-contact energy reading by using the changed velocity. + // Note that velocityChange is not a good indicator for continuing collisions, because it does not distinguish + // between bounce and sliding along a surface. + const float linearVelocity = (collision.type == CONTACT_EVENT_TYPE_START) ? + glm::length(collision.velocityChange) : + glm::length(collision.penetration) * COLLISION_PENETRATION_TO_VELOCITY; const float energy = mass * linearVelocity * linearVelocity / 2.0f; const glm::vec3 position = collision.contactPoint; - const float COLLISION_ENERGY_AT_FULL_VOLUME = 0.5f; + const float COLLISION_ENERGY_AT_FULL_VOLUME = (collision.type == CONTACT_EVENT_TYPE_START) ? 150.0f : 5.0f; const float COLLISION_MINIMUM_VOLUME = 0.005f; const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME); if (energyFactorOfFull < COLLISION_MINIMUM_VOLUME) { @@ -1137,7 +1124,7 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I); soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0); const int channelCount = sound->isStereo() ? 2 : 1; - const float factor = log(1.0f + (entity->getMaximumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); + const float factor = log(1.0f + (entity->getMinimumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); const int standardRate = AudioConstants::SAMPLE_RATE; const int resampledRate = standardRate * factor; const int nInputSamples = samples.size() / sizeof(int16_t); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 55c889d1c1..e491524c78 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -188,7 +188,7 @@ private: float _previousStageHour; int _previousStageDay; - QSet _entitiesInScene; + QHash _entitiesInScene; }; diff --git a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp index 4c764c510f..ca81ae4f2b 100644 --- a/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableDebugableEntityItem.cpp @@ -59,7 +59,8 @@ void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args) renderBoundingBox(entity, args, 0.3f, yellowColor); } - if (PhysicsEngine::physicsInfoIsActive(entity->getPhysicsInfo())) { + ObjectMotionState* motionState = static_cast(entity->getPhysicsInfo()); + if (motionState && motionState->isActive()) { renderHoverDot(entity, args); } } diff --git a/libraries/entities-renderer/src/RenderableEntityItem.cpp b/libraries/entities-renderer/src/RenderableEntityItem.cpp index 56e385e689..461b64a9e6 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableEntityItem.cpp @@ -30,7 +30,6 @@ namespace render { } template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args) { if (args) { - args->_elementsTouched++; if (payload && payload->entity && payload->entity->getVisible()) { payload->entity->render(args); } diff --git a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp index 01926675c6..4e5de331bb 100644 --- a/libraries/entities-renderer/src/RenderableLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLineEntityItem.cpp @@ -48,7 +48,9 @@ void RenderableLineEntityItem::render(RenderArgs* args) { batch.setModelTransform(Transform()); batch._glLineWidth(getLineWidth()); - DependencyManager::get()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); + if (getLinePoints().size() > 1) { + DependencyManager::get()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID); + } batch._glLineWidth(1.0f); RenderableDebugableEntityItem::render(this, args); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 81ddb912cc..74aaf615c0 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -160,7 +160,6 @@ namespace render { } template <> void payloadRender(const RenderableModelEntityItemMeta::Pointer& payload, RenderArgs* args) { if (args) { - args->_elementsTouched++; if (payload && payload->entity) { payload->entity->render(args); } @@ -212,6 +211,11 @@ void RenderableModelEntityItem::render(RenderArgs* args) { if (hasModel()) { if (_model) { + if (QUrl(getModelURL()) != _model->getURL()) { + qDebug() << "Updating model URL: " << getModelURL(); + _model->setURL(getModelURL()); + } + // check to see if when we added our models to the scene they were ready, if they were not ready, then // fix them up in the scene render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene(); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 4d85e73bcc..41c2799d97 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -380,14 +380,16 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) { getModel(); } - Transform transformToCenter = getTransformToCenter(); - transformToCenter.setScale(getDimensions() / _voxelVolumeSize); + Transform transform; + transform.setTranslation(getPosition() - getRegistrationPoint() * getDimensions()); + transform.setRotation(getRotation()); + transform.setScale(getDimensions() / _voxelVolumeSize); auto mesh = _modelGeometry.getMesh(); Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; DependencyManager::get()->bindSimpleProgram(batch); - batch.setModelTransform(transformToCenter); + batch.setModelTransform(transform); batch.setInputFormat(mesh->getVertexFormat()); batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer()); batch.setInputBuffer(gpu::Stream::NORMAL, diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 4ca39a85b0..3d284baab6 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -8,10 +8,13 @@ #include "RenderableWebEntityItem.h" +#include + #include #include +#include #include #include #include @@ -64,7 +67,6 @@ RenderableWebEntityItem::~RenderableWebEntityItem() { void RenderableWebEntityItem::render(RenderArgs* args) { QOpenGLContext * currentContext = QOpenGLContext::currentContext(); QSurface * currentSurface = currentContext->surface(); - if (!_webSurface) { _webSurface = new OffscreenQmlSurface(); _webSurface->create(currentContext); @@ -98,16 +100,35 @@ void RenderableWebEntityItem::render(RenderArgs* args) { return; } + if (event->button() == Qt::MouseButton::RightButton) { + if (event->type() == QEvent::MouseButtonPress) { + const QMouseEvent* mouseEvent = static_cast(event); + _lastPress = toGlm(mouseEvent->pos()); + } + } + if (intersection.entityID == getID()) { if (event->button() == Qt::MouseButton::RightButton) { if (event->type() == QEvent::MouseButtonRelease) { - AbstractViewStateInterface::instance()->postLambdaEvent([this] { - QMetaObject::invokeMethod(_webSurface->getRootItem(), "goBack"); - }); + const QMouseEvent* mouseEvent = static_cast(event); + ivec2 dist = glm::abs(toGlm(mouseEvent->pos()) - _lastPress); + if (!glm::any(glm::greaterThan(dist, ivec2(1)))) { + AbstractViewStateInterface::instance()->postLambdaEvent([this] { + QMetaObject::invokeMethod(_webSurface->getRootItem(), "goBack"); + }); + } + _lastPress = ivec2(INT_MIN); } return; } + // FIXME doesn't work... double click events not received + if (event->type() == QEvent::MouseButtonDblClick) { + AbstractViewStateInterface::instance()->postLambdaEvent([this] { + _webSurface->getRootItem()->setProperty("url", _sourceUrl); + }); + } + if (event->button() == Qt::MouseButton::MiddleButton) { if (event->type() == QEvent::MouseButtonRelease) { AbstractViewStateInterface::instance()->postLambdaEvent([this] { @@ -133,6 +154,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) { QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent); } }; + EntityTreeRenderer* renderer = static_cast(args->_renderer); QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardMouseEvent); QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardMouseEvent); @@ -147,6 +169,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) { _webSurface->resize(QSize(dims.x, dims.y)); currentContext->makeCurrent(currentSurface); + Glower glow(0.0f); PerformanceTimer perfTimer("RenderableWebEntityItem::render"); Q_ASSERT(getType() == EntityTypes::Web); static const glm::vec2 texMin(0.0f); @@ -168,6 +191,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) { } void RenderableWebEntityItem::setSourceUrl(const QString& value) { + qDebug() << "Setting web entity source URL to " << value; if (_sourceUrl != value) { _sourceUrl = value; if (_webSurface) { diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 05ad3a4088..47e847a166 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -33,6 +33,7 @@ private: OffscreenQmlSurface* _webSurface{ nullptr }; QMetaObject::Connection _connection; uint32_t _texture{ 0 }; + ivec2 _lastPress{ INT_MIN }; QMutex _textureLock; }; diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1617131b8e..6b8e1833d7 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -82,7 +82,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert } EntityItem::~EntityItem() { - // these pointers MUST be NULL at delete, else we probably have a dangling backpointer + // these pointers MUST be correct at delete, else we probably have a dangling backpointer // to this EntityItem in the corresponding data structure. assert(!_simulated); assert(!_element); @@ -517,12 +517,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef EntityPropertyFlags propertyFlags = encodedPropertyFlags; dataAt += propertyFlags.getEncodedLength(); bytesRead += propertyFlags.getEncodedLength(); - bool useMeters = (args.bitstreamVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS); - if (useMeters) { - READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); - } else { - READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionInDomainUnits); - } + READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition); // Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) { @@ -536,22 +531,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } } } else { - if (useMeters) { - READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); - } else { - READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensionsInDomainUnits); - } + READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); } READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation); READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity); - if (useMeters) { - READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity); - READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity); - } else { - READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocityInDomainUnits); - READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravityInDomainUnits); - } + READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity); + READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity); if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) { READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration); } @@ -562,11 +548,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime); READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript); READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); - if (useMeters) { - READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); - } else { - READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees); - } + READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity); + //READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees); READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); @@ -945,31 +928,38 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c bool EntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePosition); // this will call recalculate collision shape if needed - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensions); // NOTE: radius is obsolete + // these affect TerseUpdate properties + SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePosition); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, updateDensity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, updateVelocity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, updateAngularVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(acceleration, setAcceleration); + + // these (along with "position" above) affect tree structure + SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); + + // these (along with all properties above) affect the simulation + SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, updateDensity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, updateDamping); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, updateAngularDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, updateRestitution); SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulatorID, updateSimulatorID); + + // non-simulation properties below SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, updateAngularVelocity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, updateAngularDamping); SET_ENTITY_PROPERTY_FROM_PROPERTIES(glowLevel, setGlowLevel); SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha); SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulatorID, updateSimulatorID); SET_ENTITY_PROPERTY_FROM_PROPERTIES(marketplaceID, setMarketplaceID); SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName); @@ -1155,11 +1145,6 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) { info.setParams(getShapeType(), 0.5f * getDimensions()); } -void EntityItem::updatePositionInDomainUnits(const glm::vec3& value) { - glm::vec3 position = value * (float)TREE_SCALE; - updatePosition(position); -} - void EntityItem::updatePosition(const glm::vec3& value) { auto delta = glm::distance(getPosition(), value); if (delta > IGNORE_POSITION_DELTA) { @@ -1171,11 +1156,6 @@ void EntityItem::updatePosition(const glm::vec3& value) { } } -void EntityItem::updateDimensionsInDomainUnits(const glm::vec3& value) { - glm::vec3 dimensions = value * (float)TREE_SCALE; - updateDimensions(dimensions); -} - void EntityItem::updateDimensions(const glm::vec3& value) { auto delta = glm::distance(getDimensions(), value); if (delta > IGNORE_DIMENSIONS_DELTA) { @@ -1227,11 +1207,6 @@ void EntityItem::updateMass(float mass) { } } -void EntityItem::updateVelocityInDomainUnits(const glm::vec3& value) { - glm::vec3 velocity = value * (float)TREE_SCALE; - updateVelocity(velocity); -} - void EntityItem::updateVelocity(const glm::vec3& value) { auto delta = glm::distance(_velocity, value); if (delta > IGNORE_LINEAR_VELOCITY_DELTA) { @@ -1257,11 +1232,6 @@ void EntityItem::updateDamping(float value) { } } -void EntityItem::updateGravityInDomainUnits(const glm::vec3& value) { - glm::vec3 gravity = value * (float) TREE_SCALE; - updateGravity(gravity); -} - void EntityItem::updateGravity(const glm::vec3& value) { auto delta = glm::distance(_gravity, value); if (delta > IGNORE_GRAVITY_DELTA) { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a189c944ae..638d9bf1d7 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -325,22 +325,17 @@ public: virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags - void updatePositionInDomainUnits(const glm::vec3& value); void updatePosition(const glm::vec3& value); - void updateDimensionsInDomainUnits(const glm::vec3& value); void updateDimensions(const glm::vec3& value); void updateRotation(const glm::quat& rotation); void updateDensity(float value); void updateMass(float value); - void updateVelocityInDomainUnits(const glm::vec3& value); void updateVelocity(const glm::vec3& value); void updateDamping(float value); void updateRestitution(float value); void updateFriction(float value); - void updateGravityInDomainUnits(const glm::vec3& value); void updateGravity(const glm::vec3& value); void updateAngularVelocity(const glm::vec3& value); - void updateAngularVelocityInDegrees(const glm::vec3& value) { updateAngularVelocity(glm::radians(value)); } void updateAngularDamping(float value); void updateIgnoreForCollisions(bool value); void updateCollisionsWillMove(bool value); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 6866505d58..5a897f7fe7 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -128,37 +128,45 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit return results; } -QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& properties) { +QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties properties) { EntityItemID entityID(id); // If we have a local entity tree set, then also update it. if (_entityTree) { _entityTree->lockForWrite(); - _entityTree->updateEntity(entityID, properties); + bool updatedEntity = _entityTree->updateEntity(entityID, properties); _entityTree->unlock(); - } - // make sure the properties has a type, so that the encode can know which properties to include - if (properties.getType() == EntityTypes::Unknown) { - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); - if (entity) { - // we need to change the outgoing properties, so we make a copy, modify, and send. - EntityItemProperties modifiedProperties = properties; - entity->setLastBroadcast(usecTimestampNow()); - modifiedProperties.setType(entity->getType()); - if (modifiedProperties.hasTerseUpdateChanges()) { - // we make a bid for (or assert) our simulation ownership - auto nodeList = DependencyManager::get(); - const QUuid myNodeID = nodeList->getSessionUUID(); - modifiedProperties.setSimulatorID(myNodeID); - - if (entity->getSimulatorID() == myNodeID) { - // we think we already own simulation, so make sure we send ALL TerseUpdate properties - entity->getAllTerseUpdateProperties(modifiedProperties); + if (updatedEntity) { + _entityTree->lockForRead(); + EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + if (entity) { + // make sure the properties has a type, so that the encode can know which properties to include + properties.setType(entity->getType()); + if (properties.hasTerseUpdateChanges()) { + auto nodeList = DependencyManager::get(); + const QUuid myNodeID = nodeList->getSessionUUID(); + + if (entity->getSimulatorID() == myNodeID) { + // we think we already own the simulation, so make sure to send ALL TerseUpdate properties + entity->getAllTerseUpdateProperties(properties); + // TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object + // is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update + // and instead let the physics simulation decide when to send a terse update. This would remove + // the "slide-no-rotate" glitch (and typical a double-update) that we see during the "poke rolling + // balls" test. However, even if we solve this problem we still need to provide a "slerp the visible + // proxy toward the true physical position" feature to hide the final glitches in the remote watcher's + // simulation. + } + // we make a bid for (or assert existing) simulation ownership + properties.setSimulatorID(myNodeID); } + entity->setLastBroadcast(usecTimestampNow()); } - queueEntityMessage(PacketTypeEntityEdit, entityID, modifiedProperties); + _entityTree->unlock(); + queueEntityMessage(PacketTypeEntityEdit, entityID, properties); return id; } + return QUuid(); } queueEntityMessage(PacketTypeEntityEdit, entityID, properties); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 7761effe2f..738a011b15 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -79,7 +79,7 @@ public slots: /// edits a model updating only the included properties, will return the identified EntityItemID in case of /// successful edit, if the input entityID is for an unknown model this function will have no effect - Q_INVOKABLE QUuid editEntity(QUuid entityID, const EntityItemProperties& properties); + Q_INVOKABLE QUuid editEntity(QUuid entityID, EntityItemProperties properties); /// deletes a model Q_INVOKABLE void deleteEntity(QUuid entityID); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 937472820e..47eb845daa 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -681,7 +681,6 @@ void EntityTree::update() { QSet idsToDelete; for (auto entity : pendingDeletes) { - assert(!entity->getPhysicsInfo()); // TODO: Andrew to remove this after testing idsToDelete.insert(entity->getEntityItemID()); } diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 0d99c8e82d..5897d3e9a8 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -64,7 +64,7 @@ public: virtual bool getWantSVOfileVersions() const { return true; } virtual PacketType expectedDataPacketType() const { return PacketTypeEntityData; } virtual bool canProcessVersion(PacketVersion thisVersion) const - { return thisVersion >= VERSION_ENTITIES_SUPPORT_SPLIT_MTU; } // we support all versions with split mtu + { return thisVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS; } virtual bool handlesEditPacketType(PacketType packetType) const; virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength, const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode); diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index 72f403a4e0..bb1e3be539 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -85,7 +85,18 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) { } void LineEntityItem::setLinePoints(const QVector& points) { - _points = points; + QVector sanitizedPoints; + for (int i = 0; i < points.size(); i++) { + glm::vec3 point = points.at(i); + // Make sure all of our points are valid numbers. + // Must be greater than 0 because vector component is set to 0 if it is invalid data + if (point.x > 0 && point.y > 0 && point.z > 0){ + sanitizedPoints << point; + } else { + qDebug() << "INVALID POINT"; + } + } + _points = sanitizedPoints; _pointsChanged = true; } diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 65f97981f1..7d630f2f47 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -109,9 +109,10 @@ TransformCamera getTransformCamera() { //return camera._projection * camera._view * object._model * pos; !> { // transformModelToClipPos vec4 _worldpos = (<$objectTransform$>._model * <$modelPos$>); - <$eyePos$> = (<$cameraTransform$>._viewInverse * _worldpos); + // <$eyePos$> = (<$cameraTransform$>._viewInverse * _worldpos); vec4 _eyepos =(<$objectTransform$>._model * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0); <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos; + <$eyePos$> = (<$cameraTransform$>._projectionInverse * <$clipPos$>); } <@else@> <$eyePos$> = gl_ModelViewMatrix * <$modelPos$>; diff --git a/libraries/octree/src/OctreeRenderer.cpp b/libraries/octree/src/OctreeRenderer.cpp index 246fab8578..7852f1d4b4 100644 --- a/libraries/octree/src/OctreeRenderer.cpp +++ b/libraries/octree/src/OctreeRenderer.cpp @@ -171,23 +171,6 @@ void OctreeRenderer::render(RenderArgs* renderArgs) { _tree->recurseTreeWithOperation(renderOperation, renderArgs); _tree->unlock(); } - _meshesConsidered = renderArgs->_meshesConsidered; - _meshesRendered = renderArgs->_meshesRendered; - _meshesOutOfView = renderArgs->_meshesOutOfView; - _meshesTooSmall = renderArgs->_meshesTooSmall; - - _elementsTouched = renderArgs->_elementsTouched; - _itemsRendered = renderArgs->_itemsRendered; - _itemsOutOfView = renderArgs->_itemsOutOfView; - _itemsTooSmall = renderArgs->_itemsTooSmall; - - _materialSwitches = renderArgs->_materialSwitches; - _trianglesRendered = renderArgs->_trianglesRendered; - _quadsRendered = renderArgs->_quadsRendered; - - _translucentMeshPartsRendered = renderArgs->_translucentMeshPartsRendered; - _opaqueMeshPartsRendered = renderArgs->_opaqueMeshPartsRendered; - } void OctreeRenderer::clear() { diff --git a/libraries/octree/src/OctreeRenderer.h b/libraries/octree/src/OctreeRenderer.h index 3172d3429d..98026b732c 100644 --- a/libraries/octree/src/OctreeRenderer.h +++ b/libraries/octree/src/OctreeRenderer.h @@ -60,23 +60,6 @@ public: /// clears the tree virtual void clear(); - - int getElementsTouched() const { return _elementsTouched; } - int getItemsRendered() const { return _itemsRendered; } - int getItemsOutOfView() const { return _itemsOutOfView; } - int getItemsTooSmall() const { return _itemsTooSmall; } - - int getMeshesConsidered() const { return _meshesConsidered; } - int getMeshesRendered() const { return _meshesRendered; } - int getMeshesOutOfView() const { return _meshesOutOfView; } - int getMeshesTooSmall() const { return _meshesTooSmall; } - - int getMaterialSwitches() const { return _materialSwitches; } - int getTrianglesRendered() const { return _trianglesRendered; } - int getQuadsRendered() const { return _quadsRendered; } - - int getTranslucentMeshPartsRendered() const { return _translucentMeshPartsRendered; } - int getOpaqueMeshPartsRendered() const { return _opaqueMeshPartsRendered; } protected: virtual Octree* createTree() = 0; @@ -84,23 +67,6 @@ protected: Octree* _tree; bool _managedTree; ViewFrustum* _viewFrustum; - - int _elementsTouched; - int _itemsRendered; - int _itemsOutOfView; - int _itemsTooSmall; - - int _meshesConsidered; - int _meshesRendered; - int _meshesOutOfView; - int _meshesTooSmall; - - int _materialSwitches; - int _trianglesRendered; - int _quadsRendered; - - int _translucentMeshPartsRendered; - int _opaqueMeshPartsRendered; }; #endif // hifi_OctreeRenderer_h diff --git a/libraries/physics/src/DynamicCharacterController.cpp b/libraries/physics/src/DynamicCharacterController.cpp index 5d2a1798f9..1fca236f63 100644 --- a/libraries/physics/src/DynamicCharacterController.cpp +++ b/libraries/physics/src/DynamicCharacterController.cpp @@ -3,6 +3,8 @@ #include #include +#include + #include "BulletUtil.h" #include "DynamicCharacterController.h" @@ -267,7 +269,7 @@ void DynamicCharacterController::setDynamicsWorld(btDynamicsWorld* world) { if (world && _rigidBody) { _dynamicsWorld = world; _pendingFlags &= ~ PENDING_FLAG_JUMP; - _dynamicsWorld->addRigidBody(_rigidBody); + _dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR); _dynamicsWorld->addAction(this); //reset(_dynamicsWorld); } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 9a24aabb34..23237cab32 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -11,6 +11,7 @@ #include #include +#include #include "BulletUtil.h" #include "EntityMotionState.h" @@ -49,24 +50,17 @@ EntityMotionState::~EntityMotionState() { assert(!_entity); } -void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) { - if (flags & EntityItem::DIRTY_POSITION) { - _serverPosition = _entity->getPosition(); - } - if (flags & EntityItem::DIRTY_ROTATION) { - _serverRotation = _entity->getRotation(); - } - if (flags & EntityItem::DIRTY_LINEAR_VELOCITY) { - _serverVelocity = _entity->getVelocity(); - } - if (flags & EntityItem::DIRTY_ANGULAR_VELOCITY) { - _serverAngularVelocity = _entity->getAngularVelocity(); - } +void EntityMotionState::updateServerPhysicsVariables() { + _serverPosition = _entity->getPosition(); + _serverRotation = _entity->getRotation(); + _serverVelocity = _entity->getVelocity(); + _serverAngularVelocity = _entity->getAngularVelocity(); + _serverAcceleration = _entity->getAcceleration(); } // virtual void EntityMotionState::handleEasyChanges(uint32_t flags) { - updateServerPhysicsVariables(flags); + updateServerPhysicsVariables(); ObjectMotionState::handleEasyChanges(flags); if (flags & EntityItem::DIRTY_SIMULATOR_ID) { _loopsWithoutOwner = 0; @@ -94,7 +88,7 @@ void EntityMotionState::handleEasyChanges(uint32_t flags) { // virtual void EntityMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) { - updateServerPhysicsVariables(flags); + updateServerPhysicsVariables(); ObjectMotionState::handleHardAndEasyChanges(flags, engine); } @@ -494,6 +488,7 @@ void EntityMotionState::measureBodyAcceleration() { float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP); float invDt = 1.0f / dt; _lastMeasureStep = thisStep; + _measuredDeltaTime = dt; // Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt // hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt @@ -502,6 +497,12 @@ void EntityMotionState::measureBodyAcceleration() { _lastVelocity = velocity; } } +glm::vec3 EntityMotionState::getObjectLinearVelocityChange() const { + // This is the dampened change in linear velocity, as calculated in measureBodyAcceleration: dv = a * dt + // It is generally only meaningful during the lifespan of collision. In particular, it is not meaningful + // when the entity first starts moving via direct user action. + return _measuredAcceleration * _measuredDeltaTime; +} // virtual void EntityMotionState::setMotionType(MotionType motionType) { @@ -517,3 +518,16 @@ QString EntityMotionState::getName() { } return ""; } + +// virtual +int16_t EntityMotionState::computeCollisionGroup() { + switch (computeObjectMotionType()){ + case MOTION_TYPE_STATIC: + return COLLISION_GROUP_STATIC; + case MOTION_TYPE_KINEMATIC: + return COLLISION_GROUP_KINEMATIC; + default: + break; + } + return COLLISION_GROUP_DEFAULT; +} diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 65279dc01a..2d732f8ee0 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -28,7 +28,7 @@ public: EntityMotionState(btCollisionShape* shape, EntityItemPointer item); virtual ~EntityMotionState(); - void updateServerPhysicsVariables(uint32_t flags); + void updateServerPhysicsVariables(); virtual void handleEasyChanges(uint32_t flags); virtual void handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); @@ -64,6 +64,7 @@ public: virtual glm::vec3 getObjectLinearVelocity() const { return _entity->getVelocity(); } virtual glm::vec3 getObjectAngularVelocity() const { return _entity->getAngularVelocity(); } virtual glm::vec3 getObjectGravity() const { return _entity->getGravity(); } + virtual glm::vec3 getObjectLinearVelocityChange() const; virtual const QUuid& getObjectID() const { return _entity->getID(); } @@ -77,6 +78,8 @@ public: virtual QString getName(); + virtual int16_t computeCollisionGroup(); + friend class PhysicalEntitySimulation; protected: @@ -101,6 +104,7 @@ protected: uint32_t _lastMeasureStep; glm::vec3 _lastVelocity; glm::vec3 _measuredAcceleration; + float _measuredDeltaTime; quint8 _accelerationNearlyGravityCount; bool _candidateForOwnership; diff --git a/libraries/physics/src/ObjectMotionState.cpp b/libraries/physics/src/ObjectMotionState.cpp index 57b75f0f3b..85e67d72f7 100644 --- a/libraries/physics/src/ObjectMotionState.cpp +++ b/libraries/physics/src/ObjectMotionState.cpp @@ -82,6 +82,9 @@ void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const { glm::vec3 ObjectMotionState::getBodyLinearVelocity() const { return bulletToGLM(_body->getLinearVelocity()); } +glm::vec3 ObjectMotionState::getObjectLinearVelocityChange() const { + return glm::vec3(0.0f); // Subclasses override where meaningful. +} glm::vec3 ObjectMotionState::getBodyAngularVelocity() const { return bulletToGLM(_body->getAngularVelocity()); @@ -200,3 +203,4 @@ void ObjectMotionState::updateBodyMassProperties() { _body->setMassProps(mass, inertia); _body->updateInertiaTensor(); } + diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 246ed16627..b17dc67cff 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -39,11 +39,12 @@ enum MotionStateType { // and re-added to the physics engine and "easy" which just updates the body properties. const uint32_t HARD_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_MOTION_TYPE | EntityItem::DIRTY_SHAPE); const uint32_t EASY_DIRTY_PHYSICS_FLAGS = (uint32_t)(EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES | - EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP); + EntityItem::DIRTY_MASS | EntityItem::DIRTY_COLLISION_GROUP | + EntityItem::DIRTY_MATERIAL); // These are the set of incoming flags that the PhysicsEngine needs to hear about: -const uint32_t DIRTY_PHYSICS_FLAGS = HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS | - EntityItem::DIRTY_MATERIAL | (uint32_t)EntityItem::DIRTY_PHYSICS_ACTIVATION; +const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS | + EntityItem::DIRTY_PHYSICS_ACTIVATION); // These are the outgoing flags that the PhysicsEngine can affect: const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES; @@ -90,6 +91,7 @@ public: glm::vec3 getBodyLinearVelocity() const; glm::vec3 getBodyAngularVelocity() const; + virtual glm::vec3 getObjectLinearVelocityChange() const; virtual uint32_t getAndClearIncomingDirtyFlags() = 0; @@ -123,6 +125,10 @@ public: virtual QString getName() { return ""; } + virtual int16_t computeCollisionGroup() = 0; + + bool isActive() const { return _body ? _body->isActive() : false; } + friend class PhysicsEngine; protected: diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index b615cf0c77..70853fb5f6 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -36,7 +36,7 @@ void PhysicalEntitySimulation::init( // begin EntitySimulation overrides void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) { - // TODO: add back non-physical kinematic objects and step them forward here + // Do nothing here because the "internal" update the PhysicsEngine::stepSimualtion() which is done elsewhere. } void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) { diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index b622a37136..54b05b63d6 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "ObjectMotionState.h" #include "PhysicsEngine.h" #include "PhysicsHelpers.h" @@ -23,15 +25,25 @@ uint32_t PhysicsEngine::getNumSubsteps() { } PhysicsEngine::PhysicsEngine(const glm::vec3& offset) : - _originOffset(offset), - _characterController(nullptr) { + _originOffset(offset), + _characterController(nullptr) { + // build table of masks with their group as the key + _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_DEFAULT), COLLISION_MASK_DEFAULT); + _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_STATIC), COLLISION_MASK_STATIC); + _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_KINEMATIC), COLLISION_MASK_KINEMATIC); + _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_DEBRIS), COLLISION_MASK_DEBRIS); + _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_TRIGGER), COLLISION_MASK_TRIGGER); + _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_MY_AVATAR), COLLISION_MASK_MY_AVATAR); + _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_MY_ATTACHMENT), COLLISION_MASK_MY_ATTACHMENT); + _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_OTHER_AVATAR), COLLISION_MASK_OTHER_AVATAR); + _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_OTHER_ATTACHMENT), COLLISION_MASK_OTHER_ATTACHMENT); + _collisionMasks.insert(btHashInt((int)COLLISION_GROUP_COLLISIONLESS), COLLISION_MASK_COLLISIONLESS); } PhysicsEngine::~PhysicsEngine() { if (_characterController) { _characterController->setDynamicsWorld(nullptr); } - // TODO: delete engine components... if we ever plan to create more than one instance delete _collisionConfig; delete _collisionDispatcher; delete _broadphaseFilter; @@ -125,7 +137,8 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) { body->setFlags(BT_DISABLE_WORLD_GRAVITY); motionState->updateBodyMaterialProperties(); - _dynamicsWorld->addRigidBody(body); + int16_t group = motionState->computeCollisionGroup(); + _dynamicsWorld->addRigidBody(body, group, getCollisionMask(group)); motionState->getAndClearIncomingDirtyFlags(); } @@ -154,11 +167,11 @@ void PhysicsEngine::deleteObjects(VectorOfMotionStates& objects) { } } -// Same as above, but takes a Set instead of a Vector and ommits some cleanup operations. Only called during teardown. +// Same as above, but takes a Set instead of a Vector. Should only be called during teardown. void PhysicsEngine::deleteObjects(SetOfMotionStates& objects) { for (auto object : objects) { btRigidBody* body = object->getRigidBody(); - _dynamicsWorld->removeRigidBody(body); + removeObject(object); // NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it. object->setRigidBody(nullptr); @@ -317,6 +330,8 @@ CollisionEvents& PhysicsEngine::getCollisionEvents() { if(type != CONTACT_EVENT_TYPE_CONTINUE || _numSubsteps % CONTINUE_EVENT_FILTER_FREQUENCY == 0) { ObjectMotionState* A = static_cast(contactItr->first._a); ObjectMotionState* B = static_cast(contactItr->first._b); + glm::vec3 velocityChange = (A ? A->getObjectLinearVelocityChange() : glm::vec3(0.0f)) + + (B ? B->getObjectLinearVelocityChange() : glm::vec3(0.0f)); if (A && A->getType() == MOTIONSTATE_TYPE_ENTITY) { QUuid idA = A->getObjectID(); @@ -326,14 +341,14 @@ CollisionEvents& PhysicsEngine::getCollisionEvents() { } glm::vec3 position = bulletToGLM(contact.getPositionWorldOnB()) + _originOffset; glm::vec3 penetration = bulletToGLM(contact.distance * contact.normalWorldOnB); - _collisionEvents.push_back(Collision(type, idA, idB, position, penetration)); + _collisionEvents.push_back(Collision(type, idA, idB, position, penetration, velocityChange)); } else if (B && B->getType() == MOTIONSTATE_TYPE_ENTITY) { QUuid idB = B->getObjectID(); glm::vec3 position = bulletToGLM(contact.getPositionWorldOnA()) + _originOffset; // NOTE: we're flipping the order of A and B (so that the first objectID is never NULL) // hence we must negate the penetration. glm::vec3 penetration = - bulletToGLM(contact.distance * contact.normalWorldOnB); - _collisionEvents.push_back(Collision(type, idB, QUuid(), position, penetration)); + _collisionEvents.push_back(Collision(type, idB, QUuid(), position, penetration, velocityChange)); } } @@ -417,34 +432,7 @@ void PhysicsEngine::setCharacterController(DynamicCharacterController* character } } -bool PhysicsEngine::physicsInfoIsActive(void* physicsInfo) { - if (!physicsInfo) { - return false; - } - - ObjectMotionState* motionState = static_cast(physicsInfo); - btRigidBody* body = motionState->getRigidBody(); - if (!body) { - return false; - } - - return body->isActive(); -} - -bool PhysicsEngine::getBodyLocation(void* physicsInfo, glm::vec3& positionReturn, glm::quat& rotationReturn) { - if (!physicsInfo) { - return false; - } - - ObjectMotionState* motionState = static_cast(physicsInfo); - btRigidBody* body = motionState->getRigidBody(); - if (!body) { - return false; - } - - const btTransform& worldTrans = body->getCenterOfMassTransform(); - positionReturn = bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(); - rotationReturn = bulletToGLM(worldTrans.getRotation()); - - return true; +int16_t PhysicsEngine::getCollisionMask(int16_t group) const { + const int16_t* mask = _collisionMasks.find(btHashInt((int)group)); + return mask ? *mask : COLLISION_MASK_DEFAULT; } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 9ff85c9f11..db00a2ba01 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -91,8 +91,7 @@ public: void dumpNextStats() { _dumpNextStats = true; } - static bool physicsInfoIsActive(void* physicsInfo); - static bool getBodyLocation(void* physicsInfo, glm::vec3& positionReturn, glm::quat& rotationReturn); + int16_t getCollisionMask(int16_t group) const; private: void removeContacts(ObjectMotionState* motionState); @@ -121,6 +120,7 @@ private: QUuid _sessionID; CollisionEvents _collisionEvents; + btHashMap _collisionMasks; }; #endif // hifi_PhysicsEngine_h diff --git a/libraries/physics/src/ShapeFactory.h b/libraries/physics/src/ShapeFactory.h index 699b8a0475..f6a6dfb3e6 100644 --- a/libraries/physics/src/ShapeFactory.h +++ b/libraries/physics/src/ShapeFactory.h @@ -19,11 +19,8 @@ // translates between ShapeInfo and btShape -// TODO: rename this to ShapeFactory namespace ShapeFactory { - btConvexHullShape* createConvexHull(const QVector& points); - btCollisionShape* createShapeFromInfo(const ShapeInfo& info); }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index e1af8c69b2..b3c8fa63cf 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -93,6 +93,8 @@ Model::Model(QObject* parent) : if (_viewState) { moveToThread(_viewState->getMainThread()); } + + setSnapModelToRegistrationPoint(true, glm::vec3(0.5f)); } Model::~Model() { @@ -409,7 +411,7 @@ void Model::reset() { _meshGroupsKnown = false; _readyWhenAdded = false; // in case any of our users are using scenes - _needsReload = true; + invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid } bool Model::updateGeometry() { @@ -461,7 +463,7 @@ bool Model::updateGeometry() { _geometry = geometry; _meshGroupsKnown = false; _readyWhenAdded = false; // in case any of our users are using scenes - _needsReload = true; + invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid initJointStates(newJointStates); needToRebuild = true; } else if (_jointStates.isEmpty()) { @@ -848,7 +850,6 @@ namespace render { } template <> void payloadRender(const TransparentMeshPart::Pointer& payload, RenderArgs* args) { if (args) { - args->_elementsTouched++; return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, true); } } @@ -883,7 +884,6 @@ namespace render { } template <> void payloadRender(const OpaqueMeshPart::Pointer& payload, RenderArgs* args) { if (args) { - args->_elementsTouched++; return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, false); } } @@ -1150,11 +1150,6 @@ bool Model::renderCore(RenderArgs* args, float alpha) { // restore all the default material settings _viewState->setupWorldLight(); - if (args) { - args->_translucentMeshPartsRendered = translucentMeshPartsRendered; - args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered; - } - #ifdef WANT_DEBUG_MESHBOXES renderDebugMeshBoxes(); #endif @@ -1273,6 +1268,7 @@ Extents Model::calculateScaledOffsetExtents(const Extents& extents) const { /// Returns the world space equivalent of some box in model space. AABox Model::calculateScaledOffsetAABox(const AABox& box) const { + return AABox(calculateScaledOffsetExtents(Extents(box))); } @@ -1610,6 +1606,7 @@ void Model::simulate(float deltaTime, bool fullUpdate) { || (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint); if (isActive() && fullUpdate) { + // NOTE: this seems problematic... need to review _calculatedMeshBoxesValid = false; // if we have to simulate, we need to assume our mesh boxes are all invalid _calculatedMeshTrianglesValid = false; @@ -1998,6 +1995,7 @@ void Model::applyNextGeometry() { _meshGroupsKnown = false; _readyWhenAdded = false; // in case any of our users are using scenes _needsReload = false; // we are loaded now! + invalidCalculatedMeshBoxes(); _nextBaseGeometry.reset(); _nextGeometry.reset(); } @@ -2045,7 +2043,6 @@ void Model::setupBatchTransform(gpu::Batch& batch, RenderArgs* args) { batch.setViewTransform(_transforms[0]); } - AABox Model::getPartBounds(int meshIndex, int partIndex) { if (!_calculatedMeshPartBoxesValid) { recalculateMeshBoxes(true); @@ -2071,7 +2068,28 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran gpu::Batch& batch = *(args->_batch); auto mode = args->_renderMode; - auto alphaThreshold = args->_alphaThreshold; + // render the part bounding box + #ifdef DEBUG_BOUNDING_PARTS + { + glm::vec4 cubeColor(1.0f,0.0f,0.0f,1.0f); + AABox partBounds = getPartBounds(meshIndex, partIndex); + + glm::mat4 translation = glm::translate(partBounds.calcCenter()); + glm::mat4 scale = glm::scale(partBounds.getDimensions()); + glm::mat4 modelToWorldMatrix = translation * scale; + batch.setModelTransform(modelToWorldMatrix); + //qDebug() << "partBounds:" << partBounds; + DependencyManager::get()->renderWireCube(batch, 1.0f, cubeColor); + } + #endif //def DEBUG_BOUNDING_PARTS + + // Capture the view matrix once for the rendering of this model + if (_transforms.empty()) { + _transforms.push_back(Transform()); + } + + auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME + const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& networkMeshes = _geometry->getMeshes(); @@ -2099,8 +2117,6 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe, args, locations); - - int meshPartsRendered = 0; updateVisibleJointStates(); // if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown @@ -2109,7 +2125,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran if (meshIndex < 0 || meshIndex >= networkMeshes.size() || meshIndex > geometry.meshes.size()) { _meshGroupsKnown = false; // regenerate these lists next time around. _readyWhenAdded = false; // in case any of our users are using scenes - _needsReload = true; + invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid return; // FIXME! } @@ -2225,7 +2241,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran } if (args) { - args->_materialSwitches++; + args->_details._materialSwitches++; } // HACK: For unknown reason (yet!) this code that should be assigned only if the material changes need to be called for every @@ -2235,16 +2251,14 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran float emissiveOffset = part.emissiveParams.x; float emissiveScale = part.emissiveParams.y; GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale); - + Texture* emissiveMap = networkPart.emissiveTexture.data(); batch.setUniformTexture(locations->emissiveTextureUnit, !emissiveMap ? - textureCache->getWhiteTexture() : emissiveMap->getGPUTexture()); + textureCache->getWhiteTexture() : emissiveMap->getGPUTexture()); } } } - meshPartsRendered++; - qint64 offset = _calculatedMeshPartOffet[QPair(meshIndex, partIndex)]; if (part.quadIndices.size() > 0) { @@ -2260,8 +2274,8 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran if (args) { const int INDICES_PER_TRIANGLE = 3; const int INDICES_PER_QUAD = 4; - args->_trianglesRendered += part.triangleIndices.size() / INDICES_PER_TRIANGLE; - args->_quadsRendered += part.quadIndices.size() / INDICES_PER_QUAD; + args->_details._trianglesRendered += part.triangleIndices.size() / INDICES_PER_TRIANGLE; + args->_details._quadsRendered += part.quadIndices.size() / INDICES_PER_QUAD; } } @@ -2435,7 +2449,7 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod if (i < 0 || i >= networkMeshes.size() || i > geometry.meshes.size()) { _meshGroupsKnown = false; // regenerate these lists next time around. _readyWhenAdded = false; // in case any of our users are using scenes - _needsReload = true; + invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid continue; } @@ -2453,8 +2467,6 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod // if we got here, then check to see if this mesh is in view if (args) { bool shouldRender = true; - args->_meshesConsidered++; - if (args->_viewFrustum) { shouldRender = forceRenderMeshes || @@ -2464,17 +2476,10 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod float distance = args->_viewFrustum->distanceToCamera(_calculatedMeshBoxes.at(i).calcCenter()); shouldRender = !_viewState ? false : _viewState->shouldRenderMesh(_calculatedMeshBoxes.at(i).getLargestDimension(), distance); - if (!shouldRender) { - args->_meshesTooSmall++; - } - } else { - args->_meshesOutOfView++; } } - if (shouldRender) { - args->_meshesRendered++; - } else { + if (!shouldRender) { continue; // skip this mesh } } @@ -2565,11 +2570,6 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod batch.setUniformTexture(locations->specularTextureUnit, !specularMap ? textureCache->getWhiteTexture() : specularMap->getGPUTexture()); } - - if (args) { - args->_materialSwitches++; - } - } // HACK: For unkwon reason (yet!) this code that should be assigned only if the material changes need to be called for every @@ -2600,12 +2600,6 @@ int Model::renderMeshesFromList(QVector& list, gpu::Batch& batch, RenderMod offset += part.triangleIndices.size() * sizeof(int); } - if (args) { - const int INDICES_PER_TRIANGLE = 3; - const int INDICES_PER_QUAD = 4; - args->_trianglesRendered += part.triangleIndices.size() / INDICES_PER_TRIANGLE; - args->_quadsRendered += part.quadIndices.size() / INDICES_PER_QUAD; - } } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 8ad683e9e4..b2b6e0dc7d 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -260,7 +260,7 @@ protected: bool _snapModelToRegistrationPoint; /// is the model's offset automatically adjusted to a registration point in model space bool _snappedToRegistrationPoint; /// are we currently snapped to a registration point - glm::vec3 _registrationPoint; /// the point in model space our center is snapped to + glm::vec3 _registrationPoint = glm::vec3(0.5f); /// the point in model space our center is snapped to bool _showTrueJointTransforms; @@ -312,7 +312,12 @@ protected: float getLimbLength(int jointIndex) const; /// Allow sub classes to force invalidating the bboxes - void invalidCalculatedMeshBoxes() { _calculatedMeshBoxesValid = false; } + void invalidCalculatedMeshBoxes() { + qDebug() << "invalidCalculatedMeshBoxes()"; + _calculatedMeshBoxesValid = false; + _calculatedMeshPartBoxesValid = false; + _calculatedMeshTrianglesValid = false; + } private: diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 7fc27be5f2..f6641f7d0d 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -35,6 +35,8 @@ template <> void render::jobRun(const RenderDeferred& job, const SceneContextPoi template <> void render::jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { PerformanceTimer perfTimer("ResolveDeferred"); DependencyManager::get()->copyBack(renderContext->args); + renderContext->args->_context->syncCache(); + } diff --git a/libraries/render-utils/src/model.slv b/libraries/render-utils/src/model.slv index 2d22c0df51..c400f1e8bf 100755 --- a/libraries/render-utils/src/model.slv +++ b/libraries/render-utils/src/model.slv @@ -40,6 +40,6 @@ void main(void) { TransformObject obj = getTransformObject(); <$transformModelToEyeAndClipPos(cam, obj, gl_Vertex, interpolatedPosition, gl_Position)$> <$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$> - + // interpolatedPosition = (gl_Vertex); interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); } diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf index 9d39bf98a1..89183066da 100755 --- a/libraries/render-utils/src/model_translucent.slf +++ b/libraries/render-utils/src/model_translucent.slf @@ -54,24 +54,44 @@ void main(void) { // The view Matrix //uniform mat4 invViewMat; -vec3 evalAmbienGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) { +vec4 evalNormalColor(vec3 dir, float opacity) { + bool isX = (abs(dir.x) > 0.99); + bool isY = (abs(dir.y) > 0.99); + bool isZ = (abs(dir.z) > 0.99); + if (isX || isY || isZ) { + bool negX = (dir.x < -0.995); + bool negY = (dir.y < -0.995); + bool negZ = (dir.z < -0.995); + + if (negX || negY || negZ) { + return vec4(float(isX), float(isY), float(isZ), 0.2); + } else { + return vec4(float(isX), float(isY), float(isZ), 1.0); + } + } + + return vec4(0.5 * dir + vec3(0.5), opacity); +} + +vec4 evalAmbienGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss, float opacity) { // Need the light now Light light = getLight(); TransformCamera cam = getTransformCamera(); - mat4 invViewMat = cam._viewInverse; - - vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0)); - vec4 fragEyeVector = invViewMat * vec4(-position, 0.0); - vec3 fragEyeDir = normalize(fragEyeVector.xyz); + // mat4 viewMat = cam._viewInverse; + vec3 fragNormal; + <$transformEyeToWorldDir(cam, normal, fragNormal)$> + vec3 fragEyeVectorView = normalize(-position); + vec3 fragEyeDir; + <$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$> vec3 color = diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light); vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + color += vec3(opacity * diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); - return color; + return vec4(color, opacity); } // the diffuse texture @@ -98,12 +118,13 @@ void main(void) { vec3 fragSpecular = getMaterialSpecular(mat); float fragGloss = getMaterialShininess(mat); - vec3 color = evalAmbienGlobalColor(1.0, + vec4 fragColor = evalAmbienGlobalColor(1.0, fragPosition, fragNormal, fragDiffuse, fragSpecular, - fragGloss); + fragGloss, + fragOpacity); - gl_FragColor = vec4(color, fragOpacity); + gl_FragColor = fragColor; //vec4(fragColor, fragOpacity); } diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index ce1ab37808..c0a1639f8b 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -63,7 +63,10 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont auto& scene = sceneContext->_scene; RenderArgs* args = renderContext->args; + auto renderDetails = renderContext->args->_details._item; + renderDetails->_considered += inItems.size(); + // Culling / LOD for (auto id : inItems) { auto item = scene->getItem(id); @@ -71,7 +74,6 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont if (bound.isNull()) { outItems.push_back(id); // One more Item to render - args->_itemsRendered++; continue; } @@ -80,17 +82,16 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont bool outOfView = args->_viewFrustum->boxInFrustum(bound) == ViewFrustum::OUTSIDE; if (!outOfView) { bool bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, bound) : true; - if (bigEnoughToRender) { outItems.push_back(id); // One more Item to render - args->_itemsRendered++; } else { - args->_itemsTooSmall++; + renderDetails->_tooSmall++; } } else { - args->_itemsOutOfView++; + renderDetails->_outOfView++; } } + renderDetails->_rendered += outItems.size(); } struct ItemBound { @@ -227,6 +228,7 @@ template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer // render opaques auto& scene = sceneContext->_scene; auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape()); + auto& renderDetails = renderContext->args->_details; ItemIDs inItems; inItems.reserve(items.size()); @@ -239,7 +241,9 @@ template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer ItemIDs culledItems; if (renderContext->_cullOpaque) { + renderDetails.pointTo(RenderDetails::OPAQUE_ITEM); cullItems(sceneContext, renderContext, renderedItems, culledItems); + renderDetails.pointTo(RenderDetails::OTHER_ITEM); renderedItems = culledItems; } @@ -290,6 +294,7 @@ template <> void render::jobRun(const DrawTransparent& job, const SceneContextPo // render transparents auto& scene = sceneContext->_scene; auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape()); + auto& renderDetails = renderContext->args->_details; ItemIDs inItems; inItems.reserve(items.size()); @@ -302,7 +307,9 @@ template <> void render::jobRun(const DrawTransparent& job, const SceneContextPo ItemIDs culledItems; if (renderContext->_cullTransparent) { + renderDetails.pointTo(RenderDetails::TRANSLUCENT_ITEM); cullItems(sceneContext, renderContext, inItems, culledItems); + renderDetails.pointTo(RenderDetails::OTHER_ITEM); renderedItems = culledItems; } diff --git a/libraries/shared/src/PhysicsCollisionGroups.h b/libraries/shared/src/PhysicsCollisionGroups.h new file mode 100644 index 0000000000..cce9637cd4 --- /dev/null +++ b/libraries/shared/src/PhysicsCollisionGroups.h @@ -0,0 +1,79 @@ +// +// PhysicsCollisionGroups.h +// libraries/shared/src +// +// Created by Andrew Meadows 2015.06.03 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_PhysicsCollisionGroups_h +#define hifi_PhysicsCollisionGroups_h + +#include + +/* Note: These are the Bullet collision groups defined in btBroadphaseProxy. Only + * DefaultFilter and StaticFilter are explicitly used by Bullet (when the collision + * filter of an object is not manually specified), the rest are merely suggestions. + * +enum CollisionFilterGroups { + DefaultFilter = 1, + StaticFilter = 2, + KinematicFilter = 4, + DebrisFilter = 8, + SensorTrigger = 16, + CharacterFilter = 32, + AllFilter = -1 +} + * + * When using custom collision filters we pretty much need to do all or nothing. + * We'll be doing it all which means we define our own groups and build custom masks + * for everything. + * +*/ + +const int16_t COLLISION_GROUP_DEFAULT = 1 << 0; +const int16_t COLLISION_GROUP_STATIC = 1 << 1; +const int16_t COLLISION_GROUP_KINEMATIC = 1 << 2; +const int16_t COLLISION_GROUP_DEBRIS = 1 << 3; +const int16_t COLLISION_GROUP_TRIGGER = 1 << 4; +const int16_t COLLISION_GROUP_MY_AVATAR = 1 << 5; +const int16_t COLLISION_GROUP_OTHER_AVATAR = 1 << 6; +const int16_t COLLISION_GROUP_MY_ATTACHMENT = 1 << 7; +const int16_t COLLISION_GROUP_OTHER_ATTACHMENT = 1 << 8; +// ... +const int16_t COLLISION_GROUP_COLLISIONLESS = 1 << 15; + + +/* Note: In order for objectA to collide with objectB at the filter stage + * both (groupA & maskB) and (groupB & maskA) must be non-zero. + */ + +// DEFAULT collides with everything except COLLISIONLESS +const int16_t COLLISION_MASK_DEFAULT = ~ COLLISION_GROUP_COLLISIONLESS; + +// STATIC also doesn't collide with other STATIC +const int16_t COLLISION_MASK_STATIC = ~ (COLLISION_GROUP_COLLISIONLESS | COLLISION_MASK_STATIC); + +const int16_t COLLISION_MASK_KINEMATIC = COLLISION_MASK_DEFAULT; + +// DEBRIS also doesn't collide with other DEBRIS, or TRIGGER +const int16_t COLLISION_MASK_DEBRIS = ~ (COLLISION_GROUP_COLLISIONLESS + | COLLISION_GROUP_DEBRIS + | COLLISION_GROUP_TRIGGER); + +// TRIGGER also doesn't collide with DEBRIS, TRIGGER, or STATIC (TRIGGER only detects moveable things that matter) +const int16_t COLLISION_MASK_TRIGGER = COLLISION_MASK_DEBRIS & ~(COLLISION_GROUP_STATIC); + +// AVATAR also doesn't collide with corresponding ATTACHMENTs +const int16_t COLLISION_MASK_MY_AVATAR = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_MY_ATTACHMENT); +const int16_t COLLISION_MASK_MY_ATTACHMENT = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_MY_AVATAR); +const int16_t COLLISION_MASK_OTHER_AVATAR = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_OTHER_ATTACHMENT); +const int16_t COLLISION_MASK_OTHER_ATTACHMENT = ~(COLLISION_GROUP_COLLISIONLESS | COLLISION_GROUP_OTHER_AVATAR); + +// COLLISIONLESS gets an empty mask. +const int16_t COLLISION_MASK_COLLISIONLESS = 0; + +#endif // hifi_PhysicsCollisionGroups_h diff --git a/libraries/shared/src/PhysicsHelpers.cpp b/libraries/shared/src/PhysicsHelpers.cpp index be06920325..578c85683b 100644 --- a/libraries/shared/src/PhysicsHelpers.cpp +++ b/libraries/shared/src/PhysicsHelpers.cpp @@ -5,7 +5,7 @@ // Created by Andrew Meadows 2015.01.27 // Unless otherwise copyrighted: Copyright 2015 High Fidelity, Inc. // -// Unless otherwise licensced: Distributed under the Apache License, Version 2.0. +// Unless otherwise licensed: Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 48eecba227..1dcc85107a 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -78,15 +78,17 @@ enum ContactEventType { class Collision { public: - Collision() : type(CONTACT_EVENT_TYPE_START), idA(), idB(), contactPoint(0.0f), penetration(0.0f) { } - Collision(ContactEventType cType, const QUuid& cIdA, const QUuid& cIdB, const glm::vec3& cPoint, const glm::vec3& cPenetration) - : type(cType), idA(cIdA), idB(cIdB), contactPoint(cPoint), penetration(cPenetration) { } + Collision() : type(CONTACT_EVENT_TYPE_START), idA(), idB(), contactPoint(0.0f), penetration(0.0f), velocityChange(0.0f) { } + Collision(ContactEventType cType, const QUuid& cIdA, const QUuid& cIdB, const glm::vec3& cPoint, + const glm::vec3& cPenetration, const glm::vec3& velocityChange) + : type(cType), idA(cIdA), idB(cIdB), contactPoint(cPoint), penetration(cPenetration), velocityChange(velocityChange) { } ContactEventType type; QUuid idA; QUuid idB; glm::vec3 contactPoint; glm::vec3 penetration; + glm::vec3 velocityChange; }; Q_DECLARE_METATYPE(Collision) QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision); diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index aefaca8a31..84b3a202b4 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -22,6 +22,46 @@ class Batch; class Context; } +class RenderDetails { +public: + enum Type { + OPAQUE_ITEM, + TRANSLUCENT_ITEM, + OTHER_ITEM + }; + + struct Item { + int _considered = 0; + int _rendered = 0; + int _outOfView = 0; + int _tooSmall = 0; + }; + + int _materialSwitches = 0; + int _trianglesRendered = 0; + int _quadsRendered = 0; + + Item _opaque; + Item _translucent; + Item _other; + + Item* _item = &_other; + + void pointTo(Type type) { + switch (type) { + case OPAQUE_ITEM: + _item = &_opaque; + break; + case TRANSLUCENT_ITEM: + _item = &_translucent; + break; + case OTHER_ITEM: + _item = &_other; + break; + } + } +}; + class RenderArgs { public: typedef std::function ShoudRenderFunctor; @@ -45,24 +85,7 @@ public: RenderSide renderSide = MONO, DebugFlags debugFlags = RENDER_DEBUG_NONE, gpu::Batch* batch = nullptr, - ShoudRenderFunctor shouldRender = nullptr, - - int elementsTouched = 0, - int itemsRendered = 0, - int itemsOutOfView = 0, - int itemsTooSmall = 0, - - int meshesConsidered = 0, - int meshesRendered = 0, - int meshesOutOfView = 0, - int meshesTooSmall = 0, - - int materialSwitches = 0, - int trianglesRendered = 0, - int quadsRendered = 0, - - int translucentMeshPartsRendered = 0, - int opaqueMeshPartsRendered = 0) : + ShoudRenderFunctor shouldRender = nullptr) : _context(context), _renderer(renderer), _viewFrustum(viewFrustum), @@ -72,53 +95,21 @@ public: _renderSide(renderSide), _debugFlags(debugFlags), _batch(batch), - _shouldRender(shouldRender), - - _elementsTouched(elementsTouched), - _itemsRendered(itemsRendered), - _itemsOutOfView(itemsOutOfView), - _itemsTooSmall(itemsTooSmall), - - _meshesConsidered(meshesConsidered), - _meshesRendered(meshesRendered), - _meshesOutOfView(meshesOutOfView), - _meshesTooSmall(meshesTooSmall), - - _materialSwitches(materialSwitches), - _trianglesRendered(trianglesRendered), - _quadsRendered(quadsRendered), - - _translucentMeshPartsRendered(translucentMeshPartsRendered), - _opaqueMeshPartsRendered(opaqueMeshPartsRendered) { + _shouldRender(shouldRender) { } - gpu::Context* _context; - OctreeRenderer* _renderer; - ViewFrustum* _viewFrustum; - float _sizeScale; - int _boundaryLevelAdjust; - RenderMode _renderMode; - RenderSide _renderSide; - DebugFlags _debugFlags; - gpu::Batch* _batch; + gpu::Context* _context = nullptr; + OctreeRenderer* _renderer = nullptr; + ViewFrustum* _viewFrustum = nullptr; + float _sizeScale = 1.0f; + int _boundaryLevelAdjust = 0; + RenderMode _renderMode = DEFAULT_RENDER_MODE; + RenderSide _renderSide = MONO; + DebugFlags _debugFlags = RENDER_DEBUG_NONE; + gpu::Batch* _batch = nullptr; ShoudRenderFunctor _shouldRender; - - int _elementsTouched; - int _itemsRendered; - int _itemsOutOfView; - int _itemsTooSmall; - - int _meshesConsidered; - int _meshesRendered; - int _meshesOutOfView; - int _meshesTooSmall; - - int _materialSwitches; - int _trianglesRendered; - int _quadsRendered; - - int _translucentMeshPartsRendered; - int _opaqueMeshPartsRendered; + + RenderDetails _details; float _alphaThreshold = 0.5f; };