mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 19:21:16 +02:00
Gettting th ehighlight on transparent to work
This commit is contained in:
commit
de61f4ea0b
50 changed files with 1181 additions and 515 deletions
66
examples/example/soundToys.js
Normal file
66
examples/example/soundToys.js
Normal 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
117
examples/lineRider.js
Normal 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
495
examples/paint.js
Normal 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));
|
||||||
|
}
|
|
@ -1,30 +1,17 @@
|
||||||
// pointer.js
|
// pointer.js
|
||||||
// examples
|
// 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.
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
//
|
//
|
||||||
// Provides a pointer with option to draw on surfaces
|
// Provides a pointer with option to draw on surfaces
|
||||||
//
|
//
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
|
||||||
|
|
||||||
var lineEntityID = null;
|
var lineEntityID = null;
|
||||||
var lineIsRezzed = false;
|
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 BUTTON_SIZE = 32;
|
||||||
var PADDING = 3;
|
var PADDING = 3;
|
||||||
|
@ -43,16 +30,7 @@ var buttonOnColor = {
|
||||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||||
var screenSize = Controller.getViewportDimensions();
|
var screenSize = Controller.getViewportDimensions();
|
||||||
|
|
||||||
var drawButton = Overlays.addOverlay("image", {
|
var userCanPoint = false;
|
||||||
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 pointerButton = Overlays.addOverlay("image", {
|
var pointerButton = Overlays.addOverlay("image", {
|
||||||
x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING,
|
x: screenSize.x / 2 - BUTTON_SIZE * 2 + PADDING,
|
||||||
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
y: screenSize.y - (BUTTON_SIZE + PADDING),
|
||||||
|
@ -61,14 +39,12 @@ var pointerButton = Overlays.addOverlay("image", {
|
||||||
imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png",
|
imageURL: HIFI_PUBLIC_BUCKET + "images/laser.png",
|
||||||
color: buttonOffColor,
|
color: buttonOffColor,
|
||||||
alpha: 1
|
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 handPosition = MyAvatar.getRightPalmPosition();
|
||||||
var along = Vec3.subtract(targetPosition, handPosition);
|
var along = Vec3.subtract(targetPosition, handPosition);
|
||||||
along = Vec3.normalize(along);
|
along = Vec3.normalize(along);
|
||||||
|
@ -87,39 +63,40 @@ function removeLine() {
|
||||||
|
|
||||||
|
|
||||||
function createOrUpdateLine(event) {
|
function createOrUpdateLine(event) {
|
||||||
if (!userCanPoint) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
|
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
|
||||||
var props = Entities.getEntityProperties(intersection.entityID);
|
var props = Entities.getEntityProperties(intersection.entityID);
|
||||||
|
|
||||||
if (intersection.intersects) {
|
if (intersection.intersects && userCanPoint) {
|
||||||
startPosition = intersection.intersection;
|
var points = [nearLinePoint(intersection.intersection), 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 (lineIsRezzed) {
|
if (lineIsRezzed) {
|
||||||
Entities.editEntity(lineEntityID, {
|
Entities.editEntity(lineEntityID, {
|
||||||
position: nearLinePosition,
|
position: nearLinePoint(intersection.intersection),
|
||||||
dimensions: positionOffset,
|
linePoints: points,
|
||||||
|
dimensions: {
|
||||||
|
x: 1,
|
||||||
|
y: 1,
|
||||||
|
z: 1
|
||||||
|
},
|
||||||
|
lifetime: 15 + props.lifespan // renew lifetime
|
||||||
});
|
});
|
||||||
if (userCanDraw) {
|
|
||||||
draw();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
lineIsRezzed = true;
|
lineIsRezzed = true;
|
||||||
prevPosition = startPosition;
|
|
||||||
lineEntityID = Entities.addEntity({
|
lineEntityID = Entities.addEntity({
|
||||||
type: "Line",
|
type: "Line",
|
||||||
position: nearLinePosition,
|
position: nearLinePoint(intersection.intersection),
|
||||||
dimensions: positionOffset,
|
linePoints: points,
|
||||||
|
dimensions: {
|
||||||
|
x: 1,
|
||||||
|
y: 1,
|
||||||
|
z: 1
|
||||||
|
},
|
||||||
color: {
|
color: {
|
||||||
red: 255,
|
red: 255,
|
||||||
green: 255,
|
green: 255,
|
||||||
blue: 255
|
blue: 255
|
||||||
},
|
},
|
||||||
|
lifetime: 15 // if someone crashes while pointing, don't leave the line there forever.
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} 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
|
function mousePressEvent(event) {
|
||||||
drawDistance = Vec3.distance(startPosition, prevPosition);
|
if (!event.isLeftButton) {
|
||||||
if (drawDistance < DISTANCE_DRAW_THRESHOLD) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var offset = Vec3.subtract(startPosition, prevPosition);
|
createOrUpdateLine(event);
|
||||||
strokes.push(Entities.addEntity({
|
var clickedOverlay = Overlays.getOverlayAtPoint({
|
||||||
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({
|
|
||||||
x: event.x,
|
x: event.x,
|
||||||
y: event.y
|
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) {
|
if (clickedOverlay == pointerButton) {
|
||||||
userCanPoint = !userCanPoint;
|
userCanPoint = !userCanPoint;
|
||||||
if (userCanPoint === true) {
|
if (userCanPoint === true) {
|
||||||
Overlays.editOverlay(pointerButton, {
|
Overlays.editOverlay(pointerButton, {
|
||||||
color: buttonOnColor
|
color: buttonOnColor
|
||||||
});
|
});
|
||||||
if (userCanDraw === true) {
|
|
||||||
|
|
||||||
Overlays.editOverlay(drawButton, {
|
|
||||||
color: buttonOnColor
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Overlays.editOverlay(pointerButton, {
|
Overlays.editOverlay(pointerButton, {
|
||||||
color: buttonOffColor
|
color: buttonOffColor
|
||||||
});
|
});
|
||||||
Overlays.editOverlay(drawButton, {
|
|
||||||
color: buttonOffColor
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!event.isLeftButton || altHeld) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
|
||||||
createOrUpdateLine(event);
|
|
||||||
lineCreated = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function mouseMoveEvent(event) {
|
function mouseMoveEvent(event) {
|
||||||
createOrUpdateLine(event);
|
createOrUpdateLine(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function mouseReleaseEvent(event) {
|
function mouseReleaseEvent(event) {
|
||||||
if (!lineCreated) {
|
if (!event.isLeftButton) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Controller.mouseMoveEvent.disconnect(mouseMoveEvent);
|
|
||||||
removeLine();
|
removeLine();
|
||||||
lineCreated = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function keyPressEvent(event) {
|
|
||||||
if (event.text == "ALT") {
|
|
||||||
altHeld = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function keyReleaseEvent(event) {
|
|
||||||
if (event.text == "ALT") {
|
|
||||||
altHeld = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanup() {
|
function cleanup() {
|
||||||
for (var i = 0; i < strokes.length; i++) {
|
|
||||||
Entities.deleteEntity(strokes[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Overlays.deleteOverlay(drawButton);
|
|
||||||
Overlays.deleteOverlay(pointerButton);
|
Overlays.deleteOverlay(pointerButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Script.scriptEnding.connect(cleanup);
|
Script.scriptEnding.connect(cleanup);
|
||||||
Controller.mousePressEvent.connect(mousePressEvent);
|
|
||||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
|
||||||
|
|
||||||
Controller.keyPressEvent.connect(keyPressEvent);
|
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||||
Controller.keyReleaseEvent.connect(keyReleaseEvent);
|
Controller.mousePressEvent.connect(mousePressEvent);
|
||||||
|
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
|
@ -969,6 +969,7 @@ void Application::paintGL() {
|
||||||
OculusManager::endFrameTiming();
|
OculusManager::endFrameTiming();
|
||||||
}
|
}
|
||||||
_frameCount++;
|
_frameCount++;
|
||||||
|
Stats::getInstance()->setRenderDetails(renderArgs._details);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::runTests() {
|
void Application::runTests() {
|
||||||
|
@ -3095,8 +3096,11 @@ PickRay Application::computePickRay(float x, float y) const {
|
||||||
if (isHMDMode()) {
|
if (isHMDMode()) {
|
||||||
getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
|
getApplicationOverlay().computeHmdPickRay(glm::vec2(x, y), result.origin, result.direction);
|
||||||
} else {
|
} else {
|
||||||
auto frustum = activeRenderingThread ? getDisplayViewFrustum() : getViewFrustum();
|
if (QThread::currentThread() == activeRenderingThread) {
|
||||||
frustum->computePickRay(x, y, result.origin, result.direction);
|
getDisplayViewFrustum()->computePickRay(x, y, result.origin, result.direction);
|
||||||
|
} else {
|
||||||
|
getViewFrustum()->computePickRay(x, y, result.origin, result.direction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -3294,7 +3298,7 @@ namespace render {
|
||||||
skybox = skyStage->getSkybox();
|
skybox = skyStage->getSkybox();
|
||||||
if (skybox) {
|
if (skybox) {
|
||||||
gpu::Batch batch;
|
gpu::Batch batch;
|
||||||
model::Skybox::render(batch, *(args->_viewFrustum), *skybox);
|
model::Skybox::render(batch, *(Application::getInstance()->getDisplayViewFrustum()), *skybox);
|
||||||
|
|
||||||
gpu::GLBackend::renderBatch(batch, true);
|
gpu::GLBackend::renderBatch(batch, true);
|
||||||
glUseProgram(0);
|
glUseProgram(0);
|
||||||
|
@ -3486,7 +3490,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
||||||
_main3DScene->processPendingChangesQueue();
|
_main3DScene->processPendingChangesQueue();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FOr now every frame pass the renderCOntext
|
// For now every frame pass the renderContext
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("EngineRun");
|
PerformanceTimer perfTimer("EngineRun");
|
||||||
render::RenderContext renderContext;
|
render::RenderContext renderContext;
|
||||||
|
@ -3523,7 +3527,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
||||||
|
|
||||||
sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems);
|
sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems);
|
||||||
sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems);
|
sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,6 @@ namespace render {
|
||||||
|
|
||||||
if (avatarPtr->isInitialized() && args) {
|
if (avatarPtr->isInitialized() && args) {
|
||||||
avatarPtr->render(args, Application::getInstance()->getCamera()->getPosition());
|
avatarPtr->render(args, Application::getInstance()->getCamera()->getPosition());
|
||||||
args->_elementsTouched++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <PhysicsHelpers.h>
|
#include <PhysicsHelpers.h>
|
||||||
|
#include <PhysicsCollisionGroups.h>
|
||||||
|
|
||||||
#include "Avatar.h"
|
#include "Avatar.h"
|
||||||
#include "AvatarMotionState.h"
|
#include "AvatarMotionState.h"
|
||||||
|
@ -151,6 +152,11 @@ QUuid AvatarMotionState::getSimulatorID() const {
|
||||||
void AvatarMotionState::bump() {
|
void AvatarMotionState::bump() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// virtual
|
||||||
|
int16_t AvatarMotionState::computeCollisionGroup() {
|
||||||
|
return COLLISION_GROUP_OTHER_AVATAR;
|
||||||
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void AvatarMotionState::clearObjectBackPointer() {
|
void AvatarMotionState::clearObjectBackPointer() {
|
||||||
ObjectMotionState::clearObjectBackPointer();
|
ObjectMotionState::clearObjectBackPointer();
|
||||||
|
|
|
@ -61,6 +61,8 @@ public:
|
||||||
|
|
||||||
void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; }
|
void addDirtyFlags(uint32_t flags) { _dirtyFlags |= flags; }
|
||||||
|
|
||||||
|
virtual int16_t computeCollisionGroup();
|
||||||
|
|
||||||
friend class AvatarManager;
|
friend class AvatarManager;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -39,7 +39,8 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) {
|
||||||
setPupilDilation(_owningHead->getPupilDilation());
|
setPupilDilation(_owningHead->getPupilDilation());
|
||||||
setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients());
|
setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients());
|
||||||
|
|
||||||
invalidCalculatedMeshBoxes();
|
// FIXME - this is very expensive, we shouldn't do it if we don't have to
|
||||||
|
//invalidCalculatedMeshBoxes();
|
||||||
|
|
||||||
if (isActive()) {
|
if (isActive()) {
|
||||||
setOffset(-_geometry->getFBXGeometry().neckPivot);
|
setOffset(-_geometry->getFBXGeometry().neckPivot);
|
||||||
|
|
|
@ -467,31 +467,30 @@ void Stats::display(
|
||||||
horizontalOffset += 5;
|
horizontalOffset += 5;
|
||||||
|
|
||||||
// Model/Entity render details
|
// Model/Entity render details
|
||||||
EntityTreeRenderer* entities = Application::getInstance()->getEntities();
|
|
||||||
octreeStats.str("");
|
octreeStats.str("");
|
||||||
octreeStats << "Entity Items rendered: " << entities->getItemsRendered()
|
octreeStats << "Triangles: " << _renderDetails._trianglesRendered
|
||||||
<< " / Out of view:" << entities->getItemsOutOfView()
|
<< " / Quads:" << _renderDetails._quadsRendered
|
||||||
<< " / Too small:" << entities->getItemsTooSmall();
|
<< " / Material Switches:" << _renderDetails._materialSwitches;
|
||||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||||
|
|
||||||
if (_expanded) {
|
if (_expanded) {
|
||||||
octreeStats.str("");
|
octreeStats.str("");
|
||||||
octreeStats << " Meshes rendered: " << entities->getMeshesRendered()
|
octreeStats << " Mesh Parts Rendered Opaque: " << _renderDetails._opaque._rendered
|
||||||
<< " / Out of view:" << entities->getMeshesOutOfView()
|
<< " / Translucent:" << _renderDetails._translucent._rendered;
|
||||||
<< " / Too small:" << entities->getMeshesTooSmall();
|
|
||||||
verticalOffset += STATS_PELS_PER_LINE;
|
verticalOffset += STATS_PELS_PER_LINE;
|
||||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||||
|
|
||||||
octreeStats.str("");
|
octreeStats.str("");
|
||||||
octreeStats << " Triangles: " << entities->getTrianglesRendered()
|
octreeStats << " Opaque considered: " << _renderDetails._opaque._considered
|
||||||
<< " / Quads:" << entities->getQuadsRendered()
|
<< " / Out of view:" << _renderDetails._opaque._outOfView
|
||||||
<< " / Material Switches:" << entities->getMaterialSwitches();
|
<< " / Too small:" << _renderDetails._opaque._tooSmall;
|
||||||
verticalOffset += STATS_PELS_PER_LINE;
|
verticalOffset += STATS_PELS_PER_LINE;
|
||||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||||
|
|
||||||
octreeStats.str("");
|
octreeStats.str("");
|
||||||
octreeStats << " Mesh Parts Rendered Opaque: " << entities->getOpaqueMeshPartsRendered()
|
octreeStats << " Translucent considered: " << _renderDetails._translucent._considered
|
||||||
<< " / Translucent:" << entities->getTranslucentMeshPartsRendered();
|
<< " / Out of view:" << _renderDetails._translucent._outOfView
|
||||||
|
<< " / Too small:" << _renderDetails._translucent._tooSmall;
|
||||||
verticalOffset += STATS_PELS_PER_LINE;
|
verticalOffset += STATS_PELS_PER_LINE;
|
||||||
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
drawText(horizontalOffset, verticalOffset, scale, rotation, font, (char*)octreeStats.str().c_str(), color);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
#include <NodeList.h>
|
#include <RenderArgs.h>
|
||||||
|
|
||||||
class Stats: public QObject {
|
class Stats: public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -35,6 +35,8 @@ public:
|
||||||
int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess);
|
int inKbitsPerSecond, int outKbitsPerSecond, int voxelPacketsToProcess);
|
||||||
bool includeTimingRecord(const QString& name);
|
bool includeTimingRecord(const QString& name);
|
||||||
|
|
||||||
|
void setRenderDetails(const RenderDetails& details) { _renderDetails = details; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Stats* _sharedInstance;
|
static Stats* _sharedInstance;
|
||||||
|
|
||||||
|
@ -51,6 +53,7 @@ private:
|
||||||
|
|
||||||
int _lastHorizontalOffset;
|
int _lastHorizontalOffset;
|
||||||
|
|
||||||
|
RenderDetails _renderDetails;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Stats_h
|
#endif // hifi_Stats_h
|
||||||
|
|
|
@ -55,8 +55,6 @@ namespace render {
|
||||||
}
|
}
|
||||||
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
|
||||||
if (args) {
|
if (args) {
|
||||||
args->_elementsTouched++;
|
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
if (overlay->getAnchor() == Overlay::MY_AVATAR) {
|
if (overlay->getAnchor() == Overlay::MY_AVATAR) {
|
||||||
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
MyAvatar* avatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
|
|
|
@ -508,24 +508,6 @@ void EntityTreeRenderer::render(RenderArgs* renderArgs) {
|
||||||
applyZonePropertiesToScene(_bestZone);
|
applyZonePropertiesToScene(_bestZone);
|
||||||
|
|
||||||
_tree->unlock();
|
_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
|
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) {
|
void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args) {
|
||||||
args->_elementsTouched++;
|
|
||||||
// actually render it here...
|
// actually render it here...
|
||||||
// we need to iterate the actual entityItems of the element
|
// we need to iterate the actual entityItems of the element
|
||||||
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
|
||||||
|
@ -1019,13 +1000,12 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
||||||
_entityScripts.remove(entityID);
|
_entityScripts.remove(entityID);
|
||||||
|
|
||||||
// here's where we remove the entity payload from the scene
|
// here's where we remove the entity payload from the scene
|
||||||
auto entity = static_cast<EntityTree*>(_tree)->findEntityByID(entityID);
|
if (_entitiesInScene.contains(entityID)) {
|
||||||
if (entity && _entitiesInScene.contains(entity)) {
|
auto entity = _entitiesInScene.take(entityID);
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
auto scene = _viewState->getMain3DScene();
|
auto scene = _viewState->getMain3DScene();
|
||||||
entity->removeFromScene(entity, scene, pendingChanges);
|
entity->removeFromScene(entity, scene, pendingChanges);
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
_entitiesInScene.remove(entity);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1040,7 +1020,7 @@ void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) {
|
||||||
render::PendingChanges pendingChanges;
|
render::PendingChanges pendingChanges;
|
||||||
auto scene = _viewState->getMain3DScene();
|
auto scene = _viewState->getMain3DScene();
|
||||||
if (entity->addToScene(entity, scene, pendingChanges)) {
|
if (entity->addToScene(entity, scene, pendingChanges)) {
|
||||||
_entitiesInScene.insert(entity);
|
_entitiesInScene.insert(entity->getEntityItemID(), entity);
|
||||||
}
|
}
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
}
|
}
|
||||||
|
@ -1100,11 +1080,18 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const float mass = entity->computeMass();
|
const float mass = entity->computeMass();
|
||||||
const float COLLISION_PENTRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity()
|
const float COLLISION_PENETRATION_TO_VELOCITY = 50; // as a subsitute for RELATIVE entity->getVelocity()
|
||||||
const float linearVelocity = glm::length(collision.penetration) * COLLISION_PENTRATION_TO_VELOCITY;
|
// 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 float energy = mass * linearVelocity * linearVelocity / 2.0f;
|
||||||
const glm::vec3 position = collision.contactPoint;
|
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 COLLISION_MINIMUM_VOLUME = 0.005f;
|
||||||
const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME);
|
const float energyFactorOfFull = fmin(1.0f, energy / COLLISION_ENERGY_AT_FULL_VOLUME);
|
||||||
if (energyFactorOfFull < COLLISION_MINIMUM_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_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I);
|
||||||
soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
|
soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0);
|
||||||
const int channelCount = sound->isStereo() ? 2 : 1;
|
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 standardRate = AudioConstants::SAMPLE_RATE;
|
||||||
const int resampledRate = standardRate * factor;
|
const int resampledRate = standardRate * factor;
|
||||||
const int nInputSamples = samples.size() / sizeof(int16_t);
|
const int nInputSamples = samples.size() / sizeof(int16_t);
|
||||||
|
|
|
@ -188,7 +188,7 @@ private:
|
||||||
float _previousStageHour;
|
float _previousStageHour;
|
||||||
int _previousStageDay;
|
int _previousStageDay;
|
||||||
|
|
||||||
QSet<EntityItemPointer> _entitiesInScene;
|
QHash<EntityItemID, EntityItemPointer> _entitiesInScene;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,8 @@ void RenderableDebugableEntityItem::render(EntityItem* entity, RenderArgs* args)
|
||||||
renderBoundingBox(entity, args, 0.3f, yellowColor);
|
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);
|
renderHoverDot(entity, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ namespace render {
|
||||||
}
|
}
|
||||||
template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args) {
|
template <> void payloadRender(const RenderableEntityItemProxy::Pointer& payload, RenderArgs* args) {
|
||||||
if (args) {
|
if (args) {
|
||||||
args->_elementsTouched++;
|
|
||||||
if (payload && payload->entity && payload->entity->getVisible()) {
|
if (payload && payload->entity && payload->entity->getVisible()) {
|
||||||
payload->entity->render(args);
|
payload->entity->render(args);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,9 @@ void RenderableLineEntityItem::render(RenderArgs* args) {
|
||||||
batch.setModelTransform(Transform());
|
batch.setModelTransform(Transform());
|
||||||
|
|
||||||
batch._glLineWidth(getLineWidth());
|
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);
|
batch._glLineWidth(1.0f);
|
||||||
|
|
||||||
RenderableDebugableEntityItem::render(this, args);
|
RenderableDebugableEntityItem::render(this, args);
|
||||||
|
|
|
@ -160,7 +160,6 @@ namespace render {
|
||||||
}
|
}
|
||||||
template <> void payloadRender(const RenderableModelEntityItemMeta::Pointer& payload, RenderArgs* args) {
|
template <> void payloadRender(const RenderableModelEntityItemMeta::Pointer& payload, RenderArgs* args) {
|
||||||
if (args) {
|
if (args) {
|
||||||
args->_elementsTouched++;
|
|
||||||
if (payload && payload->entity) {
|
if (payload && payload->entity) {
|
||||||
payload->entity->render(args);
|
payload->entity->render(args);
|
||||||
}
|
}
|
||||||
|
@ -212,6 +211,11 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
|
|
||||||
if (hasModel()) {
|
if (hasModel()) {
|
||||||
if (_model) {
|
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
|
// 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
|
// fix them up in the scene
|
||||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||||
|
|
|
@ -380,14 +380,16 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||||
getModel();
|
getModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform transformToCenter = getTransformToCenter();
|
Transform transform;
|
||||||
transformToCenter.setScale(getDimensions() / _voxelVolumeSize);
|
transform.setTranslation(getPosition() - getRegistrationPoint() * getDimensions());
|
||||||
|
transform.setRotation(getRotation());
|
||||||
|
transform.setScale(getDimensions() / _voxelVolumeSize);
|
||||||
|
|
||||||
auto mesh = _modelGeometry.getMesh();
|
auto mesh = _modelGeometry.getMesh();
|
||||||
Q_ASSERT(args->_batch);
|
Q_ASSERT(args->_batch);
|
||||||
gpu::Batch& batch = *args->_batch;
|
gpu::Batch& batch = *args->_batch;
|
||||||
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
|
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch);
|
||||||
batch.setModelTransform(transformToCenter);
|
batch.setModelTransform(transform);
|
||||||
batch.setInputFormat(mesh->getVertexFormat());
|
batch.setInputFormat(mesh->getVertexFormat());
|
||||||
batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer());
|
batch.setInputBuffer(gpu::Stream::POSITION, mesh->getVertexBuffer());
|
||||||
batch.setInputBuffer(gpu::Stream::NORMAL,
|
batch.setInputBuffer(gpu::Stream::NORMAL,
|
||||||
|
|
|
@ -8,10 +8,13 @@
|
||||||
|
|
||||||
#include "RenderableWebEntityItem.h"
|
#include "RenderableWebEntityItem.h"
|
||||||
|
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
#include <glm/gtx/quaternion.hpp>
|
#include <glm/gtx/quaternion.hpp>
|
||||||
|
|
||||||
#include <gpu/GPUConfig.h>
|
#include <gpu/GPUConfig.h>
|
||||||
|
|
||||||
|
#include <GlowEffect.h>
|
||||||
#include <DeferredLightingEffect.h>
|
#include <DeferredLightingEffect.h>
|
||||||
#include <GeometryCache.h>
|
#include <GeometryCache.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
@ -64,7 +67,6 @@ RenderableWebEntityItem::~RenderableWebEntityItem() {
|
||||||
void RenderableWebEntityItem::render(RenderArgs* args) {
|
void RenderableWebEntityItem::render(RenderArgs* args) {
|
||||||
QOpenGLContext * currentContext = QOpenGLContext::currentContext();
|
QOpenGLContext * currentContext = QOpenGLContext::currentContext();
|
||||||
QSurface * currentSurface = currentContext->surface();
|
QSurface * currentSurface = currentContext->surface();
|
||||||
|
|
||||||
if (!_webSurface) {
|
if (!_webSurface) {
|
||||||
_webSurface = new OffscreenQmlSurface();
|
_webSurface = new OffscreenQmlSurface();
|
||||||
_webSurface->create(currentContext);
|
_webSurface->create(currentContext);
|
||||||
|
@ -98,16 +100,35 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
||||||
return;
|
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 (intersection.entityID == getID()) {
|
||||||
if (event->button() == Qt::MouseButton::RightButton) {
|
if (event->button() == Qt::MouseButton::RightButton) {
|
||||||
if (event->type() == QEvent::MouseButtonRelease) {
|
if (event->type() == QEvent::MouseButtonRelease) {
|
||||||
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
|
const QMouseEvent* mouseEvent = static_cast<const QMouseEvent*>(event);
|
||||||
QMetaObject::invokeMethod(_webSurface->getRootItem(), "goBack");
|
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;
|
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->button() == Qt::MouseButton::MiddleButton) {
|
||||||
if (event->type() == QEvent::MouseButtonRelease) {
|
if (event->type() == QEvent::MouseButtonRelease) {
|
||||||
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
|
AbstractViewStateInterface::instance()->postLambdaEvent([this] {
|
||||||
|
@ -133,6 +154,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
||||||
QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
|
QCoreApplication::sendEvent(_webSurface->getWindow(), &mappedEvent);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
|
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(args->_renderer);
|
||||||
QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardMouseEvent);
|
QObject::connect(renderer, &EntityTreeRenderer::mousePressOnEntity, forwardMouseEvent);
|
||||||
QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardMouseEvent);
|
QObject::connect(renderer, &EntityTreeRenderer::mouseReleaseOnEntity, forwardMouseEvent);
|
||||||
|
@ -147,6 +169,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
||||||
_webSurface->resize(QSize(dims.x, dims.y));
|
_webSurface->resize(QSize(dims.x, dims.y));
|
||||||
currentContext->makeCurrent(currentSurface);
|
currentContext->makeCurrent(currentSurface);
|
||||||
|
|
||||||
|
Glower glow(0.0f);
|
||||||
PerformanceTimer perfTimer("RenderableWebEntityItem::render");
|
PerformanceTimer perfTimer("RenderableWebEntityItem::render");
|
||||||
Q_ASSERT(getType() == EntityTypes::Web);
|
Q_ASSERT(getType() == EntityTypes::Web);
|
||||||
static const glm::vec2 texMin(0.0f);
|
static const glm::vec2 texMin(0.0f);
|
||||||
|
@ -168,6 +191,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderableWebEntityItem::setSourceUrl(const QString& value) {
|
void RenderableWebEntityItem::setSourceUrl(const QString& value) {
|
||||||
|
qDebug() << "Setting web entity source URL to " << value;
|
||||||
if (_sourceUrl != value) {
|
if (_sourceUrl != value) {
|
||||||
_sourceUrl = value;
|
_sourceUrl = value;
|
||||||
if (_webSurface) {
|
if (_webSurface) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ private:
|
||||||
OffscreenQmlSurface* _webSurface{ nullptr };
|
OffscreenQmlSurface* _webSurface{ nullptr };
|
||||||
QMetaObject::Connection _connection;
|
QMetaObject::Connection _connection;
|
||||||
uint32_t _texture{ 0 };
|
uint32_t _texture{ 0 };
|
||||||
|
ivec2 _lastPress{ INT_MIN };
|
||||||
QMutex _textureLock;
|
QMutex _textureLock;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -82,7 +82,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemPropert
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityItem::~EntityItem() {
|
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.
|
// to this EntityItem in the corresponding data structure.
|
||||||
assert(!_simulated);
|
assert(!_simulated);
|
||||||
assert(!_element);
|
assert(!_element);
|
||||||
|
@ -517,12 +517,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
|
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
|
||||||
dataAt += propertyFlags.getEncodedLength();
|
dataAt += propertyFlags.getEncodedLength();
|
||||||
bytesRead += propertyFlags.getEncodedLength();
|
bytesRead += propertyFlags.getEncodedLength();
|
||||||
bool useMeters = (args.bitstreamVersion >= VERSION_ENTITIES_USE_METERS_AND_RADIANS);
|
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
|
||||||
if (useMeters) {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePosition);
|
|
||||||
} else {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, updatePositionInDomainUnits);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS
|
// Old bitstreams had PROP_RADIUS, new bitstreams have PROP_DIMENSIONS
|
||||||
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) {
|
if (args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_DIMENSIONS) {
|
||||||
|
@ -536,22 +531,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (useMeters) {
|
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
|
||||||
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions);
|
|
||||||
} else {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensionsInDomainUnits);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
|
READ_ENTITY_PROPERTY(PROP_ROTATION, glm::quat, updateRotation);
|
||||||
READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity);
|
READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity);
|
||||||
if (useMeters) {
|
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
|
||||||
READ_ENTITY_PROPERTY(PROP_VELOCITY, glm::vec3, updateVelocity);
|
READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity);
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
|
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_ACCELERATION) {
|
||||||
READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, setAcceleration);
|
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_LIFETIME, float, updateLifetime);
|
||||||
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
|
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
|
||||||
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
|
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
|
||||||
if (useMeters) {
|
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
|
||||||
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocity);
|
//READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees);
|
||||||
} else {
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ANGULAR_VELOCITY, glm::vec3, updateAngularVelocityInDegrees);
|
|
||||||
}
|
|
||||||
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping);
|
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping);
|
||||||
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
|
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
|
||||||
READ_ENTITY_PROPERTY(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions);
|
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 EntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
bool somethingChanged = false;
|
bool somethingChanged = false;
|
||||||
|
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePosition); // this will call recalculate collision shape if needed
|
// these affect TerseUpdate properties
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensions); // NOTE: radius is obsolete
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePosition);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation);
|
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(velocity, updateVelocity);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravity);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, updateAngularVelocity);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(acceleration, setAcceleration);
|
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(damping, updateDamping);
|
||||||
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, updateAngularDamping);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, updateRestitution);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, updateRestitution);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction);
|
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(created, updateCreated);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime);
|
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(script, setScript);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionSoundURL, setCollisionSoundURL);
|
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(glowLevel, setGlowLevel);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(localRenderAlpha, setLocalRenderAlpha);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(visible, setVisible);
|
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(locked, setLocked);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData);
|
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(marketplaceID, setMarketplaceID);
|
||||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName);
|
SET_ENTITY_PROPERTY_FROM_PROPERTIES(name, setName);
|
||||||
|
|
||||||
|
@ -1155,11 +1145,6 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
info.setParams(getShapeType(), 0.5f * getDimensions());
|
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) {
|
void EntityItem::updatePosition(const glm::vec3& value) {
|
||||||
auto delta = glm::distance(getPosition(), value);
|
auto delta = glm::distance(getPosition(), value);
|
||||||
if (delta > IGNORE_POSITION_DELTA) {
|
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) {
|
void EntityItem::updateDimensions(const glm::vec3& value) {
|
||||||
auto delta = glm::distance(getDimensions(), value);
|
auto delta = glm::distance(getDimensions(), value);
|
||||||
if (delta > IGNORE_DIMENSIONS_DELTA) {
|
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) {
|
void EntityItem::updateVelocity(const glm::vec3& value) {
|
||||||
auto delta = glm::distance(_velocity, value);
|
auto delta = glm::distance(_velocity, value);
|
||||||
if (delta > IGNORE_LINEAR_VELOCITY_DELTA) {
|
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) {
|
void EntityItem::updateGravity(const glm::vec3& value) {
|
||||||
auto delta = glm::distance(_gravity, value);
|
auto delta = glm::distance(_gravity, value);
|
||||||
if (delta > IGNORE_GRAVITY_DELTA) {
|
if (delta > IGNORE_GRAVITY_DELTA) {
|
||||||
|
|
|
@ -325,22 +325,17 @@ public:
|
||||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; }
|
virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; }
|
||||||
|
|
||||||
// updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags
|
// 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 updatePosition(const glm::vec3& value);
|
||||||
void updateDimensionsInDomainUnits(const glm::vec3& value);
|
|
||||||
void updateDimensions(const glm::vec3& value);
|
void updateDimensions(const glm::vec3& value);
|
||||||
void updateRotation(const glm::quat& rotation);
|
void updateRotation(const glm::quat& rotation);
|
||||||
void updateDensity(float value);
|
void updateDensity(float value);
|
||||||
void updateMass(float value);
|
void updateMass(float value);
|
||||||
void updateVelocityInDomainUnits(const glm::vec3& value);
|
|
||||||
void updateVelocity(const glm::vec3& value);
|
void updateVelocity(const glm::vec3& value);
|
||||||
void updateDamping(float value);
|
void updateDamping(float value);
|
||||||
void updateRestitution(float value);
|
void updateRestitution(float value);
|
||||||
void updateFriction(float value);
|
void updateFriction(float value);
|
||||||
void updateGravityInDomainUnits(const glm::vec3& value);
|
|
||||||
void updateGravity(const glm::vec3& value);
|
void updateGravity(const glm::vec3& value);
|
||||||
void updateAngularVelocity(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 updateAngularDamping(float value);
|
||||||
void updateIgnoreForCollisions(bool value);
|
void updateIgnoreForCollisions(bool value);
|
||||||
void updateCollisionsWillMove(bool value);
|
void updateCollisionsWillMove(bool value);
|
||||||
|
|
|
@ -128,37 +128,45 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& properties) {
|
QUuid EntityScriptingInterface::editEntity(QUuid id, EntityItemProperties properties) {
|
||||||
EntityItemID entityID(id);
|
EntityItemID entityID(id);
|
||||||
// If we have a local entity tree set, then also update it.
|
// If we have a local entity tree set, then also update it.
|
||||||
if (_entityTree) {
|
if (_entityTree) {
|
||||||
_entityTree->lockForWrite();
|
_entityTree->lockForWrite();
|
||||||
_entityTree->updateEntity(entityID, properties);
|
bool updatedEntity = _entityTree->updateEntity(entityID, properties);
|
||||||
_entityTree->unlock();
|
_entityTree->unlock();
|
||||||
}
|
|
||||||
|
|
||||||
// make sure the properties has a type, so that the encode can know which properties to include
|
if (updatedEntity) {
|
||||||
if (properties.getType() == EntityTypes::Unknown) {
|
_entityTree->lockForRead();
|
||||||
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID);
|
||||||
if (entity) {
|
if (entity) {
|
||||||
// we need to change the outgoing properties, so we make a copy, modify, and send.
|
// make sure the properties has a type, so that the encode can know which properties to include
|
||||||
EntityItemProperties modifiedProperties = properties;
|
properties.setType(entity->getType());
|
||||||
entity->setLastBroadcast(usecTimestampNow());
|
if (properties.hasTerseUpdateChanges()) {
|
||||||
modifiedProperties.setType(entity->getType());
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
if (modifiedProperties.hasTerseUpdateChanges()) {
|
const QUuid myNodeID = nodeList->getSessionUUID();
|
||||||
// we make a bid for (or assert) our simulation ownership
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
if (entity->getSimulatorID() == myNodeID) {
|
||||||
const QUuid myNodeID = nodeList->getSessionUUID();
|
// we think we already own the simulation, so make sure to send ALL TerseUpdate properties
|
||||||
modifiedProperties.setSimulatorID(myNodeID);
|
entity->getAllTerseUpdateProperties(properties);
|
||||||
|
// TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object
|
||||||
if (entity->getSimulatorID() == myNodeID) {
|
// is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update
|
||||||
// we think we already own simulation, so make sure we send ALL TerseUpdate properties
|
// and instead let the physics simulation decide when to send a terse update. This would remove
|
||||||
entity->getAllTerseUpdateProperties(modifiedProperties);
|
// 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 id;
|
||||||
}
|
}
|
||||||
|
return QUuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
queueEntityMessage(PacketTypeEntityEdit, entityID, properties);
|
queueEntityMessage(PacketTypeEntityEdit, entityID, properties);
|
||||||
|
|
|
@ -79,7 +79,7 @@ public slots:
|
||||||
|
|
||||||
/// edits a model updating only the included properties, will return the identified EntityItemID in case of
|
/// 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
|
/// 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
|
/// deletes a model
|
||||||
Q_INVOKABLE void deleteEntity(QUuid entityID);
|
Q_INVOKABLE void deleteEntity(QUuid entityID);
|
||||||
|
|
|
@ -681,7 +681,6 @@ void EntityTree::update() {
|
||||||
QSet<EntityItemID> idsToDelete;
|
QSet<EntityItemID> idsToDelete;
|
||||||
|
|
||||||
for (auto entity : pendingDeletes) {
|
for (auto entity : pendingDeletes) {
|
||||||
assert(!entity->getPhysicsInfo()); // TODO: Andrew to remove this after testing
|
|
||||||
idsToDelete.insert(entity->getEntityItemID());
|
idsToDelete.insert(entity->getEntityItemID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ public:
|
||||||
virtual bool getWantSVOfileVersions() const { return true; }
|
virtual bool getWantSVOfileVersions() const { return true; }
|
||||||
virtual PacketType expectedDataPacketType() const { return PacketTypeEntityData; }
|
virtual PacketType expectedDataPacketType() const { return PacketTypeEntityData; }
|
||||||
virtual bool canProcessVersion(PacketVersion thisVersion) const
|
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 bool handlesEditPacketType(PacketType packetType) const;
|
||||||
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
virtual int processEditPacketData(PacketType packetType, const unsigned char* packetData, int packetLength,
|
||||||
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode);
|
const unsigned char* editData, int maxLength, const SharedNodePointer& senderNode);
|
||||||
|
|
|
@ -85,7 +85,18 @@ bool LineEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
|
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;
|
_pointsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,9 +109,10 @@ TransformCamera getTransformCamera() {
|
||||||
//return camera._projection * camera._view * object._model * pos; !>
|
//return camera._projection * camera._view * object._model * pos; !>
|
||||||
{ // transformModelToClipPos
|
{ // transformModelToClipPos
|
||||||
vec4 _worldpos = (<$objectTransform$>._model * <$modelPos$>);
|
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);
|
vec4 _eyepos =(<$objectTransform$>._model * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0);
|
||||||
<$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos;
|
<$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos;
|
||||||
|
<$eyePos$> = (<$cameraTransform$>._projectionInverse * <$clipPos$>);
|
||||||
}
|
}
|
||||||
<@else@>
|
<@else@>
|
||||||
<$eyePos$> = gl_ModelViewMatrix * <$modelPos$>;
|
<$eyePos$> = gl_ModelViewMatrix * <$modelPos$>;
|
||||||
|
|
|
@ -171,23 +171,6 @@ void OctreeRenderer::render(RenderArgs* renderArgs) {
|
||||||
_tree->recurseTreeWithOperation(renderOperation, renderArgs);
|
_tree->recurseTreeWithOperation(renderOperation, renderArgs);
|
||||||
_tree->unlock();
|
_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() {
|
void OctreeRenderer::clear() {
|
||||||
|
|
|
@ -60,23 +60,6 @@ public:
|
||||||
|
|
||||||
/// clears the tree
|
/// clears the tree
|
||||||
virtual void clear();
|
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:
|
protected:
|
||||||
virtual Octree* createTree() = 0;
|
virtual Octree* createTree() = 0;
|
||||||
|
@ -84,23 +67,6 @@ protected:
|
||||||
Octree* _tree;
|
Octree* _tree;
|
||||||
bool _managedTree;
|
bool _managedTree;
|
||||||
ViewFrustum* _viewFrustum;
|
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
|
#endif // hifi_OctreeRenderer_h
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
#include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
|
||||||
#include <LinearMath/btDefaultMotionState.h>
|
#include <LinearMath/btDefaultMotionState.h>
|
||||||
|
|
||||||
|
#include <PhysicsCollisionGroups.h>
|
||||||
|
|
||||||
#include "BulletUtil.h"
|
#include "BulletUtil.h"
|
||||||
#include "DynamicCharacterController.h"
|
#include "DynamicCharacterController.h"
|
||||||
|
|
||||||
|
@ -267,7 +269,7 @@ void DynamicCharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
||||||
if (world && _rigidBody) {
|
if (world && _rigidBody) {
|
||||||
_dynamicsWorld = world;
|
_dynamicsWorld = world;
|
||||||
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
||||||
_dynamicsWorld->addRigidBody(_rigidBody);
|
_dynamicsWorld->addRigidBody(_rigidBody, COLLISION_GROUP_MY_AVATAR, COLLISION_MASK_MY_AVATAR);
|
||||||
_dynamicsWorld->addAction(this);
|
_dynamicsWorld->addAction(this);
|
||||||
//reset(_dynamicsWorld);
|
//reset(_dynamicsWorld);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <EntityItem.h>
|
#include <EntityItem.h>
|
||||||
#include <EntityEditPacketSender.h>
|
#include <EntityEditPacketSender.h>
|
||||||
|
#include <PhysicsCollisionGroups.h>
|
||||||
|
|
||||||
#include "BulletUtil.h"
|
#include "BulletUtil.h"
|
||||||
#include "EntityMotionState.h"
|
#include "EntityMotionState.h"
|
||||||
|
@ -49,24 +50,17 @@ EntityMotionState::~EntityMotionState() {
|
||||||
assert(!_entity);
|
assert(!_entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityMotionState::updateServerPhysicsVariables(uint32_t flags) {
|
void EntityMotionState::updateServerPhysicsVariables() {
|
||||||
if (flags & EntityItem::DIRTY_POSITION) {
|
_serverPosition = _entity->getPosition();
|
||||||
_serverPosition = _entity->getPosition();
|
_serverRotation = _entity->getRotation();
|
||||||
}
|
_serverVelocity = _entity->getVelocity();
|
||||||
if (flags & EntityItem::DIRTY_ROTATION) {
|
_serverAngularVelocity = _entity->getAngularVelocity();
|
||||||
_serverRotation = _entity->getRotation();
|
_serverAcceleration = _entity->getAcceleration();
|
||||||
}
|
|
||||||
if (flags & EntityItem::DIRTY_LINEAR_VELOCITY) {
|
|
||||||
_serverVelocity = _entity->getVelocity();
|
|
||||||
}
|
|
||||||
if (flags & EntityItem::DIRTY_ANGULAR_VELOCITY) {
|
|
||||||
_serverAngularVelocity = _entity->getAngularVelocity();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void EntityMotionState::handleEasyChanges(uint32_t flags) {
|
void EntityMotionState::handleEasyChanges(uint32_t flags) {
|
||||||
updateServerPhysicsVariables(flags);
|
updateServerPhysicsVariables();
|
||||||
ObjectMotionState::handleEasyChanges(flags);
|
ObjectMotionState::handleEasyChanges(flags);
|
||||||
if (flags & EntityItem::DIRTY_SIMULATOR_ID) {
|
if (flags & EntityItem::DIRTY_SIMULATOR_ID) {
|
||||||
_loopsWithoutOwner = 0;
|
_loopsWithoutOwner = 0;
|
||||||
|
@ -94,7 +88,7 @@ void EntityMotionState::handleEasyChanges(uint32_t flags) {
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void EntityMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) {
|
void EntityMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) {
|
||||||
updateServerPhysicsVariables(flags);
|
updateServerPhysicsVariables();
|
||||||
ObjectMotionState::handleHardAndEasyChanges(flags, engine);
|
ObjectMotionState::handleHardAndEasyChanges(flags, engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,6 +488,7 @@ void EntityMotionState::measureBodyAcceleration() {
|
||||||
float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP);
|
float dt = ((float)numSubsteps * PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||||
float invDt = 1.0f / dt;
|
float invDt = 1.0f / dt;
|
||||||
_lastMeasureStep = thisStep;
|
_lastMeasureStep = thisStep;
|
||||||
|
_measuredDeltaTime = dt;
|
||||||
|
|
||||||
// Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^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
|
// hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt
|
||||||
|
@ -502,6 +497,12 @@ void EntityMotionState::measureBodyAcceleration() {
|
||||||
_lastVelocity = velocity;
|
_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
|
// virtual
|
||||||
void EntityMotionState::setMotionType(MotionType motionType) {
|
void EntityMotionState::setMotionType(MotionType motionType) {
|
||||||
|
@ -517,3 +518,16 @@ QString EntityMotionState::getName() {
|
||||||
}
|
}
|
||||||
return "";
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
EntityMotionState(btCollisionShape* shape, EntityItemPointer item);
|
EntityMotionState(btCollisionShape* shape, EntityItemPointer item);
|
||||||
virtual ~EntityMotionState();
|
virtual ~EntityMotionState();
|
||||||
|
|
||||||
void updateServerPhysicsVariables(uint32_t flags);
|
void updateServerPhysicsVariables();
|
||||||
virtual void handleEasyChanges(uint32_t flags);
|
virtual void handleEasyChanges(uint32_t flags);
|
||||||
virtual void handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine);
|
virtual void handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine);
|
||||||
|
|
||||||
|
@ -64,6 +64,7 @@ public:
|
||||||
virtual glm::vec3 getObjectLinearVelocity() const { return _entity->getVelocity(); }
|
virtual glm::vec3 getObjectLinearVelocity() const { return _entity->getVelocity(); }
|
||||||
virtual glm::vec3 getObjectAngularVelocity() const { return _entity->getAngularVelocity(); }
|
virtual glm::vec3 getObjectAngularVelocity() const { return _entity->getAngularVelocity(); }
|
||||||
virtual glm::vec3 getObjectGravity() const { return _entity->getGravity(); }
|
virtual glm::vec3 getObjectGravity() const { return _entity->getGravity(); }
|
||||||
|
virtual glm::vec3 getObjectLinearVelocityChange() const;
|
||||||
|
|
||||||
virtual const QUuid& getObjectID() const { return _entity->getID(); }
|
virtual const QUuid& getObjectID() const { return _entity->getID(); }
|
||||||
|
|
||||||
|
@ -77,6 +78,8 @@ public:
|
||||||
|
|
||||||
virtual QString getName();
|
virtual QString getName();
|
||||||
|
|
||||||
|
virtual int16_t computeCollisionGroup();
|
||||||
|
|
||||||
friend class PhysicalEntitySimulation;
|
friend class PhysicalEntitySimulation;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -101,6 +104,7 @@ protected:
|
||||||
uint32_t _lastMeasureStep;
|
uint32_t _lastMeasureStep;
|
||||||
glm::vec3 _lastVelocity;
|
glm::vec3 _lastVelocity;
|
||||||
glm::vec3 _measuredAcceleration;
|
glm::vec3 _measuredAcceleration;
|
||||||
|
float _measuredDeltaTime;
|
||||||
|
|
||||||
quint8 _accelerationNearlyGravityCount;
|
quint8 _accelerationNearlyGravityCount;
|
||||||
bool _candidateForOwnership;
|
bool _candidateForOwnership;
|
||||||
|
|
|
@ -82,6 +82,9 @@ void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const {
|
||||||
glm::vec3 ObjectMotionState::getBodyLinearVelocity() const {
|
glm::vec3 ObjectMotionState::getBodyLinearVelocity() const {
|
||||||
return bulletToGLM(_body->getLinearVelocity());
|
return bulletToGLM(_body->getLinearVelocity());
|
||||||
}
|
}
|
||||||
|
glm::vec3 ObjectMotionState::getObjectLinearVelocityChange() const {
|
||||||
|
return glm::vec3(0.0f); // Subclasses override where meaningful.
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec3 ObjectMotionState::getBodyAngularVelocity() const {
|
glm::vec3 ObjectMotionState::getBodyAngularVelocity() const {
|
||||||
return bulletToGLM(_body->getAngularVelocity());
|
return bulletToGLM(_body->getAngularVelocity());
|
||||||
|
@ -200,3 +203,4 @@ void ObjectMotionState::updateBodyMassProperties() {
|
||||||
_body->setMassProps(mass, inertia);
|
_body->setMassProps(mass, inertia);
|
||||||
_body->updateInertiaTensor();
|
_body->updateInertiaTensor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,11 +39,12 @@ enum MotionStateType {
|
||||||
// and re-added to the physics engine and "easy" which just updates the body properties.
|
// 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 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 |
|
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:
|
// 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 |
|
const uint32_t DIRTY_PHYSICS_FLAGS = (uint32_t)(HARD_DIRTY_PHYSICS_FLAGS | EASY_DIRTY_PHYSICS_FLAGS |
|
||||||
EntityItem::DIRTY_MATERIAL | (uint32_t)EntityItem::DIRTY_PHYSICS_ACTIVATION;
|
EntityItem::DIRTY_PHYSICS_ACTIVATION);
|
||||||
|
|
||||||
// These are the outgoing flags that the PhysicsEngine can affect:
|
// These are the outgoing flags that the PhysicsEngine can affect:
|
||||||
const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES;
|
const uint32_t OUTGOING_DIRTY_PHYSICS_FLAGS = EntityItem::DIRTY_TRANSFORM | EntityItem::DIRTY_VELOCITIES;
|
||||||
|
@ -90,6 +91,7 @@ public:
|
||||||
|
|
||||||
glm::vec3 getBodyLinearVelocity() const;
|
glm::vec3 getBodyLinearVelocity() const;
|
||||||
glm::vec3 getBodyAngularVelocity() const;
|
glm::vec3 getBodyAngularVelocity() const;
|
||||||
|
virtual glm::vec3 getObjectLinearVelocityChange() const;
|
||||||
|
|
||||||
virtual uint32_t getAndClearIncomingDirtyFlags() = 0;
|
virtual uint32_t getAndClearIncomingDirtyFlags() = 0;
|
||||||
|
|
||||||
|
@ -123,6 +125,10 @@ public:
|
||||||
|
|
||||||
virtual QString getName() { return ""; }
|
virtual QString getName() { return ""; }
|
||||||
|
|
||||||
|
virtual int16_t computeCollisionGroup() = 0;
|
||||||
|
|
||||||
|
bool isActive() const { return _body ? _body->isActive() : false; }
|
||||||
|
|
||||||
friend class PhysicsEngine;
|
friend class PhysicsEngine;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -36,7 +36,7 @@ void PhysicalEntitySimulation::init(
|
||||||
|
|
||||||
// begin EntitySimulation overrides
|
// begin EntitySimulation overrides
|
||||||
void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) {
|
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) {
|
void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <PhysicsCollisionGroups.h>
|
||||||
|
|
||||||
#include "ObjectMotionState.h"
|
#include "ObjectMotionState.h"
|
||||||
#include "PhysicsEngine.h"
|
#include "PhysicsEngine.h"
|
||||||
#include "PhysicsHelpers.h"
|
#include "PhysicsHelpers.h"
|
||||||
|
@ -23,15 +25,25 @@ uint32_t PhysicsEngine::getNumSubsteps() {
|
||||||
}
|
}
|
||||||
|
|
||||||
PhysicsEngine::PhysicsEngine(const glm::vec3& offset) :
|
PhysicsEngine::PhysicsEngine(const glm::vec3& offset) :
|
||||||
_originOffset(offset),
|
_originOffset(offset),
|
||||||
_characterController(nullptr) {
|
_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() {
|
PhysicsEngine::~PhysicsEngine() {
|
||||||
if (_characterController) {
|
if (_characterController) {
|
||||||
_characterController->setDynamicsWorld(nullptr);
|
_characterController->setDynamicsWorld(nullptr);
|
||||||
}
|
}
|
||||||
// TODO: delete engine components... if we ever plan to create more than one instance
|
|
||||||
delete _collisionConfig;
|
delete _collisionConfig;
|
||||||
delete _collisionDispatcher;
|
delete _collisionDispatcher;
|
||||||
delete _broadphaseFilter;
|
delete _broadphaseFilter;
|
||||||
|
@ -125,7 +137,8 @@ void PhysicsEngine::addObject(ObjectMotionState* motionState) {
|
||||||
body->setFlags(BT_DISABLE_WORLD_GRAVITY);
|
body->setFlags(BT_DISABLE_WORLD_GRAVITY);
|
||||||
motionState->updateBodyMaterialProperties();
|
motionState->updateBodyMaterialProperties();
|
||||||
|
|
||||||
_dynamicsWorld->addRigidBody(body);
|
int16_t group = motionState->computeCollisionGroup();
|
||||||
|
_dynamicsWorld->addRigidBody(body, group, getCollisionMask(group));
|
||||||
|
|
||||||
motionState->getAndClearIncomingDirtyFlags();
|
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) {
|
void PhysicsEngine::deleteObjects(SetOfMotionStates& objects) {
|
||||||
for (auto object : objects) {
|
for (auto object : objects) {
|
||||||
btRigidBody* body = object->getRigidBody();
|
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.
|
// NOTE: setRigidBody() modifies body->m_userPointer so we should clear the MotionState's body BEFORE deleting it.
|
||||||
object->setRigidBody(nullptr);
|
object->setRigidBody(nullptr);
|
||||||
|
@ -317,6 +330,8 @@ CollisionEvents& PhysicsEngine::getCollisionEvents() {
|
||||||
if(type != CONTACT_EVENT_TYPE_CONTINUE || _numSubsteps % CONTINUE_EVENT_FILTER_FREQUENCY == 0) {
|
if(type != CONTACT_EVENT_TYPE_CONTINUE || _numSubsteps % CONTINUE_EVENT_FILTER_FREQUENCY == 0) {
|
||||||
ObjectMotionState* A = static_cast<ObjectMotionState*>(contactItr->first._a);
|
ObjectMotionState* A = static_cast<ObjectMotionState*>(contactItr->first._a);
|
||||||
ObjectMotionState* B = static_cast<ObjectMotionState*>(contactItr->first._b);
|
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) {
|
if (A && A->getType() == MOTIONSTATE_TYPE_ENTITY) {
|
||||||
QUuid idA = A->getObjectID();
|
QUuid idA = A->getObjectID();
|
||||||
|
@ -326,14 +341,14 @@ CollisionEvents& PhysicsEngine::getCollisionEvents() {
|
||||||
}
|
}
|
||||||
glm::vec3 position = bulletToGLM(contact.getPositionWorldOnB()) + _originOffset;
|
glm::vec3 position = bulletToGLM(contact.getPositionWorldOnB()) + _originOffset;
|
||||||
glm::vec3 penetration = bulletToGLM(contact.distance * contact.normalWorldOnB);
|
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) {
|
} else if (B && B->getType() == MOTIONSTATE_TYPE_ENTITY) {
|
||||||
QUuid idB = B->getObjectID();
|
QUuid idB = B->getObjectID();
|
||||||
glm::vec3 position = bulletToGLM(contact.getPositionWorldOnA()) + _originOffset;
|
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)
|
// NOTE: we're flipping the order of A and B (so that the first objectID is never NULL)
|
||||||
// hence we must negate the penetration.
|
// hence we must negate the penetration.
|
||||||
glm::vec3 penetration = - bulletToGLM(contact.distance * contact.normalWorldOnB);
|
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) {
|
int16_t PhysicsEngine::getCollisionMask(int16_t group) const {
|
||||||
if (!physicsInfo) {
|
const int16_t* mask = _collisionMasks.find(btHashInt((int)group));
|
||||||
return false;
|
return mask ? *mask : COLLISION_MASK_DEFAULT;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,8 +91,7 @@ public:
|
||||||
|
|
||||||
void dumpNextStats() { _dumpNextStats = true; }
|
void dumpNextStats() { _dumpNextStats = true; }
|
||||||
|
|
||||||
static bool physicsInfoIsActive(void* physicsInfo);
|
int16_t getCollisionMask(int16_t group) const;
|
||||||
static bool getBodyLocation(void* physicsInfo, glm::vec3& positionReturn, glm::quat& rotationReturn);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void removeContacts(ObjectMotionState* motionState);
|
void removeContacts(ObjectMotionState* motionState);
|
||||||
|
@ -121,6 +120,7 @@ private:
|
||||||
|
|
||||||
QUuid _sessionID;
|
QUuid _sessionID;
|
||||||
CollisionEvents _collisionEvents;
|
CollisionEvents _collisionEvents;
|
||||||
|
btHashMap<btHashInt, int16_t> _collisionMasks;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_PhysicsEngine_h
|
#endif // hifi_PhysicsEngine_h
|
||||||
|
|
|
@ -19,11 +19,8 @@
|
||||||
|
|
||||||
// translates between ShapeInfo and btShape
|
// translates between ShapeInfo and btShape
|
||||||
|
|
||||||
// TODO: rename this to ShapeFactory
|
|
||||||
namespace ShapeFactory {
|
namespace ShapeFactory {
|
||||||
|
|
||||||
btConvexHullShape* createConvexHull(const QVector<glm::vec3>& points);
|
btConvexHullShape* createConvexHull(const QVector<glm::vec3>& points);
|
||||||
|
|
||||||
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
|
btCollisionShape* createShapeFromInfo(const ShapeInfo& info);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,8 @@ Model::Model(QObject* parent) :
|
||||||
if (_viewState) {
|
if (_viewState) {
|
||||||
moveToThread(_viewState->getMainThread());
|
moveToThread(_viewState->getMainThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSnapModelToRegistrationPoint(true, glm::vec3(0.5f));
|
||||||
}
|
}
|
||||||
|
|
||||||
Model::~Model() {
|
Model::~Model() {
|
||||||
|
@ -409,7 +411,7 @@ void Model::reset() {
|
||||||
|
|
||||||
_meshGroupsKnown = false;
|
_meshGroupsKnown = false;
|
||||||
_readyWhenAdded = false; // in case any of our users are using scenes
|
_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() {
|
bool Model::updateGeometry() {
|
||||||
|
@ -461,7 +463,7 @@ bool Model::updateGeometry() {
|
||||||
_geometry = geometry;
|
_geometry = geometry;
|
||||||
_meshGroupsKnown = false;
|
_meshGroupsKnown = false;
|
||||||
_readyWhenAdded = false; // in case any of our users are using scenes
|
_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);
|
initJointStates(newJointStates);
|
||||||
needToRebuild = true;
|
needToRebuild = true;
|
||||||
} else if (_jointStates.isEmpty()) {
|
} else if (_jointStates.isEmpty()) {
|
||||||
|
@ -848,7 +850,6 @@ namespace render {
|
||||||
}
|
}
|
||||||
template <> void payloadRender(const TransparentMeshPart::Pointer& payload, RenderArgs* args) {
|
template <> void payloadRender(const TransparentMeshPart::Pointer& payload, RenderArgs* args) {
|
||||||
if (args) {
|
if (args) {
|
||||||
args->_elementsTouched++;
|
|
||||||
return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, true);
|
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) {
|
template <> void payloadRender(const OpaqueMeshPart::Pointer& payload, RenderArgs* args) {
|
||||||
if (args) {
|
if (args) {
|
||||||
args->_elementsTouched++;
|
|
||||||
return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, false);
|
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
|
// restore all the default material settings
|
||||||
_viewState->setupWorldLight();
|
_viewState->setupWorldLight();
|
||||||
|
|
||||||
if (args) {
|
|
||||||
args->_translucentMeshPartsRendered = translucentMeshPartsRendered;
|
|
||||||
args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef WANT_DEBUG_MESHBOXES
|
#ifdef WANT_DEBUG_MESHBOXES
|
||||||
renderDebugMeshBoxes();
|
renderDebugMeshBoxes();
|
||||||
#endif
|
#endif
|
||||||
|
@ -1273,6 +1268,7 @@ Extents Model::calculateScaledOffsetExtents(const Extents& extents) const {
|
||||||
|
|
||||||
/// Returns the world space equivalent of some box in model space.
|
/// Returns the world space equivalent of some box in model space.
|
||||||
AABox Model::calculateScaledOffsetAABox(const AABox& box) const {
|
AABox Model::calculateScaledOffsetAABox(const AABox& box) const {
|
||||||
|
|
||||||
return AABox(calculateScaledOffsetExtents(Extents(box)));
|
return AABox(calculateScaledOffsetExtents(Extents(box)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1610,6 +1606,7 @@ void Model::simulate(float deltaTime, bool fullUpdate) {
|
||||||
|| (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint);
|
|| (_snapModelToRegistrationPoint && !_snappedToRegistrationPoint);
|
||||||
|
|
||||||
if (isActive() && fullUpdate) {
|
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
|
_calculatedMeshBoxesValid = false; // if we have to simulate, we need to assume our mesh boxes are all invalid
|
||||||
_calculatedMeshTrianglesValid = false;
|
_calculatedMeshTrianglesValid = false;
|
||||||
|
|
||||||
|
@ -1998,6 +1995,7 @@ void Model::applyNextGeometry() {
|
||||||
_meshGroupsKnown = false;
|
_meshGroupsKnown = false;
|
||||||
_readyWhenAdded = false; // in case any of our users are using scenes
|
_readyWhenAdded = false; // in case any of our users are using scenes
|
||||||
_needsReload = false; // we are loaded now!
|
_needsReload = false; // we are loaded now!
|
||||||
|
invalidCalculatedMeshBoxes();
|
||||||
_nextBaseGeometry.reset();
|
_nextBaseGeometry.reset();
|
||||||
_nextGeometry.reset();
|
_nextGeometry.reset();
|
||||||
}
|
}
|
||||||
|
@ -2045,7 +2043,6 @@ void Model::setupBatchTransform(gpu::Batch& batch, RenderArgs* args) {
|
||||||
batch.setViewTransform(_transforms[0]);
|
batch.setViewTransform(_transforms[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AABox Model::getPartBounds(int meshIndex, int partIndex) {
|
AABox Model::getPartBounds(int meshIndex, int partIndex) {
|
||||||
if (!_calculatedMeshPartBoxesValid) {
|
if (!_calculatedMeshPartBoxesValid) {
|
||||||
recalculateMeshBoxes(true);
|
recalculateMeshBoxes(true);
|
||||||
|
@ -2071,7 +2068,28 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
|
||||||
gpu::Batch& batch = *(args->_batch);
|
gpu::Batch& batch = *(args->_batch);
|
||||||
auto mode = args->_renderMode;
|
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 FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
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,
|
pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||||
args, locations);
|
args, locations);
|
||||||
|
|
||||||
|
|
||||||
int meshPartsRendered = 0;
|
|
||||||
updateVisibleJointStates();
|
updateVisibleJointStates();
|
||||||
|
|
||||||
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
|
// 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()) {
|
if (meshIndex < 0 || meshIndex >= networkMeshes.size() || meshIndex > geometry.meshes.size()) {
|
||||||
_meshGroupsKnown = false; // regenerate these lists next time around.
|
_meshGroupsKnown = false; // regenerate these lists next time around.
|
||||||
_readyWhenAdded = false; // in case any of our users are using scenes
|
_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!
|
return; // FIXME!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2225,7 +2241,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args) {
|
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
|
// 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 emissiveOffset = part.emissiveParams.x;
|
||||||
float emissiveScale = part.emissiveParams.y;
|
float emissiveScale = part.emissiveParams.y;
|
||||||
GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale);
|
GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale);
|
||||||
|
|
||||||
Texture* emissiveMap = networkPart.emissiveTexture.data();
|
Texture* emissiveMap = networkPart.emissiveTexture.data();
|
||||||
batch.setUniformTexture(locations->emissiveTextureUnit, !emissiveMap ?
|
batch.setUniformTexture(locations->emissiveTextureUnit, !emissiveMap ?
|
||||||
textureCache->getWhiteTexture() : emissiveMap->getGPUTexture());
|
textureCache->getWhiteTexture() : emissiveMap->getGPUTexture());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
meshPartsRendered++;
|
|
||||||
|
|
||||||
qint64 offset = _calculatedMeshPartOffet[QPair<int,int>(meshIndex, partIndex)];
|
qint64 offset = _calculatedMeshPartOffet[QPair<int,int>(meshIndex, partIndex)];
|
||||||
|
|
||||||
if (part.quadIndices.size() > 0) {
|
if (part.quadIndices.size() > 0) {
|
||||||
|
@ -2260,8 +2274,8 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
|
||||||
if (args) {
|
if (args) {
|
||||||
const int INDICES_PER_TRIANGLE = 3;
|
const int INDICES_PER_TRIANGLE = 3;
|
||||||
const int INDICES_PER_QUAD = 4;
|
const int INDICES_PER_QUAD = 4;
|
||||||
args->_trianglesRendered += part.triangleIndices.size() / INDICES_PER_TRIANGLE;
|
args->_details._trianglesRendered += part.triangleIndices.size() / INDICES_PER_TRIANGLE;
|
||||||
args->_quadsRendered += part.quadIndices.size() / INDICES_PER_QUAD;
|
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()) {
|
if (i < 0 || i >= networkMeshes.size() || i > geometry.meshes.size()) {
|
||||||
_meshGroupsKnown = false; // regenerate these lists next time around.
|
_meshGroupsKnown = false; // regenerate these lists next time around.
|
||||||
_readyWhenAdded = false; // in case any of our users are using scenes
|
_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;
|
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 we got here, then check to see if this mesh is in view
|
||||||
if (args) {
|
if (args) {
|
||||||
bool shouldRender = true;
|
bool shouldRender = true;
|
||||||
args->_meshesConsidered++;
|
|
||||||
|
|
||||||
if (args->_viewFrustum) {
|
if (args->_viewFrustum) {
|
||||||
|
|
||||||
shouldRender = forceRenderMeshes ||
|
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());
|
float distance = args->_viewFrustum->distanceToCamera(_calculatedMeshBoxes.at(i).calcCenter());
|
||||||
shouldRender = !_viewState ? false : _viewState->shouldRenderMesh(_calculatedMeshBoxes.at(i).getLargestDimension(),
|
shouldRender = !_viewState ? false : _viewState->shouldRenderMesh(_calculatedMeshBoxes.at(i).getLargestDimension(),
|
||||||
distance);
|
distance);
|
||||||
if (!shouldRender) {
|
|
||||||
args->_meshesTooSmall++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
args->_meshesOutOfView++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldRender) {
|
if (!shouldRender) {
|
||||||
args->_meshesRendered++;
|
|
||||||
} else {
|
|
||||||
continue; // skip this mesh
|
continue; // skip this mesh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2565,11 +2570,6 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod
|
||||||
batch.setUniformTexture(locations->specularTextureUnit, !specularMap ?
|
batch.setUniformTexture(locations->specularTextureUnit, !specularMap ?
|
||||||
textureCache->getWhiteTexture() : specularMap->getGPUTexture());
|
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
|
// 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);
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -260,7 +260,7 @@ protected:
|
||||||
|
|
||||||
bool _snapModelToRegistrationPoint; /// is the model's offset automatically adjusted to a registration point in model space
|
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
|
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;
|
bool _showTrueJointTransforms;
|
||||||
|
|
||||||
|
@ -312,7 +312,12 @@ protected:
|
||||||
float getLimbLength(int jointIndex) const;
|
float getLimbLength(int jointIndex) const;
|
||||||
|
|
||||||
/// Allow sub classes to force invalidating the bboxes
|
/// Allow sub classes to force invalidating the bboxes
|
||||||
void invalidCalculatedMeshBoxes() { _calculatedMeshBoxesValid = false; }
|
void invalidCalculatedMeshBoxes() {
|
||||||
|
qDebug() << "invalidCalculatedMeshBoxes()";
|
||||||
|
_calculatedMeshBoxesValid = false;
|
||||||
|
_calculatedMeshPartBoxesValid = false;
|
||||||
|
_calculatedMeshTrianglesValid = false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
template <> void render::jobRun(const ResolveDeferred& job, const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||||
PerformanceTimer perfTimer("ResolveDeferred");
|
PerformanceTimer perfTimer("ResolveDeferred");
|
||||||
DependencyManager::get<DeferredLightingEffect>()->copyBack(renderContext->args);
|
DependencyManager::get<DeferredLightingEffect>()->copyBack(renderContext->args);
|
||||||
|
renderContext->args->_context->syncCache();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,6 @@ void main(void) {
|
||||||
TransformObject obj = getTransformObject();
|
TransformObject obj = getTransformObject();
|
||||||
<$transformModelToEyeAndClipPos(cam, obj, gl_Vertex, interpolatedPosition, gl_Position)$>
|
<$transformModelToEyeAndClipPos(cam, obj, gl_Vertex, interpolatedPosition, gl_Position)$>
|
||||||
<$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$>
|
<$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$>
|
||||||
|
// interpolatedPosition = (gl_Vertex);
|
||||||
interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
|
interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,24 +54,44 @@ void main(void) {
|
||||||
// The view Matrix
|
// The view Matrix
|
||||||
//uniform mat4 invViewMat;
|
//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
|
// Need the light now
|
||||||
Light light = getLight();
|
Light light = getLight();
|
||||||
TransformCamera cam = getTransformCamera();
|
TransformCamera cam = getTransformCamera();
|
||||||
mat4 invViewMat = cam._viewInverse;
|
// mat4 viewMat = cam._viewInverse;
|
||||||
|
vec3 fragNormal;
|
||||||
vec3 fragNormal = vec3(invViewMat * vec4(normal, 0.0));
|
<$transformEyeToWorldDir(cam, normal, fragNormal)$>
|
||||||
vec4 fragEyeVector = invViewMat * vec4(-position, 0.0);
|
vec3 fragEyeVectorView = normalize(-position);
|
||||||
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
|
vec3 fragEyeDir;
|
||||||
|
<$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$>
|
||||||
|
|
||||||
vec3 color = diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light);
|
vec3 color = diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light);
|
||||||
|
|
||||||
vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss);
|
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
|
// the diffuse texture
|
||||||
|
@ -98,12 +118,13 @@ void main(void) {
|
||||||
vec3 fragSpecular = getMaterialSpecular(mat);
|
vec3 fragSpecular = getMaterialSpecular(mat);
|
||||||
float fragGloss = getMaterialShininess(mat);
|
float fragGloss = getMaterialShininess(mat);
|
||||||
|
|
||||||
vec3 color = evalAmbienGlobalColor(1.0,
|
vec4 fragColor = evalAmbienGlobalColor(1.0,
|
||||||
fragPosition,
|
fragPosition,
|
||||||
fragNormal,
|
fragNormal,
|
||||||
fragDiffuse,
|
fragDiffuse,
|
||||||
fragSpecular,
|
fragSpecular,
|
||||||
fragGloss);
|
fragGloss,
|
||||||
|
fragOpacity);
|
||||||
|
|
||||||
gl_FragColor = vec4(color, fragOpacity);
|
gl_FragColor = fragColor; //vec4(fragColor, fragOpacity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,10 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont
|
||||||
|
|
||||||
auto& scene = sceneContext->_scene;
|
auto& scene = sceneContext->_scene;
|
||||||
RenderArgs* args = renderContext->args;
|
RenderArgs* args = renderContext->args;
|
||||||
|
auto renderDetails = renderContext->args->_details._item;
|
||||||
|
|
||||||
|
renderDetails->_considered += inItems.size();
|
||||||
|
|
||||||
// Culling / LOD
|
// Culling / LOD
|
||||||
for (auto id : inItems) {
|
for (auto id : inItems) {
|
||||||
auto item = scene->getItem(id);
|
auto item = scene->getItem(id);
|
||||||
|
@ -71,7 +74,6 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont
|
||||||
|
|
||||||
if (bound.isNull()) {
|
if (bound.isNull()) {
|
||||||
outItems.push_back(id); // One more Item to render
|
outItems.push_back(id); // One more Item to render
|
||||||
args->_itemsRendered++;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,17 +82,16 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont
|
||||||
bool outOfView = args->_viewFrustum->boxInFrustum(bound) == ViewFrustum::OUTSIDE;
|
bool outOfView = args->_viewFrustum->boxInFrustum(bound) == ViewFrustum::OUTSIDE;
|
||||||
if (!outOfView) {
|
if (!outOfView) {
|
||||||
bool bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, bound) : true;
|
bool bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, bound) : true;
|
||||||
|
|
||||||
if (bigEnoughToRender) {
|
if (bigEnoughToRender) {
|
||||||
outItems.push_back(id); // One more Item to render
|
outItems.push_back(id); // One more Item to render
|
||||||
args->_itemsRendered++;
|
|
||||||
} else {
|
} else {
|
||||||
args->_itemsTooSmall++;
|
renderDetails->_tooSmall++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
args->_itemsOutOfView++;
|
renderDetails->_outOfView++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
renderDetails->_rendered += outItems.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ItemBound {
|
struct ItemBound {
|
||||||
|
@ -227,6 +228,7 @@ template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer
|
||||||
// render opaques
|
// render opaques
|
||||||
auto& scene = sceneContext->_scene;
|
auto& scene = sceneContext->_scene;
|
||||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape());
|
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape());
|
||||||
|
auto& renderDetails = renderContext->args->_details;
|
||||||
|
|
||||||
ItemIDs inItems;
|
ItemIDs inItems;
|
||||||
inItems.reserve(items.size());
|
inItems.reserve(items.size());
|
||||||
|
@ -239,7 +241,9 @@ template <> void render::jobRun(const DrawOpaque& job, const SceneContextPointer
|
||||||
|
|
||||||
ItemIDs culledItems;
|
ItemIDs culledItems;
|
||||||
if (renderContext->_cullOpaque) {
|
if (renderContext->_cullOpaque) {
|
||||||
|
renderDetails.pointTo(RenderDetails::OPAQUE_ITEM);
|
||||||
cullItems(sceneContext, renderContext, renderedItems, culledItems);
|
cullItems(sceneContext, renderContext, renderedItems, culledItems);
|
||||||
|
renderDetails.pointTo(RenderDetails::OTHER_ITEM);
|
||||||
renderedItems = culledItems;
|
renderedItems = culledItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -290,6 +294,7 @@ template <> void render::jobRun(const DrawTransparent& job, const SceneContextPo
|
||||||
// render transparents
|
// render transparents
|
||||||
auto& scene = sceneContext->_scene;
|
auto& scene = sceneContext->_scene;
|
||||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape());
|
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::transparentShape());
|
||||||
|
auto& renderDetails = renderContext->args->_details;
|
||||||
|
|
||||||
ItemIDs inItems;
|
ItemIDs inItems;
|
||||||
inItems.reserve(items.size());
|
inItems.reserve(items.size());
|
||||||
|
@ -302,7 +307,9 @@ template <> void render::jobRun(const DrawTransparent& job, const SceneContextPo
|
||||||
|
|
||||||
ItemIDs culledItems;
|
ItemIDs culledItems;
|
||||||
if (renderContext->_cullTransparent) {
|
if (renderContext->_cullTransparent) {
|
||||||
|
renderDetails.pointTo(RenderDetails::TRANSLUCENT_ITEM);
|
||||||
cullItems(sceneContext, renderContext, inItems, culledItems);
|
cullItems(sceneContext, renderContext, inItems, culledItems);
|
||||||
|
renderDetails.pointTo(RenderDetails::OTHER_ITEM);
|
||||||
renderedItems = culledItems;
|
renderedItems = culledItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
79
libraries/shared/src/PhysicsCollisionGroups.h
Normal file
79
libraries/shared/src/PhysicsCollisionGroups.h
Normal 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
|
|
@ -5,7 +5,7 @@
|
||||||
// Created by Andrew Meadows 2015.01.27
|
// Created by Andrew Meadows 2015.01.27
|
||||||
// Unless otherwise copyrighted: Copyright 2015 High Fidelity, Inc.
|
// 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
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
|
|
@ -78,15 +78,17 @@ enum ContactEventType {
|
||||||
|
|
||||||
class Collision {
|
class Collision {
|
||||||
public:
|
public:
|
||||||
Collision() : type(CONTACT_EVENT_TYPE_START), idA(), idB(), contactPoint(0.0f), penetration(0.0f) { }
|
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)
|
Collision(ContactEventType cType, const QUuid& cIdA, const QUuid& cIdB, const glm::vec3& cPoint,
|
||||||
: type(cType), idA(cIdA), idB(cIdB), contactPoint(cPoint), penetration(cPenetration) { }
|
const glm::vec3& cPenetration, const glm::vec3& velocityChange)
|
||||||
|
: type(cType), idA(cIdA), idB(cIdB), contactPoint(cPoint), penetration(cPenetration), velocityChange(velocityChange) { }
|
||||||
|
|
||||||
ContactEventType type;
|
ContactEventType type;
|
||||||
QUuid idA;
|
QUuid idA;
|
||||||
QUuid idB;
|
QUuid idB;
|
||||||
glm::vec3 contactPoint;
|
glm::vec3 contactPoint;
|
||||||
glm::vec3 penetration;
|
glm::vec3 penetration;
|
||||||
|
glm::vec3 velocityChange;
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(Collision)
|
Q_DECLARE_METATYPE(Collision)
|
||||||
QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision);
|
QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision);
|
||||||
|
|
|
@ -22,6 +22,46 @@ class Batch;
|
||||||
class Context;
|
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 {
|
class RenderArgs {
|
||||||
public:
|
public:
|
||||||
typedef std::function<bool(const RenderArgs* args, const AABox& bounds)> ShoudRenderFunctor;
|
typedef std::function<bool(const RenderArgs* args, const AABox& bounds)> ShoudRenderFunctor;
|
||||||
|
@ -45,24 +85,7 @@ public:
|
||||||
RenderSide renderSide = MONO,
|
RenderSide renderSide = MONO,
|
||||||
DebugFlags debugFlags = RENDER_DEBUG_NONE,
|
DebugFlags debugFlags = RENDER_DEBUG_NONE,
|
||||||
gpu::Batch* batch = nullptr,
|
gpu::Batch* batch = nullptr,
|
||||||
ShoudRenderFunctor shouldRender = 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) :
|
|
||||||
_context(context),
|
_context(context),
|
||||||
_renderer(renderer),
|
_renderer(renderer),
|
||||||
_viewFrustum(viewFrustum),
|
_viewFrustum(viewFrustum),
|
||||||
|
@ -72,53 +95,21 @@ public:
|
||||||
_renderSide(renderSide),
|
_renderSide(renderSide),
|
||||||
_debugFlags(debugFlags),
|
_debugFlags(debugFlags),
|
||||||
_batch(batch),
|
_batch(batch),
|
||||||
_shouldRender(shouldRender),
|
_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) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::Context* _context;
|
gpu::Context* _context = nullptr;
|
||||||
OctreeRenderer* _renderer;
|
OctreeRenderer* _renderer = nullptr;
|
||||||
ViewFrustum* _viewFrustum;
|
ViewFrustum* _viewFrustum = nullptr;
|
||||||
float _sizeScale;
|
float _sizeScale = 1.0f;
|
||||||
int _boundaryLevelAdjust;
|
int _boundaryLevelAdjust = 0;
|
||||||
RenderMode _renderMode;
|
RenderMode _renderMode = DEFAULT_RENDER_MODE;
|
||||||
RenderSide _renderSide;
|
RenderSide _renderSide = MONO;
|
||||||
DebugFlags _debugFlags;
|
DebugFlags _debugFlags = RENDER_DEBUG_NONE;
|
||||||
gpu::Batch* _batch;
|
gpu::Batch* _batch = nullptr;
|
||||||
ShoudRenderFunctor _shouldRender;
|
ShoudRenderFunctor _shouldRender;
|
||||||
|
|
||||||
int _elementsTouched;
|
RenderDetails _details;
|
||||||
int _itemsRendered;
|
|
||||||
int _itemsOutOfView;
|
|
||||||
int _itemsTooSmall;
|
|
||||||
|
|
||||||
int _meshesConsidered;
|
|
||||||
int _meshesRendered;
|
|
||||||
int _meshesOutOfView;
|
|
||||||
int _meshesTooSmall;
|
|
||||||
|
|
||||||
int _materialSwitches;
|
|
||||||
int _trianglesRendered;
|
|
||||||
int _quadsRendered;
|
|
||||||
|
|
||||||
int _translucentMeshPartsRendered;
|
|
||||||
int _opaqueMeshPartsRendered;
|
|
||||||
|
|
||||||
float _alphaThreshold = 0.5f;
|
float _alphaThreshold = 0.5f;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue