mirror of
https://github.com/overte-org/overte.git
synced 2025-04-08 07:12:40 +02:00
Merge branch 'master' into ajt/new-anim-system
This commit is contained in:
commit
5882ec02d0
25 changed files with 1027 additions and 300 deletions
88
examples/entityScripts/breakdanceEntity.js
Normal file
88
examples/entityScripts/breakdanceEntity.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
//
|
||||
// breakdanceEntity.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 9/3/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example of an entity script which when assigned to an entity, will start the breakdance game if you grab and hold the entity
|
||||
//
|
||||
// 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("../toys/breakdanceCore.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, 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)
|
||||
BreakdanceEntity = function() {
|
||||
_this = this;
|
||||
print("BreakdanceEntity constructor");
|
||||
};
|
||||
|
||||
BreakdanceEntity.prototype = {
|
||||
|
||||
// update() will be called regulary, because we've hooked the update signal in our preload() function
|
||||
// we will check out userData for the grabData. In the case of the hydraGrab script, it will tell us
|
||||
// if we're currently being grabbed and if the person grabbing us is the current interfaces avatar.
|
||||
// we will watch this for state changes and print out if we're being grabbed or released when it changes.
|
||||
update: function() {
|
||||
var GRAB_USER_DATA_KEY = "grabKey";
|
||||
|
||||
// because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID
|
||||
var entityID = _this.entityID;
|
||||
|
||||
// we want to assume that if there is no grab data, then we are not being grabbed
|
||||
var defaultGrabData = { activated: false, avatarId: null };
|
||||
|
||||
// this handy function getEntityCustomData() is available in utils.js and it will return just the specific section
|
||||
// of user data we asked for. If it's not available it returns our default data.
|
||||
var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, defaultGrabData);
|
||||
|
||||
// if the grabData says we're being grabbed, and the owner ID is our session, then we are being grabbed by this interface
|
||||
if (grabData.activated && grabData.avatarId == MyAvatar.sessionUUID) {
|
||||
|
||||
if (!_this.beingGrabbed) {
|
||||
// remember we're being grabbed so we can detect being released
|
||||
_this.beingGrabbed = true;
|
||||
breakdanceStart();
|
||||
print("I'm was grabbed...");
|
||||
} else {
|
||||
breakdanceUpdate();
|
||||
}
|
||||
|
||||
} else if (_this.beingGrabbed) {
|
||||
|
||||
// if we are not being grabbed, and we previously were, then we were just released, remember that
|
||||
// and print out a message
|
||||
_this.beingGrabbed = false;
|
||||
print("I'm was released...");
|
||||
breakdanceEnd();
|
||||
}
|
||||
},
|
||||
|
||||
// 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
|
||||
// * connecting to the update signal so we can check our grabbed state
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
Script.update.connect(this.update);
|
||||
},
|
||||
|
||||
// unload() will be called when our entity is no longer available. It may be because we were deleted,
|
||||
// or because we've left the domain or quit the application. In all cases we want to unhook our connection
|
||||
// to the update signal
|
||||
unload: function(entityID) {
|
||||
Script.update.disconnect(this.update);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new BreakdanceEntity();
|
||||
})
|
81
examples/entityScripts/detectGrabExample.js
Normal file
81
examples/entityScripts/detectGrabExample.js
Normal file
|
@ -0,0 +1,81 @@
|
|||
//
|
||||
// detectGrabExample.js
|
||||
// examples/entityScripts
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 9/3/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example of an entity script which when assigned to an entity, will detect when the entity is being grabbed by the hydraGrab script
|
||||
//
|
||||
// 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");
|
||||
|
||||
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)
|
||||
DetectGrabbed = function() {
|
||||
_this = this;
|
||||
};
|
||||
|
||||
DetectGrabbed.prototype = {
|
||||
|
||||
// update() will be called regulary, because we've hooked the update signal in our preload() function
|
||||
// we will check out userData for the grabData. In the case of the hydraGrab script, it will tell us
|
||||
// if we're currently being grabbed and if the person grabbing us is the current interfaces avatar.
|
||||
// we will watch this for state changes and print out if we're being grabbed or released when it changes.
|
||||
update: function() {
|
||||
var GRAB_USER_DATA_KEY = "grabKey";
|
||||
|
||||
// because the update() signal doesn't have a valid this, we need to use our memorized _this to access our entityID
|
||||
var entityID = _this.entityID;
|
||||
|
||||
// we want to assume that if there is no grab data, then we are not being grabbed
|
||||
var defaultGrabData = { activated: false, avatarId: null };
|
||||
|
||||
// this handy function getEntityCustomData() is available in utils.js and it will return just the specific section
|
||||
// of user data we asked for. If it's not available it returns our default data.
|
||||
var grabData = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, defaultGrabData);
|
||||
|
||||
// if the grabData says we're being grabbed, and the owner ID is our session, then we are being grabbed by this interface
|
||||
if (grabData.activated && grabData.avatarId == MyAvatar.sessionUUID) {
|
||||
|
||||
// remember we're being grabbed so we can detect being released
|
||||
_this.beingGrabbed = true;
|
||||
|
||||
// print out that we're being grabbed
|
||||
print("I'm being grabbed...");
|
||||
|
||||
} else if (_this.beingGrabbed) {
|
||||
|
||||
// if we are not being grabbed, and we previously were, then we were just released, remember that
|
||||
// and print out a message
|
||||
_this.beingGrabbed = false;
|
||||
print("I'm was released...");
|
||||
}
|
||||
},
|
||||
|
||||
// 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
|
||||
// * connecting to the update signal so we can check our grabbed state
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
Script.update.connect(this.update);
|
||||
},
|
||||
|
||||
// unload() will be called when our entity is no longer available. It may be because we were deleted,
|
||||
// or because we've left the domain or quit the application. In all cases we want to unhook our connection
|
||||
// to the update signal
|
||||
unload: function(entityID) {
|
||||
Script.update.disconnect(this.update);
|
||||
},
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new DetectGrabbed();
|
||||
})
|
|
@ -91,10 +91,7 @@ Wand.prototype.setTipColors = function(color1, color2) {
|
|||
}
|
||||
|
||||
Wand.prototype.onUpdate = function(deltaTime) {
|
||||
logDebug("Z4");
|
||||
|
||||
if (this.visible) {
|
||||
logDebug("5");
|
||||
var time = new Date().getTime() / 250;
|
||||
var scale1 = Math.abs(Math.sin(time));
|
||||
var scale2 = Math.abs(Math.cos(time));
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
//
|
||||
|
||||
|
||||
Script.include("../libraries/utils.js");
|
||||
|
||||
function getPositionPuppet() {
|
||||
var DISTANCE_IN_FRONT = 2;
|
||||
var DISTANCE_UP = 0.4;
|
||||
|
@ -513,7 +511,7 @@ breakdanceUpdate = function(deltaTime) {
|
|||
} else {
|
||||
Overlays.editOverlay(textOverlay, { text: "pose:" + poses[poseValue].name + "\n" + "animation:" + poses[poseValue].animation });
|
||||
var props = Entities.getEntityProperties(puppetEntityID);
|
||||
print("puppetEntityID:" + puppetEntityID + "age:"+props.age);
|
||||
//print("puppetEntityID:" + puppetEntityID + "age:"+props.age);
|
||||
Entities.editEntity(puppetEntityID, {
|
||||
animationURL: poses[poseValue].animation,
|
||||
lifetime: TEMPORARY_LIFETIME + props.age // renew lifetime
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("../libraries/utils.js");
|
||||
Script.include("breakdanceCore.js");
|
||||
breakdanceStart();
|
||||
Script.update.connect(breakdanceUpdate);
|
||||
|
|
|
@ -34,7 +34,7 @@ MODE_INFO[BALL_EDIT_MODE_ADD] = {
|
|||
},
|
||||
colors: [ COLORS.GREEN, COLORS.BLUE ],
|
||||
// FIXME use an http path or find a way to get the relative path to the file
|
||||
url: "file:///" + Script.resolvePath('../html/magBalls/addMode.html').replace("c:", "C:"),
|
||||
url: Script.resolvePath('../html/magBalls/addMode.html'),
|
||||
};
|
||||
|
||||
MODE_INFO[BALL_EDIT_MODE_DELETE] = {
|
||||
|
@ -45,10 +45,9 @@ MODE_INFO[BALL_EDIT_MODE_DELETE] = {
|
|||
},
|
||||
colors: [ COLORS.RED, COLORS.BLUE ],
|
||||
// FIXME use an http path or find a way to get the relative path to the file
|
||||
url: "file:///" + Script.resolvePath('../html/magBalls/deleteMode.html').replace("c:", "C:"),
|
||||
url: Script.resolvePath('../html/magBalls/deleteMode.html'),
|
||||
};
|
||||
|
||||
|
||||
var UI_POSITION_MODE_LABEL = Vec3.multiply(0.5,
|
||||
Vec3.sum(MODE_INFO[BALL_EDIT_MODE_ADD].uiPosition,
|
||||
MODE_INFO[BALL_EDIT_MODE_DELETE].uiPosition));
|
||||
|
|
|
@ -3,6 +3,7 @@ var shiftHeld = false;
|
|||
|
||||
Script.include([
|
||||
"libraries/toolBars.js",
|
||||
"libraries/utils.js",
|
||||
]);
|
||||
|
||||
var isActive = false;
|
||||
|
@ -12,24 +13,25 @@ var toolWidth = 50;
|
|||
|
||||
var addingVoxels = false;
|
||||
var deletingVoxels = false;
|
||||
var addingSpheres = false;
|
||||
var deletingSpheres = false;
|
||||
|
||||
offAlpha = 0.5;
|
||||
onAlpha = 0.9;
|
||||
var offAlpha = 0.5;
|
||||
var onAlpha = 0.9;
|
||||
var editSphereRadius = 4;
|
||||
|
||||
function floorVector(v) {
|
||||
return {x: Math.floor(v.x), y: Math.floor(v.y), z: Math.floor(v.z)};
|
||||
}
|
||||
|
||||
function vectorToString(v){
|
||||
return "{" + v.x + ", " + v.x + ", " + v.x + "}";
|
||||
}
|
||||
|
||||
var toolBar = (function () {
|
||||
var that = {},
|
||||
toolBar,
|
||||
activeButton,
|
||||
addVoxelButton,
|
||||
deleteVoxelButton,
|
||||
addSphereButton,
|
||||
deleteSphereButton,
|
||||
addTerrainButton;
|
||||
|
||||
function initialize() {
|
||||
|
@ -66,6 +68,24 @@ var toolBar = (function () {
|
|||
visible: false
|
||||
});
|
||||
|
||||
addSphereButton = toolBar.addTool({
|
||||
imageURL: toolIconUrl + "sphere-add.svg",
|
||||
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||
width: toolWidth,
|
||||
height: toolHeight,
|
||||
alpha: offAlpha,
|
||||
visible: false
|
||||
});
|
||||
|
||||
deleteSphereButton = toolBar.addTool({
|
||||
imageURL: toolIconUrl + "sphere-delete.svg",
|
||||
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||
width: toolWidth,
|
||||
height: toolHeight,
|
||||
alpha: offAlpha,
|
||||
visible: false
|
||||
});
|
||||
|
||||
addTerrainButton = toolBar.addTool({
|
||||
imageURL: toolIconUrl + "voxel-terrain.svg",
|
||||
subImage: { x: 0, y: Tool.IMAGE_WIDTH, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT },
|
||||
|
@ -78,6 +98,22 @@ var toolBar = (function () {
|
|||
that.setActive(false);
|
||||
}
|
||||
|
||||
function disableAllButtons() {
|
||||
addingVoxels = false;
|
||||
deletingVoxels = false;
|
||||
addingSpheres = false;
|
||||
deletingSpheres = false;
|
||||
|
||||
toolBar.setAlpha(offAlpha, addVoxelButton);
|
||||
toolBar.setAlpha(offAlpha, deleteVoxelButton);
|
||||
toolBar.setAlpha(offAlpha, addSphereButton);
|
||||
toolBar.setAlpha(offAlpha, deleteSphereButton);
|
||||
|
||||
toolBar.selectTool(addVoxelButton, false);
|
||||
toolBar.selectTool(deleteVoxelButton, false);
|
||||
toolBar.selectTool(addSphereButton, false);
|
||||
toolBar.selectTool(deleteSphereButton, false);
|
||||
}
|
||||
|
||||
that.setActive = function(active) {
|
||||
if (active != isActive) {
|
||||
|
@ -91,6 +127,8 @@ var toolBar = (function () {
|
|||
that.showTools = function(doShow) {
|
||||
toolBar.showTool(addVoxelButton, doShow);
|
||||
toolBar.showTool(deleteVoxelButton, doShow);
|
||||
toolBar.showTool(addSphereButton, doShow);
|
||||
toolBar.showTool(deleteSphereButton, doShow);
|
||||
toolBar.showTool(addTerrainButton, doShow);
|
||||
};
|
||||
|
||||
|
@ -103,37 +141,46 @@ var toolBar = (function () {
|
|||
}
|
||||
|
||||
if (addVoxelButton === toolBar.clicked(clickedOverlay)) {
|
||||
if (addingVoxels) {
|
||||
addingVoxels = false;
|
||||
deletingVoxels = false;
|
||||
toolBar.setAlpha(offAlpha, addVoxelButton);
|
||||
toolBar.setAlpha(offAlpha, deleteVoxelButton);
|
||||
toolBar.selectTool(addVoxelButton, false);
|
||||
toolBar.selectTool(deleteVoxelButton, false);
|
||||
} else {
|
||||
var wasAddingVoxels = addingVoxels;
|
||||
disableAllButtons()
|
||||
if (!wasAddingVoxels) {
|
||||
addingVoxels = true;
|
||||
deletingVoxels = false;
|
||||
toolBar.setAlpha(onAlpha, addVoxelButton);
|
||||
toolBar.setAlpha(offAlpha, deleteVoxelButton);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (deleteVoxelButton === toolBar.clicked(clickedOverlay)) {
|
||||
if (deletingVoxels) {
|
||||
deletingVoxels = false;
|
||||
addingVoxels = false;
|
||||
toolBar.setAlpha(offAlpha, addVoxelButton);
|
||||
toolBar.setAlpha(offAlpha, deleteVoxelButton);
|
||||
} else {
|
||||
var wasDeletingVoxels = deletingVoxels;
|
||||
disableAllButtons()
|
||||
if (!wasDeletingVoxels) {
|
||||
deletingVoxels = true;
|
||||
addingVoxels = false;
|
||||
toolBar.setAlpha(offAlpha, addVoxelButton);
|
||||
toolBar.setAlpha(onAlpha, deleteVoxelButton);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (addSphereButton === toolBar.clicked(clickedOverlay)) {
|
||||
var wasAddingSpheres = addingSpheres
|
||||
disableAllButtons()
|
||||
if (!wasAddingSpheres) {
|
||||
addingSpheres = true;
|
||||
toolBar.setAlpha(onAlpha, addSphereButton);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (deleteSphereButton === toolBar.clicked(clickedOverlay)) {
|
||||
var wasDeletingSpheres = deletingSpheres;
|
||||
disableAllButtons()
|
||||
if (!wasDeletingSpheres) {
|
||||
deletingSpheres = true;
|
||||
toolBar.setAlpha(onAlpha, deleteSphereButton);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (addTerrainButton === toolBar.clicked(clickedOverlay)) {
|
||||
addTerrainBlock();
|
||||
return true;
|
||||
|
@ -155,85 +202,212 @@ var toolBar = (function () {
|
|||
}());
|
||||
|
||||
|
||||
|
||||
function getTerrainAlignedLocation(pos) {
|
||||
var posDiv16 = Vec3.multiply(pos, 1.0 / 16.0);
|
||||
var posDiv16Floored = floorVector(posDiv16);
|
||||
return Vec3.multiply(posDiv16Floored, 16.0);
|
||||
}
|
||||
|
||||
|
||||
function lookupTerrainForLocation(pos) {
|
||||
var baseLocation = getTerrainAlignedLocation(pos);
|
||||
entitiesAtLoc = Entities.findEntities(baseLocation, 1.0);
|
||||
for (var i = 0; i < entitiesAtLoc.length; i++) {
|
||||
var id = entitiesAtLoc[i];
|
||||
var properties = Entities.getEntityProperties(id);
|
||||
if (properties.name == "terrain") {
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function grabLowestJointY() {
|
||||
var jointNames = MyAvatar.getJointNames();
|
||||
var floorY = MyAvatar.position.y;
|
||||
for (var jointName in jointNames) {
|
||||
if (MyAvatar.getJointPosition(jointNames[jointName]).y < floorY) {
|
||||
floorY = MyAvatar.getJointPosition(jointNames[jointName]).y;
|
||||
}
|
||||
}
|
||||
return floorY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
function addTerrainBlock() {
|
||||
|
||||
var myPosDiv16 = Vec3.multiply(Vec3.sum(MyAvatar.position, {x:8, x:8, z:8}), 1.0 / 16.0);
|
||||
var myPosDiv16Floored = floorVector(myPosDiv16);
|
||||
var baseLocation = Vec3.multiply(myPosDiv16Floored, 16.0);
|
||||
|
||||
if (baseLocation.y + 8 > MyAvatar.position.y) {
|
||||
var baseLocation = getTerrainAlignedLocation(Vec3.sum(MyAvatar.position, {x:8, y:8, z:8}));
|
||||
if (baseLocation.y > MyAvatar.position.y) {
|
||||
baseLocation.y -= 16;
|
||||
}
|
||||
|
||||
print("myPosDiv16 is " + vectorToString(myPosDiv16));
|
||||
print("MyPosDiv16Floored is " + vectorToString(myPosDiv16Floored));
|
||||
print("baseLocation is " + vectorToString(baseLocation));
|
||||
|
||||
alreadyThere = Entities.findEntities(baseLocation, 1.0);
|
||||
for (var i = 0; i < alreadyThere.length; i++) {
|
||||
var id = alreadyThere[i];
|
||||
var properties = Entities.getEntityProperties(id);
|
||||
if (properties.name == "terrain") {
|
||||
print("already terrain there");
|
||||
var alreadyThere = lookupTerrainForLocation(baseLocation);
|
||||
if (alreadyThere) {
|
||||
// there is already a terrain block under MyAvatar.
|
||||
// try in front of the avatar.
|
||||
facingPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(8.0, Quat.getFront(Camera.getOrientation())));
|
||||
facingPosition = Vec3.sum(facingPosition, {x:8, y:8, z:8});
|
||||
baseLocation = getTerrainAlignedLocation(facingPosition);
|
||||
alreadyThere = lookupTerrainForLocation(baseLocation);
|
||||
if (alreadyThere) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var polyVoxId = Entities.addEntity({
|
||||
var polyVoxID = Entities.addEntity({
|
||||
type: "PolyVox",
|
||||
name: "terrain",
|
||||
position: baseLocation,
|
||||
dimensions: { x: 16, y: 16, z: 16 },
|
||||
voxelVolumeSize: {x:16, y:16, z:16},
|
||||
voxelSurfaceStyle: 2
|
||||
dimensions: { x:16, y:16, z:16 },
|
||||
voxelVolumeSize: {x:16, y:64, z:16},
|
||||
voxelSurfaceStyle: 0,
|
||||
xTextureURL: "http://headache.hungry.com/~seth/hifi/dirt.jpeg",
|
||||
yTextureURL: "http://headache.hungry.com/~seth/hifi/grass.png",
|
||||
zTextureURL: "http://headache.hungry.com/~seth/hifi/dirt.jpeg"
|
||||
});
|
||||
Entities.setAllVoxels(polyVoxId, 255);
|
||||
|
||||
for (var y = 8; y < 16; y++) {
|
||||
for (var x = 0; x < 16; x++) {
|
||||
for (var z = 0; z < 16; z++) {
|
||||
Entities.setVoxel(polyVoxId, {x: x, y: y, z: z}, 0);
|
||||
}
|
||||
}
|
||||
var AvatarPositionInVoxelCoords = Entities.worldCoordsToVoxelCoords(polyVoxID, MyAvatar.position);
|
||||
// TODO -- how to find the avatar's feet?
|
||||
var topY = Math.round(AvatarPositionInVoxelCoords.y) - 4;
|
||||
Entities.setVoxelsInCuboid(polyVoxID, {x:0, y:0, z:0}, {x:16, y:topY, z:16}, 255);
|
||||
|
||||
|
||||
//////////
|
||||
// stitch together the terrain with x/y/z NeighorID properties
|
||||
//////////
|
||||
|
||||
// link neighbors to this plot
|
||||
imXNNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:16, y:0, z:0}));
|
||||
imYNNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:16, z:0}));
|
||||
imZNNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:16}));
|
||||
imXPNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:-16, y:0, z:0}));
|
||||
imYPNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:-16, z:0}));
|
||||
imZPNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:-16}));
|
||||
|
||||
if (imXNNeighborFor) {
|
||||
var properties = Entities.getEntityProperties(imXNNeighborFor);
|
||||
properties.xNNeighborID = polyVoxID;
|
||||
Entities.editEntity(imXNNeighborFor, properties);
|
||||
}
|
||||
if (imYNNeighborFor) {
|
||||
var properties = Entities.getEntityProperties(imYNNeighborFor);
|
||||
properties.yNNeighborID = polyVoxID;
|
||||
Entities.editEntity(imYNNeighborFor, properties);
|
||||
}
|
||||
if (imZNNeighborFor) {
|
||||
var properties = Entities.getEntityProperties(imZNNeighborFor);
|
||||
properties.zNNeighborID = polyVoxID;
|
||||
Entities.editEntity(imZNNeighborFor, properties);
|
||||
}
|
||||
|
||||
if (imXPNeighborFor) {
|
||||
var properties = Entities.getEntityProperties(imXPNeighborFor);
|
||||
properties.xPNeighborID = polyVoxID;
|
||||
Entities.editEntity(imXPNeighborFor, properties);
|
||||
}
|
||||
if (imYPNeighborFor) {
|
||||
var properties = Entities.getEntityProperties(imYPNeighborFor);
|
||||
properties.yPNeighborID = polyVoxID;
|
||||
Entities.editEntity(imYPNeighborFor, properties);
|
||||
}
|
||||
if (imZPNeighborFor) {
|
||||
var properties = Entities.getEntityProperties(imZPNeighborFor);
|
||||
properties.zPNeighborID = polyVoxID;
|
||||
Entities.editEntity(imZPNeighborFor, properties);
|
||||
}
|
||||
|
||||
|
||||
// link this plot to its neighbors
|
||||
var properties = Entities.getEntityProperties(polyVoxID);
|
||||
properties.xNNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:-16, y:0, z:0}));
|
||||
properties.yNNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:-16, z:0}));
|
||||
properties.zNNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:-16}));
|
||||
properties.xPNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:16, y:0, z:0}));
|
||||
properties.yPNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:16, z:0}));
|
||||
properties.zPNeighborID = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:16}));
|
||||
Entities.editEntity(polyVoxID, properties);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
function attemptVoxelChange(pickRayDir, intersection) {
|
||||
function attemptVoxelChangeForEntity(entityID, pickRayDir, intersectionLocation) {
|
||||
|
||||
var properties = Entities.getEntityProperties(intersection.entityID);
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
if (properties.type != "PolyVox") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (addingVoxels == false && deletingVoxels == false) {
|
||||
if (addingVoxels == false && deletingVoxels == false && addingSpheres == false && deletingSpheres == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var voxelPosition = Entities.worldCoordsToVoxelCoords(intersection.entityID, intersection.intersection);
|
||||
var pickRayDirInVoxelSpace = Entities.localCoordsToVoxelCoords(intersection.entityID, pickRayDir);
|
||||
var voxelOrigin = Entities.worldCoordsToVoxelCoords(entityID, Vec3.subtract(intersectionLocation, pickRayDir));
|
||||
var voxelPosition = Entities.worldCoordsToVoxelCoords(entityID, intersectionLocation);
|
||||
var pickRayDirInVoxelSpace = Vec3.subtract(voxelPosition, voxelOrigin);
|
||||
pickRayDirInVoxelSpace = Vec3.normalize(pickRayDirInVoxelSpace);
|
||||
|
||||
var doAdd = addingVoxels;
|
||||
var doDelete = deletingVoxels;
|
||||
var doAddSphere = addingSpheres;
|
||||
var doDeleteSphere = deletingSpheres;
|
||||
|
||||
if (controlHeld) {
|
||||
doAdd = deletingVoxels;
|
||||
doDelete = addingVoxels;
|
||||
if (doAdd) {
|
||||
doAdd = false;
|
||||
doDelete = true;
|
||||
} else if (doDelete) {
|
||||
doDelete = false;
|
||||
doAdd = true;
|
||||
} else if (doAddSphere) {
|
||||
doAddSphere = false;
|
||||
doDeleteSphere = true;
|
||||
} else if (doDeleteSphere) {
|
||||
doDeleteSphere = false;
|
||||
doAddSphere = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (doDelete) {
|
||||
var toErasePosition = Vec3.sum(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1));
|
||||
return Entities.setVoxel(intersection.entityID, floorVector(toErasePosition), 0);
|
||||
return Entities.setVoxel(entityID, floorVector(toErasePosition), 0);
|
||||
}
|
||||
if (doAdd) {
|
||||
var toDrawPosition = Vec3.subtract(voxelPosition, Vec3.multiply(pickRayDirInVoxelSpace, 0.1));
|
||||
return Entities.setVoxel(intersection.entityID, floorVector(toDrawPosition), 255);
|
||||
return Entities.setVoxel(entityID, floorVector(toDrawPosition), 255);
|
||||
}
|
||||
if (doDeleteSphere) {
|
||||
var toErasePosition = intersectionLocation;
|
||||
return Entities.setVoxelSphere(entityID, floorVector(toErasePosition), editSphereRadius, 0);
|
||||
}
|
||||
if (doAddSphere) {
|
||||
var toDrawPosition = intersectionLocation;
|
||||
return Entities.setVoxelSphere(entityID, floorVector(toDrawPosition), editSphereRadius, 255);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function attemptVoxelChange(pickRayDir, intersection) {
|
||||
|
||||
var ids;
|
||||
|
||||
ids = Entities.findEntities(intersection.intersection, editSphereRadius + 1.0);
|
||||
if (ids.indexOf(intersection.entityID) < 0) {
|
||||
ids.push(intersection.entityID);
|
||||
}
|
||||
|
||||
var success = false;
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
var entityID = ids[i];
|
||||
success |= attemptVoxelChangeForEntity(entityID, pickRayDir, intersection.intersection)
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
function mousePressEvent(event) {
|
||||
if (!event.isLeftButton) {
|
||||
return;
|
||||
|
|
|
@ -547,14 +547,11 @@ void SkeletonModel::computeBoundingShape() {
|
|||
// compute the default transform of this joint
|
||||
const JointState& state = _rig->getJointState(i);
|
||||
|
||||
// HACK WORKAROUND: ignore joints that may have bad translation (e.g. have been flagged as such with zero radius)
|
||||
if (state.getBoneRadius() > 0.0f) {
|
||||
// Each joint contributes a sphere at its position
|
||||
glm::vec3 axis(state.getBoneRadius());
|
||||
glm::vec3 jointPosition = state.getPosition();
|
||||
totalExtents.addPoint(jointPosition + axis);
|
||||
totalExtents.addPoint(jointPosition - axis);
|
||||
}
|
||||
// Each joint contributes a sphere at its position
|
||||
glm::vec3 axis(state.getBoneRadius());
|
||||
glm::vec3 jointPosition = state.getPosition();
|
||||
totalExtents.addPoint(jointPosition + axis);
|
||||
totalExtents.addPoint(jointPosition - axis);
|
||||
}
|
||||
|
||||
// compute bounding shape parameters
|
||||
|
|
|
@ -78,7 +78,7 @@ void StereoDisplayPlugin::activate() {
|
|||
}
|
||||
|
||||
void StereoDisplayPlugin::updateScreen() {
|
||||
for (int i = 0; i < (int) _screenActions.size(); ++i) {
|
||||
for (uint32_t i = 0; i < _screenActions.size(); ++i) {
|
||||
if (_screenActions[i]->isChecked()) {
|
||||
CONTAINER->setFullscreen(qApp->screens().at(i));
|
||||
break;
|
||||
|
|
|
@ -68,6 +68,19 @@ RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() {
|
|||
}
|
||||
|
||||
|
||||
bool isEdged(PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle) {
|
||||
switch (surfaceStyle) {
|
||||
case PolyVoxEntityItem::SURFACE_CUBIC:
|
||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
|
||||
return false;
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void RenderablePolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
|
||||
_voxelDataLock.lockForWrite();
|
||||
if (_voxelData == voxelData) {
|
||||
|
@ -88,10 +101,8 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel
|
|||
}
|
||||
|
||||
// if we are switching to or from "edged" we need to force a resize of _volData.
|
||||
bool wasEdged = (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
|
||||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES);
|
||||
bool willBeEdged = (voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
|
||||
voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES);
|
||||
bool wasEdged = isEdged(_voxelSurfaceStyle);
|
||||
bool willBeEdged = isEdged(voxelSurfaceStyle);
|
||||
|
||||
if (wasEdged != willBeEdged) {
|
||||
_volDataLock.lockForWrite();
|
||||
|
@ -113,15 +124,10 @@ void RenderablePolyVoxEntityItem::setVoxelSurfaceStyle(PolyVoxSurfaceStyle voxel
|
|||
|
||||
glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
|
||||
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
|
||||
switch (_voxelSurfaceStyle) {
|
||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
|
||||
case PolyVoxEntityItem::SURFACE_CUBIC:
|
||||
return scale / 2.0f;
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
|
||||
return scale / -2.0f;
|
||||
if (isEdged(_voxelSurfaceStyle)) {
|
||||
return scale / -2.0f;
|
||||
}
|
||||
return glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
return scale / 2.0f;
|
||||
}
|
||||
|
||||
|
||||
|
@ -130,7 +136,7 @@ glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
|
|||
glm::vec3 center = getCenterPosition();
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 positionToCenter = center - position;
|
||||
positionToCenter -= getDimensions() * glm::vec3(0.5f, 0.5f, 0.5f) - getSurfacePositionAdjustment();
|
||||
positionToCenter -= getDimensions() * Vectors::HALF - getSurfacePositionAdjustment();
|
||||
glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
|
||||
glm::mat4 scaled = glm::scale(centerToCorner, scale);
|
||||
return scaled;
|
||||
|
@ -195,6 +201,37 @@ bool RenderablePolyVoxEntityItem::setAll(uint8_t toValue) {
|
|||
}
|
||||
|
||||
|
||||
bool RenderablePolyVoxEntityItem::setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue) {
|
||||
bool result = false;
|
||||
if (_locked) {
|
||||
return result;
|
||||
}
|
||||
|
||||
int xLow = std::max(std::min((int)roundf(lowPosition.x), (int)roundf(_voxelVolumeSize.x) - 1), 0);
|
||||
int yLow = std::max(std::min((int)roundf(lowPosition.y), (int)roundf(_voxelVolumeSize.y) - 1), 0);
|
||||
int zLow = std::max(std::min((int)roundf(lowPosition.z), (int)roundf(_voxelVolumeSize.z) - 1), 0);
|
||||
int xHigh = std::max(std::min(xLow + (int)roundf(cuboidSize.x), (int)roundf(_voxelVolumeSize.x)), xLow);
|
||||
int yHigh = std::max(std::min(yLow + (int)roundf(cuboidSize.y), (int)roundf(_voxelVolumeSize.y)), yLow);
|
||||
int zHigh = std::max(std::min(zLow + (int)roundf(cuboidSize.z), (int)roundf(_voxelVolumeSize.z)), zLow);
|
||||
|
||||
_volDataLock.lockForWrite();
|
||||
_volDataDirty = true;
|
||||
|
||||
for (int x = xLow; x < xHigh; x++) {
|
||||
for (int y = yLow; y < yHigh; y++) {
|
||||
for (int z = zLow; z < zHigh; z++) {
|
||||
result |= setVoxelInternal(x, y, z, toValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
_volDataLock.unlock();
|
||||
if (result) {
|
||||
compressVolumeDataAndSendEditPacket();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool RenderablePolyVoxEntityItem::setVoxelInVolume(glm::vec3 position, uint8_t toValue) {
|
||||
if (_locked) {
|
||||
|
@ -213,7 +250,6 @@ bool RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi
|
|||
|
||||
// This three-level for loop iterates over every voxel in the volume
|
||||
_volDataLock.lockForWrite();
|
||||
_volDataDirty = true;
|
||||
for (int z = 0; z < _voxelVolumeSize.z; z++) {
|
||||
for (int y = 0; y < _voxelVolumeSize.y; y++) {
|
||||
for (int x = 0; x < _voxelVolumeSize.x; x++) {
|
||||
|
@ -228,20 +264,52 @@ bool RenderablePolyVoxEntityItem::setSphereInVolume(glm::vec3 center, float radi
|
|||
}
|
||||
}
|
||||
}
|
||||
_volDataLock.unlock();
|
||||
|
||||
if (result) {
|
||||
_volDataDirty = true;
|
||||
_volDataLock.unlock();
|
||||
compressVolumeDataAndSendEditPacket();
|
||||
} else {
|
||||
_volDataLock.unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float radiusWorldCoords, uint8_t toValue) {
|
||||
// glm::vec3 centerVoxelCoords = worldToVoxelCoordinates(centerWorldCoords);
|
||||
glm::vec4 centerVoxelCoords = worldToVoxelMatrix() * glm::vec4(centerWorldCoords, 1.0f);
|
||||
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
|
||||
float scaleY = scale.y;
|
||||
float radiusVoxelCoords = radiusWorldCoords / scaleY;
|
||||
return setSphereInVolume(glm::vec3(centerVoxelCoords), radiusVoxelCoords, toValue);
|
||||
bool result = false;
|
||||
if (_locked) {
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::mat4 vtwMatrix = voxelToWorldMatrix();
|
||||
|
||||
// This three-level for loop iterates over every voxel in the volume
|
||||
_volDataLock.lockForWrite();
|
||||
for (int z = 0; z < _voxelVolumeSize.z; z++) {
|
||||
for (int y = 0; y < _voxelVolumeSize.y; y++) {
|
||||
for (int x = 0; x < _voxelVolumeSize.x; x++) {
|
||||
// Store our current position as a vector...
|
||||
glm::vec4 pos(x + 0.5f, y + 0.5f, z + 0.5f, 1.0); // consider voxels cenetered on their coordinates
|
||||
// convert to world coordinates
|
||||
glm::vec3 worldPos = glm::vec3(vtwMatrix * pos);
|
||||
// compute how far the current position is from the center of the volume
|
||||
float fDistToCenter = glm::distance(worldPos, centerWorldCoords);
|
||||
// If the current voxel is less than 'radius' units from the center then we set its value
|
||||
if (fDistToCenter <= radiusWorldCoords) {
|
||||
result |= setVoxelInternal(x, y, z, toValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result) {
|
||||
_volDataDirty = true;
|
||||
_volDataLock.unlock();
|
||||
compressVolumeDataAndSendEditPacket();
|
||||
} else {
|
||||
_volDataLock.unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
class RaycastFunctor
|
||||
|
@ -296,7 +364,6 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
|
|||
|
||||
glm::mat4 wtvMatrix = worldToVoxelMatrix();
|
||||
glm::mat4 vtwMatrix = voxelToWorldMatrix();
|
||||
glm::mat4 vtlMatrix = voxelToLocalMatrix();
|
||||
glm::vec3 normDirection = glm::normalize(direction);
|
||||
|
||||
// the PolyVox ray intersection code requires a near and far point.
|
||||
|
@ -304,67 +371,33 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
|
|||
float distanceToEntity = glm::distance(origin, getPosition());
|
||||
float largestDimension = glm::max(getDimensions().x, getDimensions().y, getDimensions().z) * 2.0f;
|
||||
glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension);
|
||||
|
||||
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);
|
||||
glm::vec4 farInVoxel = wtvMatrix * glm::vec4(farPoint, 1.0f);
|
||||
|
||||
glm::vec4 result;
|
||||
glm::vec4 directionInVoxel = glm::normalize(farInVoxel - originInVoxel);
|
||||
|
||||
glm::vec4 result = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
PolyVox::RaycastResult raycastResult = doRayCast(originInVoxel, farInVoxel, result);
|
||||
if (raycastResult == PolyVox::RaycastResults::Completed) {
|
||||
// the ray completed its path -- nothing was hit.
|
||||
return false;
|
||||
}
|
||||
|
||||
// set up ray tests against each face of the voxel.
|
||||
glm::vec3 minXPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.0f, 0.5f, 0.5f, 0.0f)));
|
||||
glm::vec3 maxXPosition = glm::vec3(vtwMatrix * (result + glm::vec4(1.0f, 0.5f, 0.5f, 0.0f)));
|
||||
glm::vec3 minYPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 0.0f, 0.5f, 0.0f)));
|
||||
glm::vec3 maxYPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 1.0f, 0.5f, 0.0f)));
|
||||
glm::vec3 minZPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 0.5f, 0.0f, 0.0f)));
|
||||
glm::vec3 maxZPosition = glm::vec3(vtwMatrix * (result + glm::vec4(0.5f, 0.5f, 1.0f, 0.0f)));
|
||||
glm::vec3 result3 = glm::vec3(result);
|
||||
|
||||
glm::vec4 baseDimensions = glm::vec4(1.0, 1.0, 1.0, 0.0);
|
||||
glm::vec3 worldDimensions = glm::vec3(vtlMatrix * baseDimensions);
|
||||
glm::vec2 xDimensions = glm::vec2(worldDimensions.z, worldDimensions.y);
|
||||
glm::vec2 yDimensions = glm::vec2(worldDimensions.x, worldDimensions.z);
|
||||
glm::vec2 zDimensions = glm::vec2(worldDimensions.x, worldDimensions.y);
|
||||
AABox voxelBox;
|
||||
voxelBox += result3 - Vectors::HALF;
|
||||
voxelBox += result3 + Vectors::HALF;
|
||||
|
||||
glm::quat vtwRotation = extractRotation(vtwMatrix);
|
||||
glm::quat minXRotation = vtwRotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f));
|
||||
glm::quat maxXRotation = vtwRotation * glm::quat(glm::vec3(0.0f, PI_OVER_TWO, 0.0f));
|
||||
glm::quat minYRotation = vtwRotation * glm::quat(glm::vec3(PI_OVER_TWO, 0.0f, 0.0f));
|
||||
glm::quat maxYRotation = vtwRotation * glm::quat(glm::vec3(PI_OVER_TWO, 0.0f, 0.0f));
|
||||
glm::quat minZRotation = vtwRotation * glm::quat(glm::vec3(0.0f, 0.0f, 0.0f));
|
||||
glm::quat maxZRotation = vtwRotation * glm::quat(glm::vec3(0.0f, 0.0f, 0.0f));
|
||||
float voxelDistance;
|
||||
|
||||
float bestDx = FLT_MAX;
|
||||
bool hit[ 6 ];
|
||||
float dx[ 6 ] = {FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX};
|
||||
bool hit = voxelBox.findRayIntersection(glm::vec3(originInVoxel), glm::vec3(directionInVoxel), voxelDistance, face);
|
||||
|
||||
hit[0] = findRayRectangleIntersection(origin, direction, minXRotation, minXPosition, xDimensions, dx[0]);
|
||||
hit[1] = findRayRectangleIntersection(origin, direction, maxXRotation, maxXPosition, xDimensions, dx[1]);
|
||||
hit[2] = findRayRectangleIntersection(origin, direction, minYRotation, minYPosition, yDimensions, dx[2]);
|
||||
hit[3] = findRayRectangleIntersection(origin, direction, maxYRotation, maxYPosition, yDimensions, dx[3]);
|
||||
hit[4] = findRayRectangleIntersection(origin, direction, minZRotation, minZPosition, zDimensions, dx[4]);
|
||||
hit[5] = findRayRectangleIntersection(origin, direction, maxZRotation, maxZPosition, zDimensions, dx[5]);
|
||||
|
||||
bool ok = false;
|
||||
for (int i = 0; i < 6; i ++) {
|
||||
if (hit[ i ] && dx[ i ] < bestDx) {
|
||||
face = (BoxFace)i;
|
||||
distance = dx[ i ];
|
||||
ok = true;
|
||||
bestDx = dx[ i ];
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
// if the attempt to put the ray against one of the voxel-faces fails, just return the center
|
||||
glm::vec4 intersectedWorldPosition = vtwMatrix * (result + vec4(0.5f, 0.5f, 0.5f, 0.0f));
|
||||
distance = glm::distance(glm::vec3(intersectedWorldPosition), origin);
|
||||
face = BoxFace::MIN_X_FACE;
|
||||
}
|
||||
|
||||
return true;
|
||||
glm::vec4 voxelIntersectionPoint = glm::vec4(glm::vec3(originInVoxel) + glm::vec3(directionInVoxel) * voxelDistance, 1.0);
|
||||
glm::vec4 intersectionPoint = vtwMatrix * voxelIntersectionPoint;
|
||||
distance = glm::distance(origin, glm::vec3(intersectionPoint));
|
||||
return hit;
|
||||
}
|
||||
|
||||
|
||||
|
@ -380,7 +413,7 @@ PolyVox::RaycastResult RenderablePolyVoxEntityItem::doRayCast(glm::vec4 originIn
|
|||
_volDataLock.unlock();
|
||||
|
||||
// result is in voxel-space coordinates.
|
||||
result = callback._result - glm::vec4(0.5f, 0.5f, 0.5f, 0.0f);
|
||||
result = callback._result;
|
||||
return raycastResult;
|
||||
}
|
||||
|
||||
|
@ -402,21 +435,29 @@ bool RenderablePolyVoxEntityItem::isReadyToComputeShape() {
|
|||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||
_shapeInfoLock.lockForRead();
|
||||
QReadLocker(&this->_shapeInfoLock);
|
||||
info = _shapeInfo;
|
||||
_shapeInfoLock.unlock();
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setXTextureURL(QString xTextureURL) {
|
||||
PolyVoxEntityItem::setXTextureURL(xTextureURL);
|
||||
if (xTextureURL != _xTextureURL) {
|
||||
_xTexture.clear();
|
||||
PolyVoxEntityItem::setXTextureURL(xTextureURL);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setYTextureURL(QString yTextureURL) {
|
||||
PolyVoxEntityItem::setYTextureURL(yTextureURL);
|
||||
if (yTextureURL != _yTextureURL) {
|
||||
_yTexture.clear();
|
||||
PolyVoxEntityItem::setYTextureURL(yTextureURL);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setZTextureURL(QString zTextureURL) {
|
||||
PolyVoxEntityItem::setZTextureURL(zTextureURL);
|
||||
if (zTextureURL != _zTextureURL) {
|
||||
_zTexture.clear();
|
||||
PolyVoxEntityItem::setZTextureURL(zTextureURL);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
||||
|
@ -426,9 +467,12 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
|||
|
||||
_volDataLock.lockForRead();
|
||||
if (_volDataDirty) {
|
||||
_volDataLock.unlock();
|
||||
getMesh();
|
||||
} else {
|
||||
_volDataLock.unlock();
|
||||
}
|
||||
_volDataLock.unlock();
|
||||
|
||||
|
||||
_meshLock.lockForRead();
|
||||
model::MeshPointer mesh = _mesh;
|
||||
|
@ -543,23 +587,21 @@ namespace render {
|
|||
|
||||
|
||||
glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToWorldCoords(glm::vec3& voxelCoords) const {
|
||||
return glm::vec3(voxelToWorldMatrix() * glm::vec4(voxelCoords, 1.0f));
|
||||
glm::vec3 adjustedCoords;
|
||||
if (isEdged(_voxelSurfaceStyle)) {
|
||||
adjustedCoords = voxelCoords + Vectors::HALF;
|
||||
} else {
|
||||
adjustedCoords = voxelCoords - Vectors::HALF;
|
||||
}
|
||||
return glm::vec3(voxelToWorldMatrix() * glm::vec4(adjustedCoords, 1.0f));
|
||||
}
|
||||
|
||||
glm::vec3 RenderablePolyVoxEntityItem::worldCoordsToVoxelCoords(glm::vec3& worldCoords) const {
|
||||
glm::vec3 result = glm::vec3(worldToVoxelMatrix() * glm::vec4(worldCoords, 1.0f));
|
||||
switch (_voxelSurfaceStyle) {
|
||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
|
||||
case PolyVoxEntityItem::SURFACE_CUBIC:
|
||||
result += glm::vec3(0.5f, 0.5f, 0.5f);
|
||||
break;
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
|
||||
result -= glm::vec3(0.5f, 0.5f, 0.5f);
|
||||
break;
|
||||
if (isEdged(_voxelSurfaceStyle)) {
|
||||
return result - Vectors::HALF;
|
||||
}
|
||||
|
||||
return result;
|
||||
return result + Vectors::HALF;
|
||||
}
|
||||
|
||||
glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const {
|
||||
|
@ -585,8 +627,7 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize)
|
|||
}
|
||||
_onCount = 0;
|
||||
|
||||
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
|
||||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
|
||||
if (isEdged(_voxelSurfaceStyle)) {
|
||||
// with _EDGED_ we maintain an extra box of voxels around those that the user asked for. This
|
||||
// changes how the surface extractor acts -- mainly it becomes impossible to have holes in the
|
||||
// generated mesh. The non _EDGED_ modes will leave holes in the mesh at the edges of the
|
||||
|
@ -598,9 +639,11 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize)
|
|||
_volData = new PolyVox::SimpleVolume<uint8_t>(PolyVox::Region(lowCorner, highCorner));
|
||||
} else {
|
||||
PolyVox::Vector3DInt32 lowCorner(0, 0, 0);
|
||||
PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x - 1, // -1 because these corners are inclusive
|
||||
_voxelVolumeSize.y - 1,
|
||||
_voxelVolumeSize.z - 1);
|
||||
// these should each have -1 after them, but if we leave layers on the upper-axis faces,
|
||||
// they act more like I expect.
|
||||
PolyVox::Vector3DInt32 highCorner(_voxelVolumeSize.x,
|
||||
_voxelVolumeSize.y,
|
||||
_voxelVolumeSize.z);
|
||||
_volData = new PolyVox::SimpleVolume<uint8_t>(PolyVox::Region(lowCorner, highCorner));
|
||||
}
|
||||
|
||||
|
@ -613,35 +656,27 @@ void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize)
|
|||
|
||||
bool RenderablePolyVoxEntityItem::inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol,
|
||||
PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
|
||||
int x, int y, int z) {
|
||||
int x, int y, int z) const {
|
||||
// x, y, z are in user voxel-coords, not adjusted-for-edge voxel-coords.
|
||||
switch (surfaceStyle) {
|
||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
|
||||
case PolyVoxEntityItem::SURFACE_CUBIC:
|
||||
if (x < 0 || y < 0 || z < 0 ||
|
||||
x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
|
||||
if (x < 0 || y < 0 || z < 0 ||
|
||||
x >= vol->getWidth() - 2 || y >= vol->getHeight() - 2 || z >= vol->getDepth() - 2) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
if (isEdged(surfaceStyle)) {
|
||||
if (x < 0 || y < 0 || z < 0 ||
|
||||
x >= vol->getWidth() - 2 || y >= vol->getHeight() - 2 || z >= vol->getDepth() - 2) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (x < 0 || y < 0 || z < 0 ||
|
||||
x >= vol->getWidth() || y >= vol->getHeight() || z >= vol->getDepth()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) {
|
||||
_volDataLock.lockForRead();
|
||||
auto result = getVoxelInternal(x, y, z);
|
||||
_volDataLock.unlock();
|
||||
return result;
|
||||
QReadLocker(&this->_volDataLock);
|
||||
return getVoxelInternal(x, y, z);
|
||||
}
|
||||
|
||||
|
||||
|
@ -650,19 +685,13 @@ uint8_t RenderablePolyVoxEntityItem::getVoxelInternal(int x, int y, int z) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// if _voxelSurfaceStyle is SURFACE_EDGED_CUBIC, we maintain an extra layer of
|
||||
// if _voxelSurfaceStyle is *_EDGED_*, we maintain an extra layer of
|
||||
// voxels all around the requested voxel space. Having the empty voxels around
|
||||
// the edges changes how the surface extractor behaves.
|
||||
|
||||
uint8_t result;
|
||||
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
|
||||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
|
||||
result = _volData->getVoxelAt(x + 1, y + 1, z + 1);
|
||||
} else {
|
||||
result = _volData->getVoxelAt(x, y, z);
|
||||
if (isEdged(_voxelSurfaceStyle)) {
|
||||
return _volData->getVoxelAt(x + 1, y + 1, z + 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
return _volData->getVoxelAt(x, y, z);
|
||||
}
|
||||
|
||||
|
||||
|
@ -675,9 +704,7 @@ bool RenderablePolyVoxEntityItem::setVoxelInternal(int x, int y, int z, uint8_t
|
|||
|
||||
result = updateOnCount(x, y, z, toValue);
|
||||
|
||||
assert(_volData);
|
||||
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_CUBIC ||
|
||||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
|
||||
if (isEdged(_voxelSurfaceStyle)) {
|
||||
_volData->setVoxelAt(x + 1, y + 1, z + 1, toValue);
|
||||
} else {
|
||||
_volData->setVoxelAt(x, y, z, toValue);
|
||||
|
@ -710,13 +737,11 @@ bool RenderablePolyVoxEntityItem::updateOnCount(int x, int y, int z, uint8_t toV
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
void RenderablePolyVoxEntityItem::decompressVolumeData() {
|
||||
_threadRunning.acquire();
|
||||
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::decompressVolumeDataAsync);
|
||||
}
|
||||
|
||||
|
||||
// take compressed data and expand it into _volData.
|
||||
void RenderablePolyVoxEntityItem::decompressVolumeDataAsync() {
|
||||
_voxelDataLock.lockForRead();
|
||||
|
@ -777,7 +802,6 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() {
|
|||
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacketAsync);
|
||||
}
|
||||
|
||||
|
||||
// compress the data in _volData and save the results. The compressed form is used during
|
||||
// saves to disk and for transmission over the wire
|
||||
void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacketAsync() {
|
||||
|
@ -850,23 +874,157 @@ void RenderablePolyVoxEntityItem::getMesh() {
|
|||
QtConcurrent::run(this, &RenderablePolyVoxEntityItem::getMeshAsync);
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::clearOutOfDateNeighbors() {
|
||||
if (_xNNeighborID != UNKNOWN_ENTITY_ID) {
|
||||
EntityItemPointer currentXNNeighbor = _xNNeighbor.lock();
|
||||
if (currentXNNeighbor && currentXNNeighbor->getID() != _xNNeighborID) {
|
||||
_xNNeighbor.reset();
|
||||
}
|
||||
}
|
||||
if (_yNNeighborID != UNKNOWN_ENTITY_ID) {
|
||||
EntityItemPointer currentYNNeighbor = _yNNeighbor.lock();
|
||||
if (currentYNNeighbor && currentYNNeighbor->getID() != _yNNeighborID) {
|
||||
_yNNeighbor.reset();
|
||||
}
|
||||
}
|
||||
if (_zNNeighborID != UNKNOWN_ENTITY_ID) {
|
||||
EntityItemPointer currentZNNeighbor = _zNNeighbor.lock();
|
||||
if (currentZNNeighbor && currentZNNeighbor->getID() != _zNNeighborID) {
|
||||
_zNNeighbor.reset();
|
||||
}
|
||||
}
|
||||
|
||||
if (_xPNeighborID != UNKNOWN_ENTITY_ID) {
|
||||
EntityItemPointer currentXPNeighbor = _xPNeighbor.lock();
|
||||
if (currentXPNeighbor && currentXPNeighbor->getID() != _xPNeighborID) {
|
||||
_xPNeighbor.reset();
|
||||
}
|
||||
}
|
||||
if (_yPNeighborID != UNKNOWN_ENTITY_ID) {
|
||||
EntityItemPointer currentYPNeighbor = _yPNeighbor.lock();
|
||||
if (currentYPNeighbor && currentYPNeighbor->getID() != _yPNeighborID) {
|
||||
_yPNeighbor.reset();
|
||||
}
|
||||
}
|
||||
if (_zPNeighborID != UNKNOWN_ENTITY_ID) {
|
||||
EntityItemPointer currentZPNeighbor = _zPNeighbor.lock();
|
||||
if (currentZPNeighbor && currentZPNeighbor->getID() != _zPNeighborID) {
|
||||
_zPNeighbor.reset();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::cacheNeighbors() {
|
||||
clearOutOfDateNeighbors();
|
||||
EntityTreeElement* element = getElement();
|
||||
EntityTree* tree = element ? element->getTree() : nullptr;
|
||||
if (!tree) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_xNNeighborID != UNKNOWN_ENTITY_ID && _xNNeighbor.expired()) {
|
||||
_xNNeighbor = tree->findEntityByID(_xNNeighborID);
|
||||
}
|
||||
if (_yNNeighborID != UNKNOWN_ENTITY_ID && _yNNeighbor.expired()) {
|
||||
_yNNeighbor = tree->findEntityByID(_yNNeighborID);
|
||||
}
|
||||
if (_zNNeighborID != UNKNOWN_ENTITY_ID && _zNNeighbor.expired()) {
|
||||
_zNNeighbor = tree->findEntityByID(_zNNeighborID);
|
||||
}
|
||||
|
||||
if (_xPNeighborID != UNKNOWN_ENTITY_ID && _xPNeighbor.expired()) {
|
||||
_xPNeighbor = tree->findEntityByID(_xPNeighborID);
|
||||
}
|
||||
if (_yPNeighborID != UNKNOWN_ENTITY_ID && _yPNeighbor.expired()) {
|
||||
_yPNeighbor = tree->findEntityByID(_yPNeighborID);
|
||||
}
|
||||
if (_zPNeighborID != UNKNOWN_ENTITY_ID && _zPNeighbor.expired()) {
|
||||
_zPNeighbor = tree->findEntityByID(_zPNeighborID);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::copyUpperEdgesFromNeighbors() {
|
||||
if (_voxelSurfaceStyle != PolyVoxEntityItem::SURFACE_MARCHING_CUBES) {
|
||||
return;
|
||||
}
|
||||
|
||||
EntityItemPointer currentXPNeighbor = _xPNeighbor.lock();
|
||||
EntityItemPointer currentYPNeighbor = _yPNeighbor.lock();
|
||||
EntityItemPointer currentZPNeighbor = _zPNeighbor.lock();
|
||||
|
||||
if (currentXPNeighbor) {
|
||||
auto polyVoxXPNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentXPNeighbor);
|
||||
if (polyVoxXPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
||||
for (int y = 0; y < _volData->getHeight(); y++) {
|
||||
for (int z = 0; z < _volData->getDepth(); z++) {
|
||||
uint8_t neighborValue = polyVoxXPNeighbor->getVoxel(0, y, z);
|
||||
_volData->setVoxelAt(_volData->getWidth() - 1, y, z, neighborValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentYPNeighbor) {
|
||||
auto polyVoxYPNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentYPNeighbor);
|
||||
if (polyVoxYPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
||||
for (int x = 0; x < _volData->getWidth(); x++) {
|
||||
for (int z = 0; z < _volData->getDepth(); z++) {
|
||||
uint8_t neighborValue = polyVoxYPNeighbor->getVoxel(x, 0, z);
|
||||
_volData->setVoxelAt(x, _volData->getWidth() - 1, z, neighborValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentZPNeighbor) {
|
||||
auto polyVoxZPNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentZPNeighbor);
|
||||
if (polyVoxZPNeighbor->getVoxelVolumeSize() == _voxelVolumeSize) {
|
||||
for (int x = 0; x < _volData->getWidth(); x++) {
|
||||
for (int y = 0; y < _volData->getHeight(); y++) {
|
||||
uint8_t neighborValue = polyVoxZPNeighbor->getVoxel(x, y, 0);
|
||||
_volData->setVoxelAt(x, y, _volData->getDepth() - 1, neighborValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::getMeshAsync() {
|
||||
model::MeshPointer mesh(new model::Mesh());
|
||||
|
||||
cacheNeighbors();
|
||||
|
||||
// A mesh object to hold the result of surface extraction
|
||||
PolyVox::SurfaceMesh<PolyVox::PositionMaterialNormal> polyVoxMesh;
|
||||
|
||||
_volDataLock.lockForRead();
|
||||
if (!_volData) {
|
||||
_volDataLock.unlock();
|
||||
return;
|
||||
}
|
||||
copyUpperEdgesFromNeighbors();
|
||||
|
||||
switch (_voxelSurfaceStyle) {
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES:
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: {
|
||||
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||
surfaceExtractor.execute();
|
||||
break;
|
||||
}
|
||||
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: {
|
||||
PolyVox::MarchingCubesSurfaceExtractor<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||
surfaceExtractor.execute();
|
||||
break;
|
||||
}
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC:
|
||||
case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: {
|
||||
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||
surfaceExtractor.execute();
|
||||
break;
|
||||
}
|
||||
case PolyVoxEntityItem::SURFACE_CUBIC: {
|
||||
PolyVox::CubicSurfaceExtractorWithNormals<PolyVox::SimpleVolume<uint8_t>> surfaceExtractor
|
||||
(_volData, _volData->getEnclosingRegion(), &polyVoxMesh);
|
||||
|
@ -908,7 +1066,7 @@ void RenderablePolyVoxEntityItem::getMeshAsync() {
|
|||
_meshLock.unlock();
|
||||
_volDataDirty = false;
|
||||
_volDataLock.unlock();
|
||||
|
||||
bonkNeighbors();
|
||||
_threadRunning.release();
|
||||
}
|
||||
|
||||
|
@ -925,7 +1083,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
|
|||
|
||||
if (_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_MARCHING_CUBES ||
|
||||
_voxelSurfaceStyle == PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES) {
|
||||
/* pull each triangle in the mesh into a polyhedron which can be collided with */
|
||||
// pull each triangle in the mesh into a polyhedron which can be collided with
|
||||
unsigned int i = 0;
|
||||
|
||||
_meshLock.lockForRead();
|
||||
|
@ -972,10 +1130,16 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
|
|||
} else {
|
||||
unsigned int i = 0;
|
||||
|
||||
_volDataLock.lockForRead();
|
||||
if (!_volData) {
|
||||
_volDataLock.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
for (int z = 0; z < _voxelVolumeSize.z; z++) {
|
||||
for (int y = 0; y < _voxelVolumeSize.y; y++) {
|
||||
for (int x = 0; x < _voxelVolumeSize.x; x++) {
|
||||
if (getVoxel(x, y, z) > 0) {
|
||||
if (getVoxelInternal(x, y, z) > 0) {
|
||||
|
||||
if ((x > 0 && getVoxel(x - 1, y, z) > 0) &&
|
||||
(y > 0 && getVoxel(x, y - 1, z) > 0) &&
|
||||
|
@ -1033,6 +1197,7 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
|
|||
}
|
||||
}
|
||||
}
|
||||
_volDataLock.unlock();
|
||||
}
|
||||
|
||||
if (points.isEmpty()) {
|
||||
|
@ -1056,3 +1221,93 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
|
|||
_threadRunning.release();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void RenderablePolyVoxEntityItem::setXNNeighborID(const EntityItemID& xNNeighborID) {
|
||||
if (xNNeighborID != _xNNeighborID) {
|
||||
PolyVoxEntityItem::setXNNeighborID(xNNeighborID);
|
||||
cacheNeighbors();
|
||||
EntityItemPointer currentXNNeighbor = _xNNeighbor.lock();
|
||||
if (currentXNNeighbor && currentXNNeighbor->getType() == EntityTypes::PolyVox) {
|
||||
auto polyVoxXNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentXNNeighbor);
|
||||
polyVoxXNNeighbor->setXPNeighborID(_id);
|
||||
polyVoxXNNeighbor->rebakeMesh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setYNNeighborID(const EntityItemID& yNNeighborID) {
|
||||
if (yNNeighborID != _yNNeighborID) {
|
||||
PolyVoxEntityItem::setYNNeighborID(yNNeighborID);
|
||||
cacheNeighbors();
|
||||
EntityItemPointer currentYNNeighbor = _yNNeighbor.lock();
|
||||
if (currentYNNeighbor && currentYNNeighbor->getType() == EntityTypes::PolyVox) {
|
||||
auto polyVoxYNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentYNNeighbor);
|
||||
polyVoxYNNeighbor->setYPNeighborID(_id);
|
||||
polyVoxYNNeighbor->rebakeMesh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setZNNeighborID(const EntityItemID& zNNeighborID) {
|
||||
if (zNNeighborID != _zNNeighborID) {
|
||||
PolyVoxEntityItem::setZNNeighborID(zNNeighborID);
|
||||
cacheNeighbors();
|
||||
EntityItemPointer currentZNNeighbor = _yNNeighbor.lock();
|
||||
if (currentZNNeighbor && currentZNNeighbor->getType() == EntityTypes::PolyVox) {
|
||||
auto polyVoxZNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentZNNeighbor);
|
||||
polyVoxZNNeighbor->setZPNeighborID(_id);
|
||||
polyVoxZNNeighbor->rebakeMesh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RenderablePolyVoxEntityItem::setXPNeighborID(const EntityItemID& xPNeighborID) {
|
||||
if (xPNeighborID != _xPNeighborID) {
|
||||
PolyVoxEntityItem::setXPNeighborID(xPNeighborID);
|
||||
rebakeMesh();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setYPNeighborID(const EntityItemID& yPNeighborID) {
|
||||
if (yPNeighborID != _yPNeighborID) {
|
||||
PolyVoxEntityItem::setYPNeighborID(yPNeighborID);
|
||||
rebakeMesh();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::setZPNeighborID(const EntityItemID& zPNeighborID) {
|
||||
if (zPNeighborID != _zPNeighborID) {
|
||||
PolyVoxEntityItem::setZPNeighborID(zPNeighborID);
|
||||
rebakeMesh();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RenderablePolyVoxEntityItem::rebakeMesh() {
|
||||
QReadLocker(&this->_volDataLock);
|
||||
_volDataDirty = true;
|
||||
}
|
||||
|
||||
void RenderablePolyVoxEntityItem::bonkNeighbors() {
|
||||
clearOutOfDateNeighbors();
|
||||
cacheNeighbors();
|
||||
|
||||
EntityItemPointer currentXNNeighbor = _xNNeighbor.lock();
|
||||
EntityItemPointer currentYNNeighbor = _yNNeighbor.lock();
|
||||
EntityItemPointer currentZNNeighbor = _zNNeighbor.lock();
|
||||
|
||||
if (currentXNNeighbor && currentXNNeighbor->getType() == EntityTypes::PolyVox) {
|
||||
auto polyVoxXNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentXNNeighbor);
|
||||
polyVoxXNNeighbor->rebakeMesh();
|
||||
}
|
||||
if (currentYNNeighbor && currentYNNeighbor->getType() == EntityTypes::PolyVox) {
|
||||
auto polyVoxYNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentYNNeighbor);
|
||||
polyVoxYNNeighbor->rebakeMesh();
|
||||
}
|
||||
if (currentZNNeighbor && currentZNNeighbor->getType() == EntityTypes::PolyVox) {
|
||||
auto polyVoxZNNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentZNNeighbor);
|
||||
polyVoxZNNeighbor->rebakeMesh();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ public:
|
|||
// coords are in world-space
|
||||
virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue);
|
||||
virtual bool setAll(uint8_t toValue);
|
||||
virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue);
|
||||
|
||||
virtual void setXTextureURL(QString xTextureURL);
|
||||
virtual void setYTextureURL(QString yTextureURL);
|
||||
|
@ -105,6 +106,16 @@ public:
|
|||
std::shared_ptr<render::Scene> scene,
|
||||
render::PendingChanges& pendingChanges);
|
||||
|
||||
virtual void setXNNeighborID(const EntityItemID& xNNeighborID);
|
||||
virtual void setYNNeighborID(const EntityItemID& yNNeighborID);
|
||||
virtual void setZNNeighborID(const EntityItemID& zNNeighborID);
|
||||
|
||||
virtual void setXPNeighborID(const EntityItemID& xPNeighborID);
|
||||
virtual void setYPNeighborID(const EntityItemID& yPNeighborID);
|
||||
virtual void setZPNeighborID(const EntityItemID& zPNeighborID);
|
||||
|
||||
virtual void rebakeMesh();
|
||||
|
||||
private:
|
||||
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
|
||||
// may not match _voxelVolumeSize.
|
||||
|
@ -130,7 +141,7 @@ private:
|
|||
int _onCount; // how many non-zero voxels are in _volData
|
||||
|
||||
bool inUserBounds(const PolyVox::SimpleVolume<uint8_t>* vol, PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
|
||||
int x, int y, int z);
|
||||
int x, int y, int z) const;
|
||||
uint8_t getVoxelInternal(int x, int y, int z);
|
||||
bool setVoxelInternal(int x, int y, int z, uint8_t toValue);
|
||||
bool updateOnCount(int x, int y, int z, uint8_t toValue);
|
||||
|
@ -147,6 +158,18 @@ private:
|
|||
void computeShapeInfoWorkerAsync();
|
||||
|
||||
QSemaphore _threadRunning{1};
|
||||
|
||||
// these are cached lookups of _xNNeighborID, _yNNeighborID, _zNNeighborID, _xPNeighborID, _yPNeighborID, _zPNeighborID
|
||||
EntityItemWeakPointer _xNNeighbor; // neighor found by going along negative X axis
|
||||
EntityItemWeakPointer _yNNeighbor;
|
||||
EntityItemWeakPointer _zNNeighbor;
|
||||
EntityItemWeakPointer _xPNeighbor; // neighor found by going along positive X axis
|
||||
EntityItemWeakPointer _yPNeighbor;
|
||||
EntityItemWeakPointer _zPNeighbor;
|
||||
void clearOutOfDateNeighbors();
|
||||
void cacheNeighbors();
|
||||
void copyUpperEdgesFromNeighbors();
|
||||
void bonkNeighbors();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -12,16 +12,12 @@
|
|||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
|
||||
layout(location = 0) out vec4 _fragColor0;
|
||||
layout(location = 1) out vec4 _fragColor1;
|
||||
layout(location = 2) out vec4 _fragColor2;
|
||||
|
||||
<@include model/Material.slh@>
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
in vec3 _normal;
|
||||
in vec4 _position;
|
||||
in vec4 _inPosition;
|
||||
in vec4 _worldPosition;
|
||||
|
||||
uniform sampler2D xMap;
|
||||
uniform sampler2D yMap;
|
||||
|
@ -29,12 +25,12 @@ uniform sampler2D zMap;
|
|||
uniform vec3 voxelVolumeSize;
|
||||
|
||||
void main(void) {
|
||||
vec3 worldNormal = cross(dFdy(_inPosition.xyz), dFdx(_inPosition.xyz));
|
||||
vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz));
|
||||
worldNormal = normalize(worldNormal);
|
||||
|
||||
float inPositionX = (_inPosition.x - 0.5) / voxelVolumeSize.x;
|
||||
float inPositionY = (_inPosition.y - 0.5) / voxelVolumeSize.y;
|
||||
float inPositionZ = (_inPosition.z - 0.5) / voxelVolumeSize.z;
|
||||
float inPositionX = (_worldPosition.x - 0.5) / voxelVolumeSize.x;
|
||||
float inPositionY = (_worldPosition.y - 0.5) / voxelVolumeSize.y;
|
||||
float inPositionZ = (_worldPosition.z - 0.5) / voxelVolumeSize.z;
|
||||
|
||||
vec4 xyDiffuse = texture(xMap, vec2(-inPositionX, -inPositionY));
|
||||
vec4 xzDiffuse = texture(yMap, vec2(-inPositionX, inPositionZ));
|
||||
|
@ -43,12 +39,7 @@ void main(void) {
|
|||
vec3 xyDiffuseScaled = xyDiffuse.rgb * abs(worldNormal.z);
|
||||
vec3 xzDiffuseScaled = xzDiffuse.rgb * abs(worldNormal.y);
|
||||
vec3 yzDiffuseScaled = yzDiffuse.rgb * abs(worldNormal.x);
|
||||
|
||||
vec4 diffuse = vec4(xyDiffuseScaled + xzDiffuseScaled + yzDiffuseScaled, 1.0);
|
||||
|
||||
Material mat = getMaterial();
|
||||
|
||||
_fragColor0 = vec4(diffuse.rgb, 0.0);
|
||||
_fragColor1 = vec4(_normal, 1.0);
|
||||
_fragColor2 = vec4(getMaterialSpecular(mat), getMaterialShininess(mat) / 128.0);
|
||||
packDeferredFragment(_normal, 0.0, vec3(diffuse), vec3(0.01, 0.01, 0.01), 10.0);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<$declareStandardTransform()$>
|
||||
|
||||
out vec4 _position;
|
||||
out vec4 _inPosition;
|
||||
out vec4 _worldPosition;
|
||||
out vec3 _normal;
|
||||
|
||||
void main(void) {
|
||||
|
@ -26,5 +26,5 @@ void main(void) {
|
|||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$>
|
||||
<$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$>
|
||||
_inPosition = inPosition;
|
||||
_worldPosition = inPosition;
|
||||
}
|
||||
|
|
|
@ -32,26 +32,8 @@ public:
|
|||
QScriptValue toScriptValue(QScriptEngine* engine) const;
|
||||
|
||||
bool isInvalidID() const { return *this == UNKNOWN_ENTITY_ID; }
|
||||
|
||||
// QUuid id;
|
||||
};
|
||||
|
||||
// inline bool operator<(const EntityItemID& a, const EntityItemID& b) {
|
||||
// return a.id < b.id;
|
||||
// }
|
||||
|
||||
// inline bool operator==(const EntityItemID& a, const EntityItemID& b) {
|
||||
// return a.id == b.id;
|
||||
// }
|
||||
|
||||
// inline bool operator!=(const EntityItemID& a, const EntityItemID& b) {
|
||||
// return !(a == b);
|
||||
// }
|
||||
|
||||
// inline uint qHash(const EntityItemID& a, uint seed) {
|
||||
// return qHash(a.id, seed);
|
||||
// }
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const EntityItemID& id) {
|
||||
debug << "[entity-id:" << id.toString() << "]";
|
||||
return debug;
|
||||
|
|
|
@ -109,6 +109,13 @@ CONSTRUCT_PROPERTY(strokeWidths, QVector<float>()),
|
|||
CONSTRUCT_PROPERTY(xTextureURL, ""),
|
||||
CONSTRUCT_PROPERTY(yTextureURL, ""),
|
||||
CONSTRUCT_PROPERTY(zTextureURL, ""),
|
||||
CONSTRUCT_PROPERTY(xNNeighborID, UNKNOWN_ENTITY_ID),
|
||||
CONSTRUCT_PROPERTY(yNNeighborID, UNKNOWN_ENTITY_ID),
|
||||
CONSTRUCT_PROPERTY(zNNeighborID, UNKNOWN_ENTITY_ID),
|
||||
CONSTRUCT_PROPERTY(xPNeighborID, UNKNOWN_ENTITY_ID),
|
||||
CONSTRUCT_PROPERTY(yPNeighborID, UNKNOWN_ENTITY_ID),
|
||||
CONSTRUCT_PROPERTY(zPNeighborID, UNKNOWN_ENTITY_ID),
|
||||
|
||||
|
||||
_id(UNKNOWN_ENTITY_ID),
|
||||
_idSet(false),
|
||||
|
@ -377,6 +384,12 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_X_TEXTURE_URL, xTextureURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_Y_TEXTURE_URL, yTextureURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_Z_TEXTURE_URL, zTextureURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_X_N_NEIGHBOR_ID, xNNeighborID);
|
||||
CHECK_PROPERTY_CHANGE(PROP_Y_N_NEIGHBOR_ID, yNNeighborID);
|
||||
CHECK_PROPERTY_CHANGE(PROP_Z_N_NEIGHBOR_ID, zNNeighborID);
|
||||
CHECK_PROPERTY_CHANGE(PROP_X_P_NEIGHBOR_ID, xPNeighborID);
|
||||
CHECK_PROPERTY_CHANGE(PROP_Y_P_NEIGHBOR_ID, yPNeighborID);
|
||||
CHECK_PROPERTY_CHANGE(PROP_Z_P_NEIGHBOR_ID, zPNeighborID);
|
||||
|
||||
changedProperties += _stage.getChangedProperties();
|
||||
changedProperties += _atmosphere.getChangedProperties();
|
||||
|
@ -521,6 +534,14 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(yTextureURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(zTextureURL);
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(xNNeighborID);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(yNNeighborID);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(zNNeighborID);
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(xPNeighborID);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(yPNeighborID);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(zPNeighborID);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
|
@ -620,6 +641,14 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(yTextureURL, QString, setYTextureURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(zTextureURL, QString, setZTextureURL);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(xNNeighborID, EntityItemID, setXNNeighborID);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(yNNeighborID, EntityItemID, setYNNeighborID);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(zNNeighborID, EntityItemID, setZNNeighborID);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(xPNeighborID, EntityItemID, setXPNeighborID);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(yPNeighborID, EntityItemID, setYPNeighborID);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(zPNeighborID, EntityItemID, setZPNeighborID);
|
||||
|
||||
_lastEdited = usecTimestampNow();
|
||||
}
|
||||
|
||||
|
@ -852,6 +881,12 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent
|
|||
APPEND_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, properties.getXTextureURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, properties.getYTextureURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, properties.getZTextureURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_X_N_NEIGHBOR_ID, properties.getXNNeighborID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Y_N_NEIGHBOR_ID, properties.getYNNeighborID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Z_N_NEIGHBOR_ID, properties.getZNNeighborID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_X_P_NEIGHBOR_ID, properties.getXPNeighborID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Y_P_NEIGHBOR_ID, properties.getYPNeighborID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Z_P_NEIGHBOR_ID, properties.getZPNeighborID());
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Line) {
|
||||
|
@ -1115,6 +1150,12 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_X_TEXTURE_URL, QString, setXTextureURL);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_TEXTURE_URL, QString, setYTextureURL);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Z_TEXTURE_URL, QString, setZTextureURL);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_X_N_NEIGHBOR_ID, EntityItemID, setXNNeighborID);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_N_NEIGHBOR_ID, EntityItemID, setYNNeighborID);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Z_N_NEIGHBOR_ID, EntityItemID, setZNNeighborID);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_X_P_NEIGHBOR_ID, EntityItemID, setXPNeighborID);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Y_P_NEIGHBOR_ID, EntityItemID, setYPNeighborID);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_Z_P_NEIGHBOR_ID, EntityItemID, setZPNeighborID);
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Line) {
|
||||
|
@ -1248,13 +1289,21 @@ void EntityItemProperties::markAllChanged() {
|
|||
_descriptionChanged = true;
|
||||
_faceCameraChanged = true;
|
||||
_actionDataChanged = true;
|
||||
|
||||
|
||||
_normalsChanged = true;
|
||||
_strokeWidthsChanged = true;
|
||||
|
||||
_xTextureURLChanged = true;
|
||||
_yTextureURLChanged = true;
|
||||
_zTextureURLChanged = true;
|
||||
|
||||
_xNNeighborIDChanged = true;
|
||||
_yNNeighborIDChanged = true;
|
||||
_zNNeighborIDChanged = true;
|
||||
|
||||
_xPNeighborIDChanged = true;
|
||||
_yPNeighborIDChanged = true;
|
||||
_zPNeighborIDChanged = true;
|
||||
}
|
||||
|
||||
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||
|
|
|
@ -161,6 +161,12 @@ public:
|
|||
DEFINE_PROPERTY_REF(PROP_X_TEXTURE_URL, XTextureURL, xTextureURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_Y_TEXTURE_URL, YTextureURL, yTextureURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_Z_TEXTURE_URL, ZTextureURL, zTextureURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_X_N_NEIGHBOR_ID, XNNeighborID, xNNeighborID, EntityItemID);
|
||||
DEFINE_PROPERTY_REF(PROP_Y_N_NEIGHBOR_ID, YNNeighborID, yNNeighborID, EntityItemID);
|
||||
DEFINE_PROPERTY_REF(PROP_Z_N_NEIGHBOR_ID, ZNNeighborID, zNNeighborID, EntityItemID);
|
||||
DEFINE_PROPERTY_REF(PROP_X_P_NEIGHBOR_ID, XPNeighborID, xPNeighborID, EntityItemID);
|
||||
DEFINE_PROPERTY_REF(PROP_Y_P_NEIGHBOR_ID, YPNeighborID, yPNeighborID, EntityItemID);
|
||||
DEFINE_PROPERTY_REF(PROP_Z_P_NEIGHBOR_ID, ZPNeighborID, zPNeighborID, EntityItemID);
|
||||
|
||||
static QString getBackgroundModeString(BackgroundMode mode);
|
||||
|
||||
|
@ -327,6 +333,12 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, XTextureURL, xTextureURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, YTextureURL, yTextureURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZTextureURL, zTextureURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, XNNeighborID, xNNeighborID, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, YNNeighborID, yNNeighborID, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZNNeighborID, zNNeighborID, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, XPNeighborID, xPNeighborID, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, YPNeighborID, yPNeighborID, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ZPNeighborID, zPNeighborID, "");
|
||||
|
||||
properties.getStage().debugDump();
|
||||
properties.getAtmosphere().debugDump();
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#ifndef hifi_EntityItemPropertiesMacros_h
|
||||
#define hifi_EntityItemPropertiesMacros_h
|
||||
|
||||
#include "EntityItemID.h"
|
||||
|
||||
#define APPEND_ENTITY_PROPERTY(P,V) \
|
||||
if (requestedProperties.getHasProperty(P)) { \
|
||||
LevelDetails propertyLevel = packetData->startLevel(); \
|
||||
|
@ -106,6 +108,9 @@ inline QScriptValue convertScriptValue(QScriptEngine* e, const QByteArray& v) {
|
|||
return QScriptValue(QString(b64));
|
||||
}
|
||||
|
||||
inline QScriptValue convertScriptValue(QScriptEngine* e, const EntityItemID& v) { return QScriptValue(QUuid(v).toString()); }
|
||||
|
||||
|
||||
#define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(G,g,P,p) \
|
||||
if (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P()) { \
|
||||
QScriptValue groupProperties = properties.property(#g); \
|
||||
|
@ -143,6 +148,9 @@ inline int int_convertFromScriptValue(const QScriptValue& v, bool& isValid) { re
|
|||
inline bool bool_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }
|
||||
inline QString QString_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); }
|
||||
inline QUuid QUuid_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
|
||||
inline EntityItemID EntityItemID_convertFromScriptValue(const QScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
|
||||
|
||||
|
||||
|
||||
inline QDateTime QDateTime_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
|
||||
isValid = true;
|
||||
|
|
|
@ -124,21 +124,28 @@ enum EntityPropertyList {
|
|||
|
||||
PROP_FACE_CAMERA,
|
||||
PROP_SCRIPT_TIMESTAMP,
|
||||
|
||||
|
||||
PROP_ACTION_DATA,
|
||||
|
||||
|
||||
PROP_X_TEXTURE_URL, // used by PolyVox
|
||||
PROP_Y_TEXTURE_URL, // used by PolyVox
|
||||
PROP_Z_TEXTURE_URL, // used by PolyVox
|
||||
|
||||
|
||||
// Used by PolyLine entity
|
||||
PROP_NORMALS,
|
||||
PROP_STROKE_WIDTHS,
|
||||
|
||||
|
||||
// used by particles
|
||||
PROP_VELOCITY_SPREAD,
|
||||
PROP_ACCELERATION_SPREAD,
|
||||
|
||||
PROP_X_N_NEIGHBOR_ID, // used by PolyVox
|
||||
PROP_Y_N_NEIGHBOR_ID, // used by PolyVox
|
||||
PROP_Z_N_NEIGHBOR_ID, // used by PolyVox
|
||||
PROP_X_P_NEIGHBOR_ID, // used by PolyVox
|
||||
PROP_Y_P_NEIGHBOR_ID, // used by PolyVox
|
||||
PROP_Z_P_NEIGHBOR_ID, // used by PolyVox
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ATTENTION: add new properties to end of list just ABOVE this line
|
||||
PROP_AFTER_LAST_ITEM,
|
||||
|
|
|
@ -493,6 +493,13 @@ bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) {
|
|||
});
|
||||
}
|
||||
|
||||
bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition,
|
||||
const glm::vec3& cuboidSize, int value) {
|
||||
return setVoxels(entityID, [lowPosition, cuboidSize, value](PolyVoxEntityItem& polyVoxEntity) {
|
||||
return polyVoxEntity.setCuboid(lowPosition, cuboidSize, value);
|
||||
});
|
||||
}
|
||||
|
||||
bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector<glm::vec3>& points) {
|
||||
EntityItemPointer entity = static_cast<EntityItemPointer>(_entityTree->findEntityByEntityItemID(entityID));
|
||||
if (!entity) {
|
||||
|
|
|
@ -122,6 +122,8 @@ public slots:
|
|||
Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value);
|
||||
Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value);
|
||||
Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value);
|
||||
Q_INVOKABLE bool setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition,
|
||||
const glm::vec3& cuboidSize, int value);
|
||||
|
||||
Q_INVOKABLE bool setAllPoints(QUuid entityID, const QVector<glm::vec3>& points);
|
||||
Q_INVOKABLE bool appendPoint(QUuid entityID, const glm::vec3& point);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QWriteLocker>
|
||||
|
||||
#include <ByteCountCoding.h>
|
||||
|
||||
|
@ -56,13 +57,14 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const Ent
|
|||
_voxelSurfaceStyle(PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE),
|
||||
_xTextureURL(PolyVoxEntityItem::DEFAULT_X_TEXTURE_URL),
|
||||
_yTextureURL(PolyVoxEntityItem::DEFAULT_Y_TEXTURE_URL),
|
||||
_zTextureURL(PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL)
|
||||
{
|
||||
_zTextureURL(PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL) {
|
||||
_type = EntityTypes::PolyVox;
|
||||
setProperties(properties);
|
||||
}
|
||||
|
||||
void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
|
||||
QWriteLocker(&this->_voxelDataLock);
|
||||
|
||||
assert((int)_voxelVolumeSize.x == _voxelVolumeSize.x);
|
||||
assert((int)_voxelVolumeSize.y == _voxelVolumeSize.y);
|
||||
assert((int)_voxelVolumeSize.z == _voxelVolumeSize.z);
|
||||
|
@ -96,6 +98,12 @@ void PolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) {
|
|||
}
|
||||
}
|
||||
|
||||
const glm::vec3& PolyVoxEntityItem::getVoxelVolumeSize() const {
|
||||
QWriteLocker locker(&this->_voxelDataLock);
|
||||
return _voxelVolumeSize;
|
||||
}
|
||||
|
||||
|
||||
EntityItemProperties PolyVoxEntityItem::getProperties() const {
|
||||
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(voxelVolumeSize, getVoxelVolumeSize);
|
||||
|
@ -104,6 +112,12 @@ EntityItemProperties PolyVoxEntityItem::getProperties() const {
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(xTextureURL, getXTextureURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(yTextureURL, getYTextureURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(zTextureURL, getZTextureURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(xNNeighborID, getXNNeighborID);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(yNNeighborID, getYNNeighborID);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(zNNeighborID, getZNNeighborID);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(xPNeighborID, getXPNeighborID);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(yPNeighborID, getYPNeighborID);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(zPNeighborID, getZPNeighborID);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
@ -116,6 +130,12 @@ bool PolyVoxEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(xTextureURL, setXTextureURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(yTextureURL, setYTextureURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(zTextureURL, setZTextureURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(xNNeighborID, setXNNeighborID);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(yNNeighborID, setYNNeighborID);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(zNNeighborID, setZNNeighborID);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(xPNeighborID, setXPNeighborID);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(yPNeighborID, setYPNeighborID);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(zPNeighborID, setZPNeighborID);
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
|
@ -143,6 +163,12 @@ int PolyVoxEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* dat
|
|||
READ_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, QString, setXTextureURL);
|
||||
READ_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, QString, setYTextureURL);
|
||||
READ_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, QString, setZTextureURL);
|
||||
READ_ENTITY_PROPERTY(PROP_X_N_NEIGHBOR_ID, EntityItemID, setXNNeighborID);
|
||||
READ_ENTITY_PROPERTY(PROP_Y_N_NEIGHBOR_ID, EntityItemID, setYNNeighborID);
|
||||
READ_ENTITY_PROPERTY(PROP_Z_N_NEIGHBOR_ID, EntityItemID, setZNNeighborID);
|
||||
READ_ENTITY_PROPERTY(PROP_X_P_NEIGHBOR_ID, EntityItemID, setXPNeighborID);
|
||||
READ_ENTITY_PROPERTY(PROP_Y_P_NEIGHBOR_ID, EntityItemID, setYPNeighborID);
|
||||
READ_ENTITY_PROPERTY(PROP_Z_P_NEIGHBOR_ID, EntityItemID, setZPNeighborID);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
@ -157,16 +183,22 @@ EntityPropertyFlags PolyVoxEntityItem::getEntityProperties(EncodeBitstreamParams
|
|||
requestedProperties += PROP_X_TEXTURE_URL;
|
||||
requestedProperties += PROP_Y_TEXTURE_URL;
|
||||
requestedProperties += PROP_Z_TEXTURE_URL;
|
||||
requestedProperties += PROP_X_N_NEIGHBOR_ID;
|
||||
requestedProperties += PROP_Y_N_NEIGHBOR_ID;
|
||||
requestedProperties += PROP_Z_N_NEIGHBOR_ID;
|
||||
requestedProperties += PROP_X_P_NEIGHBOR_ID;
|
||||
requestedProperties += PROP_Y_P_NEIGHBOR_ID;
|
||||
requestedProperties += PROP_Z_P_NEIGHBOR_ID;
|
||||
return requestedProperties;
|
||||
}
|
||||
|
||||
void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
|
||||
EntityPropertyFlags& requestedProperties,
|
||||
EntityPropertyFlags& propertyFlags,
|
||||
EntityPropertyFlags& propertiesDidntFit,
|
||||
int& propertyCount,
|
||||
OctreeElement::AppendState& appendState) const {
|
||||
int& propertyCount,
|
||||
OctreeElement::AppendState& appendState) const {
|
||||
bool successPropertyFits = true;
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_VOXEL_VOLUME_SIZE, getVoxelVolumeSize());
|
||||
|
@ -175,7 +207,12 @@ void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeB
|
|||
APPEND_ENTITY_PROPERTY(PROP_X_TEXTURE_URL, getXTextureURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Y_TEXTURE_URL, getYTextureURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Z_TEXTURE_URL, getZTextureURL());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_X_N_NEIGHBOR_ID, getXNNeighborID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Y_N_NEIGHBOR_ID, getYNNeighborID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Z_N_NEIGHBOR_ID, getZNNeighborID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_X_P_NEIGHBOR_ID, getXPNeighborID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Y_P_NEIGHBOR_ID, getYPNeighborID());
|
||||
APPEND_ENTITY_PROPERTY(PROP_Z_P_NEIGHBOR_ID, getZPNeighborID());
|
||||
}
|
||||
|
||||
void PolyVoxEntityItem::debugDump() const {
|
||||
|
@ -187,15 +224,12 @@ void PolyVoxEntityItem::debugDump() const {
|
|||
}
|
||||
|
||||
void PolyVoxEntityItem::setVoxelData(QByteArray voxelData) {
|
||||
_voxelDataLock.lockForWrite();
|
||||
QWriteLocker(&this->_voxelDataLock);
|
||||
_voxelData = voxelData;
|
||||
_voxelDataDirty = true;
|
||||
_voxelDataLock.unlock();
|
||||
}
|
||||
|
||||
const QByteArray PolyVoxEntityItem::getVoxelData() const {
|
||||
_voxelDataLock.lockForRead();
|
||||
auto result = _voxelData;
|
||||
_voxelDataLock.unlock();
|
||||
return result;
|
||||
QReadLocker(&this->_voxelDataLock);
|
||||
return _voxelData;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
virtual void debugDump() const;
|
||||
|
||||
virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize);
|
||||
virtual const glm::vec3& getVoxelVolumeSize() const { return _voxelVolumeSize; }
|
||||
virtual const glm::vec3& getVoxelVolumeSize() const;
|
||||
|
||||
virtual void setVoxelData(QByteArray voxelData);
|
||||
virtual const QByteArray getVoxelData() const;
|
||||
|
@ -85,6 +85,7 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
// coords are in world-space
|
||||
virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) { return false; }
|
||||
virtual bool setAll(uint8_t toValue) { return false; }
|
||||
virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int value) { return false; }
|
||||
|
||||
virtual uint8_t getVoxel(int x, int y, int z) { return 0; }
|
||||
virtual bool setVoxel(int x, int y, int z, uint8_t toValue) { return false; }
|
||||
|
@ -103,6 +104,28 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
virtual void setZTextureURL(QString zTextureURL) { _zTextureURL = zTextureURL; }
|
||||
virtual const QString& getZTextureURL() const { return _zTextureURL; }
|
||||
|
||||
virtual void setXNNeighborID(const EntityItemID& xNNeighborID) { _xNNeighborID = xNNeighborID; }
|
||||
void setXNNeighborID(const QString& xNNeighborID) { setXNNeighborID(QUuid(xNNeighborID)); }
|
||||
virtual const EntityItemID& getXNNeighborID() const { return _xNNeighborID; }
|
||||
virtual void setYNNeighborID(const EntityItemID& yNNeighborID) { _yNNeighborID = yNNeighborID; }
|
||||
void setYNNeighborID(const QString& yNNeighborID) { setYNNeighborID(QUuid(yNNeighborID)); }
|
||||
virtual const EntityItemID& getYNNeighborID() const { return _yNNeighborID; }
|
||||
virtual void setZNNeighborID(const EntityItemID& zNNeighborID) { _zNNeighborID = zNNeighborID; }
|
||||
void setZNNeighborID(const QString& zNNeighborID) { setZNNeighborID(QUuid(zNNeighborID)); }
|
||||
virtual const EntityItemID& getZNNeighborID() const { return _zNNeighborID; }
|
||||
|
||||
virtual void setXPNeighborID(const EntityItemID& xPNeighborID) { _xPNeighborID = xPNeighborID; }
|
||||
void setXPNeighborID(const QString& xPNeighborID) { setXPNeighborID(QUuid(xPNeighborID)); }
|
||||
virtual const EntityItemID& getXPNeighborID() const { return _xPNeighborID; }
|
||||
virtual void setYPNeighborID(const EntityItemID& yPNeighborID) { _yPNeighborID = yPNeighborID; }
|
||||
void setYPNeighborID(const QString& yPNeighborID) { setYPNeighborID(QUuid(yPNeighborID)); }
|
||||
virtual const EntityItemID& getYPNeighborID() const { return _yPNeighborID; }
|
||||
virtual void setZPNeighborID(const EntityItemID& zPNeighborID) { _zPNeighborID = zPNeighborID; }
|
||||
void setZPNeighborID(const QString& zPNeighborID) { setZPNeighborID(QUuid(zPNeighborID)); }
|
||||
virtual const EntityItemID& getZPNeighborID() const { return _zPNeighborID; }
|
||||
|
||||
virtual void rebakeMesh() {};
|
||||
|
||||
protected:
|
||||
glm::vec3 _voxelVolumeSize; // this is always 3 bytes
|
||||
|
||||
|
@ -116,6 +139,14 @@ class PolyVoxEntityItem : public EntityItem {
|
|||
QString _yTextureURL;
|
||||
QString _zTextureURL;
|
||||
|
||||
// for non-edged surface styles, these are used to compute the high-axis edges
|
||||
EntityItemID _xNNeighborID{UNKNOWN_ENTITY_ID};
|
||||
EntityItemID _yNNeighborID{UNKNOWN_ENTITY_ID};
|
||||
EntityItemID _zNNeighborID{UNKNOWN_ENTITY_ID};
|
||||
|
||||
EntityItemID _xPNeighborID{UNKNOWN_ENTITY_ID};
|
||||
EntityItemID _yPNeighborID{UNKNOWN_ENTITY_ID};
|
||||
EntityItemID _zPNeighborID{UNKNOWN_ENTITY_ID};
|
||||
};
|
||||
|
||||
#endif // hifi_PolyVoxEntityItem_h
|
||||
|
|
|
@ -2562,6 +2562,7 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
|||
int maxJointIndex = firstFBXCluster.jointIndex;
|
||||
glm::mat4 inverseModelTransform = glm::inverse(modelTransform);
|
||||
if (clusterIDs.size() > 1) {
|
||||
// this is a multi-mesh joint
|
||||
extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size());
|
||||
extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size());
|
||||
float maxWeight = 0.0f;
|
||||
|
@ -2645,6 +2646,7 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// this is a single-mesh joint
|
||||
int jointIndex = maxJointIndex;
|
||||
FBXJoint& joint = geometry.joints[jointIndex];
|
||||
JointShapeInfo& jointShapeInfo = jointShapeInfos[jointIndex];
|
||||
|
@ -2665,6 +2667,7 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
|||
}
|
||||
float radiusScale = extractUniformScale(joint.transform * firstFBXCluster.inverseBindMatrix);
|
||||
|
||||
// compute average vertex
|
||||
glm::vec3 averageVertex(0.0f);
|
||||
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
||||
float proj = glm::dot(boneDirection, boneEnd - vertex);
|
||||
|
@ -2674,29 +2677,26 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
|||
++jointShapeInfo.numVertexWeights;
|
||||
averageVertex += vertex;
|
||||
}
|
||||
|
||||
// compute joint's radius
|
||||
int numVertices = extracted.mesh.vertices.size();
|
||||
jointShapeInfo.numVertices = numVertices;
|
||||
if (numVertices > 0) {
|
||||
// compute average radius
|
||||
averageVertex /= (float)jointShapeInfo.numVertices;
|
||||
float averageRadius = 0.0f;
|
||||
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
||||
averageRadius += glm::distance(vertex, averageVertex);
|
||||
}
|
||||
jointShapeInfo.averageRadius = averageRadius * radiusScale / (float)jointShapeInfo.numVertices;
|
||||
averageRadius *= radiusScale / (float)jointShapeInfo.numVertices;
|
||||
|
||||
// final radius is minimum of average and weighted
|
||||
float weightedRadius = jointShapeInfo.sumWeightedRadii / jointShapeInfo.sumVertexWeights;
|
||||
jointShapeInfo.averageRadius = glm::min(weightedRadius, averageRadius);
|
||||
}
|
||||
|
||||
// BUG: the boneBegin and/or boneEnd are incorrect for meshes that are "connected
|
||||
// under the bone" without weights. Unfortunately we haven't been able to find it yet.
|
||||
// Although the the mesh vertices are correct in the model-frame, the joint's transform
|
||||
// in the same frame is just BAD.
|
||||
//
|
||||
// HACK WORKAROUND: prevent these shapes from contributing to the collision capsule by setting
|
||||
// some key members of jointShapeInfo to zero:
|
||||
jointShapeInfo.numVertices = 0;
|
||||
// clear sumVertexWeights (this flags it as a single-mesh joint for later)
|
||||
jointShapeInfo.sumVertexWeights = 0.0f;
|
||||
jointShapeInfo.numVertexWeights = 0;
|
||||
jointShapeInfo.boneBegin = glm::vec3(0.0f);
|
||||
jointShapeInfo.averageRadius = 0.0f;
|
||||
}
|
||||
extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex);
|
||||
|
||||
|
@ -2732,22 +2732,12 @@ FBXGeometry* extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping
|
|||
}
|
||||
|
||||
if (jointShapeInfo.sumVertexWeights > 0.0f) {
|
||||
// mutiple meshes contributed to the bone radius and now that all
|
||||
// contributing meshes are done we can finally compute the boneRadius
|
||||
joint.boneRadius = jointShapeInfo.sumWeightedRadii / jointShapeInfo.sumVertexWeights;
|
||||
}
|
||||
|
||||
// the joint is "capsule-like" if it had ANY mesh vertices successfully projected onto the bone
|
||||
// AND its boneRadius is not too close to zero
|
||||
bool collideLikeCapsule = jointShapeInfo.numVertexWeights > 0
|
||||
&& glm::length(jointShapeInfo.boneBegin) > EPSILON;
|
||||
|
||||
if (!collideLikeCapsule) {
|
||||
// this joint's mesh did not successfully project onto the bone axis
|
||||
// so it isn't "capsule-like" and we need to estimate its radius a different way:
|
||||
// the average radius to the average point.
|
||||
if (jointShapeInfo.numVertexWeights == 0
|
||||
&& jointShapeInfo.numVertices > 0) {
|
||||
joint.boneRadius = jointShapeInfo.averageRadius;
|
||||
}
|
||||
} else {
|
||||
// single-mesh joint
|
||||
joint.boneRadius = jointShapeInfo.averageRadius;
|
||||
}
|
||||
}
|
||||
geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());
|
||||
|
|
|
@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) {
|
|||
case EntityAdd:
|
||||
case EntityEdit:
|
||||
case EntityData:
|
||||
return VERSION_ENTITIES_PARTICLE_MODIFICATIONS;
|
||||
return VERSION_ENTITIES_POLYVOX_NEIGHBORS;
|
||||
case AvatarData:
|
||||
return 13;
|
||||
default:
|
||||
|
|
|
@ -144,5 +144,6 @@ const PacketVersion VERSION_POLYVOX_TEXTURES = 36;
|
|||
const PacketVersion VERSION_ENTITIES_POLYLINE = 37;
|
||||
const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38;
|
||||
const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39;
|
||||
const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40;
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
Loading…
Reference in a new issue