Dar
Hi, I just started using voxel. I was wondering how can I do a costum brush. I've seen videos of people sculpting with spheres but I can't find any tutorials or documents.

Thanks,
-D
0 0
voxelfarmtorres
Please check the tutorial here:

http://www.voxelfarm.com/doc.html?custom-brush-shapes

Let us know if this addressed your questions.
0 0
Ryan W. Anderson
I have a question to add to this. The link you provided shows how you can import an .fbx to use as a brush in Voxel Studio. Do you provide functions in the SDK to do something similar? (Load an .fbx mesh to add/remove voxel material from a scene?)
0 0
voxelfarmtorres
Brushes in Voxel Studio use a process we call "mesh stamping". This is the same as voxelizing the mesh into the scene. In the OpenGL example included in the SDK there is a portion that shows mesh stamping. Just look for calls to the "stampMesh()" function.

You will see that this function takes an abstract interface IMeshStampSource as a parameter to describe the mesh you want to voxelize. It is an abstract interface because there may be multiple sources for meshes, not just FBX. IMeshStampSource is a very simple interface that just lists the faces and vertices in your mesh.

In order to read FBX files, you will need the FBX SDK from Autodesk. Autodesk provides multiple examples of how to read vertices and faces. With this information you can create your own implementation of IMeshStampSource.

Here is the one we use in Voxel Studio:


