Commit a8e8d3e6 authored by David Flynn's avatar David Flynn
Browse files

geom: use single level based tree position representation

The geometry tree nodes contain a position element (pos) that identifies
the spatial position of the node.  At internal nodes this node position
is the partial position of a point and may either be represented using
the magnitude of the decoded points, or the magnitude of the current
depth.

The first form equates to:
 nextPos = curPos | (xyz << currentNodeSize)

The second:
 nextPos = (curPos << 1) | xyz

Where xyz represents a position bit from the coded occupancy.

In order to use the first form to determine neighbour relationships,
curPos must be shifted down to represent position within the current
depth.  This repeated shifting, along with the introduction of
simultaneous quantised and unquantised positions becomes increasingly
difficult to follow when adding non-cubic nodes (via OtQtBt).

This commit switches the representation to the second form above,
eliminating various shifted forms and duplicate state.  A decoded
positions is inverse quantised when reaching a leaf node.
parent 220acf28
...@@ -431,7 +431,7 @@ AttributeDecoder::decodeReflectancesRaht( ...@@ -431,7 +431,7 @@ AttributeDecoder::decodeReflectancesRaht(
const int voxelCount = int(pointCloud.getPointCount()); const int voxelCount = int(pointCloud.getPointCount());
std::vector<MortonCodeWithIndex> packedVoxel(voxelCount); std::vector<MortonCodeWithIndex> packedVoxel(voxelCount);
for (int n = 0; n < voxelCount; n++) { for (int n = 0; n < voxelCount; n++) {
packedVoxel[n].mortonCode = mortonAddr(pointCloud[n], 0); packedVoxel[n].mortonCode = mortonAddr(pointCloud[n]);
packedVoxel[n].index = n; packedVoxel[n].index = n;
} }
sort(packedVoxel.begin(), packedVoxel.end()); sort(packedVoxel.begin(), packedVoxel.end());
...@@ -491,7 +491,7 @@ AttributeDecoder::decodeColorsRaht( ...@@ -491,7 +491,7 @@ AttributeDecoder::decodeColorsRaht(
const int voxelCount = int(pointCloud.getPointCount()); const int voxelCount = int(pointCloud.getPointCount());
std::vector<MortonCodeWithIndex> packedVoxel(voxelCount); std::vector<MortonCodeWithIndex> packedVoxel(voxelCount);
for (int n = 0; n < voxelCount; n++) { for (int n = 0; n < voxelCount; n++) {
packedVoxel[n].mortonCode = mortonAddr(pointCloud[n], 0); packedVoxel[n].mortonCode = mortonAddr(pointCloud[n]);
packedVoxel[n].index = n; packedVoxel[n].index = n;
} }
sort(packedVoxel.begin(), packedVoxel.end()); sort(packedVoxel.begin(), packedVoxel.end());
......
...@@ -775,7 +775,7 @@ AttributeEncoder::encodeReflectancesTransformRaht( ...@@ -775,7 +775,7 @@ AttributeEncoder::encodeReflectancesTransformRaht(
const int voxelCount = int(pointCloud.getPointCount()); const int voxelCount = int(pointCloud.getPointCount());
std::vector<MortonCodeWithIndex> packedVoxel(voxelCount); std::vector<MortonCodeWithIndex> packedVoxel(voxelCount);
for (int n = 0; n < voxelCount; n++) { for (int n = 0; n < voxelCount; n++) {
packedVoxel[n].mortonCode = mortonAddr(pointCloud[n], 0); packedVoxel[n].mortonCode = mortonAddr(pointCloud[n]);
packedVoxel[n].index = n; packedVoxel[n].index = n;
} }
sort(packedVoxel.begin(), packedVoxel.end()); sort(packedVoxel.begin(), packedVoxel.end());
...@@ -844,7 +844,7 @@ AttributeEncoder::encodeColorsTransformRaht( ...@@ -844,7 +844,7 @@ AttributeEncoder::encodeColorsTransformRaht(
const int voxelCount = int(pointCloud.getPointCount()); const int voxelCount = int(pointCloud.getPointCount());
std::vector<MortonCodeWithIndex> packedVoxel(voxelCount); std::vector<MortonCodeWithIndex> packedVoxel(voxelCount);
for (int n = 0; n < voxelCount; n++) { for (int n = 0; n < voxelCount; n++) {
packedVoxel[n].mortonCode = mortonAddr(pointCloud[n], 0); packedVoxel[n].mortonCode = mortonAddr(pointCloud[n]);
packedVoxel[n].index = n; packedVoxel[n].index = n;
} }
sort(packedVoxel.begin(), packedVoxel.end()); sort(packedVoxel.begin(), packedVoxel.end());
......
...@@ -44,14 +44,13 @@ namespace pcc { ...@@ -44,14 +44,13 @@ namespace pcc {
void void
updateGeometryOccupancyAtlas( updateGeometryOccupancyAtlas(
const Vec3<uint32_t>& currentPosition, const Vec3<uint32_t>& currentPosition,
const int nodeSizeLog2,
const pcc::ringbuf<PCCOctree3Node>& fifo, const pcc::ringbuf<PCCOctree3Node>& fifo,
const pcc::ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd, const pcc::ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd,
MortonMap3D* occupancyAtlas, MortonMap3D* occupancyAtlas,
Vec3<uint32_t>* atlasOrigin) Vec3<uint32_t>* atlasOrigin)
{ {
const uint32_t mask = (1 << occupancyAtlas->cubeSizeLog2()) - 1; const uint32_t mask = (1 << occupancyAtlas->cubeSizeLog2()) - 1;
const int shift = occupancyAtlas->cubeSizeLog2() + nodeSizeLog2; const int shift = occupancyAtlas->cubeSizeLog2();
const auto currentOrigin = currentPosition >> shift; const auto currentOrigin = currentPosition >> shift;
// only refresh the atlas if the current position lies outside the // only refresh the atlas if the current position lies outside the
...@@ -67,9 +66,9 @@ updateGeometryOccupancyAtlas( ...@@ -67,9 +66,9 @@ updateGeometryOccupancyAtlas(
if (currentOrigin != it->pos >> shift) if (currentOrigin != it->pos >> shift)
break; break;
const uint32_t x = (it->pos[0] >> nodeSizeLog2) & mask; const uint32_t x = it->pos[0] & mask;
const uint32_t y = (it->pos[1] >> nodeSizeLog2) & mask; const uint32_t y = it->pos[1] & mask;
const uint32_t z = (it->pos[2] >> nodeSizeLog2) & mask; const uint32_t z = it->pos[2] & mask;
occupancyAtlas->setByte(x, y, z, it->siblingOccupancy); occupancyAtlas->setByte(x, y, z, it->siblingOccupancy);
} }
} }
...@@ -79,14 +78,13 @@ updateGeometryOccupancyAtlas( ...@@ -79,14 +78,13 @@ updateGeometryOccupancyAtlas(
void void
updateGeometryOccupancyAtlasOccChild( updateGeometryOccupancyAtlasOccChild(
const Vec3<uint32_t>& pos, const Vec3<uint32_t>& pos,
int nodeSizeLog2,
uint8_t childOccupancy, uint8_t childOccupancy,
MortonMap3D* occupancyAtlas) MortonMap3D* occupancyAtlas)
{ {
uint32_t mask = (1 << occupancyAtlas->cubeSizeLog2()) - 1; uint32_t mask = (1 << occupancyAtlas->cubeSizeLog2()) - 1;
uint32_t x = (pos[0] >> nodeSizeLog2) & mask; uint32_t x = pos[0] & mask;
uint32_t y = (pos[1] >> nodeSizeLog2) & mask; uint32_t y = pos[1] & mask;
uint32_t z = (pos[2] >> nodeSizeLog2) & mask; uint32_t z = pos[2] & mask;
occupancyAtlas->setChildOcc(x, y, z, childOccupancy); occupancyAtlas->setChildOcc(x, y, z, childOccupancy);
} }
...@@ -140,14 +138,13 @@ GeometryNeighPattern ...@@ -140,14 +138,13 @@ GeometryNeighPattern
makeGeometryNeighPattern( makeGeometryNeighPattern(
bool adjacent_child_contextualization_enabled_flag, bool adjacent_child_contextualization_enabled_flag,
const Vec3<uint32_t>& position, const Vec3<uint32_t>& position,
const int nodeSizeLog2,
const MortonMap3D& occupancyAtlas) const MortonMap3D& occupancyAtlas)
{ {
const int mask = occupancyAtlas.cubeSize() - 1; const int mask = occupancyAtlas.cubeSize() - 1;
const int cubeSizeMinusOne = mask; const int cubeSizeMinusOne = mask;
const int32_t x = (position[0] >> nodeSizeLog2) & mask; const int32_t x = position[0] & mask;
const int32_t y = (position[1] >> nodeSizeLog2) & mask; const int32_t y = position[1] & mask;
const int32_t z = (position[2] >> nodeSizeLog2) & mask; const int32_t z = position[2] & mask;
uint8_t neighPattern; uint8_t neighPattern;
if ( if (
x > 0 && x < cubeSizeMinusOne && y > 0 && y < cubeSizeMinusOne && z > 0 x > 0 && x < cubeSizeMinusOne && y > 0 && y < cubeSizeMinusOne && z > 0
......
...@@ -177,14 +177,12 @@ struct GeometryNeighPattern { ...@@ -177,14 +177,12 @@ struct GeometryNeighPattern {
GeometryNeighPattern makeGeometryNeighPattern( GeometryNeighPattern makeGeometryNeighPattern(
bool adjacent_child_contextualization_enabled_flag, bool adjacent_child_contextualization_enabled_flag,
const Vec3<uint32_t>& currentPosition, const Vec3<uint32_t>& currentPosition,
const int nodeSizeLog2,
const MortonMap3D& occupancyAtlas); const MortonMap3D& occupancyAtlas);
// populate (if necessary) the occupancy atlas with occupancy information // populate (if necessary) the occupancy atlas with occupancy information
// from @fifo. // from @fifo.
void updateGeometryOccupancyAtlas( void updateGeometryOccupancyAtlas(
const Vec3<uint32_t>& position, const Vec3<uint32_t>& position,
const int nodeSizeLog2,
const ringbuf<PCCOctree3Node>& fifo, const ringbuf<PCCOctree3Node>& fifo,
const ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd, const ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd,
MortonMap3D* occupancyAtlas, MortonMap3D* occupancyAtlas,
...@@ -192,7 +190,6 @@ void updateGeometryOccupancyAtlas( ...@@ -192,7 +190,6 @@ void updateGeometryOccupancyAtlas(
void updateGeometryOccupancyAtlasOccChild( void updateGeometryOccupancyAtlasOccChild(
const Vec3<uint32_t>& pos, const Vec3<uint32_t>& pos,
int nodeSizeLog2,
uint8_t childOccupancy, uint8_t childOccupancy,
MortonMap3D* occupancyAtlas); MortonMap3D* occupancyAtlas);
......
...@@ -378,16 +378,13 @@ mortonAddr(const int32_t x, const int32_t y, const int32_t z) ...@@ -378,16 +378,13 @@ mortonAddr(const int32_t x, const int32_t y, const int32_t z)
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
// Convert a vector position (divided by 2^depth) to morton order address. // Convert a vector position to morton order address.
template<typename T> template<typename T>
int64_t int64_t
mortonAddr(const Vec3<T>& vec, int depth) mortonAddr(const Vec3<T>& vec)
{ {
int x = int(vec.x()) >> depth; return mortonAddr(int(vec.x()), int(vec.y()), int(vec.z()));
int y = int(vec.y()) >> depth;
int z = int(vec.z()) >> depth;
return mortonAddr(x, y, z);
} }
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
......
...@@ -63,14 +63,13 @@ void ...@@ -63,14 +63,13 @@ void
predictGeometryOccupancyIntra( predictGeometryOccupancyIntra(
const MortonMap3D& occupancyAtlas, const MortonMap3D& occupancyAtlas,
Vec3<uint32_t> pos, Vec3<uint32_t> pos,
int nodeSizeLog2,
int* occupancyIsPredicted, int* occupancyIsPredicted,
int* occupancyPrediction) int* occupancyPrediction)
{ {
uint32_t mask = occupancyAtlas.cubeSize() - 1; uint32_t mask = occupancyAtlas.cubeSize() - 1;
int32_t x = (pos[0] >> nodeSizeLog2) & mask; int32_t x = pos[0] & mask;
int32_t y = (pos[1] >> nodeSizeLog2) & mask; int32_t y = pos[1] & mask;
int32_t z = (pos[2] >> nodeSizeLog2) & mask; int32_t z = pos[2] & mask;
int score[8] = {0, 0, 0, 0, 0, 0, 0, 0}; int score[8] = {0, 0, 0, 0, 0, 0, 0, 0};
int numOccupied = 0; int numOccupied = 0;
......
...@@ -47,7 +47,6 @@ namespace pcc { ...@@ -47,7 +47,6 @@ namespace pcc {
void predictGeometryOccupancyIntra( void predictGeometryOccupancyIntra(
const MortonMap3D& occupancyAtlas, const MortonMap3D& occupancyAtlas,
Vec3<uint32_t> pos, Vec3<uint32_t> pos,
int nodeSizeLog2,
int* occupacyIsPredIntra, int* occupacyIsPredIntra,
int* occupacyPredIntra); int* occupacyPredIntra);
......
...@@ -116,7 +116,6 @@ updateGeometryNeighState( ...@@ -116,7 +116,6 @@ updateGeometryNeighState(
bool siblingRestriction, bool siblingRestriction,
const ringbuf<PCCOctree3Node>::iterator& bufEnd, const ringbuf<PCCOctree3Node>::iterator& bufEnd,
int64_t numNodesNextLvl, int64_t numNodesNextLvl,
int childSizeLog2,
PCCOctree3Node& child, PCCOctree3Node& child,
int childIdx, int childIdx,
uint8_t neighPattern, uint8_t neighPattern,
...@@ -124,7 +123,7 @@ updateGeometryNeighState( ...@@ -124,7 +123,7 @@ updateGeometryNeighState(
{ {
int64_t midx; int64_t midx;
if (!siblingRestriction) { if (!siblingRestriction) {
midx = child.mortonIdx = mortonAddr(child.pos, childSizeLog2); midx = child.mortonIdx = mortonAddr(child.pos);
} }
static const struct { static const struct {
......
...@@ -78,9 +78,8 @@ struct PCCOctree3Node { ...@@ -78,9 +78,8 @@ struct PCCOctree3Node {
// The occupancy map used describing the current node and its siblings. // The occupancy map used describing the current node and its siblings.
uint8_t siblingOccupancy; uint8_t siblingOccupancy;
// The qp used for geometry quantisation
int qp; int qp;
Vec3<uint32_t> pos_quant;
Vec3<uint32_t> pos_base;
}; };
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------
...@@ -92,7 +91,6 @@ void updateGeometryNeighState( ...@@ -92,7 +91,6 @@ void updateGeometryNeighState(
bool siblingRestriction, bool siblingRestriction,
const ringbuf<PCCOctree3Node>::iterator& bufEnd, const ringbuf<PCCOctree3Node>::iterator& bufEnd,
int64_t numNodesNextLvl, int64_t numNodesNextLvl,
int childSizeLog2,
PCCOctree3Node& child, PCCOctree3Node& child,
int childIdx, int childIdx,
uint8_t neighPattern, uint8_t neighPattern,
......
...@@ -411,19 +411,38 @@ GeometryOctreeDecoder::decodeDirectPosition( ...@@ -411,19 +411,38 @@ GeometryOctreeDecoder::decodeDirectPosition(
if (_arithmeticDecoder->decode(_ctxNumIdcmPointsEq1)) if (_arithmeticDecoder->decode(_ctxNumIdcmPointsEq1))
numPoints++; numPoints++;
QuantizerGeom quantizer(node.qp); for (int i = 0; i < numPoints; i++)
for (int i = 0; i < numPoints; i++) { *(outputPoints++) = decodePointPosition(nodeSizeLog2);
// convert node-relative position to world position
Vec3<uint32_t> pos = decodePointPosition(nodeSizeLog2);
*(outputPoints++) = {
double(quantizer.scale(node.pos_quant[0] + pos[0]) + node.pos_base[0]),
double(quantizer.scale(node.pos_quant[1] + pos[1]) + node.pos_base[1]),
double(quantizer.scale(node.pos_quant[2] + pos[2]) + node.pos_base[2])};
}
return numPoints; return numPoints;
} }
//-------------------------------------------------------------------------
// Helper to inverse quantise positions
Vec3<uint32_t>
invQuantPosition(int qp, int quantBitMask, const Vec3<uint32_t>& pos)
{
// pos represents the position within the coded tree as follows:
// |pppppqqqqqq|00
// - p = unquantised bit
// - q = quantised bit
// - 0 = bits that were not coded (MSBs of q)
// The reconstruction is:
// |ppppp00qqqqqq|
QuantizerGeom quantizer(qp);
int shiftBits = (qp - 4) / 6;
Vec3<uint32_t> recon;
for (int k = 0; k < 3; k++) {
int posQuant = pos[k] & (quantBitMask >> shiftBits);
recon[k] = (pos[k] ^ posQuant) << shiftBits;
recon[k] |= quantizer.scale(posQuant);
}
return recon;
}
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
void void
...@@ -474,11 +493,15 @@ decodeGeometryOctree( ...@@ -474,11 +493,15 @@ decodeGeometryOctree(
int sliceQp = gps.geom_base_qp + gbh.geom_slice_qp_offset; int sliceQp = gps.geom_base_qp + gbh.geom_slice_qp_offset;
int numLvlsUntilQpOffset = -1; int numLvlsUntilQpOffset = -1;
int posQuantBits = 0;
if (gbh.geom_octree_qp_offset_enabled_flag) if (gbh.geom_octree_qp_offset_enabled_flag)
numLvlsUntilQpOffset = gbh.geom_octree_qp_offset_depth; numLvlsUntilQpOffset = gbh.geom_octree_qp_offset_depth;
else if (gps.geom_scaling_enabled_flag) else if (gps.geom_scaling_enabled_flag) {
node00.qp = sliceQp; node00.qp = sliceQp;
// determine the mask of LSBs used in quantisation
posQuantBits = (1 << (nodeSizeLog2 - numLvlsUntilQpOffset)) - 1;
}
for (; !fifo.empty(); fifo.pop_front()) { for (; !fifo.empty(); fifo.pop_front()) {
if (fifo.begin() == fifoCurrLvlEnd) { if (fifo.begin() == fifoCurrLvlEnd) {
...@@ -503,11 +526,8 @@ decodeGeometryOctree( ...@@ -503,11 +526,8 @@ decodeGeometryOctree(
PCCOctree3Node& node0 = fifo.front(); PCCOctree3Node& node0 = fifo.front();
if (numLvlsUntilQpOffset == 0) { if (numLvlsUntilQpOffset == 0)
node0.qp = decoder.decodeQpOffset() + sliceQp; node0.qp = decoder.decodeQpOffset() + sliceQp;
node0.pos_base = node0.pos;
node0.pos_quant = {0, 0, 0};
}
int shiftBits = (node0.qp - 4) / 6; int shiftBits = (node0.qp - 4) / 6;
int effectiveNodeSizeLog2 = nodeSizeLog2 - shiftBits; int effectiveNodeSizeLog2 = nodeSizeLog2 - shiftBits;
...@@ -519,12 +539,12 @@ decodeGeometryOctree( ...@@ -519,12 +539,12 @@ decodeGeometryOctree(
if (gps.neighbour_avail_boundary_log2) { if (gps.neighbour_avail_boundary_log2) {
updateGeometryOccupancyAtlas( updateGeometryOccupancyAtlas(
node0.pos, nodeSizeLog2, fifo, fifoCurrLvlEnd, &occupancyAtlas, node0.pos, fifo, fifoCurrLvlEnd, &occupancyAtlas,
&occupancyAtlasOrigin); &occupancyAtlasOrigin);
GeometryNeighPattern gnp = makeGeometryNeighPattern( GeometryNeighPattern gnp = makeGeometryNeighPattern(
gps.adjacent_child_contextualization_enabled_flag, node0.pos, gps.adjacent_child_contextualization_enabled_flag, node0.pos,
nodeSizeLog2, occupancyAtlas); occupancyAtlas);
node0.neighPattern = gnp.neighPattern; node0.neighPattern = gnp.neighPattern;
occupancyAdjacencyGt0 = gnp.adjacencyGt0; occupancyAdjacencyGt0 = gnp.adjacencyGt0;
...@@ -538,7 +558,7 @@ decodeGeometryOctree( ...@@ -538,7 +558,7 @@ decodeGeometryOctree(
// generate intra prediction // generate intra prediction
if (effectiveNodeSizeLog2 < gps.intra_pred_max_node_size_log2) { if (effectiveNodeSizeLog2 < gps.intra_pred_max_node_size_log2) {
predictGeometryOccupancyIntra( predictGeometryOccupancyIntra(
occupancyAtlas, node0.pos, nodeSizeLog2, &occupancyIsPredicted, occupancyAtlas, node0.pos, &occupancyIsPredicted,
&occupancyPrediction); &occupancyPrediction);
} }
...@@ -554,7 +574,7 @@ decodeGeometryOctree( ...@@ -554,7 +574,7 @@ decodeGeometryOctree(
// update atlas for advanced neighbours // update atlas for advanced neighbours
if (gps.neighbour_avail_boundary_log2) { if (gps.neighbour_avail_boundary_log2) {
updateGeometryOccupancyAtlasOccChild( updateGeometryOccupancyAtlasOccChild(
node0.pos, nodeSizeLog2, occupancy, &occupancyAtlas); node0.pos, occupancy, &occupancyAtlas);
} }
// population count of occupancy for IDCM // population count of occupancy for IDCM
...@@ -583,11 +603,12 @@ decodeGeometryOctree( ...@@ -583,11 +603,12 @@ decodeGeometryOctree(
numPoints = decoder.decodePositionLeafNumPoints(); numPoints = decoder.decodePositionLeafNumPoints();
} }
QuantizerGeom quantizer(node0.qp); // the final bits from the leaf:
const Vec3<double> point( Vec3<uint32_t> pos{(node0.pos[0] << 1) + x, (node0.pos[1] << 1) + y,
quantizer.scale(node0.pos_quant[0] + x) + node0.pos_base[0], (node0.pos[2] << 1) + z};
quantizer.scale(node0.pos_quant[1] + y) + node0.pos_base[1],
quantizer.scale(node0.pos_quant[2] + z) + node0.pos_base[2]); pos = invQuantPosition(node0.qp, posQuantBits, pos);
const Vec3<double> point(pos[0], pos[1], pos[2]);
for (int i = 0; i < numPoints; ++i) for (int i = 0; i < numPoints; ++i)
pointCloud[processedPointCount++] = point; pointCloud[processedPointCount++] = point;
...@@ -601,23 +622,26 @@ decodeGeometryOctree( ...@@ -601,23 +622,26 @@ decodeGeometryOctree(
auto& child = fifo.back(); auto& child = fifo.back();
child.qp = node0.qp; child.qp = node0.qp;
child.pos_quant[0] = node0.pos_quant[0] + (x << effectiveChildSizeLog2); child.pos[0] = (node0.pos[0] << 1) + x;
child.pos_quant[1] = node0.pos_quant[1] + (y << effectiveChildSizeLog2); child.pos[1] = (node0.pos[1] << 1) + y;
child.pos_quant[2] = node0.pos_quant[2] + (z << effectiveChildSizeLog2); child.pos[2] = (node0.pos[2] << 1) + z;
child.pos_base = node0.pos_base;
child.pos[0] = node0.pos[0] + (x << childSizeLog2);
child.pos[1] = node0.pos[1] + (y << childSizeLog2);
child.pos[2] = node0.pos[2] + (z << childSizeLog2);
child.numSiblingsPlus1 = numOccupied; child.numSiblingsPlus1 = numOccupied;
child.siblingOccupancy = occupancy; child.siblingOccupancy = occupancy;
bool idcmEnabled = gps.inferred_direct_coding_mode_enabled_flag; bool idcmEnabled = gps.inferred_direct_coding_mode_enabled_flag;
if (isDirectModeEligible( if (isDirectModeEligible(
idcmEnabled, effectiveNodeSizeLog2, node0, child)) { idcmEnabled, effectiveNodeSizeLog2, node0, child)) {
// todo(df): this should go away when output is integer
Vec3<uint32_t> pointResidual[2];
int numPoints = decoder.decodeDirectPosition( int numPoints = decoder.decodeDirectPosition(
effectiveChildSizeLog2, child, &pointCloud[processedPointCount]); effectiveChildSizeLog2, child, pointResidual);
processedPointCount += numPoints;
for (int j = 0; j < numPoints; j++) {
auto pos = (child.pos << effectiveChildSizeLog2) + pointResidual[j];
pos = invQuantPosition(node0.qp, posQuantBits, pos);
pointCloud[processedPointCount++] =
Vec3<double>(pos[0], pos[1], pos[2]);
}
if (numPoints > 0) { if (numPoints > 0) {
// node fully decoded, do not split: discard child // node fully decoded, do not split: discard child
...@@ -634,7 +658,7 @@ decodeGeometryOctree( ...@@ -634,7 +658,7 @@ decodeGeometryOctree(
if (!gps.neighbour_avail_boundary_log2) { if (!gps.neighbour_avail_boundary_log2) {
updateGeometryNeighState( updateGeometryNeighState(
gps.neighbour_context_restriction_flag, fifo.end(), numNodesNextLvl, gps.neighbour_context_restriction_flag, fifo.end(), numNodesNextLvl,
childSizeLog2, child, i, node0.neighPattern, occupancy); child, i, node0.neighPattern, occupancy);
} }
} }
} }
...@@ -645,9 +669,15 @@ decodeGeometryOctree( ...@@ -645,9 +669,15 @@ decodeGeometryOctree(
pointCloud.resize(processedPointCount); pointCloud.resize(processedPointCount);
// return partial coding result // return partial coding result
// todo(df): node.pos is still in quantised form -- this is probably wrong // - add missing levels to node positions and inverse quantise
if (nodesRemaining) { if (nodesRemaining) {
for (auto& node : fifo) {
int quantRemovedBits = (node.qp - 4) / 6;
auto pos = node.pos << nodeSizeLog2 - quantRemovedBits;
node.pos = invQuantPosition(node.qp, posQuantBits, pos);
}
*nodesRemaining = std::move(fifo); *nodesRemaining = std::move(fifo);
return;
} }
} }
......
...@@ -442,18 +442,17 @@ geometryQuantization( ...@@ -442,18 +442,17 @@ geometryQuantization(
{ {
QuantizerGeom quantizer = QuantizerGeom(node.qp); QuantizerGeom quantizer = QuantizerGeom(node.qp);
int qpShift = (node.qp - 4) / 6; int qpShift = (node.qp - 4) / 6;
Vec3<uint32_t> start_pos = node.pos; int quantBitsMask = (1 << nodeSizeLog2) - 1;
Vec3<uint32_t> start_pos_quant = 0; Vec3<uint32_t> end_pos_quant = ((1 << nodeSizeLog2) >> qpShift) - 1;
Vec3<uint32_t> end_pos_quant = (1 << nodeSizeLog2) >> qpShift;
for (int i = node.start; i < node.end; i++) { for (int i = node.start; i < node.end; i++) {
Vec3<double> reconPoint, quantizedPoint; Vec3<double> reconPoint;
for (int k = 0; k < 3; k++) { for (int k = 0; k < 3; k++) {
int64_t k_pos = pointCloud[i][k] - start_pos[k]; uint32_t pos = uint32_t(pointCloud[i][k]);
uint32_t quantPos = quantizer.quantize(pos & quantBitsMask);
quantPos = PCCClip(quantPos, 0, end_pos_quant[k]);
k_pos = quantizer.quantize(k_pos); pointCloud[i][k] = quantPos;
k_pos = PCCClip(k_pos, start_pos_quant[k], end_pos_quant[k] - 1); reconPoint[k] = (pos & ~quantBitsMask) + quantizer.scale(quantPos);
pointCloud[i][k] = k_pos;
reconPoint[k] = quantizer.scale(k_pos) + start_pos[k];