0

I am trying to implement a basic custom sampler, and here is the code that I have been working with. As I attempt to render the scene, I encounter an error stating that the traverse() method is not implemented, despite being present in the class. My custom sampler is similar to the one presented in the tutorial here. Firstly, is it possible to create a custom sampler in Mitsuba using Python? Secondly, any help with this code would be welcome. Thank you!

/mitsuba/~/.local/lib/python3.10/site-packages/mitsuba/python/util.py:364)   
RuntimeError: ​[Sampler] Sampler::traverse_1_cb_ro(): not implemented!
The above exception was the direct cause of the following exception:
RuntimeError: drjit.custom(<mitsuba.python.util._RenderOp>): error while performing a custom differentiable operation. (see above).

Code to be reproduced:

import mitsuba as mi
import drjit as dr
mi.set_variant('llvm_ad_rgb')

#Custom Sampler
class MySampler(mi.Sampler):
    def __init__(self, props):
        super().__init__(props)
        self.sample_count = props.get('sample_count', 256)
        self.base_seed = props.get('seed', 0)
        self.rng = mi.PCG32()  # The magical dice!
        self.seed(self.base_seed, 1)  # Get ready to roll!

    def seed(self, seed: int, wavefront_size: int) -> None:
        self.rng.seed(seed, wavefront_size)

    def next_1d(self, active=True):
        # Roll the dice and give a random number between 0 and 1!
        #This works for custom_sampler in Sphere example
        #return dr.uint32_to_float(self.rng())
        x = self.rng.next_float32()
        return self.rng.next_float32()
    
    def next_2d(self, active=True):
        # Roll twice to get an X and Y spot
        return mi.Point2f(self.next_1d(active), self.next_1d(active))

    def advance(self):
        # After coloring one spot, move to the next!
        pass  # (Our simple dice doesn't need to do anything here)

    def set_sample_count(self, sample_count: int):
        self.sample_count = sample_count

    def get_sample_count(self) -> int:
        return self.sample_count

    def current_sample_index(self) -> int:
        return 0  # We're not keeping track in this simple sampler

    def clone(self):
        # Make a new magic dice for a new painter-robot
        new_sampler = MySampler(mi.Properties())
        new_sampler.sample_count = self.sample_count
        new_sampler.base_seed = self.base_seed
        return new_sampler
    
    def traverse(self, cb):
         super().traverse(cb) # Call the base class implementation
         cb.put_parameter('sample_count', self.sample_count, mi.ParamFlags.NonDifferentiable)
         cb.put_parameter('base_seed', self.base_seed, mi.ParamFlags.NonDifferentiable)
    

    def to_string(self):
        return f"MySampler[\n  sample_count = {self.sample_count},\n  base_seed = {self.base_seed}\n]"

mi.register_sampler("mysampler", lambda props: MySampler(props))
scene = mi.load_file('teapot.xml')
image_xml = mi.render(scene)
import matplotlib.pyplot as plt
plt.axis('off')
plt.imshow(image_xml ** (1.0 / 2.2));

Teapot XML File is as follows:

<scene version="3.0.0">
    <default name="integrator" value="volpath" />
    <default name="spp" value="256" />
    <default name="resy" value="720" />
    <default name="resx" value="1280" />
    <default name="max_depth" value="65" />
    <integrator type="$integrator">
        <integer name="max_depth" value="$max_depth" />
    </integrator>


    <sensor type="perspective">
        <float name="fov" value="35" />
        <transform name="to_world">
            <matrix value="0.00560664 -0.488405 -0.872599 23.1701 0 0.872613 -0.488413 15.7142 0.999984 0.00274286 0.00490048 -0.172476 0 0 0 1" />
        </transform>
        <sampler type="mysampler" id="Sampler">
            <integer name="sample_count" value="$spp" />
        </sampler>
        <film type="hdrfilm">
            <integer name="width" value="$resx" />
            <integer name="height" value="$resy" />
            <string name="file_format" value="openexr" />
            <string name="pixel_format" value="rgb" />
            <rfilter type="tent" />
        </film>
    </sensor>
    <bsdf type="twosided" id="FloorBSDF">
        <bsdf type="diffuse">
            <texture name="reflectance" type="checkerboard">
                <rgb name="color1" value="0.325, 0.31, 0.25" />
                <rgb name="color0" value="0.725, 0.71, 0.68" />
                <transform name="to_uv">
                    <scale x="10.000000" y="10.000000" />
                </transform>
            </texture>
        </bsdf>
    </bsdf>
    <shape type="rectangle" id="Floor">
        <transform name="to_world">
            <matrix value="-34.6854 36.1079 4.61062e-006 -0.708772 -4.37713e-006 2.18856e-006 -50.0685 0 -36.1079 -34.6854 1.6405e-006 -0.732108 0 0 0 1" />
        </transform>
        <ref id="FloorBSDF" />
    </shape>
    <shape type="obj">
        <string name="filename" value="models/Mesh003.obj" />
        <transform name="to_world">
            <matrix value="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1" />
        </transform>
        <bsdf type="dielectric">
            <float name="int_ior" value="1.5" />
            <float name="ext_ior" value="1" />
        </bsdf>
    </shape>
    <shape type="obj">
        <string name="filename" value="models/Mesh001.obj" />
        <transform name="to_world">
            <matrix value="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1" />
        </transform>
        <bsdf type="dielectric">
            <float name="int_ior" value="1.5" />
            <float name="ext_ior" value="1" />
        </bsdf>
    </shape>
    <shape type="obj">
        <string name="filename" value="models/Mesh002.obj" />
        <transform name="to_world">
            <matrix value="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1" />
        </transform>
        <boolean name="face_normals" value="true" />
        <bsdf type="dielectric">
            <float name="int_ior" value="1.33" />
            <float name="ext_ior" value="1" />
        </bsdf>
        <medium type="homogeneous" name="interior">
            <rgb name="albedo" value="0, 0, 0" />
            <rgb name="sigma_t" value="0.1486, 0.321, 0.736" />
        </medium>
    </shape>
    <shape type="obj">
        <string name="filename" value="models/Mesh000.obj" />
        <transform name="to_world">
            <matrix value="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1" />
        </transform>
        <bsdf type="dielectric">
            <float name="int_ior" value="1.13" />
            <float name="ext_ior" value="1" />
        </bsdf>
        <medium type="homogeneous" name="exterior">
            <rgb name="albedo" value="0, 0, 0" />
            <rgb name="sigma_t" value="0.1486, 0.321, 0.736" />
        </medium>
    </shape>
    <emitter type="envmap">
        <transform name="to_world">
            <matrix value="-0.922278 0 0.386527 0 0 1 0 0 -0.386527 0 -0.922278 1.17369 0 0 0 1" />
        </transform>
        <string name="filename" value="textures/envmap.hdr" />
    </emitter>

</scene>
2
  • example in link uses mi.BSDF but you use mi.Sampler and maybe this makes difference. Commented Jul 5 at 13:22
  • documentation for Sampler doesn't mention Sampler.traverse() - so maybe you shouldn't use super().traverse(). Example in tutorial also doesn't use super().traverse() Commented Jul 5 at 13:25

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.