Solved Python Volume access

Hello,

I'm trying to read a VolumeObject from Python, just trying to visualize the voxel count for now. When I acces a volume interface, like this...

	def GetDParameter(self, node, id, flags):
		paramId = id[0].id
		if paramId == c4d.UNITY_VOLUME_VoxelCount:
			volume = self.get_volume_object(node)
			if volume == None: return False
			vi = volume.GetVolume()
			data = vi.GetActiveVoxelCount()
			return (True, data, flags | c4d.DESCFLAGS_GET_PARAM_GET)
		return False

It works, but I always hit this debug breakpoint. Removing that code stops the critical stop.
Do I need to dispose the interface in any way?

/Volumes/Branches/build_osx/osx-4-release/depot/release/20.0/frameworks/kernel.framework/source/memory/systemallocator.cpp(487): CRITICAL: Stop: Damaged block (or from a different allocator

Also, how to iterate the volume using a GridIterator?
There's nothing like the step methods from C++ SDK, how do I do the loop?

Hi @rsodre, there are few examples of volume usage in python in Github repository.

Especially gridaccessor_read_r20.py which demonstrate how to read data for a given voxel.

So here on a volume builder, the next script is working as expected, note that it's very important to import maxon and volume from maxon.frameworks.

import c4d
import maxon
from maxon.frameworks import volume


def main():
    # Checks if there is an active object
    if op is None:
        raise RuntimeError("Failed to retrieve op.")

    # Checks if the active object is a Volume builder
    if not op.IsInstanceOf(c4d.Ovolumebuilder):
        raise TypeError("op is not a c4d.Ovolumebuilder.")

    # Gets the C4D Volume Object from the cache
    cache = op.GetCache()
    if cache is None:
        raise RuntimeError("Failed to retrieve the cache of the volume builder.")

    # Checks if the cache is a C4D Volume Object
    if not cache.IsInstanceOf(c4d.Ovolume):
        raise TypeError("cache is not a c4d.Ovolume.")

    # Gets the Volume object linked to this Ovolume object.
    volume = cache.GetVolume()
    if volume is None:
        raise RuntimeError("Failed to retrieve the maxon.frameworks.volume.VolumeRef.")

    print(volume.GetActiveVoxelCount())

if __name__ == '__main__':
    main()

Unfortunately, there is no GridIterator in Python available.

So even if you import maxon, and the volume module you still have the issue, I would say that maybe your volumeobject is not correctly built, but without more code, it's hard to reproduce your issue.

Cheers,
Maxime.

I'll devour hat repository, thanks!

I'm getting the volume from a VolumeBuilder's cache.
My code so far is here (very early WIP)

Hi @m_adam.

About the critical stop, it happens even with your code.
I run C4D R20.059 from XCode 10.3

What should the coordinate in access.GetValue(vec) be?
If I try the voxel coordinate, it always returns the same value, testing everything inside volume.GetGetActiveVoxelDim()
If I try world coordinates, all values are negative (inside and outside) the volume.

From the docs, volume. GetWorldBoundingBox() should return a maxon.Range, but this type is not documented anywhere. In practice, it returns a type that is unknown...
UnknownDataType(net.maxon.parametrictype.range<net.maxon.parametrictype.vec<3,float64>>)

I need to extract a normalized SDF from the volume.
Pretty basic but I can't figure out how just with api descriptions.

Hi @rsodre, unfortunately, due to a bug solved in R21, it's not possible in R20 to run Cinema 4D as debug mode and call MAXON_CPYTHON_FUNCTION in release mode.

The issue is that the Python volume framework does use the MAXON_CPYTHON_FUNCTION, so this leads to the behavior that the memory model is not the same.

So I guess if you try your code in regular Cinema 4D (without Xcode and not running c4d in debug mode), it will work without issue, could you confirm?

GetValue works in the global space of the volume grid. This grid can be retrieved from a volumeRef with GetGridTransform.
However, since it's a maxon.Matrix64 this is a bit problematic since maxon.Matrix64 and maxon.Vector doesn't support * operator. So you have to translate them in c4d type (manually) then reconvert it back to a Maxon datatype (this will be done on the fly).

Correct, maxon.Range is not yet implemented in Python so a UnknownDataType is returned so C++.

While I'm happy to assist you on Python Maxon API, I have to admit that the Maxon API regarding Python is far from being feature complete, and regarding your knowledge I advise you to do what you want in C++, it will be far way easier with the GridAccessor.

Cheers,
Maxime.

@m_adam got it! it's working now.

The final code for my float sdf exporter is here.