Gettting th ehighlight on transparent to work

This commit is contained in:
Sam Gateau 2015-06-08 02:52:13 -07:00
commit de61f4ea0b
50 changed files with 1181 additions and 515 deletions

View file

@ -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);

117
examples/lineRider.js Normal file
View file

@ -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);
}

495
examples/paint.js Normal file
View file

@ -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));
}

View file

@ -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);
Controller.mouseMoveEvent.connect(mouseMoveEvent);
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);

View file

@ -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);
}

View file

@ -74,7 +74,6 @@ namespace render {
if (avatarPtr->isInitialized() && args) {
avatarPtr->render(args, Application::getInstance()->getCamera()->getPosition());
args->_elementsTouched++;
}
}
}

View file

@ -10,6 +10,7 @@
//
#include <PhysicsHelpers.h>
#include <PhysicsCollisionGroups.h>
#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();

View file

@ -61,6 +61,8 @@ public:
void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; }
virtual int16_t computeCollisionGroup();
friend class AvatarManager;
protected:

View file

@ -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);

View file

@ -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);
}

View file

@ -14,7 +14,7 @@
#include <QObject>
#include <NodeList.h>
#include <RenderArgs.h>
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

View file

@ -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<AvatarManager>()->getMyAvatar();

View file

@ -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<EntityTreeElement*>(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<EntityTree*>(_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);

View file

@ -188,7 +188,7 @@ private:
float _previousStageHour;
int _previousStageDay;
QSet<EntityItemPointer> _entitiesInScene;
QHash<EntityItemID, EntityItemPointer> _entitiesInScene;
};

View file

@ -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<ObjectMotionState*>(entity->getPhysicsInfo());
if (motionState && motionState->isActive()) {
renderHoverDot(entity, args);
}
}

View file

@ -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);
}

View file

@ -48,7 +48,9 @@ void RenderableLineEntityItem::render(RenderArgs* args) {
batch.setModelTransform(Transform());
batch._glLineWidth(getLineWidth());
DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID);
if (getLinePoints().size() > 1) {
DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::LINE_STRIP, _lineVerticesID);
}
batch._glLineWidth(1.0f);
RenderableDebugableEntityItem::render(this, args);

View file

@ -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();

View file

@ -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<DeferredLightingEffect>()->bindSimpleProgram(batch);
batch.setModelTransform(transformToCenter);
batch.setModelTransform(transform);
batch.setInputFormat(mesh->getVertexFormat());
batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer());
batch.setInputBuffer(gpu::Stream::NORMAL,

View file

@ -8,10 +8,13 @@
#include "RenderableWebEntityItem.h"
#include <QMouseEvent>
#include <glm/gtx/quaternion.hpp>
#include <gpu/GPUConfig.h>
#include <GlowEffect.h>
#include <DeferredLightingEffect.h>
#include <GeometryCache.h>
#include <PerfStat.h>
@ -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<const QMouseEvent*>(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<const QMouseEvent*>(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<EntityTreeRenderer*>(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) {

View file

@ -33,6 +33,7 @@ private:
OffscreenQmlSurface* _webSurface{ nullptr };
QMetaObject::Connection _connection;
uint32_t _texture{ 0 };
ivec2 _lastPress{ INT_MIN };
QMutex _textureLock;
};

View file

@ -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) {

View file

@ -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);

View file

@ -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<NodeList>();
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<NodeList>();
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);

View file

@ -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);

View file

@ -681,7 +681,6 @@ void EntityTree::update() {
QSet<EntityItemID> idsToDelete;
for (auto entity : pendingDeletes) {
assert(!entity->getPhysicsInfo()); // TODO: Andrew to remove this after testing
idsToDelete.insert(entity->getEntityItemID());
}

View file

@ -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);

View file

@ -85,7 +85,18 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
}
void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
_points = points;
QVector<glm::vec3> 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;
}

View file

@ -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$>;

View file

@ -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() {

View file

@ -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

View file

@ -3,6 +3,8 @@
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
#include <LinearMath/btDefaultMotionState.h>
#include <PhysicsCollisionGroups.h>
#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);
}

View file

@ -11,6 +11,7 @@
#include <EntityItem.h>
#include <EntityEditPacketSender.h>
#include <PhysicsCollisionGroups.h>
#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;
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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:

View file

@ -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) {

View file

@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <PhysicsCollisionGroups.h>
#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<ObjectMotionState*>(contactItr->first._a);
ObjectMotionState* B = static_cast<ObjectMotionState*>(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<ObjectMotionState*>(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<ObjectMotionState*>(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;
}

View file

@ -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<btHashInt, int16_t> _collisionMasks;
};
#endif // hifi_PhysicsEngine_h

View file

@ -19,11 +19,8 @@
// translates between ShapeInfo and btShape
// TODO: rename this to ShapeFactory
namespace ShapeFactory {
btConvexHullShape* createConvexHull(const QVector<glm::vec3>& points);
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
};

View file

@ -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<DeferredLightingEffect>()->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<NetworkMesh>& 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<int,int>(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<int>& 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<int>& 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<int>& 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<int>& 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<int>& 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;
}
}
}

View file

@ -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:

View file

@ -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<DeferredLightingEffect>()->copyBack(renderContext->args);
renderContext->args->_context->syncCache();
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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 <stdint.h>
/* 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

View file

@ -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
//

View file

@ -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);

View file

@ -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<bool(const RenderArgs* args, const AABox& bounds)> 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;
};