class CMeshFBXSource : public IMeshStampSource
{
public:
  TVector<CFastQuadrics*> solids;
  TVector<MaterialId> solidMaterials;
  double minCoords[3];
  double maxCoords[3];
public:
  CMeshFBXSource(char* filename, const TMap<String, MaterialId>& materialPalette);
  /// Returns the number of solids
  virtual int getSolidCount() { return (int)solids.size(); }
  /// Returns the material of a solid
  virtual MaterialId getSolidMaterial(int solid) { return solidMaterials[solid]; }
  /// Returns the number of faces in a solid
  virtual int getFaceCount(int solid){ return solids[solid]->faceCount; }
  /// Get the vertices of a face of a solid
  virtual void CMeshFBXSource::getFace(int solid,
    int index,
    Algebra::Vector& v0,
    Algebra::Vector& v1,
    Algebra::Vector& v2)
  {
    CFastQuadrics* mesh = solids[solid];
    FQ_Face& f = mesh->faces[index];
    FQ_Vertex& mv0 = mesh->vertices[f[0]];
    FQ_Vertex& mv1 = mesh->vertices[f[2]];
    FQ_Vertex& mv2 = mesh->vertices[f[1]];
    v0.x = (float)((mv0.x - minCoords[0]) / (maxCoords[0] - minCoords[0]));
    v0.y = (float)((mv0.y - minCoords[1]) / (maxCoords[1] - minCoords[1]));
    v0.z = (float)((mv0.z - minCoords[2]) / (maxCoords[2] - minCoords[2]));
    v1.x = (float)((mv1.x - minCoords[0]) / (maxCoords[0] - minCoords[0]));
    v1.y = (float)((mv1.y - minCoords[1]) / (maxCoords[1] - minCoords[1]));
    v1.z = (float)((mv1.z - minCoords[2]) / (maxCoords[2] - minCoords[2]));
    v2.x = (float)((mv2.x - minCoords[0]) / (maxCoords[0] - minCoords[0]));
    v2.y = (float)((mv2.y - minCoords[1]) / (maxCoords[1] - minCoords[1]));
    v2.z = (float)((mv2.z - minCoords[2]) / (maxCoords[2] - minCoords[2]));
  }
private:
  void processNode(FbxNode* node, VoxelFarm::Algebra::Matrix matrix, bool& minCoordSet, const TMap<String, MaterialId>& materialPalette);
};
void CMeshFBXSource::processNode(FbxNode* node, VoxelFarm::Algebra::Matrix matrix, bool& minCoordSet, const TMap<String, MaterialId>& materialPalette)
{
  int subnodeCount = node->GetChildCount();
  for (int i = 0; i < subnodeCount; i++)
  {
    FbxNode* subnode = node->GetChild(i);
    processNode(subnode, matrix, minCoordSet, materialPalette);
  }
  FbxNodeAttribute* lNodeAttribute = node->GetNodeAttribute();
  if (lNodeAttribute == NULL || lNodeAttribute->GetAttributeType() != FbxNodeAttribute::eMesh)
    return;
  FbxMesh* mesh = node->GetMesh();
  if (mesh == NULL)
    return;
  FbxMatrix transform = node->EvaluateGlobalTransform();
  const FbxVector4 lT = node->GetGeometricTranslation(FbxNode::eSourcePivot);
  const FbxVector4 lR = node->GetGeometricRotation(FbxNode::eSourcePivot);
  const FbxVector4 lS = node->GetGeometricScaling(FbxNode::eSourcePivot);
  FbxAMatrix geometric(lT, lR, lS);
  transform *= geometric;
  Matrix mat;
  for (int elx = 0; elx < 4; elx++)
    for (int ely = 0; ely < 4; ely++)
      mat.m[elx * 4 + ely] = (float)transform.Get(elx, ely);
  MaterialId material = 1;
  if (node->GetMaterialCount() > 0)
  {
    String matId = node->GetMaterial(0)->GetName();
    TMap<String, MaterialId>::const_iterator imat = materialPalette.find(matId);
    if (imat != materialPalette.end())
    {
      material = imat->second;
    }
  }
  int faceCount = 0;
  int vertCount = 0;
  FbxVector4* verts = mesh->GetControlPoints();
  for (int i = 0; i < mesh->GetPolygonCount(); i++)
  {
    int polySize = mesh->GetPolygonSize(i);
    if (polySize == 4)
    {
      faceCount += 2;
      vertCount += 6;
    }
    else if (polySize == 3)
    {
      faceCount += 1;
      vertCount += 3;
    }
  }
  if (faceCount == 0)
    return;
  CFastQuadrics* fq = new CFastQuadrics();
  fq->allocate(vertCount, faceCount);
  for (int i = 0; i < mesh->GetPolygonCount(); i++)
  {
    double vertCoords[4][3] = {0};
    int polySize = mesh->GetPolygonSize(i);
    for (int j = 0; j < polySize; j++)
    {
      int cpIndex = mesh->GetPolygonVertex(i, j);
      for (int axis = 0; axis < 3; axis++)
      {
        vertCoords[j][axis] = verts[cpIndex].mData[axis];
      }
      Vector v = Vector_withValues((float)vertCoords[j][0], (float)vertCoords[j][1], (float)vertCoords[j][2]);
      v = Matrix_multiplyVector(mat, v);
      vertCoords[j][0] = v.x;
      vertCoords[j][1] = v.y;
      vertCoords[j][2] = v.z;
      if (!minCoordSet)
      {
        for (int axis = 0; axis < 3; axis++)
        {
          minCoords[axis] = vertCoords[j][axis];
          maxCoords[axis] = vertCoords[j][axis];
        }
        minCoordSet = true;
      }
      else
      {
        for (int axis = 0; axis < 3; axis++)
        {
          minCoords[axis] = min(minCoords[axis], vertCoords[j][axis]);
          maxCoords[axis] = max(maxCoords[axis], vertCoords[j][axis]);
        }
      }
    }
    int id0 = fq->addVertex(vertCoords[0][0], vertCoords[0][1], vertCoords[0][2], 0);
    int id1 = fq->addVertex(vertCoords[1][0], vertCoords[1][1], vertCoords[1][2], 0);
    int id2 = fq->addVertex(vertCoords[2][0], vertCoords[2][1], vertCoords[2][2], 0);
    fq->addFace(id0, id1, id2, 0);
    if (polySize == 4)
    {
      int id3 = fq->addVertex(vertCoords[0][0], vertCoords[0][1], vertCoords[0][2], 0);
      int id4 = fq->addVertex(vertCoords[2][0], vertCoords[2][1], vertCoords[2][2], 0);
      int id5 = fq->addVertex(vertCoords[3][0], vertCoords[3][1], vertCoords[3][2], 0);
      fq->addFace(id3, id4, id5, 0);
    }
  }
  solids.push_back(fq);
  solidMaterials.push_back(material);
}
CMeshFBXSource::CMeshFBXSource(char* filename, const TMap<String, MaterialId>& materialPalette)
{
  FbxManager* fbx;
  FbxImporter* importer;
  FbxScene* scene;
  //createfbx file manager
  fbx = FbxManager::Create();
  //create scene importer
  importer = FbxImporter::Create(fbx, "import");
  scene = FbxScene::Create(fbx, "scene");
  //load the fbx file
  bool success = importer->Initialize(filename, -1, fbx->GetIOSettings());
  if (!success)
    return;
  //import the scene
  importer->Import(scene);
  int dir;
  scene->GetGlobalSettings().GetAxisSystem().GetUpVector(dir);
  FbxAxisSystem max;
  max.ConvertScene(scene);
  scene->GetGlobalSettings().GetAxisSystem().GetUpVector(dir);
  importer->Destroy();
  //get root node
  Matrix matrix = Matrix_identity();
  bool minCoordSet = false;
  processNode(scene->GetRootNode(), matrix, minCoordSet, materialPalette);
}




0 0