Anasky

I've recently started implementing the C++ library version of VoxelFarm using the VoxelFarmThinClient and VoxelFarmGenerationServer as examples to extract the code from.
Unfortunately though, I can't for the life of me get the VoxelFarmThinClient code to be working in my framework seeing as it really doesn't like rendering without a shader.

Now, what I am trying to do is to obtain the vertices (hopefully in a triangle-strip way) and generate a VBO out of it which I can then render.
The server part of the code works, I've tested that using the ThinClient to connect to my own server.

Can anyone help me with this?

Thanks!
Anasky

0 0
voxelfarmtorres
Each cell in the scene will have a CCellData object associated with it. Once the cell is ready for baking (that is, sending to GPU), the CCellData object contains the vertices in the vertices array.

The following OpenGL code creates a VBO with this. It is all you need to later render each cell:


glGenBuffersARB(1, &vboVertices);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboVertices);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, size*3*sizeof(float), cellData->vertices[medium], GL_STATIC_DRAW_ARB);


Here "medium" is the identifier for the material medium, which can be solid, water, etc. Use zero for solid content, which likely makes for most of your test scene.

Once you upload the VBO to GPU, you can call the "releaseData()" function to the CellData object, which will free the vertex data from CPU memory.
0 0
Anasky

Hey torres,

I've copied that code from the ThinClient demo, and good to know I'm going the right way 😉 (I assumed there was more than that seeing as it wasn't completely working yet).

My current assumption is that I'm not correctly placing the cells in the world, as it seems like there's a lot of cells placed on top of each other (which at first made me think it was garbage values). Is there a way to get the modelmatrix from the CCellData?

0 0
voxelfarmtorres
Yes, you need to position each cell in its correct location related to the viewer. The following code computes the transform (scale and translation) for a given cell using standard OpenGL:

int level, xc, yc, zc;
unpackCellId(cellData->cell, level, xc, yc, zc);

double scale = CELL_SIZE*(1 << level);

// Compute origin coordinates for the cell in world coordinates
double offsetX = xc*scale;
double offsetY = yc*scale;
double offsetZ = zc*scale;

// Translate relative to cell origin in scene
glTranslatef(
(float)(scale*xc - view->xpos),
(float)(scale*yc - view->ypos),
(float)(scale*zc - view->zpos));

// Cell vertices are in 0..1 range, scale to world cell dimensions
glScalef((float)scale, (float)scale, (float)scale);

0 0
Anasky

Untitled.png 
Well, looks like a promising start 😃

Thanks!

0 0
Anasky
Is there a way to get the modelMatrix irregardless of the player's position? Seeing as that's normally the job for the other matrices?
0 0
voxelfarmtorres
The code above computes the cell's transform for the viewer's position, that is where the camera is located. This is why the view coordinates are subtracted from each cell position.

Voxel Farm worlds can be so large that absolute cell coordinates are expressed in 64bit floats. As long as you bring these coordinates into a reference frame by subtracting the reference frame, you will be able to render in 32bit float systems like OpenGL, Unreal Engine, Unity, etc.
0 0
Anasky

Untitled.png 

We're going places! 😃
So far it seems to work fine for as long as I don't update the clipmapView's position, once I do the following error shows up (hopefully you'll be able to tell why?):

Exception thrown at 0x000000013F34660F in GameClient.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF

At the code (which is copied from the demo):
while (!terminated)
{
   // Call contourLoop() to process any queued cells
   if (!clipmapView->contourLoop( &threadGenerator, threadContext, threadContextCellData, stats ))
   {
       Sleep( 200 );
   }
}

The way I'm modifying my clipmapView's position is by using the following:
[Init, copied from demo]
// Let's start far, far away
m_ClipmapView->xpos = 2000000.0;
m_ClipmapView->ypos = 50200.0;
m_ClipmapView->zpos = 2000000.0;

m_ClipmapView->xoffs = m_ClipmapView->xpos;
m_ClipmapView->yoffs = m_ClipmapView->zpos;
m_ClipmapView->zoffs = m_ClipmapView->ypos;

[Update, m_Player->GetPosition() doesn't exceed [-1000; 1000]]
m_ClipmapView->xpos = m_ClipmapView->xoffs + Main->m_Player->GetPosition( ).x;
m_ClipmapView->ypos = m_ClipmapView->zoffs + Main->m_Player->GetPosition( ).y;
m_ClipmapView->zpos = m_ClipmapView->yoffs + Main->m_Player->GetPosition( ).z;

It doesn't look like this should crash it, and yet commenting out those last 3 lines prevents it from crashing..

 

I'll be continuing the search awaiting your answer, just hoping you have had some previous similar experience, or can help me with the not-so-descriptive error.
Thanks in advance! 😉

EDIT: The crash comes from VoxelFarm::CClipmapView::contourLoop(class VoxelFarm::CGenerator *,class VoxelFarm::ContourThreadContext *,class VoxelFarm::CCellData::ThreadContext *,struct VoxelFarm::StatTracker (* const)[51]), but I can't see the code of that...

0 0
voxelfarmtorres
The usual suspects in this case are the thread context and stats objects. These objects need to be unique per thread calling the contourLoop() function and their lifetime should be enough to cover the while() loop.

It is a bit hard to help in this case, since we lack the rest of your code.
0 0
Anasky

That seems to be the case though in my code [frown]

I've attached the files (it's about 500 lines of code fortunately, and most of it is copied from the ThinClient demo. I've been trying to merge it with the OpenGL demo, so not everything is 1:1. I can't provide a compilable version though since you'd need the entire framework...)

0 0
Anasky
Little update: I just tested it with a single contour thread, and it's still giving me the issue. The scene thread is still present, but they're separated code so shouldn't collide with the stat object.

In case some code is useful here, see below:
void clsVoxelFarm::clsContourThread::BackgroundTask( void* Data )
{
  // We always collect stats
  VoxelFarm::LODStats stats;

  // For thread safety all work buffers must be created per thread.
  VoxelFarm::ContourThreadContext* threadContext = VF_NEW VoxelFarm::ContourThreadContext( );

  // Create a copy generator to be used by the thread
  VoxelFarm::CGenerator threadGenerator( *m_VoxelFarm->GetClipmapView( )->generator );

  // Create a thread context for cell data processing
  VoxelFarm::CCellData::ThreadContext* threadContextCellData = VF_NEW VoxelFarm::CCellData::ThreadContext( );

  // Loop forever
  while (m_Terminated == false)
  {
    // Call contourLoop in the cell, if it returns false it means there are no cells to process
    if (!m_VoxelFarm->GetClipmapView( )->contourLoop( &threadGenerator, threadContext, threadContextCellData, stats ))
    {
      Sleep( 200 );
      stats[ 0 ][ VoxelFarm::STAT_CONTOUR_LOOP_IDLE ].time += 200;
    }
    // If an activation thread was set for this thread wait for it
    // The thread will sleep until it is needed
    if (m_ActivationEvent != 0)
    {
      WaitForSingleObject( m_ActivationEvent, INFINITE );
    }
  }

  // Release work buffers
  VF_DELETE threadContext;
  VF_DELETE threadContextCellData;
}

void clsVoxelFarm::clsSceneThread::BackgroundTask( void* Data )
{
  // We always collect stats
  VoxelFarm::LODStats stats;

  while (m_Terminated == false)
  {
    // Call sceneLoop() function to discover new scenes
    if (!m_VoxelFarm->GetClipmapView( )->sceneLoop( stats ))
    {
      Sleep( 200 );
    }
  }
}


Any help would be vastly appreciated, been stuck on this for so damn long...
0 0
voxelfarmtorres
We may have found the issue with your code.

After calling getNextCellToDestroy(), you are doing a loop over the multiple mediums. You have the call to notifyCellDestroyed() inside this loop, meaning you will notify many times the same cell was destroyed. This will put the same pointer multiple times in the queue for destruction.


for (int medium = 0; medium < VoxelFarm::CCellData::MEDIUM_MAX; medium++)
{

    ...

    m_VoxelFarmClient->destroyData( cellData->cell );
    m_ClipmapView->notifyCellDestroyed( cellData );
}



The calls to destroyData() and notifyCellDestroyed() should be outside this loop.
0 0
Anasky

Thanks so much! 😃
Small copy/paste mistake apparently... I'll test it when I'm back home this evening 😉
(Apologies for the duplicate post, given the question changing I figured it might be cleaner to write it down in a separate thread)

To be continued 😉 (thanks again!)

0 0
Anasky

It's no longer crashing, so yay!

Currently struggling with it randomly disappearing in certain areas. Is there a specific location where I have to update the player's position? Like does it have to be in the main thread? Would the update thread be better, or perhaps the sceneThread? Or is there another reason why certain cells might become invalid even though I'm still within range? (It causes gaps, cells beyond those disappearing cells still show)

0 0
namrog84
As discovered in the Unreal plugin.  

The function SetClipmapviewFocus is recommended to be called once per game Tick 

Inside that function it calls into
vfWorld->setCoordinates(
focusVec.X*UE_TO_VOX + ORIGINX,
focusVec.Z*UE_TO_VOX + ORIGINZ,
focusVec.Y*UE_TO_VOX + ORIGINY
);


Which vfWorld is implemented in VoxelFarmBundle.cpp as

if (initialized && clipmapView){
clipmapView->xpos = x;
clipmapView->ypos = y;
clipmapView->zpos = z;
}


And in your case above, you already have access to the m_ClipmapView
So you need to just update your m_ClipmapView->xpos for each xpos, ypos, zpos per game tick as well.

In your above code you had
m_ClipmapView->xoffs = m_ClipmapView->xpos
You should instead set that to
m_ClipmapView->xoffs = 2000000.0
m_ClipmapView->xpos = playerLocationX; 


and xpos will be continously updated, and xoffs will be left static as your 'origin' into the voxel world. 
0 0