working on stitching marching-cube polyvoxs together

This commit is contained in:
Seth Alves 2015-08-30 18:42:15 -07:00
parent 64d0ce47f3
commit 41a2ff2fff
4 changed files with 183 additions and 127 deletions

View file

@ -155,48 +155,111 @@ 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 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");
return;
}
var alreadyThere = lookupTerrainForLocation(baseLocation);
if (alreadyThere) {
return;
}
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:32, 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++) {
// XXX use setCuboid
for (var y = 16; y < 32; 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);
Entities.setVoxel(polyVoxId, {x:x, y:y, z:z}, 0);
}
}
}
//////////
// stitch together the terrain with x/y/z NeighorID properties
//////////
// link plots which are lower on the axes to this one
imXNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:-16, y:0, z:0}));
if (imXNeighborFor) {
var properties = Entities.getEntityProperties(imXNeighborFor);
properties.xNeighborID = polyVoxId;
Entities.editEntity(imXNeighborFor, properties);
}
imYNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:-16, z:0}));
if (imYNeighborFor) {
var properties = Entities.getEntityProperties(imYNeighborFor);
properties.yNeighborID = polyVoxId;
Entities.editEntity(imYNeighborFor, properties);
}
imZNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:-16}));
if (imZNeighborFor) {
var properties = Entities.getEntityProperties(imZNeighborFor);
properties.zNeighborID = polyVoxId;
Entities.editEntity(imZNeighborFor, properties);
}
// link this plot to plots which are higher on the axes
xNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:16, y:0, z:0}));
if (xNeighborFor) {
var properties = Entities.getEntityProperties(polyVoxId);
properties.xNeighborID = xNeighborFor;
Entities.editEntity(polyVoxId, properties);
}
yNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:16, z:0}));
if (yNeighborFor) {
var properties = Entities.getEntityProperties(polyVoxId);
properties.yNeighborID = yNeighborFor;
Entities.editEntity(polyVoxId, properties);
}
zNeighborFor = lookupTerrainForLocation(Vec3.sum(baseLocation, {x:0, y:0, z:16}));
if (zNeighborFor) {
var properties = Entities.getEntityProperties(polyVoxId);
properties.zNeighborID = zNeighborFor;
Entities.editEntity(polyVoxId, properties);
}
return true;
}

View file

@ -68,6 +68,19 @@ RenderablePolyVoxEntityItem::~RenderablePolyVoxEntityItem() {
}
bool isEdged(PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle) {
switch (surfaceStyle) {
case PolyVoxEntityItem::SURFACE_CUBIC:
return true;
case PolyVoxEntityItem::SURFACE_MARCHING_CUBES:
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;
}
@ -429,9 +435,12 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
_volDataLock.lockForRead();
if (_volDataDirty) {
_volDataLock.unlock();
getMesh();
} else {
_volDataLock.unlock();
}
_volDataLock.unlock();
_meshLock.lockForRead();
model::MeshPointer mesh = _mesh;
@ -551,18 +560,10 @@ glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToWorldCoords(glm::vec3& voxel
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 - glm::vec3(0.5f, 0.5f, 0.5f);
}
return result;
return result + glm::vec3(0.5f, 0.5f, 0.5f);
}
glm::vec3 RenderablePolyVoxEntityItem::voxelCoordsToLocalCoords(glm::vec3& voxelCoords) const {
@ -588,8 +589,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
@ -601,27 +601,12 @@ 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 because these corners are inclusive
// 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));
// // XXX
// {
// for (int x = 0; x <= _voxelVolumeSize.x; x++) {
// for (int y = 0; y <= _voxelVolumeSize.y; y++) {
// for (int z = 0; z <= _voxelVolumeSize.z; z++) {
// if (x == _voxelVolumeSize.x ||
// y == _voxelVolumeSize.y ||
// z == _voxelVolumeSize.z) {
// setVoxelInternal(x, y, z, 255);
// }
// }
// }
// }
// }
}
// having the "outside of voxel-space" value be 255 has helped me notice some problems.
@ -635,25 +620,19 @@ bool RenderablePolyVoxEntityItem::inUserBounds(const PolyVox::SimpleVolume<uint8
PolyVoxEntityItem::PolyVoxSurfaceStyle surfaceStyle,
int x, int y, int z) {
// 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;
}
@ -670,19 +649,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);
}
@ -695,9 +668,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);
@ -893,8 +864,7 @@ void RenderablePolyVoxEntityItem::clearOutOfDateNeighbors() {
}
void RenderablePolyVoxEntityItem::cacheNeighbors() {
if (_voxelSurfaceStyle != PolyVoxEntityItem::SURFACE_CUBIC &&
_voxelSurfaceStyle != PolyVoxEntityItem::SURFACE_MARCHING_CUBES) {
if (_voxelSurfaceStyle != PolyVoxEntityItem::SURFACE_MARCHING_CUBES) {
return;
}
@ -917,8 +887,7 @@ void RenderablePolyVoxEntityItem::cacheNeighbors() {
}
void RenderablePolyVoxEntityItem::copyUpperEdgesFromNeighbors() {
if (_voxelSurfaceStyle != PolyVoxEntityItem::SURFACE_CUBIC &&
_voxelSurfaceStyle != PolyVoxEntityItem::SURFACE_MARCHING_CUBES) {
if (_voxelSurfaceStyle != PolyVoxEntityItem::SURFACE_MARCHING_CUBES) {
return;
}
@ -927,36 +896,51 @@ void RenderablePolyVoxEntityItem::copyUpperEdgesFromNeighbors() {
EntityItemPointer currentZNeighbor = _zNeighbor.lock();
if (currentXNeighbor) {
auto polyVoxXNeighbor = std::dynamic_pointer_cast<PolyVoxEntityItem>(currentXNeighbor);
for (int y = 0; y < _voxelVolumeSize.y; y++) {
for (int z = 0; z < _voxelVolumeSize.z; y++) {
uint8_t neighborValue = polyVoxXNeighbor->getVoxel(0, y, z);
_volData->setVoxelAt(_voxelVolumeSize.x, y, z, neighborValue);
auto polyVoxXNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentXNeighbor);
if (polyVoxXNeighbor->_volData->getEnclosingRegion() == _volData->getEnclosingRegion()) {
for (int y = 0; y < _volData->getHeight(); y++) {
for (int z = 0; z < _volData->getDepth(); z++) {
uint8_t neighborValue = polyVoxXNeighbor->_volData->getVoxelAt(1, y, z);
_volData->setVoxelAt(_volData->getWidth() - 1, y, z, neighborValue);
}
}
}
}
if (currentYNeighbor) {
auto polyVoxYNeighbor = std::dynamic_pointer_cast<PolyVoxEntityItem>(currentYNeighbor);
for (int x = 0; x < _voxelVolumeSize.x; x++) {
for (int z = 0; z < _voxelVolumeSize.z; z++) {
uint8_t neighborValue = polyVoxYNeighbor->getVoxel(x, 0, z);
_volData->setVoxelAt(x, _voxelVolumeSize.y, z, neighborValue);
auto polyVoxYNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentYNeighbor);
if (polyVoxYNeighbor->_volData->getEnclosingRegion() == _volData->getEnclosingRegion()) {
for (int x = 0; x < _volData->getWidth(); x++) {
for (int z = 0; z < _volData->getDepth(); z++) {
uint8_t neighborValue = polyVoxYNeighbor->_volData->getVoxelAt(x, 1, z);
_volData->setVoxelAt(x, _volData->getWidth() - 1, z, neighborValue);
}
}
}
}
if (currentZNeighbor) {
auto polyVoxZNeighbor = std::dynamic_pointer_cast<PolyVoxEntityItem>(currentZNeighbor);
for (int x = 0; x < _voxelVolumeSize.x; x++) {
for (int y = 0; y < _voxelVolumeSize.y; y++) {
uint8_t neighborValue = polyVoxZNeighbor->getVoxel(x, y, 0);
_volData->setVoxelAt(x, y, _voxelVolumeSize.z, neighborValue);
auto polyVoxZNeighbor = std::dynamic_pointer_cast<RenderablePolyVoxEntityItem>(currentZNeighbor);
if (polyVoxZNeighbor->_volData->getEnclosingRegion() == _volData->getEnclosingRegion()) {
for (int x = 0; x < _volData->getWidth(); x++) {
for (int y = 0; y < _volData->getHeight(); y++) {
uint8_t neighborValue = polyVoxZNeighbor->_volData->getVoxelAt(x, y, 1);
_volData->setVoxelAt(x, y, _volData->getDepth() - 1, neighborValue);
}
}
}
}
}
// PolyVox::Region shrinkRegion(PolyVox::Region originalRegion) {
// PolyVox::Region smallerRegion = originalRegion;
// smallerRegion.shiftLowerCorner(PolyVox::Vector3DInt32(1, 1, 1));
// smallerRegion.shiftUpperCorner(PolyVox::Vector3DInt32(-1, -1, -1));
// return smallerRegion;
// }
void RenderablePolyVoxEntityItem::getMeshAsync() {
model::MeshPointer mesh(new model::Mesh());
@ -968,14 +952,24 @@ void RenderablePolyVoxEntityItem::getMeshAsync() {
_volDataLock.lockForRead();
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);

View file

@ -56,11 +56,7 @@ 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),
_xNeighborID(UNKNOWN_ENTITY_ID),
_yNeighborID(UNKNOWN_ENTITY_ID),
_zNeighborID(UNKNOWN_ENTITY_ID)
{
_zTextureURL(PolyVoxEntityItem::DEFAULT_Z_TEXTURE_URL) {
_type = EntityTypes::PolyVox;
setProperties(properties);
}
@ -169,6 +165,9 @@ EntityPropertyFlags PolyVoxEntityItem::getEntityProperties(EncodeBitstreamParams
requestedProperties += PROP_X_TEXTURE_URL;
requestedProperties += PROP_Y_TEXTURE_URL;
requestedProperties += PROP_Z_TEXTURE_URL;
requestedProperties += PROP_X_NEIGHBOR_ID;
requestedProperties += PROP_Y_NEIGHBOR_ID;
requestedProperties += PROP_Z_NEIGHBOR_ID;
return requestedProperties;
}

View file

@ -128,9 +128,9 @@ class PolyVoxEntityItem : public EntityItem {
QString _zTextureURL;
// for non-edged surface styles, these are used to compute the high-axis edges
EntityItemID _xNeighborID;
EntityItemID _yNeighborID;
EntityItemID _zNeighborID;
EntityItemID _xNeighborID{UNKNOWN_ENTITY_ID};
EntityItemID _yNeighborID{UNKNOWN_ENTITY_ID};
EntityItemID _zNeighborID{UNKNOWN_ENTITY_ID};
};
#endif // hifi_PolyVoxEntityItem_h