Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Volume Builder Type Fog Should it be solid?

    Cinema 4D SDK
    c++ 2024
    2
    3
    488
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D
      d_schmidt
      last edited by

      Hello, I'm using a Volume Builder, with Volume Type Fog and I'm getting some results I didn't expect with the location of the voxels. Would it be expected that the entire Volume would be filled and 'solid' with Fog mode?

      It's not the most elegant test case, but it's the one I can trim down.

      //Get the volume from the volume builder object.
      maxon::Volume       volume = volumeObject->GetVolume();
      maxon::GridIteratorRef<maxon::Float32, maxon::ITERATORTYPE::ON> iterator = maxon::GridIteratorRef<maxon::Float32, maxon::ITERATORTYPE::ON>::Create() iferr_return;
      iterator.Init(volume)iferr_return;
      maxon::Matrix transform = volume.GetGridTransform();
      
      BaseDocument* doc = GetActiveDocument();
      BaseObject* sphere = BaseObject::Alloc(Osphere);
      BaseContainer* con = sphere->GetDataInstance();
      con->SetFloat(PRIM_SPHERE_RAD, 5);
      
      for (; iterator.IsNotAtEnd(); iterator.StepNext())
      {
                      const maxon::IntVector32 coord = iterator66.GetCoords();
                      BaseObject* clone = static_cast<BaseObject*>( sphere->GetClone(COPYFLAGS::NONE, nullptr));
                      clone->SetAbsPos(transform* Vector(coord));
                      doc->InsertObject(clone, nullptr, nullptr);
      }
      

      This code will create a sphere at the location of each active voxel. This was the easiest way I could think of showing the active voxels.

      If I use a cube underneath a Volume Builder and delete away some of the spheres then the hollow inside, which I didn't think would happen with Fog mode.
      Screenshot 2025-02-27 at 4.36.23 PM.png
      Screenshot with the spheres deleted to show the hollow interior.

      Dan

      1 Reply Last reply Reply Quote 0
      • M
        m_adam
        last edited by m_adam

        Hey @d_schmidt yes this is expected, openvdb is sparse with 4 level tile options. Since our volume tool use openVDB we inherit from that.

        In the context of OpenVDB and similar data structures, "sparse" refers to a way of efficiently representing and storing data in which only the non-empty or non-default parts are explicitly kept in memory. This is in contrast to dense representations, where every element is stored regardless of whether it holds meaningful information or not.
        In a sparse representation like OpenVDB, the data structure is designed to allocate memory only for the parts of the voxel grid that contain relevant data (i.e., active voxels), while ignoring the regions that are empty or hold similar values. This allows for significant memory savings and performance improvements, especially when dealing with large grids where most of the space is empty/similar.

        So with that's said the way to retrieve what you expected is with the next code. Note that I've used Multi-Instance for speed reason and not polluting too much the viewport.

        constexpr inline Int ConvertVoxelLevelToAmount(TREEVOXELLEVEL level)
        {
        	switch (level)
        	{
        		case TREEVOXELLEVEL::ROOT:
        		{
        			return 32;
        		}
        		case TREEVOXELLEVEL::TWO:
        		{
        			return 16;
        		}
        		case TREEVOXELLEVEL::THREE:
        		{
        			return 8;
        		}
        		case TREEVOXELLEVEL::LEAF:
        		{
        			return 1;
        		}
        	}
        	static_assert(true, "Unsupported voxel depth");
        	return 0;
        }
        
        class Command : public CommandData
        {
        public:
        
          virtual Bool Execute(BaseDocument* doc, GeDialog* parentManager)
          {
            iferr_scope_handler
            {
              return true;
            };
        
            BaseObject* object = doc->GetFirstObject();
            if (!object)
              return true;
        
            if (!object->IsInstanceOf(Ovolumebuilder))
              return true;
        
            VolumeBuilder* const volumeBuilder = static_cast<VolumeBuilder*>(object);
        
            // get cache
            BaseObject* const cache = volumeBuilder->GetCache();
            if (cache == nullptr)
              return true;
        
            // check for volume object
            if (!cache->IsInstanceOf(Ovolume))
              return true;
        
            const VolumeObject* const volumeObject = static_cast<VolumeObject*>(cache);
            maxon::Volume volume = volumeObject->GetVolume();
            maxon::GridIteratorRef<maxon::Float32, maxon::ITERATORTYPE::ON> iterator = maxon::GridIteratorRef<maxon::Float32, maxon::ITERATORTYPE::ON>::Create() iferr_return;
            iterator.Init(volume) iferr_return;
            maxon::Matrix transform = volume.GetGridTransform();
        
            BaseObject* sphere = BaseObject::Alloc(Osphere);
            BaseContainer* con = sphere->GetDataInstance();
            con->SetFloat(PRIM_SPHERE_RAD, 5);
        
            doc->InsertObject(sphere, nullptr, nullptr);
        
            // create instance object
            InstanceObject* const instance = InstanceObject::Alloc();
            if (instance == nullptr)
              return true;
        
            doc->InsertObject(instance, nullptr, nullptr);
            instance->SetReferenceObject(sphere) iferr_return;
        
            if (!instance->SetParameter(ConstDescID(DescLevel(INSTANCEOBJECT_RENDERINSTANCE_MODE)), INSTANCEOBJECT_RENDERINSTANCE_MODE_MULTIINSTANCE, DESCFLAGS_SET::NONE))
              return true;
        
            maxon::BaseArray<Matrix> matrices;
        
            for (; iterator.IsNotAtEnd(); iterator.StepNext())
            {
              if (iterator.GetValue() < 0.0)
                continue;
        
              const Int voxelAmount = ConvertVoxelLevelToAmount(iterator.GetVoxelLevel());
              for (Int32 voxelIndexX = 0; voxelIndexX < voxelAmount; voxelIndexX++)
              {
                for (Int32 voxelIndexY = 0; voxelIndexY < voxelAmount; voxelIndexY++)
                {
                  for (Int32 voxelIndexZ = 0; voxelIndexZ < voxelAmount; voxelIndexZ++)
                  {
                    const maxon::IntVector32 voxelCoord = iterator.GetCoords();
                    Matrix m;
                    m.off = transform * Vector(voxelCoord.x + voxelIndexX, voxelCoord.y + voxelIndexY, voxelCoord.z + voxelIndexZ);
                    matrices.Append(std::move(m)) iferr_return;
                  }
                }
              }			
            }
            instance->SetInstanceMatrices(matrices) iferr_return;
        
            EventAdd();
        
            return dlg.Open(DLG_TYPE::ASYNC, ID_ACTIVEOBJECT, -1, -1, 500, 300);
          }
        
          virtual Int32 GetState(BaseDocument* doc, GeDialog* parentManager)
          {
            return CMD_ENABLED;
          }
        };
        

        Cheers,
        Maxime.

        MAXON SDK Specialist

        Development Blog, MAXON Registered Developer

        1 Reply Last reply Reply Quote 1
        • D
          d_schmidt
          last edited by

          Hi @m_adam ,

          Thank you so much! That was exactly what I needed.

          Dan

          1 Reply Last reply Reply Quote 0
          • First post
            Last post