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