mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:23:54 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into hobbes
This commit is contained in:
commit
a22ee03732
46 changed files with 2387 additions and 555 deletions
|
@ -18,7 +18,7 @@ var RainSquall = function (properties) {
|
|||
dropFallSpeed = 1, // m/s
|
||||
dropLifetime = 60, // Seconds
|
||||
dropSpinMax = 0, // Maximum angular velocity per axis; deg/s
|
||||
debug = false, // Display origin circle; don't use running on Stack Manager
|
||||
debug = true, // Display origin circle; don't use running on Stack Manager
|
||||
// Other
|
||||
squallCircle,
|
||||
SQUALL_CIRCLE_COLOR = { red: 255, green: 0, blue: 0 },
|
||||
|
@ -151,8 +151,10 @@ var RainSquall = function (properties) {
|
|||
};
|
||||
};
|
||||
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
|
||||
center.y += 10;
|
||||
var rainSquall1 = new RainSquall({
|
||||
origin: { x: 1195, y: 1223, z: 1020 },
|
||||
origin:center,
|
||||
radius: 25,
|
||||
dropsPerMinute: 120,
|
||||
dropSize: { x: 0.1, y: 0.1, z: 0.1 },
|
||||
|
|
289
examples/closePaint.js
Normal file
289
examples/closePaint.js
Normal file
|
@ -0,0 +1,289 @@
|
|||
//
|
||||
// closePaint.js
|
||||
// examples
|
||||
//
|
||||
// Created by Eric Levina on 9/30/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Run this script to be able to paint on entities you are close to, with hydras.
|
||||
//
|
||||
// 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("libraries/utils.js");
|
||||
|
||||
|
||||
var RIGHT_HAND = 1;
|
||||
var LEFT_HAND = 0;
|
||||
|
||||
var MIN_POINT_DISTANCE = 0.02;
|
||||
var MAX_POINT_DISTANCE = 0.5;
|
||||
|
||||
var SPATIAL_CONTROLLERS_PER_PALM = 2;
|
||||
var TIP_CONTROLLER_OFFSET = 1;
|
||||
|
||||
var TRIGGER_ON_VALUE = 0.3;
|
||||
|
||||
var MAX_DISTANCE = 10;
|
||||
|
||||
var MAX_POINTS_PER_LINE = 40;
|
||||
|
||||
var RIGHT_4_ACTION = 18;
|
||||
var RIGHT_2_ACTION = 16;
|
||||
|
||||
var LEFT_4_ACTION = 17;
|
||||
var LEFT_2_ACTION = 16;
|
||||
|
||||
var HUE_INCREMENT = 0.02;
|
||||
|
||||
var MIN_STROKE_WIDTH = 0.002;
|
||||
var MAX_STROKE_WIDTH = 0.04;
|
||||
|
||||
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
|
||||
|
||||
function MyController(hand, triggerAction) {
|
||||
this.hand = hand;
|
||||
this.strokes = [];
|
||||
this.painting = false;
|
||||
this.currentStrokeWidth = MIN_STROKE_WIDTH;
|
||||
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
this.getHandPosition = MyAvatar.getRightPalmPosition;
|
||||
this.getHandRotation = MyAvatar.getRightPalmRotation;
|
||||
} else {
|
||||
this.getHandPosition = MyAvatar.getLeftPalmPosition;
|
||||
this.getHandRotation = MyAvatar.getLeftPalmRotation;
|
||||
}
|
||||
|
||||
this.triggerAction = triggerAction;
|
||||
this.palm = SPATIAL_CONTROLLERS_PER_PALM * hand;
|
||||
this.tip = SPATIAL_CONTROLLERS_PER_PALM * hand + TIP_CONTROLLER_OFFSET;
|
||||
|
||||
|
||||
this.strokeColor = {
|
||||
h: 0.8,
|
||||
s: 0.8,
|
||||
l: 0.4
|
||||
};
|
||||
|
||||
|
||||
this.laserPointer = Overlays.addOverlay("circle3d", {
|
||||
color: hslToRgb(this.strokeColor),
|
||||
solid: true,
|
||||
position: center
|
||||
});
|
||||
this.triggerValue = 0;
|
||||
this.prevTriggerValue = 0;
|
||||
var _this = this;
|
||||
|
||||
this.update = function() {
|
||||
this.updateControllerState();
|
||||
this.search();
|
||||
if (this.canPaint === true) {
|
||||
this.paint(this.intersection.intersection, this.intersection.surfaceNormal);
|
||||
}
|
||||
};
|
||||
|
||||
this.paint = function(position, normal) {
|
||||
if (this.painting === false) {
|
||||
if (this.oldPosition) {
|
||||
this.newStroke(this.oldPosition);
|
||||
} else {
|
||||
this.newStroke(position);
|
||||
}
|
||||
this.painting = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
var localPoint = Vec3.subtract(position, this.strokeBasePosition);
|
||||
//Move stroke a bit forward along normal so it doesnt zfight with mesh its drawing on
|
||||
localPoint = Vec3.sum(localPoint, Vec3.multiply(normal, 0.001 + Math.random() * .001)); //rand avoid z fighting
|
||||
|
||||
var distance = Vec3.distance(localPoint, this.strokePoints[this.strokePoints.length - 1]);
|
||||
if (this.strokePoints.length > 0 && distance < MIN_POINT_DISTANCE) {
|
||||
//need a minimum distance to avoid binormal NANs
|
||||
return;
|
||||
}
|
||||
if (this.strokePoints.length > 0 && distance > MAX_POINT_DISTANCE) {
|
||||
//Prevents drawing lines accross models
|
||||
this.painting = false;
|
||||
return;
|
||||
}
|
||||
if (this.strokePoints.length === 0) {
|
||||
localPoint = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
}
|
||||
|
||||
this.strokePoints.push(localPoint);
|
||||
this.strokeNormals.push(normal);
|
||||
this.strokeWidths.push(this.currentStrokeWidth);
|
||||
Entities.editEntity(this.currentStroke, {
|
||||
linePoints: this.strokePoints,
|
||||
normals: this.strokeNormals,
|
||||
strokeWidths: this.strokeWidths
|
||||
});
|
||||
if (this.strokePoints.length === MAX_POINTS_PER_LINE) {
|
||||
this.painting = false;
|
||||
return;
|
||||
}
|
||||
this.oldPosition = position;
|
||||
}
|
||||
|
||||
this.newStroke = function(position) {
|
||||
this.strokeBasePosition = position;
|
||||
this.currentStroke = Entities.addEntity({
|
||||
position: position,
|
||||
type: "PolyLine",
|
||||
color: hslToRgb(this.strokeColor),
|
||||
dimensions: {
|
||||
x: 50,
|
||||
y: 50,
|
||||
z: 50
|
||||
},
|
||||
lifetime: 200
|
||||
});
|
||||
this.strokePoints = [];
|
||||
this.strokeNormals = [];
|
||||
this.strokeWidths = [];
|
||||
|
||||
this.strokes.push(this.currentStroke);
|
||||
|
||||
}
|
||||
|
||||
this.updateControllerState = function() {
|
||||
this.triggerValue = Controller.getActionValue(this.triggerAction);
|
||||
if (this.triggerValue > TRIGGER_ON_VALUE && this.prevTriggerValue <= TRIGGER_ON_VALUE) {
|
||||
this.squeeze();
|
||||
} else if (this.triggerValue < TRIGGER_ON_VALUE && this.prevTriggerValue >= TRIGGER_ON_VALUE) {
|
||||
this.release();
|
||||
}
|
||||
|
||||
this.prevTriggerValue = this.triggerValue;
|
||||
}
|
||||
|
||||
this.squeeze = function() {
|
||||
this.tryPainting = true;
|
||||
|
||||
}
|
||||
this.release = function() {
|
||||
this.painting = false;
|
||||
this.tryPainting = false;
|
||||
this.canPaint = false;
|
||||
this.oldPosition = null;
|
||||
}
|
||||
this.search = function() {
|
||||
|
||||
// the trigger is being pressed, do a ray test
|
||||
var handPosition = this.getHandPosition();
|
||||
var pickRay = {
|
||||
origin: handPosition,
|
||||
direction: Quat.getUp(this.getHandRotation())
|
||||
};
|
||||
|
||||
|
||||
this.intersection = Entities.findRayIntersection(pickRay, true);
|
||||
if (this.intersection.intersects) {
|
||||
var distance = Vec3.distance(handPosition, this.intersection.intersection);
|
||||
if (distance < MAX_DISTANCE) {
|
||||
var displayPoint = this.intersection.intersection;
|
||||
displayPoint = Vec3.sum(displayPoint, Vec3.multiply(this.intersection.surfaceNormal, .01));
|
||||
if (this.tryPainting) {
|
||||
this.canPaint = true;
|
||||
}
|
||||
this.currentStrokeWidth = map(this.triggerValue, TRIGGER_ON_VALUE, 1, MIN_STROKE_WIDTH, MAX_STROKE_WIDTH);
|
||||
var laserSize = map(distance, 1, MAX_DISTANCE, 0.01, 0.1);
|
||||
laserSize += this.currentStrokeWidth / 2;
|
||||
Overlays.editOverlay(this.laserPointer, {
|
||||
visible: true,
|
||||
position: displayPoint,
|
||||
rotation: orientationOf(this.intersection.surfaceNormal),
|
||||
size: {
|
||||
x: laserSize,
|
||||
y: laserSize
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
this.hitFail();
|
||||
}
|
||||
} else {
|
||||
this.hitFail();
|
||||
}
|
||||
};
|
||||
|
||||
this.hitFail = function() {
|
||||
this.canPaint = false;
|
||||
|
||||
Overlays.editOverlay(this.laserPointer, {
|
||||
visible: false
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
this.cleanup = function() {
|
||||
Overlays.deleteOverlay(this.laserPointer);
|
||||
this.strokes.forEach(function(stroke) {
|
||||
Entities.deleteEntity(stroke);
|
||||
});
|
||||
}
|
||||
|
||||
this.cycleColorDown = function() {
|
||||
this.strokeColor.h -= HUE_INCREMENT;
|
||||
if (this.strokeColor.h < 0) {
|
||||
this.strokeColor = 1;
|
||||
}
|
||||
Overlays.editOverlay(this.laserPointer, {
|
||||
color: hslToRgb(this.strokeColor)
|
||||
});
|
||||
}
|
||||
|
||||
this.cycleColorUp = function() {
|
||||
this.strokeColor.h += HUE_INCREMENT;
|
||||
if (this.strokeColor.h > 1) {
|
||||
this.strokeColor.h = 0;
|
||||
}
|
||||
Overlays.editOverlay(this.laserPointer, {
|
||||
color: hslToRgb(this.strokeColor)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var rightController = new MyController(RIGHT_HAND, Controller.findAction("RIGHT_HAND_CLICK"));
|
||||
var leftController = new MyController(LEFT_HAND, Controller.findAction("LEFT_HAND_CLICK"));
|
||||
|
||||
Controller.actionEvent.connect(function(action, state) {
|
||||
if (state === 0) {
|
||||
return;
|
||||
}
|
||||
if (action === RIGHT_4_ACTION) {
|
||||
rightController.cycleColorUp();
|
||||
} else if (action === RIGHT_2_ACTION) {
|
||||
rightController.cycleColorDown();
|
||||
}
|
||||
if (action === LEFT_4_ACTION) {
|
||||
leftController.cycleColorUp();
|
||||
} else if (action === LEFT_2_ACTION) {
|
||||
leftController.cycleColorDown();
|
||||
}
|
||||
});
|
||||
|
||||
function update() {
|
||||
rightController.update();
|
||||
leftController.update();
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
rightController.cleanup();
|
||||
leftController.cleanup();
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
Script.update.connect(update);
|
|
@ -1,252 +0,0 @@
|
|||
(function() {
|
||||
// Script.include("../libraries/utils.js");
|
||||
//Need absolute path for now, for testing before PR merge and s3 cloning. Will change post-merge
|
||||
|
||||
Script.include("../libraries/utils.js");
|
||||
GRAB_FRAME_USER_DATA_KEY = "grabFrame";
|
||||
this.userData = {};
|
||||
|
||||
var TIP_OFFSET_Z = 0.14;
|
||||
var TIP_OFFSET_Y = 0.04;
|
||||
|
||||
var ZERO_VEC = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}
|
||||
|
||||
var MAX_POINTS_PER_LINE = 40;
|
||||
var MIN_POINT_DISTANCE = 0.01;
|
||||
var STROKE_WIDTH = 0.02;
|
||||
|
||||
var self = this;
|
||||
|
||||
var timeSinceLastMoved = 0;
|
||||
var RESET_TIME_THRESHOLD = 5;
|
||||
var DISTANCE_FROM_HOME_THRESHOLD = 0.5;
|
||||
var HOME_POSITION = {
|
||||
x: 549.12,
|
||||
y: 495.555,
|
||||
z: 503.77
|
||||
};
|
||||
this.getUserData = function() {
|
||||
|
||||
|
||||
if (this.properties.userData) {
|
||||
this.userData = JSON.parse(this.properties.userData);
|
||||
}
|
||||
}
|
||||
|
||||
this.updateUserData = function() {
|
||||
Entities.editEntity(this.entityId, {
|
||||
userData: JSON.stringify(this.userData)
|
||||
});
|
||||
}
|
||||
|
||||
this.update = function(deltaTime) {
|
||||
self.getUserData();
|
||||
self.properties = Entities.getEntityProperties(self.entityId);
|
||||
|
||||
if (Vec3.length(self.properties.velocity) < 0.1 && Vec3.distance(HOME_POSITION, self.properties.position) > DISTANCE_FROM_HOME_THRESHOLD) {
|
||||
timeSinceLastMoved += deltaTime;
|
||||
if (timeSinceLastMoved > RESET_TIME_THRESHOLD) {
|
||||
self.reset();
|
||||
timeSinceLastMoved = 0;
|
||||
}
|
||||
} else {
|
||||
timeSinceLastMoved = 0;
|
||||
}
|
||||
|
||||
//Only activate for the user who grabbed the object
|
||||
if (self.userData.grabKey && self.userData.grabKey.activated === true && self.userData.grabKey.avatarId == MyAvatar.sessionUUID) {
|
||||
if (self.activated !== true) {
|
||||
//We were just grabbed, so create a particle system
|
||||
self.grab();
|
||||
}
|
||||
//Move emitter to where entity is always when its activated
|
||||
self.sprayStream();
|
||||
} else if (self.userData.grabKey && self.userData.grabKey.activated === false && self.activated) {
|
||||
self.letGo();
|
||||
}
|
||||
}
|
||||
|
||||
this.grab = function() {
|
||||
this.activated = true;
|
||||
var animationSettings = JSON.stringify({
|
||||
fps: 30,
|
||||
loop: true,
|
||||
firstFrame: 1,
|
||||
lastFrame: 10000,
|
||||
running: true
|
||||
});
|
||||
var PI = 3.141593;
|
||||
var DEG_TO_RAD = PI / 180.0;
|
||||
|
||||
this.paintStream = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
animationSettings: animationSettings,
|
||||
position: this.properties.position,
|
||||
textures: "https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png",
|
||||
emitSpeed: 0,
|
||||
speedSpread: 0.02,
|
||||
polarFinish: 2 * DEG_TO_RAD,
|
||||
emitAcceleration: ZERO_VEC,
|
||||
emitRate: 100,
|
||||
particleRadius: 0.01,
|
||||
color: {
|
||||
red: 170,
|
||||
green: 20,
|
||||
blue: 150
|
||||
},
|
||||
lifetime: 50, //probably wont be holding longer than this straight
|
||||
});
|
||||
}
|
||||
|
||||
this.letGo = function() {
|
||||
this.activated = false;
|
||||
Entities.deleteEntity(this.paintStream);
|
||||
this.paintStream = null;
|
||||
}
|
||||
|
||||
this.reset = function() {
|
||||
Entities.editEntity(self.entityId, {
|
||||
position: HOME_POSITION,
|
||||
rotation: Quat.fromPitchYawRollDegrees(0, 0, 0),
|
||||
angularVelocity: ZERO_VEC,
|
||||
velocity: ZERO_VEC
|
||||
});
|
||||
}
|
||||
|
||||
this.sprayStream = function() {
|
||||
var forwardVec = Quat.getFront(Quat.multiply(self.properties.rotation , Quat.fromPitchYawRollDegrees(0, 90, 0)));
|
||||
forwardVec = Vec3.normalize(forwardVec);
|
||||
|
||||
var upVec = Quat.getUp(self.properties.rotation);
|
||||
var position = Vec3.sum(self.properties.position, Vec3.multiply(forwardVec, TIP_OFFSET_Z));
|
||||
position = Vec3.sum(position, Vec3.multiply(upVec, TIP_OFFSET_Y))
|
||||
Entities.editEntity(self.paintStream, {
|
||||
position: position,
|
||||
emitOrientation: forwardVec,
|
||||
emitSpeed: 5
|
||||
});
|
||||
|
||||
//Now check for an intersection with an entity
|
||||
//move forward so ray doesnt intersect with gun
|
||||
var origin = Vec3.sum(position, forwardVec);
|
||||
var pickRay = {
|
||||
origin: origin,
|
||||
direction: Vec3.multiply(forwardVec, 2)
|
||||
}
|
||||
|
||||
var intersection = Entities.findRayIntersection(pickRay, true);
|
||||
if (intersection.intersects) {
|
||||
var normal = Vec3.multiply(-1, Quat.getFront(intersection.properties.rotation));
|
||||
this.paint(intersection.intersection, normal);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
this.paint = function(position, normal) {
|
||||
if (!this.painting) {
|
||||
|
||||
this.newStroke(position);
|
||||
this.painting = true;
|
||||
}
|
||||
|
||||
if (this.strokePoints.length > MAX_POINTS_PER_LINE) {
|
||||
this.painting = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var localPoint = Vec3.subtract(position, this.strokeBasePosition);
|
||||
//Move stroke a bit forward along normal so it doesnt zfight with mesh its drawing on
|
||||
localPoint = Vec3.sum(localPoint, Vec3.multiply(normal, .1));
|
||||
|
||||
if (this.strokePoints.length > 0 && Vec3.distance(localPoint, this.strokePoints[this.strokePoints.length - 1]) < MIN_POINT_DISTANCE) {
|
||||
//need a minimum distance to avoid binormal NANs
|
||||
return;
|
||||
}
|
||||
|
||||
this.strokePoints.push(localPoint);
|
||||
this.strokeNormals.push(normal);
|
||||
this.strokeWidths.push(STROKE_WIDTH);
|
||||
Entities.editEntity(this.currentStroke, {
|
||||
linePoints: this.strokePoints,
|
||||
normals: this.strokeNormals,
|
||||
strokeWidths: this.strokeWidths
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
this.newStroke = function(position) {
|
||||
this.strokeBasePosition = position;
|
||||
this.currentStroke = Entities.addEntity({
|
||||
position: position,
|
||||
type: "PolyLine",
|
||||
color: {
|
||||
red: randInt(160, 250),
|
||||
green: randInt(10, 20),
|
||||
blue: randInt(190, 250)
|
||||
},
|
||||
dimensions: {
|
||||
x: 50,
|
||||
y: 50,
|
||||
z: 50
|
||||
},
|
||||
lifetime: 100
|
||||
});
|
||||
this.strokePoints = [];
|
||||
this.strokeNormals = [];
|
||||
this.strokeWidths = [];
|
||||
|
||||
this.strokes.push(this.currentStroke);
|
||||
}
|
||||
|
||||
this.preload = function(entityId) {
|
||||
this.strokes = [];
|
||||
this.activated = false;
|
||||
this.entityId = entityId;
|
||||
this.properties = Entities.getEntityProperties(self.entityId);
|
||||
this.getUserData();
|
||||
|
||||
//Only activate for the avatar who is grabbing the can!
|
||||
if (this.userData.grabKey && this.userData.grabKey.activated) {
|
||||
this.activated = true;
|
||||
}
|
||||
if (!this.userData.grabFrame) {
|
||||
var data = {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0, 0, 0)
|
||||
}
|
||||
setEntityCustomData(GRAB_FRAME_USER_DATA_KEY, this.entityId, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.unload = function() {
|
||||
Script.update.disconnect(this.update);
|
||||
if(this.paintStream) {
|
||||
Entities.deleteEntity(this.paintStream);
|
||||
}
|
||||
this.strokes.forEach(function(stroke) {
|
||||
Entities.deleteEntity(stroke);
|
||||
});
|
||||
}
|
||||
Script.update.connect(this.update);
|
||||
});
|
||||
|
||||
|
||||
|
||||
function randFloat(min, max) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
||||
function randInt(min, max) {
|
||||
return Math.floor(Math.random() * (max - min)) + min;
|
||||
}
|
|
@ -179,3 +179,69 @@ pointInExtents = function(point, minPoint, maxPoint) {
|
|||
(point.y >= minPoint.y && point.y <= maxPoint.y) &&
|
||||
(point.z >= minPoint.z && point.z <= maxPoint.z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an HSL color value to RGB. Conversion formula
|
||||
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
|
||||
* Assumes h, s, and l are contained in the set [0, 1] and
|
||||
* returns r, g, and b in the set [0, 255].
|
||||
*
|
||||
* @param Number h The hue
|
||||
* @param Number s The saturation
|
||||
* @param Number l The lightness
|
||||
* @return Array The RGB representation
|
||||
*/
|
||||
hslToRgb = function(hsl, hueOffset) {
|
||||
var r, g, b;
|
||||
if (hsl.s == 0) {
|
||||
r = g = b = hsl.l; // achromatic
|
||||
} else {
|
||||
var hue2rgb = function hue2rgb(p, q, t) {
|
||||
if (t < 0) t += 1;
|
||||
if (t > 1) t -= 1;
|
||||
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||
if (t < 1 / 2) return q;
|
||||
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||
return p;
|
||||
}
|
||||
|
||||
var q = hsl.l < 0.5 ? hsl.l * (1 + hsl.s) : hsl.l + hsl.s - hsl.l * hsl.s;
|
||||
var p = 2 * hsl.l - q;
|
||||
r = hue2rgb(p, q, hsl.h + 1 / 3);
|
||||
g = hue2rgb(p, q, hsl.h);
|
||||
b = hue2rgb(p, q, hsl.h - 1 / 3);
|
||||
}
|
||||
|
||||
return {
|
||||
red: Math.round(r * 255),
|
||||
green: Math.round(g * 255),
|
||||
blue: Math.round(b * 255)
|
||||
};
|
||||
}
|
||||
|
||||
map = function(value, min1, max1, min2, max2) {
|
||||
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
|
||||
}
|
||||
|
||||
orientationOf = function(vector) {
|
||||
var Y_AXIS = {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
};
|
||||
var X_AXIS = {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
|
||||
var theta = 0.0;
|
||||
|
||||
var RAD_TO_DEG = 180.0 / Math.PI;
|
||||
var direction, yaw, pitch;
|
||||
direction = Vec3.normalize(vector);
|
||||
yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS);
|
||||
pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS);
|
||||
return Quat.multiply(yaw, pitch);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
// sprayPaintSpawner.js
|
||||
//
|
||||
// Created by Eric Levin on 9/3/15
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This is script spwans a spreay paint can model with the sprayPaintCan.js entity script attached
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
//Just temporarily using my own bucket here so others can test the entity. Once PR is tested and merged, then the entity script will appear in its proper place in S3, and I wil switch it
|
||||
// var scriptURL = "https://hifi-public.s3.amazonaws.com/eric/scripts/sprayPaintCan.js?=v6 ";
|
||||
var scriptURL = Script.resolvePath("entityScripts/sprayPaintCan.js?v2");
|
||||
var modelURL = "https://hifi-public.s3.amazonaws.com/eric/models/paintcan.fbx";
|
||||
|
||||
var sprayCan = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "spraycan",
|
||||
modelURL: modelURL,
|
||||
position: {x: 549.12, y:495.55, z:503.77},
|
||||
rotation: {x: 0, y: 0, z: 0, w: 1},
|
||||
dimensions: {
|
||||
x: 0.07,
|
||||
y: 0.17,
|
||||
z: 0.07
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
shapeType: 'box',
|
||||
script: scriptURL,
|
||||
gravity: {x: 0, y: -0.5, z: 0},
|
||||
velocity: {x: 0, y: -1, z: 0}
|
||||
});
|
||||
|
||||
function cleanup() {
|
||||
|
||||
// Uncomment the below line to delete sprayCan on script reload- for faster iteration during development
|
||||
// Entities.deleteEntity(sprayCan);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
BIN
examples/tests/dot.png
Normal file
BIN
examples/tests/dot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
46
examples/tests/overlayMouseTrackingTest.js
Normal file
46
examples/tests/overlayMouseTrackingTest.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
MouseTracker = function() {
|
||||
this.WIDTH = 60;
|
||||
this.HEIGHT = 60;
|
||||
|
||||
this.overlay = Overlays.addOverlay("image", {
|
||||
imageURL: Script.resolvePath("dot.png"),
|
||||
width: this.HEIGHT,
|
||||
height: this.WIDTH,
|
||||
x: 100,
|
||||
y: 100,
|
||||
visible: true
|
||||
});
|
||||
|
||||
var that = this;
|
||||
Script.scriptEnding.connect(function() {
|
||||
that.onCleanup();
|
||||
});
|
||||
|
||||
Controller.mousePressEvent.connect(function(event) {
|
||||
that.onMousePress(event);
|
||||
});
|
||||
|
||||
Controller.mouseMoveEvent.connect(function(event) {
|
||||
that.onMouseMove(event);
|
||||
});
|
||||
}
|
||||
|
||||
MouseTracker.prototype.onCleanup = function() {
|
||||
Overlays.deleteOverlay(this.overlay);
|
||||
}
|
||||
|
||||
MouseTracker.prototype.onMousePress = function(event) {
|
||||
}
|
||||
|
||||
MouseTracker.prototype.onMouseMove = function(event) {
|
||||
var width = Overlays.width();
|
||||
var height = Overlays.height();
|
||||
var x = Math.max(event.x, 0);
|
||||
x = Math.min(x, width);
|
||||
var y = Math.max(event.y, 0);
|
||||
y = Math.min(y, height);
|
||||
Overlays.editOverlay(this.overlay, {x: x - this.WIDTH / 2.0, y: y - this.HEIGHT / 2.0});
|
||||
}
|
||||
|
||||
|
||||
new MouseTracker();
|
52
examples/toys/cat.js
Normal file
52
examples/toys/cat.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// cat.js
|
||||
// examples/toybox/entityScripts
|
||||
//
|
||||
// Created by Eric Levin on 9/21/15.
|
||||
// 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
|
||||
/*global Cat, print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */
|
||||
|
||||
|
||||
(function() {
|
||||
|
||||
var _this;
|
||||
Cat = function() {
|
||||
_this = this;
|
||||
this.meowSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Animals/cat_meow.wav");
|
||||
};
|
||||
|
||||
Cat.prototype = {
|
||||
isMeowing: false,
|
||||
injector: null,
|
||||
startTouch: function() {
|
||||
if (this.isMeowing !== true) {
|
||||
this.meow();
|
||||
this.isMeowing = true;
|
||||
}
|
||||
|
||||
},
|
||||
meow: function() {
|
||||
this.injector = Audio.playSound(this.meowSound, {
|
||||
position: this.position,
|
||||
volume: 0.1
|
||||
});
|
||||
Script.setTimeout(function() {
|
||||
_this.isMeowing = false;
|
||||
}, this.soundClipTime);
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
this.position = Entities.getEntityProperties(this.entityID, "position").position;
|
||||
this.soundClipTime = 700;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new Cat();
|
||||
});
|
|
@ -15,21 +15,14 @@
|
|||
(function() {
|
||||
Script.include("../../utilities.js");
|
||||
Script.include("../../libraries/utils.js");
|
||||
|
||||
var _this;
|
||||
// this is the "constructor" for the entity as a JS object we don't do much here
|
||||
var Doll = function() {
|
||||
_this = this;
|
||||
this.screamSounds = [SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/KenDoll_1%2303.wav")];
|
||||
};
|
||||
|
||||
Doll.prototype = {
|
||||
startAnimationSetting: JSON.stringify({
|
||||
running: true,
|
||||
fps: 30,
|
||||
startFrame: 0,
|
||||
lastFrame: 128,
|
||||
startAutomatically: true
|
||||
}),
|
||||
stopAnimationSetting: JSON.stringify({running: false}),
|
||||
audioInjector: null,
|
||||
isGrabbed: false,
|
||||
setLeftHand: function() {
|
||||
|
@ -41,26 +34,27 @@
|
|||
},
|
||||
|
||||
startNearGrab: function() {
|
||||
if (this.isGrabbed === false) {
|
||||
Entities.editEntity(this.entityID, {
|
||||
animationURL: "https://hifi-public.s3.amazonaws.com/models/Bboys/zombie_scream.fbx",
|
||||
animationFrameIndex: 0
|
||||
});
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
animationURL: "https://hifi-public.s3.amazonaws.com/models/Bboys/zombie_scream.fbx",
|
||||
animationSettings: this.startAnimationSetting
|
||||
});
|
||||
Entities.editEntity(_this.entityID, {
|
||||
animationIsPlaying: true
|
||||
});
|
||||
|
||||
var position = Entities.getEntityProperties(this.entityID, "position").position;
|
||||
this.audioInjector = Audio.playSound(this.screamSounds[randInt(0, this.screamSounds.length)], {
|
||||
position: position,
|
||||
volume: 0.1
|
||||
});
|
||||
var position = Entities.getEntityProperties(this.entityID, "position").position;
|
||||
this.audioInjector = Audio.playSound(this.screamSounds[randInt(0, this.screamSounds.length)], {
|
||||
position: position,
|
||||
volume: 0.1
|
||||
});
|
||||
|
||||
this.isGrabbed = true;
|
||||
this.initialHand = this.hand;
|
||||
}
|
||||
this.isGrabbed = true;
|
||||
this.initialHand = this.hand;
|
||||
},
|
||||
|
||||
continueNearGrab: function() {
|
||||
var props = Entities.getEntityProperties(this.entityID, "position");
|
||||
var props = Entities.getEntityProperties(this.entityID, ["position"]);
|
||||
var audioOptions = {
|
||||
position: props.position
|
||||
};
|
||||
|
@ -69,24 +63,23 @@
|
|||
|
||||
releaseGrab: function() {
|
||||
if (this.isGrabbed === true && this.hand === this.initialHand) {
|
||||
|
||||
this.audioInjector.stop();
|
||||
Entities.editEntity(this.entityID, {
|
||||
animationFrameIndex: 0
|
||||
});
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
animationSettings: this.stopAnimationSetting,
|
||||
animationURL: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx",
|
||||
animationURL: "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx"
|
||||
});
|
||||
|
||||
this.isGrabbed = false;
|
||||
}
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
// preload() will be called when the entity has become visible (or known) to the interface
|
||||
// it gives us a chance to set our local JavaScript object up. In this case it means:
|
||||
// * remembering our entityID, so we can access it in cases where we're called without an entityID
|
||||
this.entityID = entityID;
|
||||
},
|
||||
};
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new Doll();
|
||||
});
|
||||
});
|
||||
|
|
202
examples/toys/lightSwitchGarage.js
Normal file
202
examples/toys/lightSwitchGarage.js
Normal file
|
@ -0,0 +1,202 @@
|
|||
//
|
||||
// lightSwitchGarage.js.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Eric Levin on 9/21/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
(function() {
|
||||
|
||||
var _this;
|
||||
|
||||
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
|
||||
// our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
|
||||
LightSwitchGarage = function() {
|
||||
_this = this;
|
||||
|
||||
this.lightStateKey = "lightStateKey";
|
||||
this.resetKey = "resetMe";
|
||||
|
||||
this.switchSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_2.wav");
|
||||
|
||||
};
|
||||
|
||||
LightSwitchGarage.prototype = {
|
||||
|
||||
clickReleaseOnEntity: function(entityID, mouseEvent) {
|
||||
if (!mouseEvent.isLeftButton) {
|
||||
return;
|
||||
}
|
||||
this.toggleLights();
|
||||
},
|
||||
|
||||
startNearGrabNonColliding: function() {
|
||||
this.toggleLights();
|
||||
},
|
||||
|
||||
toggleLights: function() {
|
||||
var defaultLightData = {
|
||||
on: false
|
||||
};
|
||||
var lightState = getEntityCustomData(this.lightStateKey, this.entityID, defaultLightData);
|
||||
if (lightState.on === true) {
|
||||
this.clearLights();
|
||||
} else if (lightState.on === false) {
|
||||
this.createLights();
|
||||
}
|
||||
|
||||
this.flipLights();
|
||||
|
||||
Audio.playSound(this.switchSound, {
|
||||
volume: 0.5,
|
||||
position: this.position
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
clearLights: function() {
|
||||
var entities = Entities.findEntities(MyAvatar.position, 100);
|
||||
var self = this;
|
||||
entities.forEach(function(entity) {
|
||||
var resetData = getEntityCustomData(self.resetKey, entity, {})
|
||||
if (resetData.resetMe === true && resetData.lightType === "Sconce Light Garage") {
|
||||
Entities.deleteEntity(entity);
|
||||
}
|
||||
});
|
||||
|
||||
setEntityCustomData(this.lightStateKey, this.entityID, {
|
||||
on: false
|
||||
});
|
||||
},
|
||||
|
||||
createLights: function() {
|
||||
|
||||
var sconceLight3 = Entities.addEntity({
|
||||
type: "Light",
|
||||
position: {
|
||||
x: 545.49468994140625,
|
||||
y: 496.24026489257812,
|
||||
z: 500.63516235351562
|
||||
},
|
||||
|
||||
name: "Sconce 3 Light",
|
||||
dimensions: {
|
||||
x: 2.545,
|
||||
y: 2.545,
|
||||
z: 2.545
|
||||
},
|
||||
cutoff: 90,
|
||||
color: {
|
||||
red: 217,
|
||||
green: 146,
|
||||
blue: 24
|
||||
}
|
||||
});
|
||||
|
||||
setEntityCustomData(this.resetKey, sconceLight3, {
|
||||
resetMe: true,
|
||||
lightType: "Sconce Light Garage"
|
||||
});
|
||||
|
||||
var sconceLight4 = Entities.addEntity({
|
||||
type: "Light",
|
||||
position: {
|
||||
x: 550.90399169921875,
|
||||
y: 496.24026489257812,
|
||||
z: 507.90237426757812
|
||||
},
|
||||
name: "Sconce 4 Light",
|
||||
dimensions: {
|
||||
x: 2.545,
|
||||
y: 2.545,
|
||||
z: 2.545
|
||||
},
|
||||
cutoff: 90,
|
||||
color: {
|
||||
red: 217,
|
||||
green: 146,
|
||||
blue: 24
|
||||
}
|
||||
});
|
||||
|
||||
setEntityCustomData(this.resetKey, sconceLight4, {
|
||||
resetMe: true,
|
||||
lightType: "Sconce Light Garage"
|
||||
});
|
||||
|
||||
var sconceLight5 = Entities.addEntity({
|
||||
type: "Light",
|
||||
position: {
|
||||
x: 548.407958984375,
|
||||
y: 496.24026489257812,
|
||||
z: 509.5504150390625
|
||||
},
|
||||
name: "Sconce 5 Light",
|
||||
dimensions: {
|
||||
x: 2.545,
|
||||
y: 2.545,
|
||||
z: 2.545
|
||||
},
|
||||
cutoff: 90,
|
||||
color: {
|
||||
red: 217,
|
||||
green: 146,
|
||||
blue: 24
|
||||
}
|
||||
});
|
||||
|
||||
setEntityCustomData(this.resetKey, sconceLight5, {
|
||||
resetMe: true,
|
||||
lightType: "Sconce Light Garage"
|
||||
});
|
||||
|
||||
setEntityCustomData(this.lightStateKey, this.entityID, {
|
||||
on: true
|
||||
});
|
||||
},
|
||||
|
||||
flipLights: function() {
|
||||
// flip model to give illusion of light switch being flicked
|
||||
var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation;
|
||||
var axis = {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
};
|
||||
var dQ = Quat.angleAxis(180, axis);
|
||||
rotation = Quat.multiply(rotation, dQ);
|
||||
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
rotation: rotation
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
|
||||
//The light switch is static, so just cache its position once
|
||||
this.position = Entities.getEntityProperties(this.entityID, "position").position;
|
||||
var defaultLightData = {
|
||||
on: false
|
||||
};
|
||||
var lightState = getEntityCustomData(this.lightStateKey, this.entityID, defaultLightData);
|
||||
|
||||
//If light is off, then we create two new lights- at the position of the sconces
|
||||
if (lightState.on === false) {
|
||||
this.createLights();
|
||||
this.flipLights();
|
||||
}
|
||||
//If lights are on, do nothing!
|
||||
},
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new LightSwitchGarage();
|
||||
})
|
179
examples/toys/lightSwitchHall.js
Normal file
179
examples/toys/lightSwitchHall.js
Normal file
|
@ -0,0 +1,179 @@
|
|||
//
|
||||
// lightSwitchHall.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Eric Levin on 9/21/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
(function() {
|
||||
|
||||
var _this;
|
||||
|
||||
|
||||
// this is the "constructor" for the entity as a JS object we don't do much here, but we do want to remember
|
||||
// our this object, so we can access it in cases where we're called without a this (like in the case of various global signals)
|
||||
LightSwitchHall = function() {
|
||||
_this = this;
|
||||
|
||||
this.lightStateKey = "lightStateKey";
|
||||
this.resetKey = "resetMe";
|
||||
|
||||
this.switchSound = SoundCache.getSound("https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_2.wav");
|
||||
};
|
||||
|
||||
LightSwitchHall.prototype = {
|
||||
|
||||
clickReleaseOnEntity: function(entityId, mouseEvent) {
|
||||
if (!mouseEvent.isLeftButton) {
|
||||
return;
|
||||
}
|
||||
this.toggleLights();
|
||||
},
|
||||
|
||||
startNearGrabNonColliding: function() {
|
||||
this.toggleLights();
|
||||
},
|
||||
|
||||
toggleLights: function() {
|
||||
var defaultLightData = {
|
||||
on: false
|
||||
};
|
||||
var lightState = getEntityCustomData(this.lightStateKey, this.entityID, defaultLightData);
|
||||
if (lightState.on === true) {
|
||||
this.clearLights();
|
||||
} else if (lightState.on === false) {
|
||||
this.createLights();
|
||||
}
|
||||
|
||||
// flip model to give illusion of light switch being flicked
|
||||
this.flipLights();
|
||||
|
||||
Audio.playSound(this.switchSound, {
|
||||
volume: 0.5,
|
||||
position: this.position
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
clearLights: function() {
|
||||
var entities = Entities.findEntities(MyAvatar.position, 100);
|
||||
var self = this;
|
||||
entities.forEach(function(entity) {
|
||||
var resetData = getEntityCustomData(self.resetKey, entity, {})
|
||||
if (resetData.resetMe === true && resetData.lightType === "Sconce Light Hall") {
|
||||
Entities.deleteEntity(entity);
|
||||
}
|
||||
});
|
||||
|
||||
setEntityCustomData(this.lightStateKey, this.entityID, {
|
||||
on: false
|
||||
});
|
||||
},
|
||||
|
||||
createLights: function() {
|
||||
var sconceLight1 = Entities.addEntity({
|
||||
type: "Light",
|
||||
position: {
|
||||
x: 543.75,
|
||||
y: 496.24,
|
||||
z: 511.13
|
||||
},
|
||||
name: "Sconce 1 Light",
|
||||
dimensions: {
|
||||
x: 2.545,
|
||||
y: 2.545,
|
||||
z: 2.545
|
||||
},
|
||||
cutoff: 90,
|
||||
color: {
|
||||
red: 217,
|
||||
green: 146,
|
||||
blue: 24
|
||||
}
|
||||
});
|
||||
|
||||
setEntityCustomData(this.resetKey, sconceLight1, {
|
||||
resetMe: true,
|
||||
lightType: "Sconce Light Hall"
|
||||
});
|
||||
|
||||
var sconceLight2 = Entities.addEntity({
|
||||
type: "Light",
|
||||
position: {
|
||||
x: 540.1,
|
||||
y: 496.24,
|
||||
z: 505.57
|
||||
},
|
||||
name: "Sconce 2 Light",
|
||||
dimensions: {
|
||||
x: 2.545,
|
||||
y: 2.545,
|
||||
z: 2.545
|
||||
},
|
||||
cutoff: 90,
|
||||
color: {
|
||||
red: 217,
|
||||
green: 146,
|
||||
blue: 24
|
||||
}
|
||||
});
|
||||
|
||||
setEntityCustomData(this.resetKey, sconceLight2, {
|
||||
resetMe: true,
|
||||
lightType: "Sconce Light Hall"
|
||||
});
|
||||
|
||||
setEntityCustomData(this.lightStateKey, this.entityID, {
|
||||
on: true
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
flipLights: function() {
|
||||
// flip model to give illusion of light switch being flicked
|
||||
var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation;
|
||||
var axis = {
|
||||
x: 0,
|
||||
y: 1,
|
||||
z: 0
|
||||
};
|
||||
var dQ = Quat.angleAxis(180, axis);
|
||||
rotation = Quat.multiply(rotation, dQ);
|
||||
|
||||
|
||||
Entities.editEntity(this.entityID, {
|
||||
rotation: rotation
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
// preload() will be called when the entity has become visible (or known) to the interface
|
||||
// it gives us a chance to set our local JavaScript object up. In this case it means:
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
|
||||
//The light switch is static, so just cache its position once
|
||||
this.position = Entities.getEntityProperties(this.entityID, "position").position;
|
||||
var defaultLightData = {
|
||||
on: false
|
||||
};
|
||||
var lightState = getEntityCustomData(this.lightStateKey, this.entityID, defaultLightData);
|
||||
|
||||
//If light is off, then we create two new lights- at the position of the sconces
|
||||
if (lightState.on === false) {
|
||||
this.createLights();
|
||||
this.flipLights();
|
||||
|
||||
}
|
||||
//If lights are on, do nothing!
|
||||
},
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new LightSwitchHall();
|
||||
})
|
162
examples/toys/sprayPaintCan.js
Normal file
162
examples/toys/sprayPaintCan.js
Normal file
|
@ -0,0 +1,162 @@
|
|||
//
|
||||
// sprayPaintCan.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Eric Levin on 9/21/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
|
||||
(function() {
|
||||
// Script.include("../libraries/utils.js");
|
||||
//Need absolute path for now, for testing before PR merge and s3 cloning. Will change post-merge
|
||||
|
||||
Script.include("../libraries/utils.js");
|
||||
|
||||
this.spraySound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/sprayPaintSound.wav");
|
||||
|
||||
var TIP_OFFSET_Z = 0.02;
|
||||
var TIP_OFFSET_Y = 0.08;
|
||||
|
||||
var ZERO_VEC = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
};
|
||||
|
||||
// if the trigger value goes below this while held, the can will stop spraying. if it goes above, it will spray
|
||||
var DISABLE_SPRAY_THRESHOLD = 0.5;
|
||||
|
||||
var MAX_POINTS_PER_LINE = 40;
|
||||
var MIN_POINT_DISTANCE = 0.01;
|
||||
var STROKE_WIDTH = 0.02;
|
||||
|
||||
this.setRightHand = function() {
|
||||
this.hand = 'RIGHT';
|
||||
}
|
||||
|
||||
this.setLeftHand = function() {
|
||||
this.hand = 'LEFT';
|
||||
}
|
||||
|
||||
this.startNearGrab = function() {
|
||||
this.whichHand = this.hand;
|
||||
}
|
||||
|
||||
this.toggleWithTriggerPressure = function() {
|
||||
var handClickString = this.whichHand + "_HAND_CLICK";
|
||||
|
||||
var handClick = Controller.findAction(handClickString);
|
||||
|
||||
this.triggerValue = Controller.getActionValue(handClick);
|
||||
if (this.triggerValue < DISABLE_SPRAY_THRESHOLD && this.spraying === true) {
|
||||
this.spraying = false;
|
||||
this.disableStream();
|
||||
} else if (this.triggerValue >= DISABLE_SPRAY_THRESHOLD && this.spraying === false) {
|
||||
this.spraying = true;
|
||||
this.enableStream();
|
||||
}
|
||||
}
|
||||
|
||||
this.enableStream = function() {
|
||||
var position = Entities.getEntityProperties(this.entityId, "position").position;
|
||||
var animationSettings = JSON.stringify({
|
||||
fps: 30,
|
||||
loop: true,
|
||||
firstFrame: 1,
|
||||
lastFrame: 10000,
|
||||
running: true
|
||||
});
|
||||
var PI = 3.141593;
|
||||
var DEG_TO_RAD = PI / 180.0;
|
||||
|
||||
this.paintStream = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
name: "streamEffect",
|
||||
animationSettings: animationSettings,
|
||||
position: position,
|
||||
textures: "https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png",
|
||||
emitSpeed: 3,
|
||||
speedSpread: 0.02,
|
||||
emitAcceleration: ZERO_VEC,
|
||||
emitRate: 100,
|
||||
particleRadius: 0.01,
|
||||
radiusSpread: 0.005,
|
||||
polarFinish: 0.05,
|
||||
color: {
|
||||
red: 170,
|
||||
green: 20,
|
||||
blue: 150
|
||||
},
|
||||
lifetime: 50, //probably wont be holding longer than this straight
|
||||
});
|
||||
|
||||
setEntityCustomData(this.resetKey, this.paintStream, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
this.sprayInjector = Audio.playSound(this.spraySound, {
|
||||
position: position,
|
||||
volume: this.sprayVolume,
|
||||
loop: true
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
this.releaseGrab = function() {
|
||||
this.disableStream();
|
||||
}
|
||||
|
||||
this.disableStream = function() {
|
||||
Entities.deleteEntity(this.paintStream);
|
||||
this.paintStream = null;
|
||||
this.spraying = false;
|
||||
this.sprayInjector.stop();
|
||||
}
|
||||
|
||||
|
||||
this.continueNearGrab = function() {
|
||||
|
||||
this.toggleWithTriggerPressure();
|
||||
|
||||
if (this.spraying === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
var props = Entities.getEntityProperties(this.entityId, ["position, rotation"]);
|
||||
var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(0, 90, 0)));
|
||||
forwardVec = Vec3.normalize(forwardVec);
|
||||
var forwardQuat = orientationOf(forwardVec);
|
||||
var upVec = Quat.getUp(props.rotation);
|
||||
var position = Vec3.sum(props.position, Vec3.multiply(forwardVec, TIP_OFFSET_Z));
|
||||
position = Vec3.sum(position, Vec3.multiply(upVec, TIP_OFFSET_Y))
|
||||
Entities.editEntity(this.paintStream, {
|
||||
position: position,
|
||||
emitOrientation: forwardQuat,
|
||||
});
|
||||
|
||||
this.sprayInjector.setOptions({
|
||||
position: position,
|
||||
volume: this.sprayVolume
|
||||
});
|
||||
}
|
||||
|
||||
this.preload = function(entityId) {
|
||||
this.sprayVolume = 0.1;
|
||||
this.spraying = false;
|
||||
this.entityId = entityId;
|
||||
this.resetKey = "resetMe";
|
||||
}
|
||||
|
||||
|
||||
this.unload = function() {
|
||||
if (this.paintStream) {
|
||||
Entities.deleteEntity(this.paintStream);
|
||||
}
|
||||
this.strokes.forEach(function(stroke) {
|
||||
Entities.deleteEntity(stroke);
|
||||
});
|
||||
}
|
||||
});
|
|
@ -1849,8 +1849,16 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
|
||||
|
||||
_entities.mouseMoveEvent(event, deviceID);
|
||||
{
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget);
|
||||
QMouseEvent mappedEvent(event->type(),
|
||||
transformedPos,
|
||||
event->screenPos(), event->button(),
|
||||
event->buttons(), event->modifiers());
|
||||
_controllerScriptingInterface.emitMouseMoveEvent(&mappedEvent, deviceID); // send events to any registered scripts
|
||||
}
|
||||
|
||||
_controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isMouseCaptured()) {
|
||||
return;
|
||||
|
@ -1865,12 +1873,19 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) {
|
||||
// Inhibit the menu if the user is using alt-mouse dragging
|
||||
_altPressed = false;
|
||||
|
||||
if (!_aboutToQuit) {
|
||||
_entities.mousePressEvent(event, deviceID);
|
||||
}
|
||||
|
||||
_controllerScriptingInterface.emitMousePressEvent(event); // send events to any registered scripts
|
||||
{
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget);
|
||||
QMouseEvent mappedEvent(event->type(),
|
||||
transformedPos,
|
||||
event->screenPos(), event->button(),
|
||||
event->buttons(), event->modifiers());
|
||||
_controllerScriptingInterface.emitMousePressEvent(&mappedEvent); // send events to any registered scripts
|
||||
}
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isMouseCaptured()) {
|
||||
|
@ -1921,7 +1936,15 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) {
|
|||
_entities.mouseReleaseEvent(event, deviceID);
|
||||
}
|
||||
|
||||
_controllerScriptingInterface.emitMouseReleaseEvent(event); // send events to any registered scripts
|
||||
{
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
QPointF transformedPos = offscreenUi->mapToVirtualScreen(event->localPos(), _glWidget);
|
||||
QMouseEvent mappedEvent(event->type(),
|
||||
transformedPos,
|
||||
event->screenPos(), event->button(),
|
||||
event->buttons(), event->modifiers());
|
||||
_controllerScriptingInterface.emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts
|
||||
}
|
||||
|
||||
// if one of our scripts have asked to capture this event, then stop processing it
|
||||
if (_controllerScriptingInterface.isMouseCaptured()) {
|
||||
|
|
|
@ -141,6 +141,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) {
|
|||
auto state = gpu::StatePointer(new gpu::State());
|
||||
// enable decal blend
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_gridPipeline.reset(gpu::Pipeline::create(program, state));
|
||||
}
|
||||
|
@ -152,6 +153,7 @@ void Stars::render(RenderArgs* renderArgs, float alpha) {
|
|||
auto state = gpu::StatePointer(new gpu::State());
|
||||
// enable decal blend
|
||||
state->setDepthTest(gpu::State::DepthTest(false));
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
state->setAntialiasedLineEnable(true); // line smoothing also smooth points
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA);
|
||||
_starsPipeline.reset(gpu::Pipeline::create(program, state));
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "Overlays.h"
|
||||
|
||||
#include <QScriptValueIterator>
|
||||
#include <QtScript/QScriptValueIterator>
|
||||
|
||||
#include <limits>
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
|||
#include "TextOverlay.h"
|
||||
#include "Text3DOverlay.h"
|
||||
#include "Web3DOverlay.h"
|
||||
#include <QtQuick/QQuickWindow>
|
||||
|
||||
|
||||
Overlays::Overlays() : _nextOverlayID(1) {
|
||||
|
@ -331,10 +332,6 @@ void Overlays::setParentPanel(unsigned int childId, unsigned int panelId) {
|
|||
|
||||
unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
||||
glm::vec2 pointCopy = point;
|
||||
if (qApp->isHMDMode()) {
|
||||
pointCopy = qApp->getApplicationCompositor().screenToOverlay(point);
|
||||
}
|
||||
|
||||
QReadLocker lock(&_lock);
|
||||
if (!_enabled) {
|
||||
return 0;
|
||||
|
@ -607,3 +604,13 @@ void Overlays::deletePanel(unsigned int panelId) {
|
|||
bool Overlays::isAddedOverlay(unsigned int id) {
|
||||
return _overlaysHUD.contains(id) || _overlaysWorld.contains(id);
|
||||
}
|
||||
|
||||
float Overlays::width() const {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
return offscreenUi->getWindow()->size().width();
|
||||
}
|
||||
|
||||
float Overlays::height() const {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
return offscreenUi->getWindow()->size().height();
|
||||
}
|
|
@ -113,6 +113,10 @@ public slots:
|
|||
/// overlay; in meters if it is a 3D text overlay
|
||||
QSizeF textSize(unsigned int id, const QString& text) const;
|
||||
|
||||
// Return the size of the virtual screen
|
||||
float width() const;
|
||||
float height() const;
|
||||
|
||||
|
||||
/// adds a panel that has already been created
|
||||
unsigned int addPanel(OverlayPanel::Pointer panel);
|
||||
|
|
|
@ -1573,14 +1573,17 @@ void EntityItemProperties::markAllChanged() {
|
|||
_accelerationSpreadChanged = true;
|
||||
_particleRadiusChanged = true;
|
||||
_radiusSpreadChanged = true;
|
||||
_radiusStartChanged = true;
|
||||
_radiusFinishChanged = true;
|
||||
_colorSpreadChanged = true;
|
||||
_colorStartChanged = true;
|
||||
_colorFinishChanged = true;
|
||||
_alphaSpreadChanged = true;
|
||||
_alphaStartChanged = true;
|
||||
_alphaFinishChanged = true;
|
||||
|
||||
// Only mark the following as changed if their values are specified in the properties when the particle is created. If their
|
||||
// values are specified then they are marked as changed in getChangedProperties().
|
||||
//_radiusStartChanged = true;
|
||||
//_radiusFinishChanged = true;
|
||||
//_colorStartChanged = true;
|
||||
//_colorFinishChanged = true;
|
||||
//_alphaStartChanged = true;
|
||||
//_alphaFinishChanged = true;
|
||||
|
||||
_marketplaceIDChanged = true;
|
||||
|
||||
|
|
|
@ -177,12 +177,12 @@ public:
|
|||
float getParticleRadius() const { return _particleRadius; }
|
||||
|
||||
static const float DEFAULT_RADIUS_START;
|
||||
bool _isRadiusStartInitialized;
|
||||
bool _isRadiusStartInitialized = false;
|
||||
void setRadiusStart(float radiusStart) { _radiusStart = radiusStart; _isRadiusStartInitialized = true; }
|
||||
float getRadiusStart() const { return _isRadiusStartInitialized ? _radiusStart : _particleRadius; }
|
||||
|
||||
static const float DEFAULT_RADIUS_FINISH;
|
||||
bool _isRadiusFinishInitialized;
|
||||
bool _isRadiusFinishInitialized = false;
|
||||
void setRadiusFinish(float radiusFinish) { _radiusFinish = radiusFinish; _isRadiusFinishInitialized = true; }
|
||||
float getRadiusFinish() const { return _isRadiusFinishInitialized ? _radiusFinish : _particleRadius; }
|
||||
|
||||
|
|
28
libraries/gpu/src/gpu/DrawUnitQuadTexcoord.slv
Normal file
28
libraries/gpu/src/gpu/DrawUnitQuadTexcoord.slv
Normal file
|
@ -0,0 +1,28 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// Draw the unit quad [-1,-1 -> 1,1] amd pass along the unit texcoords [0, 0 -> 1, 1]. Not transform used.
|
||||
// Simply draw a Triangle_strip of 2 triangles, no input buffers or index buffer needed
|
||||
//
|
||||
// Created by Sam Gateau on 6/22/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
|
||||
//
|
||||
out vec2 varTexCoord0;
|
||||
|
||||
void main(void) {
|
||||
const vec4 UNIT_QUAD[4] = vec4[4](
|
||||
vec4(-1.0, -1.0, 0.0, 1.0),
|
||||
vec4(1.0, -1.0, 0.0, 1.0),
|
||||
vec4(-1.0, 1.0, 0.0, 1.0),
|
||||
vec4(1.0, 1.0, 0.0, 1.0)
|
||||
);
|
||||
vec4 pos = UNIT_QUAD[gl_VertexID];
|
||||
|
||||
varTexCoord0 = (pos.xy + 1) * 0.5;
|
||||
|
||||
gl_Position = pos;
|
||||
}
|
|
@ -247,7 +247,13 @@ bool Framebuffer::setDepthStencilBuffer(const TexturePointer& texture, const For
|
|||
|
||||
_bufferMask = ( _bufferMask & ~BUFFER_DEPTHSTENCIL);
|
||||
if (texture) {
|
||||
_bufferMask |= BUFFER_DEPTHSTENCIL;
|
||||
if (format.getSemantic() == gpu::DEPTH) {
|
||||
_bufferMask |= BUFFER_DEPTH;
|
||||
} else if (format.getSemantic() == gpu::STENCIL) {
|
||||
_bufferMask |= BUFFER_STENCIL;
|
||||
} else if (format.getSemantic() == gpu::DEPTH_STENCIL) {
|
||||
_bufferMask |= BUFFER_DEPTHSTENCIL;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -116,6 +116,8 @@ public:
|
|||
bool isEmpty() const { return (_bufferMask == 0); }
|
||||
bool hasColor() const { return (getBufferMask() & BUFFER_COLORS); }
|
||||
bool hasDepthStencil() const { return (getBufferMask() & BUFFER_DEPTHSTENCIL); }
|
||||
bool hasDepth() const { return (getBufferMask() & BUFFER_DEPTH); }
|
||||
bool hasStencil() const { return (getBufferMask() & BUFFER_STENCIL); }
|
||||
|
||||
bool validateTargetCompatibility(const Texture& texture, uint32 subresource = 0) const;
|
||||
|
||||
|
|
|
@ -132,20 +132,26 @@ void GLBackend::renderPassTransfer(Batch& batch) {
|
|||
const size_t numCommands = batch.getCommands().size();
|
||||
const Batch::Commands::value_type* command = batch.getCommands().data();
|
||||
const Batch::CommandOffsets::value_type* offset = batch.getCommandOffsets().data();
|
||||
|
||||
for (auto& cached : batch._buffers._items) {
|
||||
if (cached._data) {
|
||||
syncGPUObject(*cached._data);
|
||||
|
||||
{ // Sync all the buffers
|
||||
PROFILE_RANGE("syncGPUBuffer");
|
||||
|
||||
for (auto& cached : batch._buffers._items) {
|
||||
if (cached._data) {
|
||||
syncGPUObject(*cached._data);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Reset the transform buffers
|
||||
_transform._cameras.resize(0);
|
||||
_transform._cameraOffsets.clear();
|
||||
_transform._objects.resize(0);
|
||||
_transform._objectOffsets.clear();
|
||||
|
||||
for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) {
|
||||
switch (*command) {
|
||||
{ // Sync all the buffers
|
||||
PROFILE_RANGE("syncCPUTransform");
|
||||
_transform._cameras.resize(0);
|
||||
_transform._cameraOffsets.clear();
|
||||
_transform._objects.resize(0);
|
||||
_transform._objectOffsets.clear();
|
||||
|
||||
for (_commandIndex = 0; _commandIndex < numCommands; ++_commandIndex) {
|
||||
switch (*command) {
|
||||
case Batch::COMMAND_draw:
|
||||
case Batch::COMMAND_drawIndexed:
|
||||
case Batch::COMMAND_drawInstanced:
|
||||
|
@ -164,11 +170,16 @@ void GLBackend::renderPassTransfer(Batch& batch) {
|
|||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
command++;
|
||||
offset++;
|
||||
}
|
||||
command++;
|
||||
offset++;
|
||||
}
|
||||
_transform.transfer();
|
||||
|
||||
{ // Sync the transform buffers
|
||||
PROFILE_RANGE("syncGPUTransform");
|
||||
_transform.transfer();
|
||||
}
|
||||
}
|
||||
|
||||
void GLBackend::renderPassDraw(Batch& batch) {
|
||||
|
|
|
@ -100,7 +100,18 @@ GLBackend::GLFramebuffer* GLBackend::syncGPUObject(const Framebuffer& framebuffe
|
|||
if (surface) {
|
||||
auto gltexture = GLBackend::syncGPUObject(*surface);
|
||||
if (gltexture) {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, gltexture->_texture, 0);
|
||||
GLenum attachement = GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
if (!framebuffer.hasStencil()) {
|
||||
attachement = GL_DEPTH_ATTACHMENT;
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0);
|
||||
} else if (!framebuffer.hasDepth()) {
|
||||
attachement = GL_STENCIL_ATTACHMENT;
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, attachement, GL_TEXTURE_2D, gltexture->_texture, 0);
|
||||
} else {
|
||||
attachement = GL_DEPTH_STENCIL_ATTACHMENT;
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachement, GL_RENDERBUFFER, gltexture->_texture);
|
||||
}
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -642,8 +642,13 @@ void GLBackend::do_setStateStencil(State::StencilActivation activation, State::S
|
|||
|
||||
if (activation.isEnabled()) {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilMaskSeparate(GL_FRONT, activation.getWriteMaskFront());
|
||||
glStencilMaskSeparate(GL_BACK, activation.getWriteMaskBack());
|
||||
|
||||
if (activation.getWriteMaskFront() != activation.getWriteMaskBack()) {
|
||||
glStencilMaskSeparate(GL_FRONT, activation.getWriteMaskFront());
|
||||
glStencilMaskSeparate(GL_BACK, activation.getWriteMaskBack());
|
||||
} else {
|
||||
glStencilMask(activation.getWriteMaskFront());
|
||||
}
|
||||
|
||||
static GLenum STENCIL_OPS[] = {
|
||||
GL_KEEP,
|
||||
|
@ -655,11 +660,16 @@ void GLBackend::do_setStateStencil(State::StencilActivation activation, State::S
|
|||
GL_INCR,
|
||||
GL_DECR };
|
||||
|
||||
glStencilFuncSeparate(GL_FRONT, STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]);
|
||||
glStencilFuncSeparate(GL_FRONT, GL_COMPARISON_FUNCTIONS[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask());
|
||||
if (frontTest != backTest) {
|
||||
glStencilOpSeparate(GL_FRONT, STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]);
|
||||
glStencilFuncSeparate(GL_FRONT, GL_COMPARISON_FUNCTIONS[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask());
|
||||
|
||||
glStencilFuncSeparate(GL_BACK, STENCIL_OPS[backTest.getFailOp()], STENCIL_OPS[backTest.getPassOp()], STENCIL_OPS[backTest.getDepthFailOp()]);
|
||||
glStencilFuncSeparate(GL_BACK, GL_COMPARISON_FUNCTIONS[backTest.getFunction()], backTest.getReference(), backTest.getReadMask());
|
||||
glStencilOpSeparate(GL_BACK, STENCIL_OPS[backTest.getFailOp()], STENCIL_OPS[backTest.getPassOp()], STENCIL_OPS[backTest.getDepthFailOp()]);
|
||||
glStencilFuncSeparate(GL_BACK, GL_COMPARISON_FUNCTIONS[backTest.getFunction()], backTest.getReference(), backTest.getReadMask());
|
||||
} else {
|
||||
glStencilOp(STENCIL_OPS[frontTest.getFailOp()], STENCIL_OPS[frontTest.getPassOp()], STENCIL_OPS[frontTest.getDepthFailOp()]);
|
||||
glStencilFunc(GL_COMPARISON_FUNCTIONS[frontTest.getFunction()], frontTest.getReference(), frontTest.getReadMask());
|
||||
}
|
||||
} else {
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
|
|
|
@ -66,7 +66,9 @@ public:
|
|||
texel.internalFormat = GL_RG;
|
||||
break;
|
||||
case gpu::DEPTH_STENCIL:
|
||||
texel.internalFormat = GL_DEPTH_STENCIL;
|
||||
texel.type = GL_UNSIGNED_BYTE;
|
||||
texel.format = GL_DEPTH_STENCIL;
|
||||
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
|
@ -197,7 +199,9 @@ public:
|
|||
texel.internalFormat = GL_RG;
|
||||
break;
|
||||
case gpu::DEPTH_STENCIL:
|
||||
texel.internalFormat = GL_DEPTH_STENCIL;
|
||||
texel.type = GL_UNSIGNED_BYTE;
|
||||
texel.format = GL_DEPTH_STENCIL;
|
||||
texel.internalFormat = GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
|
@ -334,22 +338,34 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
|||
}
|
||||
|
||||
GLTexelFormat texelFormat = GLTexelFormat::evalGLTexelFormat(texture.getTexelFormat(), srcFormat);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0,
|
||||
texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0,
|
||||
texelFormat.format, texelFormat.type, bytes);
|
||||
|
||||
if (bytes && texture.isAutogenerateMips()) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}/* else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
}*/
|
||||
|
||||
object->_target = GL_TEXTURE_2D;
|
||||
auto semantic = texture.getTexelFormat().getSemantic();
|
||||
|
||||
syncSampler(texture.getSampler(), texture.getType(), object);
|
||||
if (semantic == gpu::DEPTH_STENCIL) {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDeleteTextures(1, &object->_texture);
|
||||
|
||||
glGenRenderbuffers(1, &object->_texture);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, object->_texture);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, texture.getWidth(), texture.getHeight());
|
||||
// At this point the mip pixels have been loaded, we can notify
|
||||
texture.notifyMipFaceGPULoaded(0, 0);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
|
||||
} else {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0,
|
||||
texelFormat.internalFormat, texture.getWidth(), texture.getHeight(), 0,
|
||||
texelFormat.format, texelFormat.type, bytes);
|
||||
|
||||
if (bytes && texture.isAutogenerateMips()) {
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
|
||||
object->_target = GL_TEXTURE_2D;
|
||||
|
||||
syncSampler(texture.getSampler(), texture.getType(), object);
|
||||
}
|
||||
|
||||
// At this point the mip pixels have been loaded, we can notify
|
||||
texture.notifyMipFaceGPULoaded(0, 0);
|
||||
|
|
|
@ -130,19 +130,27 @@ void GLBackend::TransformStageState::preUpdate(size_t commandIndex, const Stereo
|
|||
|
||||
void GLBackend::TransformStageState::transfer() const {
|
||||
static QByteArray bufferData;
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _cameraBuffer);
|
||||
bufferData.resize(_cameraUboSize * _cameras.size());
|
||||
for (size_t i = 0; i < _cameras.size(); ++i) {
|
||||
memcpy(bufferData.data() + (_cameraUboSize * i), &_cameras[i], sizeof(TransformCamera));
|
||||
if (!_cameras.empty()) {
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _cameraBuffer);
|
||||
bufferData.resize(_cameraUboSize * _cameras.size());
|
||||
for (size_t i = 0; i < _cameras.size(); ++i) {
|
||||
memcpy(bufferData.data() + (_cameraUboSize * i), &_cameras[i], sizeof(TransformCamera));
|
||||
}
|
||||
glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
|
||||
}
|
||||
glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _objectBuffer);
|
||||
bufferData.resize(_objectUboSize * _objects.size());
|
||||
for (size_t i = 0; i < _objects.size(); ++i) {
|
||||
memcpy(bufferData.data() + (_objectUboSize * i), &_objects[i], sizeof(TransformObject));
|
||||
|
||||
if (!_objects.empty()) {
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, _objectBuffer);
|
||||
bufferData.resize(_objectUboSize * _objects.size());
|
||||
for (size_t i = 0; i < _objects.size(); ++i) {
|
||||
memcpy(bufferData.data() + (_objectUboSize * i), &_objects[i], sizeof(TransformObject));
|
||||
}
|
||||
glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
|
||||
}
|
||||
|
||||
if (!_cameras.empty() || !_objects.empty()) {
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
}
|
||||
glBufferData(GL_UNIFORM_BUFFER, bufferData.size(), bufferData.data(), GL_DYNAMIC_DRAW);
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, 0);
|
||||
CHECK_GL_ERROR();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
//
|
||||
#include "StandardShaderLib.h"
|
||||
|
||||
#include "DrawUnitQuadTexcoord_vert.h"
|
||||
#include "DrawTransformUnitQuad_vert.h"
|
||||
#include "DrawTexcoordRectTransformUnitQuad_vert.h"
|
||||
#include "DrawViewportQuadTransformTexcoord_vert.h"
|
||||
|
@ -21,6 +22,7 @@
|
|||
|
||||
using namespace gpu;
|
||||
|
||||
ShaderPointer StandardShaderLib::_drawUnitQuadTexcoordVS;
|
||||
ShaderPointer StandardShaderLib::_drawTransformUnitQuadVS;
|
||||
ShaderPointer StandardShaderLib::_drawTexcoordRectTransformUnitQuadVS;
|
||||
ShaderPointer StandardShaderLib::_drawViewportQuadTransformTexcoordVS;
|
||||
|
@ -55,6 +57,12 @@ ShaderPointer StandardShaderLib::getProgram(GetShader getVS, GetShader getPS) {
|
|||
}
|
||||
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawUnitQuadTexcoordVS() {
|
||||
if (!_drawUnitQuadTexcoordVS) {
|
||||
_drawUnitQuadTexcoordVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(DrawUnitQuadTexcoord_vert)));
|
||||
}
|
||||
return _drawUnitQuadTexcoordVS;
|
||||
}
|
||||
|
||||
ShaderPointer StandardShaderLib::getDrawTransformUnitQuadVS() {
|
||||
if (!_drawTransformUnitQuadVS) {
|
||||
|
|
|
@ -23,6 +23,9 @@ namespace gpu {
|
|||
class StandardShaderLib {
|
||||
public:
|
||||
|
||||
// Shader draws the unit quad in the full viewport clipPos = ([(-1,-1),(1,1)]) and the unit texcoord = [(0,0),(1,1)].
|
||||
static ShaderPointer getDrawUnitQuadTexcoordVS();
|
||||
|
||||
// Shader draw the unit quad objectPos = ([(-1,-1),(1,1)]) and transform it by the full model transform stack (Model, View, Proj).
|
||||
// A texcoord attribute is also generated texcoord = [(0,0),(1,1)]
|
||||
static ShaderPointer getDrawTransformUnitQuadVS();
|
||||
|
@ -44,6 +47,7 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
static ShaderPointer _drawUnitQuadTexcoordVS;
|
||||
static ShaderPointer _drawTransformUnitQuadVS;
|
||||
static ShaderPointer _drawTexcoordRectTransformUnitQuadVS;
|
||||
static ShaderPointer _drawViewportQuadTransformTexcoordVS;
|
||||
|
|
|
@ -143,11 +143,11 @@ public:
|
|||
static const int PASS_OP_OFFSET = 12;
|
||||
|
||||
uint16 _functionAndOperations;
|
||||
uint8 _reference = 0;
|
||||
int8 _reference = 0;
|
||||
uint8 _readMask = 0xff;
|
||||
public:
|
||||
|
||||
StencilTest(uint8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) :
|
||||
StencilTest(int8 reference = 0, uint8 readMask =0xFF, ComparisonFunction func = ALWAYS, StencilOp failOp = STENCIL_OP_KEEP, StencilOp depthFailOp = STENCIL_OP_KEEP, StencilOp passOp = STENCIL_OP_KEEP) :
|
||||
_functionAndOperations(func | (failOp << FAIL_OP_OFFSET) | (depthFailOp << DEPTH_FAIL_OP_OFFSET) | (passOp << PASS_OP_OFFSET)),
|
||||
_reference(reference), _readMask(readMask)
|
||||
{}
|
||||
|
@ -157,7 +157,7 @@ public:
|
|||
StencilOp getDepthFailOp() const { return StencilOp((_functionAndOperations & DEPTH_FAIL_OP_MASK) >> DEPTH_FAIL_OP_OFFSET); }
|
||||
StencilOp getPassOp() const { return StencilOp((_functionAndOperations & PASS_OP_MASK) >> PASS_OP_OFFSET); }
|
||||
|
||||
uint8 getReference() const { return _reference; }
|
||||
int8 getReference() const { return _reference; }
|
||||
uint8 getReadMask() const { return _readMask; }
|
||||
|
||||
int32 getRaw() const { return *(reinterpret_cast<const int32*>(this)); }
|
||||
|
|
|
@ -13,11 +13,12 @@
|
|||
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <PerfStat.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include "SixenseManager.h"
|
||||
#include "UserActivityLogger.h"
|
||||
|
||||
|
@ -38,14 +39,9 @@ const unsigned int RIGHT_MASK = 1U << 1;
|
|||
|
||||
const int CALIBRATION_STATE_IDLE = 0;
|
||||
const int CALIBRATION_STATE_X = 1;
|
||||
const int CALIBRATION_STATE_Y = 2;
|
||||
const int CALIBRATION_STATE_Z = 3;
|
||||
const int CALIBRATION_STATE_COMPLETE = 4;
|
||||
const int CALIBRATION_STATE_COMPLETE = 2;
|
||||
|
||||
// default (expected) location of neck in sixense space
|
||||
const float NECK_X = 0.25f; // meters
|
||||
const float NECK_Y = 0.3f; // meters
|
||||
const float NECK_Z = 0.3f; // meters
|
||||
const glm::vec3 DEFAULT_AVATAR_POSITION(-0.25f, -0.35f, -0.3f); // in hydra frame
|
||||
|
||||
const float CONTROLLER_THRESHOLD = 0.35f;
|
||||
|
||||
|
@ -92,9 +88,7 @@ bool SixenseManager::isSupported() const {
|
|||
void SixenseManager::activate() {
|
||||
#ifdef HAVE_SIXENSE
|
||||
_calibrationState = CALIBRATION_STATE_IDLE;
|
||||
// By default we assume the _neckBase (in orb frame) is as high above the orb
|
||||
// as the "torso" is below it.
|
||||
_neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z);
|
||||
_avatarPosition = DEFAULT_AVATAR_POSITION;
|
||||
|
||||
CONTAINER->addMenu(MENU_PATH);
|
||||
CONTAINER->addMenuItem(MENU_PATH, TOGGLE_SMOOTH,
|
||||
|
@ -258,11 +252,13 @@ void SixenseManager::update(float deltaTime, bool jointsCaptured) {
|
|||
#ifdef HAVE_SIXENSE
|
||||
|
||||
// the calibration sequence is:
|
||||
// (1) press BUTTON_FWD on both hands
|
||||
// (2) reach arm straight out to the side (X)
|
||||
// (3) lift arms staight up above head (Y)
|
||||
// (4) move arms a bit forward (Z)
|
||||
// (5) release BUTTON_FWD on both hands
|
||||
// (1) reach arm straight out to the sides (xAxis is to the left)
|
||||
// (2) press BUTTON_FWD on both hands and hold for one second
|
||||
// (3) release both BUTTON_FWDs
|
||||
//
|
||||
// The code will:
|
||||
// (4) assume that the orb is on a flat surface (yAxis is UP)
|
||||
// (5) compute the forward direction (zAxis = xAxis cross yAxis)
|
||||
|
||||
const float MINIMUM_ARM_REACH = 0.3f; // meters
|
||||
const float MAXIMUM_NOISE_LEVEL = 0.05f; // meters
|
||||
|
@ -279,21 +275,16 @@ void SixenseManager::updateCalibration(void* controllersX) {
|
|||
return;
|
||||
}
|
||||
switch (_calibrationState) {
|
||||
case CALIBRATION_STATE_Y:
|
||||
case CALIBRATION_STATE_Z:
|
||||
case CALIBRATION_STATE_COMPLETE:
|
||||
{
|
||||
// compute calibration results
|
||||
// ATM we only handle the case where the XAxis has been measured, and we assume the rest
|
||||
// (i.e. that the orb is on a level surface)
|
||||
// TODO: handle COMPLETE state where all three axes have been defined. This would allow us
|
||||
// to also handle the case where left and right controllers have been reversed.
|
||||
_neckBase = 0.5f * (_reachLeft + _reachRight); // neck is midway between right and left reaches
|
||||
_avatarPosition = - 0.5f * (_reachLeft + _reachRight); // neck is midway between right and left hands
|
||||
glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft);
|
||||
glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis));
|
||||
xAxis = glm::normalize(glm::cross(yAxis, zAxis));
|
||||
_orbRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, yAxis, zAxis)));
|
||||
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, Vectors::UNIT_Y));
|
||||
xAxis = glm::normalize(glm::cross(Vectors::UNIT_Y, zAxis));
|
||||
_avatarRotation = glm::inverse(glm::quat_cast(glm::mat3(xAxis, Vectors::UNIT_Y, zAxis)));
|
||||
const float Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR = -0.3f;
|
||||
_avatarPosition.y += Y_OFFSET_CALIBRATED_HANDS_TO_AVATAR;
|
||||
qCDebug(inputplugins, "succeess: sixense calibration");
|
||||
}
|
||||
break;
|
||||
|
@ -349,54 +340,10 @@ void SixenseManager::updateCalibration(void* controllersX) {
|
|||
_lockExpiry = now + LOCK_DURATION;
|
||||
_lastDistance = 0.0f;
|
||||
_reachUp = 0.5f * (_reachLeft + _reachRight);
|
||||
_calibrationState = CALIBRATION_STATE_Y;
|
||||
_calibrationState = CALIBRATION_STATE_COMPLETE;
|
||||
qCDebug(inputplugins, "success: sixense calibration: left");
|
||||
}
|
||||
}
|
||||
else if (_calibrationState == CALIBRATION_STATE_Y) {
|
||||
glm::vec3 torso = 0.5f * (_reachLeft + _reachRight);
|
||||
glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight);
|
||||
float distance = (averagePosition - torso).y;
|
||||
if (fabsf(distance) > fabsf(_lastDistance) + MAXIMUM_NOISE_LEVEL) {
|
||||
// distance is increasing so acquire the data and push the expiry out
|
||||
_reachUp = averagePosition;
|
||||
_lastDistance = distance;
|
||||
_lockExpiry = now + LOCK_DURATION;
|
||||
} else if (now > _lockExpiry) {
|
||||
if (_lastDistance > MINIMUM_ARM_REACH) {
|
||||
// lock has expired so clamp the data and move on
|
||||
_reachForward = _reachUp;
|
||||
_lastDistance = 0.0f;
|
||||
_lockExpiry = now + LOCK_DURATION;
|
||||
_calibrationState = CALIBRATION_STATE_Z;
|
||||
qCDebug(inputplugins, "success: sixense calibration: up");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_calibrationState == CALIBRATION_STATE_Z) {
|
||||
glm::vec3 xAxis = glm::normalize(_reachRight - _reachLeft);
|
||||
glm::vec3 torso = 0.5f * (_reachLeft + _reachRight);
|
||||
//glm::vec3 yAxis = glm::normalize(_reachUp - torso);
|
||||
glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 zAxis = glm::normalize(glm::cross(xAxis, yAxis));
|
||||
|
||||
glm::vec3 averagePosition = 0.5f * (_averageLeft + _averageRight);
|
||||
float distance = glm::dot((averagePosition - torso), zAxis);
|
||||
if (fabs(distance) > fabs(_lastDistance)) {
|
||||
// distance is increasing so acquire the data and push the expiry out
|
||||
_reachForward = averagePosition;
|
||||
_lastDistance = distance;
|
||||
_lockExpiry = now + LOCK_DURATION;
|
||||
} else if (now > _lockExpiry) {
|
||||
if (fabsf(_lastDistance) > 0.05f * MINIMUM_ARM_REACH) {
|
||||
// lock has expired so clamp the data and move on
|
||||
_calibrationState = CALIBRATION_STATE_COMPLETE;
|
||||
qCDebug(inputplugins, "success: sixense calibration: forward");
|
||||
// TODO: it is theoretically possible to detect that the controllers have been
|
||||
// accidentally switched (left hand is holding right controller) and to swap the order.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_SIXENSE
|
||||
|
@ -456,12 +403,9 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int
|
|||
// z
|
||||
|
||||
// Transform the measured position into body frame.
|
||||
glm::vec3 neck = _neckBase;
|
||||
// Set y component of the "neck" to raise the measured position a little bit.
|
||||
neck.y = 0.5f;
|
||||
position = _orbRotation * (position - neck);
|
||||
position = _avatarRotation * (position + _avatarPosition);
|
||||
|
||||
// From ABOVE the hand canonical axes looks like this:
|
||||
// From ABOVE the hand canonical axes look like this:
|
||||
//
|
||||
// | | | | y | | | |
|
||||
// | | | | | | | | |
|
||||
|
@ -480,28 +424,25 @@ void SixenseManager::handlePoseEvent(glm::vec3 position, glm::quat rotation, int
|
|||
//
|
||||
// Qsh = angleAxis(PI, zAxis) * angleAxis(-PI/2, xAxis)
|
||||
//
|
||||
const glm::vec3 xAxis = glm::vec3(1.0f, 0.0f, 0.0f);
|
||||
const glm::vec3 yAxis = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
const glm::vec3 zAxis = glm::vec3(0.0f, 0.0f, 1.0f);
|
||||
const glm::quat sixenseToHand = glm::angleAxis(PI, zAxis) * glm::angleAxis(-PI/2.0f, xAxis);
|
||||
const glm::quat sixenseToHand = glm::angleAxis(PI, Vectors::UNIT_Z) * glm::angleAxis(-PI/2.0f, Vectors::UNIT_X);
|
||||
|
||||
// In addition to Qsh each hand has pre-offset introduced by the shape of the sixense controllers
|
||||
// and how they fit into the hand in their relaxed state. This offset is a quarter turn about
|
||||
// the sixense's z-axis, with its direction different for the two hands:
|
||||
float sign = (index == 0) ? 1.0f : -1.0f;
|
||||
const glm::quat preOffset = glm::angleAxis(sign * PI / 2.0f, zAxis);
|
||||
const glm::quat preOffset = glm::angleAxis(sign * PI / 2.0f, Vectors::UNIT_Z);
|
||||
|
||||
// Finally, there is a post-offset (same for both hands) to get the hand's rest orientation
|
||||
// (fingers forward, palm down) aligned properly in the avatar's model-frame,
|
||||
// and then a flip about the yAxis to get into model-frame.
|
||||
const glm::quat postOffset = glm::angleAxis(PI, yAxis) * glm::angleAxis(PI / 2.0f, xAxis);
|
||||
const glm::quat postOffset = glm::angleAxis(PI, Vectors::UNIT_Y) * glm::angleAxis(PI / 2.0f, Vectors::UNIT_X);
|
||||
|
||||
// The total rotation of the hand uses the formula:
|
||||
//
|
||||
// rotation = postOffset * Qsh^ * (measuredRotation * preOffset) * Qsh
|
||||
//
|
||||
// TODO: find a shortcut with fewer rotations.
|
||||
rotation = postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand;
|
||||
rotation = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand;
|
||||
|
||||
_poseStateMap[makeInput(JointChannel(index)).getChannel()] = UserInputMapper::PoseValue(position, rotation);
|
||||
#endif // HAVE_SIXENSE
|
||||
|
|
|
@ -97,8 +97,8 @@ private:
|
|||
int _calibrationState;
|
||||
|
||||
// these are calibration results
|
||||
glm::vec3 _neckBase; // midpoint between controllers during X-axis calibration
|
||||
glm::quat _orbRotation; // rotates from orb frame into body frame
|
||||
glm::vec3 _avatarPosition; // in hydra-frame
|
||||
glm::quat _avatarRotation; // in hydra-frame
|
||||
float _armLength;
|
||||
|
||||
// these are measured values used to compute the calibration results
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
using namespace model;
|
||||
|
||||
Skybox::Skybox() {
|
||||
Data data;
|
||||
_dataBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Data), (const gpu::Byte*) &data));
|
||||
|
||||
/* // PLease create a default engineer skybox
|
||||
_cubemap.reset( gpu::Texture::createCube(gpu::Element::COLOR_RGBA_32, 1));
|
||||
|
@ -36,7 +38,7 @@ Skybox::Skybox() {
|
|||
}
|
||||
|
||||
void Skybox::setColor(const Color& color) {
|
||||
_color = color;
|
||||
_dataBuffer.edit<Data>()._color = color;
|
||||
}
|
||||
|
||||
void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
|
||||
|
@ -44,12 +46,40 @@ void Skybox::setCubemap(const gpu::TexturePointer& cubemap) {
|
|||
}
|
||||
|
||||
|
||||
void Skybox::updateDataBuffer() const {
|
||||
auto blend = 0.0f;
|
||||
if (getCubemap() && getCubemap()->isDefined()) {
|
||||
blend = 1.0f;
|
||||
// If pitch black neutralize the color
|
||||
if (glm::all(glm::equal(getColor(), glm::vec3(0.0f)))) {
|
||||
blend = 2.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (blend != _dataBuffer.get<Data>()._blend) {
|
||||
_dataBuffer.edit<Data>()._blend = blend;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Skybox::render(gpu::Batch& batch, const ViewFrustum& frustum) const {
|
||||
updateDataBuffer();
|
||||
Skybox::render(batch, frustum, (*this));
|
||||
}
|
||||
|
||||
|
||||
void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Skybox& skybox) {
|
||||
// Create the static shared elements used to render the skybox
|
||||
static gpu::BufferPointer theBuffer;
|
||||
static gpu::Stream::FormatPointer theFormat;
|
||||
|
||||
if (skybox.getCubemap()) {
|
||||
if (!theBuffer) {
|
||||
static gpu::BufferPointer theConstants;
|
||||
static gpu::PipelinePointer thePipeline;
|
||||
const int SKYBOX_SKYMAP_SLOT = 0;
|
||||
const int SKYBOX_CONSTANTS_SLOT = 0;
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&] {
|
||||
{
|
||||
const float CLIP = 1.0f;
|
||||
const glm::vec2 vertices[4] = { { -CLIP, -CLIP }, { CLIP, -CLIP }, { -CLIP, CLIP }, { CLIP, CLIP } };
|
||||
theBuffer = std::make_shared<gpu::Buffer>(sizeof(vertices), (const gpu::Byte*) vertices);
|
||||
|
@ -57,62 +87,49 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
theFormat->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ));
|
||||
}
|
||||
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
{
|
||||
auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert)));
|
||||
auto skyFS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(Skybox_frag)));
|
||||
auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyVS, skyFS));
|
||||
|
||||
Transform viewTransform;
|
||||
viewFrustum.evalViewTransform(viewTransform);
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewTransform);
|
||||
batch.setModelTransform(Transform()); // only for Mac
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
|
||||
batch.setInputFormat(theFormat);
|
||||
gpu::Shader::BindingSet bindings;
|
||||
bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), SKYBOX_SKYMAP_SLOT));
|
||||
bindings.insert(gpu::Shader::Binding(std::string("skyboxBuffer"), SKYBOX_CONSTANTS_SLOT));
|
||||
if (!gpu::Shader::makeProgram(*skyShader, bindings)) {
|
||||
|
||||
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||
static gpu::BufferPointer theConstants;
|
||||
static gpu::PipelinePointer thePipeline;
|
||||
static int SKYBOX_CONSTANTS_SLOT = 0; // need to be defined by the compilation of the shader
|
||||
if (!thePipeline) {
|
||||
auto skyVS = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(Skybox_vert)));
|
||||
auto skyFS = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(Skybox_frag)));
|
||||
auto skyShader = gpu::ShaderPointer(gpu::Shader::createProgram(skyVS, skyFS));
|
||||
|
||||
gpu::Shader::BindingSet bindings;
|
||||
bindings.insert(gpu::Shader::Binding(std::string("cubeMap"), 0));
|
||||
if (!gpu::Shader::makeProgram(*skyShader, bindings)) {
|
||||
|
||||
}
|
||||
|
||||
SKYBOX_CONSTANTS_SLOT = skyShader->getBuffers().findLocation("skyboxBuffer");
|
||||
if (SKYBOX_CONSTANTS_SLOT == gpu::Shader::INVALID_LOCATION) {
|
||||
SKYBOX_CONSTANTS_SLOT = skyShader->getUniforms().findLocation("skyboxBuffer");
|
||||
}
|
||||
|
||||
auto skyState = std::make_shared<gpu::State>();
|
||||
|
||||
thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState));
|
||||
|
||||
auto color = glm::vec4(1.0f);
|
||||
theConstants = std::make_shared<gpu::Buffer>(sizeof(color), (const gpu::Byte*) &color);
|
||||
}
|
||||
|
||||
if (glm::all(glm::equal(skybox.getColor(), glm::vec3(0.0f)))) {
|
||||
auto color = glm::vec4(1.0f);
|
||||
theConstants->setSubData(0, sizeof(color), (const gpu::Byte*) &color);
|
||||
} else {
|
||||
theConstants->setSubData(0, sizeof(Color), (const gpu::Byte*) &skybox.getColor());
|
||||
}
|
||||
auto skyState = std::make_shared<gpu::State>();
|
||||
skyState->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
|
||||
batch.setPipeline(thePipeline);
|
||||
batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, theConstants, 0, theConstants->getSize());
|
||||
batch.setResourceTexture(0, skybox.getCubemap());
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
thePipeline = gpu::PipelinePointer(gpu::Pipeline::create(skyShader, skyState));
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
// skybox has no cubemap, just clear the color buffer
|
||||
auto color = skybox.getColor();
|
||||
batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(color, 0.0f), 0.0f, 0, true);
|
||||
// Render
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
|
||||
Transform viewTransform;
|
||||
viewFrustum.evalViewTransform(viewTransform);
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewTransform);
|
||||
batch.setModelTransform(Transform()); // only for Mac
|
||||
batch.setInputBuffer(gpu::Stream::POSITION, theBuffer, 0, 8);
|
||||
batch.setInputFormat(theFormat);
|
||||
|
||||
gpu::TexturePointer skymap;
|
||||
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||
skymap = skybox.getCubemap();
|
||||
}
|
||||
|
||||
batch.setPipeline(thePipeline);
|
||||
batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, skybox._dataBuffer);
|
||||
batch.setResourceTexture(SKYBOX_SKYMAP_SLOT, skymap);
|
||||
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
batch.setResourceTexture(SKYBOX_SKYMAP_SLOT, nullptr);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -30,20 +30,28 @@ public:
|
|||
virtual ~Skybox() {};
|
||||
|
||||
void setColor(const Color& color);
|
||||
const Color& getColor() const { return _color; }
|
||||
const Color getColor() const { return _dataBuffer.get<Data>()._color; }
|
||||
|
||||
void setCubemap(const gpu::TexturePointer& cubemap);
|
||||
const gpu::TexturePointer& getCubemap() const { return _cubemap; }
|
||||
|
||||
virtual void render(gpu::Batch& batch, const ViewFrustum& frustum) const {
|
||||
render(batch, frustum, (*this));
|
||||
}
|
||||
virtual void render(gpu::Batch& batch, const ViewFrustum& frustum) const;
|
||||
|
||||
|
||||
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const Skybox& skybox);
|
||||
|
||||
protected:
|
||||
gpu::TexturePointer _cubemap;
|
||||
Color _color{1.0f, 1.0f, 1.0f};
|
||||
|
||||
class Data {
|
||||
public:
|
||||
glm::vec3 _color{ 1.0f, 1.0f, 1.0f };
|
||||
float _blend = 1.0f;
|
||||
};
|
||||
|
||||
mutable gpu::BufferView _dataBuffer;
|
||||
|
||||
void updateDataBuffer() const;
|
||||
};
|
||||
typedef std::shared_ptr< Skybox > SkyboxPointer;
|
||||
|
||||
|
|
|
@ -40,8 +40,18 @@ void main(void) {
|
|||
#else
|
||||
|
||||
vec3 coord = normalize(_normal);
|
||||
vec3 texel = texture(cubeMap, coord).rgb;
|
||||
vec3 color = texel * _skybox._color.rgb;
|
||||
|
||||
// Skybox color or blend with skymap
|
||||
vec3 color = _skybox._color.rgb;
|
||||
if (_skybox._color.a > 0.0) {
|
||||
vec3 texel = texture(cubeMap, coord).rgb;
|
||||
if (_skybox._color.a < 2.0) {
|
||||
color *= texel;
|
||||
} else {
|
||||
color = texel;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction
|
||||
_fragColor = vec4(pixel, 0.0);
|
||||
|
||||
|
|
|
@ -32,7 +32,8 @@ void ProceduralSkybox::setProcedural(const ProceduralPointer& procedural) {
|
|||
if (_procedural) {
|
||||
_procedural->_vertexSource = ProceduralSkybox_vert;
|
||||
_procedural->_fragmentSource = ProceduralSkybox_frag;
|
||||
// No pipeline state customization
|
||||
// Adjust the pipeline state for background using the stencil test
|
||||
_procedural->_state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,6 +43,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& frustum) con
|
|||
|
||||
void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const ProceduralSkybox& skybox) {
|
||||
if (!(skybox._procedural)) {
|
||||
skybox.updateDataBuffer();
|
||||
Skybox::render(batch, viewFrustum, skybox);
|
||||
}
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ void Environment::setupAtmosphereProgram(const char* vertSource, const char* fra
|
|||
auto state = std::make_shared<gpu::State>();
|
||||
|
||||
state->setCullMode(gpu::State::CULL_NONE);
|
||||
state->setDepthTest(false);
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
state->setBlendFunction(true,
|
||||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
|
|
@ -35,7 +35,9 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) {
|
|||
_frameBufferSize = frameBufferSize;
|
||||
_primaryFramebufferFull.reset();
|
||||
_primaryFramebufferDepthColor.reset();
|
||||
_primaryFramebufferStencilColor.reset();
|
||||
_primaryDepthTexture.reset();
|
||||
_primaryStencilTexture.reset();
|
||||
_primaryColorTexture.reset();
|
||||
_primaryNormalTexture.reset();
|
||||
_primarySpecularTexture.reset();
|
||||
|
@ -47,6 +49,7 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) {
|
|||
void FramebufferCache::createPrimaryFramebuffer() {
|
||||
_primaryFramebufferFull = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_primaryFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_primaryFramebufferStencilColor = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
|
||||
auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
||||
auto width = _frameBufferSize.width();
|
||||
|
@ -63,12 +66,19 @@ void FramebufferCache::createPrimaryFramebuffer() {
|
|||
|
||||
_primaryFramebufferDepthColor->setRenderBuffer(0, _primaryColorTexture);
|
||||
|
||||
_primaryFramebufferStencilColor->setRenderBuffer(0, _primaryColorTexture);
|
||||
|
||||
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
|
||||
_primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler));
|
||||
|
||||
auto stencilFormat = gpu::Element(gpu::VEC2, gpu::UINT32, gpu::DEPTH_STENCIL);
|
||||
_primaryStencilTexture = gpu::TexturePointer(gpu::Texture::create2D(stencilFormat, width, height, defaultSampler));
|
||||
|
||||
_primaryFramebufferFull->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
_primaryFramebufferDepthColor->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
_primaryFramebufferStencilColor->setDepthStencilBuffer(_primaryStencilTexture, stencilFormat);
|
||||
|
||||
_selfieFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler));
|
||||
|
@ -89,6 +99,12 @@ gpu::FramebufferPointer FramebufferCache::getPrimaryFramebufferDepthColor() {
|
|||
return _primaryFramebufferDepthColor;
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer FramebufferCache::getPrimaryFramebufferStencilColor() {
|
||||
if (!_primaryFramebufferStencilColor) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primaryFramebufferStencilColor;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getPrimaryDepthTexture() {
|
||||
if (!_primaryDepthTexture) {
|
||||
|
@ -97,6 +113,13 @@ gpu::TexturePointer FramebufferCache::getPrimaryDepthTexture() {
|
|||
return _primaryDepthTexture;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getPrimaryStencilTexture() {
|
||||
if (!_primaryStencilTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primaryStencilTexture;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getPrimaryColorTexture() {
|
||||
if (!_primaryColorTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
|
|
|
@ -31,8 +31,10 @@ public:
|
|||
/// used for scene rendering.
|
||||
gpu::FramebufferPointer getPrimaryFramebuffer();
|
||||
gpu::FramebufferPointer getPrimaryFramebufferDepthColor();
|
||||
gpu::FramebufferPointer getPrimaryFramebufferStencilColor();
|
||||
|
||||
gpu::TexturePointer getPrimaryDepthTexture();
|
||||
gpu::TexturePointer getPrimaryStencilTexture();
|
||||
gpu::TexturePointer getPrimaryColorTexture();
|
||||
gpu::TexturePointer getPrimaryNormalTexture();
|
||||
gpu::TexturePointer getPrimarySpecularTexture();
|
||||
|
@ -58,7 +60,9 @@ private:
|
|||
|
||||
gpu::FramebufferPointer _primaryFramebufferFull;
|
||||
gpu::FramebufferPointer _primaryFramebufferDepthColor;
|
||||
gpu::FramebufferPointer _primaryFramebufferStencilColor;
|
||||
gpu::TexturePointer _primaryDepthTexture;
|
||||
gpu::TexturePointer _primaryStencilTexture;
|
||||
gpu::TexturePointer _primaryColorTexture;
|
||||
gpu::TexturePointer _primaryNormalTexture;
|
||||
gpu::TexturePointer _primarySpecularTexture;
|
||||
|
|
|
@ -496,6 +496,13 @@ QPointF OffscreenQmlSurface::mapWindowToUi(const QPointF& sourcePosition, QObjec
|
|||
return QPointF(offscreenPosition.x, offscreenPosition.y);
|
||||
}
|
||||
|
||||
QPointF OffscreenQmlSurface::mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget) {
|
||||
QPointF transformedPos = _mouseTranslator(originalPoint);
|
||||
transformedPos = mapWindowToUi(transformedPos, originalWidget);
|
||||
return transformedPos;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
// Event handling customization
|
||||
|
@ -541,8 +548,9 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
|
|||
|
||||
case QEvent::Wheel: {
|
||||
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
|
||||
QPointF transformedPos = mapToVirtualScreen(wheelEvent->pos(), originalDestination);
|
||||
QWheelEvent mappedEvent(
|
||||
mapWindowToUi(wheelEvent->pos(), originalDestination),
|
||||
transformedPos,
|
||||
wheelEvent->delta(), wheelEvent->buttons(),
|
||||
wheelEvent->modifiers(), wheelEvent->orientation());
|
||||
mappedEvent.ignore();
|
||||
|
@ -558,9 +566,7 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even
|
|||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove: {
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
QPointF originalPos = mouseEvent->localPos();
|
||||
QPointF transformedPos = _mouseTranslator(originalPos);
|
||||
transformedPos = mapWindowToUi(transformedPos, originalDestination);
|
||||
QPointF transformedPos = mapToVirtualScreen(mouseEvent->localPos(), originalDestination);
|
||||
QMouseEvent mappedEvent(mouseEvent->type(),
|
||||
transformedPos,
|
||||
mouseEvent->screenPos(), mouseEvent->button(),
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
QQuickWindow* getWindow();
|
||||
QObject* getEventHandler();
|
||||
|
||||
QPointF mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget);
|
||||
virtual bool eventFilter(QObject* originalDestination, QEvent* event);
|
||||
|
||||
signals:
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <RenderArgs.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <gpu/Context.h>
|
||||
#include <gpu/StandardShaderLib.h>
|
||||
|
||||
#include "FramebufferCache.h"
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
@ -28,21 +29,27 @@
|
|||
#include "overlay3D_vert.h"
|
||||
#include "overlay3D_frag.h"
|
||||
|
||||
#include "drawOpaqueStencil_frag.h"
|
||||
|
||||
using namespace render;
|
||||
|
||||
void SetupDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
RenderArgs* args = renderContext->args;
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
|
||||
auto primaryFboStencil = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferStencilColor();
|
||||
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferDepthColor();
|
||||
|
||||
batch.enableStereo(false);
|
||||
batch.setFramebuffer(nullptr);
|
||||
batch.setFramebuffer(primaryFbo);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setStateScissorRect(args->_viewport);
|
||||
|
||||
batch.setFramebuffer(primaryFboStencil);
|
||||
batch.clearFramebuffer(
|
||||
gpu::Framebuffer::BUFFER_STENCIL,
|
||||
vec4(vec3(0), 1), 1.0, 0.0, true);
|
||||
|
||||
batch.setFramebuffer(primaryFbo);
|
||||
batch.clearFramebuffer(
|
||||
gpu::Framebuffer::BUFFER_COLOR0 |
|
||||
gpu::Framebuffer::BUFFER_DEPTH,
|
||||
|
@ -65,7 +72,6 @@ void ResolveDeferred::run(const SceneContextPointer& sceneContext, const RenderC
|
|||
|
||||
RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||
_jobs.push_back(Job(new SetupDeferred::JobModel("SetupFramebuffer")));
|
||||
_jobs.push_back(Job(new DrawBackground::JobModel("DrawBackground")));
|
||||
|
||||
_jobs.push_back(Job(new PrepareDeferred::JobModel("PrepareDeferred")));
|
||||
_jobs.push_back(Job(new FetchItems::JobModel("FetchOpaque",
|
||||
|
@ -79,7 +85,10 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
|||
_jobs.push_back(Job(new DepthSortItems::JobModel("DepthSortOpaque", _jobs.back().getOutput())));
|
||||
auto& renderedOpaques = _jobs.back().getOutput();
|
||||
_jobs.push_back(Job(new DrawOpaqueDeferred::JobModel("DrawOpaqueDeferred", _jobs.back().getOutput())));
|
||||
|
||||
|
||||
_jobs.push_back(Job(new DrawStencilDeferred::JobModel("DrawOpaqueStencil")));
|
||||
_jobs.push_back(Job(new DrawBackgroundDeferred::JobModel("DrawBackgroundDeferred")));
|
||||
|
||||
_jobs.push_back(Job(new DrawLight::JobModel("DrawLight")));
|
||||
_jobs.push_back(Job(new RenderDeferred::JobModel("RenderDeferred")));
|
||||
_jobs.push_back(Job(new ResolveDeferred::JobModel("ResolveDeferred")));
|
||||
|
@ -226,7 +235,9 @@ const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() {
|
|||
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
state->setDepthTest(false);
|
||||
// additive blending
|
||||
state->setBlendFunction(true, gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
||||
_opaquePipeline.reset(gpu::Pipeline::create(program, state));
|
||||
}
|
||||
|
@ -289,3 +300,95 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
|
|||
args->_whiteTexture.reset();
|
||||
}
|
||||
}
|
||||
|
||||
gpu::PipelinePointer DrawStencilDeferred::_opaquePipeline;
|
||||
const gpu::PipelinePointer& DrawStencilDeferred::getOpaquePipeline() {
|
||||
if (!_opaquePipeline) {
|
||||
const gpu::int8 STENCIL_OPAQUE = 1;
|
||||
auto vs = gpu::StandardShaderLib::getDrawUnitQuadTexcoordVS();
|
||||
auto ps = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(drawOpaqueStencil_frag)));
|
||||
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vs, ps));
|
||||
|
||||
|
||||
gpu::Shader::makeProgram((*program));
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(STENCIL_OPAQUE, 0xFF, gpu::ALWAYS, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE, gpu::State::STENCIL_OP_REPLACE));
|
||||
state->setColorWriteMask(0);
|
||||
|
||||
_opaquePipeline.reset(gpu::Pipeline::create(program, state));
|
||||
}
|
||||
return _opaquePipeline;
|
||||
}
|
||||
|
||||
void DrawStencilDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
|
||||
// from the touched pixel generate the stencil buffer
|
||||
RenderArgs* args = renderContext->args;
|
||||
doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
args->_batch = &batch;
|
||||
|
||||
auto primaryFboColorDepthStencil = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferStencilColor();
|
||||
auto primaryDepth = DependencyManager::get<FramebufferCache>()->getPrimaryDepthTexture();
|
||||
|
||||
batch.enableStereo(false);
|
||||
|
||||
batch.setFramebuffer(primaryFboColorDepthStencil);
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setStateScissorRect(args->_viewport);
|
||||
|
||||
batch.setPipeline(getOpaquePipeline());
|
||||
batch.setResourceTexture(0, primaryDepth);
|
||||
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
batch.setResourceTexture(0, nullptr);
|
||||
|
||||
});
|
||||
args->_batch = nullptr;
|
||||
}
|
||||
|
||||
void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
|
||||
// render backgrounds
|
||||
auto& scene = sceneContext->_scene;
|
||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::background());
|
||||
|
||||
|
||||
ItemIDsBounds inItems;
|
||||
inItems.reserve(items.size());
|
||||
for (auto id : items) {
|
||||
inItems.emplace_back(id);
|
||||
}
|
||||
RenderArgs* args = renderContext->args;
|
||||
doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
args->_batch = &batch;
|
||||
|
||||
auto primaryFboColorStencil = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferStencilColor();
|
||||
auto primaryFboFull = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
|
||||
|
||||
batch.enableSkybox(true);
|
||||
|
||||
batch.setFramebuffer(primaryFboColorStencil);
|
||||
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setStateScissorRect(args->_viewport);
|
||||
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||
args->_viewFrustum->evalViewTransform(viewMat);
|
||||
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
|
||||
renderItems(sceneContext, renderContext, inItems);
|
||||
|
||||
batch.setFramebuffer(primaryFboFull);
|
||||
|
||||
});
|
||||
args->_batch = nullptr;
|
||||
}
|
|
@ -59,6 +59,23 @@ public:
|
|||
typedef render::Job::ModelI<DrawTransparentDeferred, render::ItemIDsBounds> JobModel;
|
||||
};
|
||||
|
||||
class DrawStencilDeferred {
|
||||
static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
|
||||
public:
|
||||
static const gpu::PipelinePointer& getOpaquePipeline();
|
||||
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
|
||||
typedef render::Job::Model<DrawStencilDeferred> JobModel;
|
||||
};
|
||||
|
||||
class DrawBackgroundDeferred {
|
||||
public:
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
|
||||
typedef render::Job::Model<DrawBackgroundDeferred> JobModel;
|
||||
};
|
||||
|
||||
class DrawOverlay3D {
|
||||
static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
|
||||
public:
|
||||
|
|
24
libraries/render-utils/src/drawOpaqueStencil.slf
Normal file
24
libraries/render-utils/src/drawOpaqueStencil.slf
Normal file
|
@ -0,0 +1,24 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// drawOpaqueStencil.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 9/29/15.
|
||||
// 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
|
||||
//
|
||||
|
||||
in vec2 varTexCoord0;
|
||||
|
||||
uniform sampler2D depthTexture;
|
||||
|
||||
void main(void) {
|
||||
float depth = texture(depthTexture, varTexCoord0.xy).r;
|
||||
if (depth >= 1.0) {
|
||||
discard;
|
||||
}
|
||||
}
|
|
@ -257,6 +257,7 @@ class DrawBackground {
|
|||
public:
|
||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext);
|
||||
|
||||
|
||||
typedef Job::Model<DrawBackground> JobModel;
|
||||
};
|
||||
|
||||
|
|
|
@ -23,12 +23,12 @@ float Interpolate::bezierInterpolate(float y1, float y2, float y3, float u) {
|
|||
float Interpolate::interpolate3Points(float y1, float y2, float y3, float u) {
|
||||
assert(0.0f <= u && u <= 1.0f);
|
||||
|
||||
if (u <= 0.5f && y1 == y2 || u >= 0.5f && y2 == y3) {
|
||||
if ((u <= 0.5f && y1 == y2) || (u >= 0.5f && y2 == y3)) {
|
||||
// Flat line.
|
||||
return y2;
|
||||
}
|
||||
|
||||
if (y2 >= y1 && y2 >= y3 || y2 <= y1 && y2 <= y3) {
|
||||
if ((y2 >= y1 && y2 >= y3) || (y2 <= y1 && y2 <= y3)) {
|
||||
// U or inverted-U shape.
|
||||
// Make the slope at y2 = 0, which means that the control points half way between the value points have the value y2.
|
||||
if (u <= 0.5f) {
|
||||
|
|
834
unpublishedScripts/masterReset.js
Normal file
834
unpublishedScripts/masterReset.js
Normal file
|
@ -0,0 +1,834 @@
|
|||
// masterReset.js
|
||||
// Created by Eric Levin on 9/23/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
|
||||
//
|
||||
|
||||
/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, pointInExtents, vec3equal, setEntityCustomData, getEntityCustomData */
|
||||
//per script
|
||||
/*global deleteAllToys, createAllToys, createGates, createPingPongBallGun, createFire, createPottedPlant, createCombinedArmChair, createBasketballHoop, createBasketBall, createSprayCan, createDoll, createWand, createDice, createCat, deleteAllToys, createFlashlight, createBlocks, createMagballs, createLightSwitches */
|
||||
var utilitiesScript = Script.resolvePath("../examples/libraries/utils.js");
|
||||
Script.include(utilitiesScript);
|
||||
|
||||
var resetKey = "resetMe";
|
||||
var GRABBABLE_DATA_KEY = "grabbableKey";
|
||||
|
||||
var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
|
||||
var shouldDeleteOnEndScript = false;
|
||||
|
||||
//Before creating anything, first search a radius and delete all the things that should be deleted
|
||||
deleteAllToys();
|
||||
createAllToys();
|
||||
|
||||
function createAllToys() {
|
||||
createBlocks({
|
||||
x: 548.3,
|
||||
y: 495.55,
|
||||
z: 504.4
|
||||
});
|
||||
|
||||
createSprayCan({
|
||||
x: 549.7,
|
||||
y: 495.6,
|
||||
z: 503.91
|
||||
});
|
||||
|
||||
createBasketBall({
|
||||
x: 547.73,
|
||||
y: 495.5,
|
||||
z: 505.47
|
||||
});
|
||||
|
||||
createDoll({
|
||||
x: 546.67,
|
||||
y: 495.41,
|
||||
z: 505.09
|
||||
});
|
||||
|
||||
createWand({
|
||||
x: 546.71,
|
||||
y: 495.55,
|
||||
z: 506.15
|
||||
});
|
||||
|
||||
createDice();
|
||||
|
||||
createFlashlight({
|
||||
x: 545.72,
|
||||
y: 495.41,
|
||||
z: 505.78
|
||||
});
|
||||
|
||||
createCat({
|
||||
x: 551.09,
|
||||
y: 494.98,
|
||||
z: 503.49
|
||||
});
|
||||
|
||||
|
||||
createCombinedArmChair({
|
||||
x: 549.29,
|
||||
y: 495.05,
|
||||
z: 508.22
|
||||
});
|
||||
|
||||
createPottedPlant({
|
||||
x: 554.26,
|
||||
y: 495.23,
|
||||
z: 504.53
|
||||
});
|
||||
|
||||
createPingPongBallGun();
|
||||
|
||||
createBasketballHoop();
|
||||
|
||||
createGates();
|
||||
|
||||
createFire();
|
||||
// //Handles toggling of all sconce lights
|
||||
createLightSwitches();
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
function deleteAllToys() {
|
||||
var entities = Entities.findEntities(MyAvatar.position, 100);
|
||||
|
||||
entities.forEach(function (entity) {
|
||||
//params: customKey, id, defaultValue
|
||||
var shouldReset = getEntityCustomData(resetKey, entity, {}).resetMe;
|
||||
if (shouldReset === true) {
|
||||
Entities.deleteEntity(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createFire() {
|
||||
|
||||
|
||||
var myOrientation = Quat.fromPitchYawRollDegrees(-90, 0, 0.0);
|
||||
|
||||
var animationSettings = JSON.stringify({
|
||||
fps: 30,
|
||||
running: true,
|
||||
loop: true,
|
||||
firstFrame: 1,
|
||||
lastFrame: 10000
|
||||
});
|
||||
|
||||
|
||||
var fire = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
name: "fire",
|
||||
animationSettings: animationSettings,
|
||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||
position: {
|
||||
x: 551.45,
|
||||
y: 494.82,
|
||||
z: 502.05
|
||||
},
|
||||
emitRate: 100,
|
||||
colorStart: {
|
||||
red: 70,
|
||||
green: 70,
|
||||
blue: 137
|
||||
},
|
||||
color: {
|
||||
red: 200,
|
||||
green: 99,
|
||||
blue: 42
|
||||
},
|
||||
colorFinish: {
|
||||
red: 255,
|
||||
green: 99,
|
||||
blue: 32
|
||||
},
|
||||
radiusSpread: 0.01,
|
||||
radiusStart: 0.02,
|
||||
radiusEnd: 0.001,
|
||||
particleRadius: 0.05,
|
||||
radiusFinish: 0.0,
|
||||
emitOrientation: myOrientation,
|
||||
emitSpeed: 0.3,
|
||||
speedSpread: 0.1,
|
||||
alphaStart: 0.05,
|
||||
alpha: 0.1,
|
||||
alphaFinish: 0.05,
|
||||
emitDimensions: {
|
||||
x: 1,
|
||||
y: 1,
|
||||
z: 0.1
|
||||
},
|
||||
polarFinish: 0.1,
|
||||
emitAcceleration: {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: 0.0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: 0.1,
|
||||
y: 0.01,
|
||||
z: 0.1
|
||||
},
|
||||
lifespan: 1
|
||||
});
|
||||
|
||||
|
||||
setEntityCustomData(resetKey, fire, {
|
||||
resetMe: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function createCat(position) {
|
||||
var scriptURL = Script.resolvePath("../examples/toys/cat.js");
|
||||
var modelURL = "http://hifi-public.s3.amazonaws.com/ryan/Dark_Cat.fbx";
|
||||
var animationURL = "http://hifi-public.s3.amazonaws.com/ryan/sleeping.fbx";
|
||||
var animationSettings = JSON.stringify({
|
||||
running: true,
|
||||
});
|
||||
var cat = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: modelURL,
|
||||
name: "cat",
|
||||
script: scriptURL,
|
||||
animationURL: animationURL,
|
||||
animationSettings: animationSettings,
|
||||
position: position,
|
||||
rotation: {
|
||||
w: 0.35020983219146729,
|
||||
x: -4.57763671875e-05,
|
||||
y: 0.93664455413818359,
|
||||
z: -1.52587890625e-05
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.15723302960395813,
|
||||
y: 0.50762706995010376,
|
||||
z: 0.90716040134429932
|
||||
},
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, cat, {
|
||||
resetMe: true
|
||||
});
|
||||
}
|
||||
|
||||
function createFlashlight(position) {
|
||||
var scriptURL = Script.resolvePath('../examples/toys/flashlight/flashlight.js');
|
||||
var modelURL = "https://hifi-public.s3.amazonaws.com/models/props/flashlight.fbx";
|
||||
|
||||
var flashlight = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: modelURL,
|
||||
name: "flashlight",
|
||||
script: scriptURL,
|
||||
position: position,
|
||||
dimensions: {
|
||||
x: 0.08,
|
||||
y: 0.30,
|
||||
z: 0.08
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -3.5,
|
||||
z: 0
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.01,
|
||||
z: 0
|
||||
},
|
||||
shapeType: 'box',
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, flashlight, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function createLightSwitches() {
|
||||
var modelURL = "http://hifi-public.s3.amazonaws.com/ryan/lightswitch.fbx?v1";
|
||||
var scriptURL = Script.resolvePath("../examples/toys/lightSwitchHall.js");
|
||||
|
||||
var lightSwitchHall = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: modelURL,
|
||||
name: "Light Switch Hall",
|
||||
script: scriptURL,
|
||||
position: {
|
||||
x: 543.27764892578125,
|
||||
y: 495.67999267578125,
|
||||
z: 511.00564575195312
|
||||
},
|
||||
rotation: {
|
||||
w: 0.63280689716339111,
|
||||
x: 0.63280689716339111,
|
||||
y: -0.31551080942153931,
|
||||
z: 0.31548023223876953
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.10546875,
|
||||
y: 0.032372996211051941,
|
||||
z: 0.16242524981498718
|
||||
}
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, lightSwitchHall, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
scriptURL = Script.resolvePath("../examples/toys/lightSwitchGarage.js");
|
||||
|
||||
var lightSwitchGarage = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: modelURL,
|
||||
name: "Light Switch Garage",
|
||||
script: scriptURL,
|
||||
position: {
|
||||
x: 545.62,
|
||||
y: 495.68,
|
||||
z: 500.21
|
||||
},
|
||||
rotation: {
|
||||
w: 0.20082402229309082,
|
||||
x: 0.20082402229309082,
|
||||
y: -0.67800414562225342,
|
||||
z: 0.67797362804412842
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.10546875,
|
||||
y: 0.032372996211051941,
|
||||
z: 0.16242524981498718
|
||||
}
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, lightSwitchGarage, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function createDice() {
|
||||
var diceProps = {
|
||||
type: "Model",
|
||||
modelURL: "http://s3.amazonaws.com/hifi-public/models/props/Dice/goldDie.fbx",
|
||||
collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/dice/diceCollide.wav",
|
||||
name: "dice",
|
||||
position: {
|
||||
x: 541,
|
||||
y: 494.96,
|
||||
z: 509.1
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.09,
|
||||
y: 0.09,
|
||||
z: 0.09
|
||||
},
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -3.5,
|
||||
z: 0
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.01,
|
||||
z: 0
|
||||
},
|
||||
shapeType: "box",
|
||||
collisionsWillMove: true
|
||||
};
|
||||
var dice1 = Entities.addEntity(diceProps);
|
||||
|
||||
diceProps.position = {
|
||||
x: 541.05,
|
||||
y: 494.96,
|
||||
z: 509.0
|
||||
};
|
||||
|
||||
var dice2 = Entities.addEntity(diceProps);
|
||||
|
||||
setEntityCustomData(resetKey, dice1, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, dice2, {
|
||||
resetMe: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function createGates() {
|
||||
var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/ryan/fence.fbx';
|
||||
|
||||
var rotation1 = Quat.fromPitchYawRollDegrees(0, 36, 0);
|
||||
|
||||
var gate1 = Entities.addEntity({
|
||||
name: 'Back Door Gate',
|
||||
type: 'Model',
|
||||
shapeType: 'box',
|
||||
modelURL: MODEL_URL,
|
||||
position: {
|
||||
x: 546.52,
|
||||
y: 494.76,
|
||||
z: 498.87
|
||||
},
|
||||
dimensions: {
|
||||
x: 1.42,
|
||||
y: 1.13,
|
||||
z: 0.25
|
||||
},
|
||||
rotation: rotation1,
|
||||
collisionsWillMove: true,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -50,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 1,
|
||||
angularDamping: 10,
|
||||
mass: 10,
|
||||
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, gate1, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
setEntityCustomData(GRABBABLE_DATA_KEY, gate1, {
|
||||
grabbable: false
|
||||
});
|
||||
|
||||
var rotation2 = Quat.fromPitchYawRollDegrees(0, -16, 0);
|
||||
var gate2 = Entities.addEntity({
|
||||
name: 'Front Door Fence',
|
||||
type: 'Model',
|
||||
modelURL: MODEL_URL,
|
||||
shapeType: 'box',
|
||||
position: {
|
||||
x: 531.15,
|
||||
y: 495.11,
|
||||
z: 520.20
|
||||
},
|
||||
dimensions: {
|
||||
x: 1.42,
|
||||
y: 1.13,
|
||||
z: 0.2
|
||||
},
|
||||
rotation: rotation2,
|
||||
collisionsWillMove: true,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -100,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 1,
|
||||
angularDamping: 10,
|
||||
mass: 10,
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, gate2, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
setEntityCustomData(GRABBABLE_DATA_KEY, gate2, {
|
||||
grabbable: false
|
||||
});
|
||||
}
|
||||
|
||||
function createPingPongBallGun() {
|
||||
var MODEL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun.fbx';
|
||||
var COLLISION_HULL_URL = 'http://hifi-public.s3.amazonaws.com/models/ping_pong_gun/ping_pong_gun_collision_hull.obj';
|
||||
var scriptURL = Script.resolvePath('../examples/toys/ping_pong_gun/pingPongGun.js');
|
||||
|
||||
var position = {
|
||||
x: 548.6,
|
||||
y: 495.4,
|
||||
z: 503.39
|
||||
};
|
||||
|
||||
var rotation = Quat.fromPitchYawRollDegrees(0, 36, 0);
|
||||
|
||||
var pingPongGun = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: MODEL_URL,
|
||||
shapeType: 'compound',
|
||||
compoundShapeURL: COLLISION_HULL_URL,
|
||||
script: scriptURL,
|
||||
position: position,
|
||||
rotation: rotation,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.67,
|
||||
y: 0.14,
|
||||
z: 0.09
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, pingPongGun, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function createBasketballHoop() {
|
||||
var position = {
|
||||
x: 539.23,
|
||||
y: 496.13,
|
||||
z: 475.89
|
||||
};
|
||||
var rotation = Quat.fromPitchYawRollDegrees(0, 58.49, 0);
|
||||
|
||||
var hoopURL = "http://hifi-public.s3.amazonaws.com/models/basketball_hoop/basketball_hoop.fbx";
|
||||
var hoopCollisionHullURL = "http://hifi-public.s3.amazonaws.com/models/basketball_hoop/basketball_hoop_collision_hull.obj";
|
||||
|
||||
var hoop = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: hoopURL,
|
||||
position: position,
|
||||
rotation: rotation,
|
||||
shapeType: 'compound',
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
dimensions: {
|
||||
x: 1.89,
|
||||
y: 3.99,
|
||||
z: 3.79
|
||||
},
|
||||
compoundShapeURL: hoopCollisionHullURL
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, hoop, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
setEntityCustomData(GRABBABLE_DATA_KEY, hoop, {
|
||||
grabbable: false
|
||||
});
|
||||
}
|
||||
|
||||
function createWand(position) {
|
||||
var WAND_MODEL = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/wand.fbx';
|
||||
var WAND_COLLISION_SHAPE = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/wand/actual_no_top_collision_hull.obj';
|
||||
var scriptURL = Script.resolvePath("../examples/toys/bubblewand/wand.js");
|
||||
|
||||
var entity = Entities.addEntity({
|
||||
name: 'Bubble Wand',
|
||||
type: "Model",
|
||||
modelURL: WAND_MODEL,
|
||||
position: position,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.05,
|
||||
y: 0.25,
|
||||
z: 0.05
|
||||
},
|
||||
//must be enabled to be grabbable in the physics engine
|
||||
shapeType: 'compound',
|
||||
collisionsWillMove: true,
|
||||
compoundShapeURL: WAND_COLLISION_SHAPE,
|
||||
//Look into why bubble wand is going through table when gravity is enabled
|
||||
// gravity: {x: 0, y: -3.5, z: 0},
|
||||
// velocity: {x: 0, y: -0.01, z:0},
|
||||
script: scriptURL
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, entity, {
|
||||
resetMe: true
|
||||
});
|
||||
}
|
||||
|
||||
function createBasketBall(position) {
|
||||
|
||||
var modelURL = "http://s3.amazonaws.com/hifi-public/models/content/basketball2.fbx";
|
||||
|
||||
var entity = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: modelURL,
|
||||
position: position,
|
||||
collisionsWillMove: true,
|
||||
shapeType: "sphere",
|
||||
name: "basketball",
|
||||
dimensions: {
|
||||
x: 0.25,
|
||||
y: 0.26,
|
||||
z: 0.25
|
||||
},
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -7,
|
||||
z: 0
|
||||
},
|
||||
restitution: 10,
|
||||
linearDamping: 0.0,
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.01,
|
||||
z: 0
|
||||
},
|
||||
collisionSoundURL: "http://s3.amazonaws.com/hifi-public/sounds/basketball/basketball.wav"
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, entity, {
|
||||
resetMe: true
|
||||
});
|
||||
}
|
||||
|
||||
function createDoll(position) {
|
||||
var modelURL = "http://hifi-public.s3.amazonaws.com/models/Bboys/bboy2/bboy2.fbx";
|
||||
var scriptURL = Script.resolvePath("../examples/toys/doll/doll.js");
|
||||
|
||||
var naturalDimensions = {
|
||||
x: 1.63,
|
||||
y: 1.67,
|
||||
z: 0.26
|
||||
};
|
||||
var desiredDimensions = Vec3.multiply(naturalDimensions, 0.15);
|
||||
var entity = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "doll",
|
||||
modelURL: modelURL,
|
||||
script: scriptURL,
|
||||
position: position,
|
||||
shapeType: 'box',
|
||||
dimensions: desiredDimensions,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -5,
|
||||
z: 0
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.1,
|
||||
z: 0
|
||||
},
|
||||
collisionsWillMove: true
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, entity, {
|
||||
resetMe: true
|
||||
});
|
||||
}
|
||||
|
||||
function createSprayCan(position) {
|
||||
var scriptURL = Script.resolvePath("../examples/toys/sprayPaintCan.js");
|
||||
var modelURL = "https://hifi-public.s3.amazonaws.com/eric/models/paintcan.fbx";
|
||||
|
||||
var entity = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "spraycan",
|
||||
modelURL: modelURL,
|
||||
position: position,
|
||||
dimensions: {
|
||||
x: 0.07,
|
||||
y: 0.17,
|
||||
z: 0.07
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
shapeType: 'box',
|
||||
script: scriptURL,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -0.5,
|
||||
z: 0
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -1,
|
||||
z: 0
|
||||
}
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, entity, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function createPottedPlant(position) {
|
||||
var modelURL = "http://hifi-public.s3.amazonaws.com/models/potted_plant/potted_plant.fbx";
|
||||
|
||||
var entity = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "Potted Plant",
|
||||
modelURL: modelURL,
|
||||
position: position,
|
||||
dimensions: {
|
||||
x: 1.10,
|
||||
y: 2.18,
|
||||
z: 1.07
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
shapeType: 'box',
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -9.8,
|
||||
z: 0
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 0.4
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, entity, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
|
||||
setEntityCustomData(GRABBABLE_DATA_KEY, entity, {
|
||||
grabbable: false
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function createCombinedArmChair(position) {
|
||||
var modelURL = "http://hifi-public.s3.amazonaws.com/models/red_arm_chair/combined_chair.fbx";
|
||||
var RED_ARM_CHAIR_COLLISION_HULL = "http://hifi-public.s3.amazonaws.com/models/red_arm_chair/red_arm_chair_collision_hull.obj";
|
||||
|
||||
var rotation = Quat.fromPitchYawRollDegrees(0, -143, 0);
|
||||
|
||||
var entity = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "Red Arm Chair",
|
||||
modelURL: modelURL,
|
||||
shapeType: 'compound',
|
||||
compoundShapeURL: RED_ARM_CHAIR_COLLISION_HULL,
|
||||
position: position,
|
||||
rotation: rotation,
|
||||
dimensions: {
|
||||
x: 1.26,
|
||||
y: 1.56,
|
||||
z: 1.35
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -0.8,
|
||||
z: 0
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
linearDamping: 0.2
|
||||
});
|
||||
|
||||
setEntityCustomData(resetKey, entity, {
|
||||
resetMe: true
|
||||
});
|
||||
|
||||
setEntityCustomData(GRABBABLE_DATA_KEY, entity, {
|
||||
grabbable: false
|
||||
});
|
||||
}
|
||||
|
||||
function createBlocks(position) {
|
||||
var baseURL = HIFI_PUBLIC_BUCKET + "models/content/planky/";
|
||||
var collisionSoundURL = "https://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/ToyWoodBlock.L.wav";
|
||||
var NUM_BLOCKS_PER_COLOR = 4;
|
||||
var i, j;
|
||||
|
||||
var blockTypes = [{
|
||||
url: "planky_blue.fbx",
|
||||
dimensions: {
|
||||
x: 0.05,
|
||||
y: 0.05,
|
||||
z: 0.25
|
||||
}
|
||||
}, {
|
||||
url: "planky_green.fbx",
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
z: 0.25
|
||||
}
|
||||
}, {
|
||||
url: "planky_natural.fbx",
|
||||
dimensions: {
|
||||
x: 0.05,
|
||||
y: 0.05,
|
||||
z: 0.05
|
||||
}
|
||||
}, {
|
||||
url: "planky_yellow.fbx",
|
||||
dimensions: {
|
||||
x: 0.03,
|
||||
y: 0.05,
|
||||
z: 0.25
|
||||
}
|
||||
}, {
|
||||
url: "planky_red.fbx",
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.05,
|
||||
z: 0.25
|
||||
}
|
||||
}, ];
|
||||
|
||||
var modelURL, entity;
|
||||
for (i = 0; i < blockTypes.length; i++) {
|
||||
for (j = 0; j < NUM_BLOCKS_PER_COLOR; j++) {
|
||||
modelURL = baseURL + blockTypes[i].url;
|
||||
entity = Entities.addEntity({
|
||||
type: "Model",
|
||||
modelURL: modelURL,
|
||||
position: Vec3.sum(position, {
|
||||
x: j / 10,
|
||||
y: i / 10,
|
||||
z: 0
|
||||
}),
|
||||
shapeType: 'box',
|
||||
name: "block",
|
||||
dimensions: blockTypes[i].dimensions,
|
||||
collisionsWillMove: true,
|
||||
collisionSoundURL: collisionSoundURL,
|
||||
gravity: {
|
||||
x: 0,
|
||||
y: -2.5,
|
||||
z: 0
|
||||
},
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: -0.01,
|
||||
z: 0
|
||||
}
|
||||
});
|
||||
|
||||
//customKey, id, data
|
||||
setEntityCustomData(resetKey, entity, {
|
||||
resetMe: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
deleteAllToys();
|
||||
}
|
||||
|
||||
if (shouldDeleteOnEndScript) {
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
}
|
Loading…
Reference in a new issue