Ryan W. Anderson
I'm trying to re-create the "simple" demo in Unreal engine. Everything is working until I try to run "VoxelFarm::contourCellDataMCA(threadContext, NULL, &materialLibrary, &cellData, NULL, threadContextCellData, true , stats)" then the engine crashes with an access violation. If I comment out that line, everything works.

Error: "Exception thrown at 0x00007FFC1952547F (UE4Editor-CHEngine-Win64-DebugGame.dll) in UE4Editor.exe: 0xC0000005: Access violation reading location 0x0000000000000010."

Any ideas?

Code below. Note that I'm using libnoise to generate my perlin noise, but it fails the same way when I cut and paste the CSimpleVoxelLayer_Perlin3D class from the demo.


// TestSimpleVoxelTerrain.cpp

#include "CHEngine.h"
#include "TestSimpleVoxelTerrain.h"
#include  "VoxelLayer_Perlin3D.h"

// Sets default values
ATestSimpleVoxelTerrain::ATestSimpleVoxelTerrain()
{
   // Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
  PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void ATestSimpleVoxelTerrain::BeginPlay()
{
  Super::BeginPlay();
  // We always collect stats
  VoxelFarm::LODStats stats;
  // We need at least two different materials 0 = air, 1 = solid
  VoxelFarm::CMaterialLibrary materialLibrary;
  materialLibrary.materialCount = 2;
  materialLibrary.materialIndex = VF_ALLOC(VoxelFarm::CMaterial, 2);
  memset(materialLibrary.materialIndex, 0, 2 * sizeof(VoxelFarm::CMaterial));
  // Let's engage the billboard generation too
  memset(&materialLibrary.billboardPack, 0, sizeof(materialLibrary.billboardPack));
  materialLibrary.materialIndex[0].billboard = -1;
  materialLibrary.materialIndex[1].billboard = 1;
  materialLibrary.materialIndex[1].billboardType = 1;
  // Declare a generator object. This object can combine many voxel layers.
  VoxelFarm::CGenerator generator;
  // Add the test voxel layer to the generator.
  VoxelLayer_Perlin3D layer;
  generator.addVoxelLayer(&layer);
  // Create a ContourThreadContext object to hold the work buffers
  VoxelFarm::ContourThreadContext* threadContext = VF_NEW VoxelFarm::ContourThreadContext();
  VoxelFarm::CCellData::ThreadContext* threadContextCellData = VF_NEW VoxelFarm::CCellData::ThreadContext();
  // Get number of iterations from command line
  //int iterations = (argv[1] != NULL) ? atoi(argv[1]) : 0;
  int iterations = 1;
  // Loop
  int cellCount = 0;
  do
  {
    // Get a random cell, at a random LOD
    int level = rand() % VoxelFarm::LEVELS;
    int xc = rand();
    int yc = rand();
    int zc = rand();
    VoxelFarm::CellId cell = VoxelFarm::packCellId(level, xc, yc, zc);
    // Ask the generator to create the voxels for the cell
    bool empty;
    threadContext->data->clear();
    generator.generate(cell, threadContext->data, empty, stats);
    if (empty)
    {
      continue;
    }
    // Contour the voxel data and produce a mesh for the cell (CCellData)
    VoxelFarm::CCellData cellData(cell);
    
    /// we pass NULL for the clipmapView. This will ignore material instance references.
    if (!VoxelFarm::contourCellDataMCA(threadContext, NULL, &materialLibrary, &cellData, NULL, threadContextCellData, true , stats))
    {
      continue;
    }
    
    // Print how many triangles we got
    int faces = cellData.faceCount[VoxelFarm::CCellData::MEDIUM_SOLID];
    /*std::cout <<
      //cell << " \t" <<
      "LOD" << level << " \t" <<
      "(" << xc << "," << yc << "," << zc << ") \t" <<
      faces << " faces." << std::endl;*/
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Green, FString::Printf(TEXT("Cell: %f"), cell));
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Green, FString::Printf(TEXT("LOD: %f"), level));
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Green, FString::Printf(TEXT("(%f, %f, %f)"), xc, yc, zc));
    GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Green, FString::Printf(TEXT("Faces: %f"), faces));
    cellCount++;
  } while (cellCount < iterations);
  // Release work buffers
  VF_DELETE threadContext;
  VF_DELETE threadContextCellData;
}
// Called every frame
void ATestSimpleVoxelTerrain::Tick( float DeltaTime )
{
  Super::Tick( DeltaTime );
}



// TestSimpleVoxelTerrain.h

#pragma once
#include "GameFramework/Actor.h"
#include "TestSimpleVoxelTerrain.generated.h"
UCLASS()
class CHENGINE_API ATestSimpleVoxelTerrain : public AActor
{
  GENERATED_BODY()
  
public:  
  // Sets default values for this actor's properties
  ATestSimpleVoxelTerrain();
  // Called when the game starts or when spawned
  virtual void BeginPlay() override;
  
  // Called every frame
  virtual void Tick( float DeltaSeconds ) override;
  
  
};



// VoxelLayer_Perlin3D.cpp

#include "CHEngine.h"
#include "VoxelLayer_Perlin3D.h"
#include "noise.h"
using namespace noise;
void VoxelLayer_Perlin3D::getContourData(VoxelFarm::CellId cell, VoxelFarm::ContourVoxelData* data, bool& empty, void* threadContext)
{
  int level, xc, yc, zc;
  VoxelFarm::unpackCellId(cell, level, xc, yc, zc);
  double scale = VoxelFarm::CELL_SIZE*(1 << level);
  double cellOriginX = xc*scale;
  double cellOriginY = yc*scale;
  double cellOriginZ = zc*scale;
  module::Perlin perlinNoise;
  empty = true;
  for (int z = 0; z < VoxelFarm::BLOCK_SIZE; z++)
    for (int x = 0; x < VoxelFarm::BLOCK_SIZE; x++)
      for (int y = 0; y < VoxelFarm::BLOCK_SIZE; y++)
      {
        double dx = (double)(x - VoxelFarm::BLOCK_MARGIN) / (double)(VoxelFarm::BLOCK_DIMENSION);
        double dy = (double)(y - VoxelFarm::BLOCK_MARGIN) / (double)(VoxelFarm::BLOCK_DIMENSION);
        double dz = (double)(z - VoxelFarm::BLOCK_MARGIN) / (double)(VoxelFarm::BLOCK_DIMENSION);
        double worldX = 0.00001*(xc + dx)*scale;
        double worldY = 0.00001*(yc + dy)*scale;
        double worldZ = 0.00001*(zc + dz)*scale;
        //double field = VoxelFarm::PerlinNoise3D(worldX, worldY, worldZ, 0.5, 2.0, 2);
        //double field = PerlinNoise3D(worldX, worldY, worldZ, 0.5, 2.0, 2);
        perlinNoise.SetOctaveCount(2);
        perlinNoise.SetPersistence(0.5);
        perlinNoise.SetFrequency(2.0);
        double field = perlinNoise.GetValue(worldX, worldY, worldZ);
        // Compute voxel index in the voxel buffer
        VoxelFarm::ContourVoxelData::Index index(x, y, z);
        // If field is positive, the voxel is solid
        if (field > 0.0)
        {
        // Set material 1 to indicate solid
        data->setMaterial(index, 1);
        empty = false;
        }
      }
}


// VoxelLayer_Perlin3D.h
#pragma once
#include "mapindex.h"
#include "VoxelLayer.h"
#include "Generator.h"
#include "contour.h"
#include "CellData.h"
/**
 * 
 */
class CHENGINE_API VoxelLayer_Perlin3D : public VoxelFarm::IVoxelLayer
{
public:
  void getContourData(VoxelFarm::CellId cell, VoxelFarm::ContourVoxelData* data, bool& empty, void* threadContext);
};

0 0