0
\$\begingroup\$

I'm trying to implement a voxel engine in C++ using OpenGL, and I've been working on the rendering of the world. In order to render, I have a 3D array of uint16's that hold that id of the block at the point. I also have a 3D array of uint8's that I am using to store the visibility data for that point, where each bit represents if a face is visible. I have it so the blocks render and all of the proper faces are hidden if needed, but all of the blocks are offset by a power of 2 from where they are stored in the array. So the block at [0][0][0] is rendered at (0, 0, 0), and the block at 11 is rendered at (1, 1, 1), but the block at [2][2][2] is rendered at (4, 4, 4) and the block at [3][3][3] is rendered at (8, 8, 8), and so on and so forth.

This is the result of drawing the above situation: enter image description here

I'm still a little new to the more advanced concepts of C++, like triple pointers, which I'm using for the 3D array, so I think the error is somewhere in there. This is the code for creating the arrays:

uint16*** _blockData; //Contains a 3D array of uint16s that are the ids of the blocks in the region
uint8*** _visibilityData; //Contains a 3D array of bytes that hold the visibility data for the faces

   //Allocate memory for the world data
_blockData = new uint16**[REGION_DIM];
for (int i = 0; i < REGION_DIM; i++)
{
    _blockData[i] = new uint16*[REGION_DIM];

    for (int j = 0; j < REGION_DIM; j++)
        _blockData[i][j] = new uint16[REGION_DIM];
}

//Allocate memory for the visibility
_visibilityData = new uint8**[REGION_DIM];
for (int i = 0; i < REGION_DIM; i++)
{
    _visibilityData[i] = new uint8*[REGION_DIM];

    for (int j = 0; j < REGION_DIM; j++)
        _visibilityData[i][j] = new uint8[REGION_DIM];
}

Here is the code used to create the block mesh for the region:

//Check if the positive x face is visible, this happens for every face
//Block::VERT_X_POS is just an array of non-transformed cube verts for one face 
//These checks are in a triple loop, which goes over every place in the array
if (_visibilityData[x][y][z] & 0x01 > 0)
{
    _vertexData->AddData(&(translateVertices(Block::VERT_X_POS, x, y, z)[0]), sizeof(Block::VERT_X_POS));
}

//This is a seperate method, not in the loop
glm::vec3* translateVertices(const glm::vec3 data[], uint16 x, uint16 y, uint16 z)
{
    glm::vec3* copy = new glm::vec3[6];
    memcpy(&copy, &data, sizeof(data));

    for(int i = 0; i < 6; i++)
        copy[i] += glm::vec3(x, -y, z); //Make +y go down instead

    return copy;
}

I cannot see where the blocks may be getting offset by more than they should be, and certainly not why the offsets are a power of 2. Any help is greatly appreciated. Thanks.

\$\endgroup\$
7
  • 3
    \$\begingroup\$ Things like int*** are completely the wrong thing to use here. A "triple pointer" is not logically the same thing as a 3-dimensional array. You can just use a plain std::vector and claculate offsets manually with something like z * width * height + y * width + x (with the total size being width * height * depth of course). \$\endgroup\$ Oct 25, 2013 at 17:38
  • \$\begingroup\$ @SeanMiddleditch, I changed the storage to a 1D array using the z * width * height + y * width + x code provided, initialized by uint16* _blockData = new uint16[REGION_DIM * REGION_DIM * REGION_DIM];. Now I am getting an error if the array doesn't contain at least one value that isn't 0 at the end of the Region constructor, where the array is being initialized. More specifically, this error. \$\endgroup\$
    – sm81095
    Oct 25, 2013 at 19:14
  • \$\begingroup\$ @SeanMiddleditch You should really make that an answer. \$\endgroup\$
    – Engineer
    Oct 25, 2013 at 19:20
  • \$\begingroup\$ I found that memcpy() is not the way to go when copying arrays of glm::vec3's, so I switched it to just copying the values over one index at a time. This seemed to fix the power-of-two rendering errors. \$\endgroup\$
    – sm81095
    Oct 25, 2013 at 19:51
  • 1
    \$\begingroup\$ @NickWiggill: I didn't realize that was the answer; I stopped reading as soon as I got that far and was just giving what I thought was a tangential tip. :) \$\endgroup\$ Oct 25, 2013 at 20:13

1 Answer 1

3
\$\begingroup\$

Things like int*** are completely the wrong thing to use here. A "triple pointer" is not logically the same thing as a 3-dimensional array. You can just use a plain std::vector and claculate offsets manually with something like z * width * height + y * width + x (with the total size being width * height * depth of course).

Create a vector, resize it, then copy in the right data. If you don't resize first, you must be sure to use push_back or back_inserter:

// or just pass the size to the constructor; same diff
std::vector<int> blocks;
blocks.resize(width * height * depth);

// not idiomatic C++, but it should work
std::memcpy(data.data(), source_array, blocks.size() * sizeof(blocks.at(0));

// better option if you resize first; may or may not be equivalent to memcpy depending on implementation and the PODness of the vector's contained type
std::copy(source_begin, source_end, begin(data));

// and the better option if you don't resize first, though this may resize multiple times internally, and is not the most efficient choice
std::copy(source_begin, source_end, std::back_inserter(blocks));
\$\endgroup\$
1
  • \$\begingroup\$ Many thanks. I managed to put a stop-gap measure on the drawing being off, and I'll try this later as a way to store the blocks. I got a "triple pointer" working for now, but I'll see if this way is more efficient later on. \$\endgroup\$
    – sm81095
    Oct 25, 2013 at 21:02

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .