After some investigation, i suspect that the bsdf modifier “df::measured_factor” introduced in MDL 2019.1 has a bug regarding how the input image is handled at the 0°/90° border.
the gradient image is a 1px-wide and 91-px high bitmap with a gradient from “black” at the top to “grey” at the bottom, with two control pixel bands (see (https://filebin.ca/5RvrEdgXy3UJ/Gradient.png) )
With a simple directional light source shining straight down, i now look straight down onto a flat surface using the above material, using a camera with a large viewing angle. I see a surface that nicely matches the gradient and shows the control rings
BUT: Right at the center, directly below the viewpoint, as the viewing angle approaches the normal, there is a dark spot where the brightest spot should be. The dark spot vanishes if i make the top pixel in the image the same color as the bottom pixel, and becomes an almost white spot if i change the top pixel to white. From what i understand, the top pixel should not have any influence here, the reflectance values at this spot should be controlled only by the bottom pixels of the input image.
Is this a bug in the MDL/Optix or am I maybe missing / misunderstanding the documentation?
Is your texture runtime based on mdl_textures.cu from the OptiX 6.5.0 examples?
This example runtime contains a bug in WRAP_AND_CROP_OR_RETURN_BLACK which causes the wrong clamping.
Here is an updated version which should clamp correctly:
// Applies wrapping and cropping to the given coordinate.
// Note: This macro returns if wrap mode is clip and the coordinate is out of range.
#define WRAP_AND_CROP_OR_RETURN_BLACK(val, inv_dim, wrap_mode, crop_vals, store_res_func) \
do { \
if ( (wrap_mode) == mi::neuraylib::TEX_WRAP_REPEAT && \
(crop_vals)[0] == 0.0f && (crop_vals)[1] == 1.0f ) { \
/* Do nothing, use texture sampler default behavior */ \
} \
else \
{ \
if ( (wrap_mode) == mi::neuraylib::TEX_WRAP_REPEAT ) \
val = val - floorf(val); \
else { \
if ( (wrap_mode) == mi::neuraylib::TEX_WRAP_CLIP && (val < 0.0f || val >= 1.0f) ) { \
store_res_func(result, 0.0f); \
return; \
} \
else if ( (wrap_mode) == mi::neuraylib::TEX_WRAP_MIRRORED_REPEAT ) { \
float floored_val = floorf(val); \
if ( (int(floored_val) & 1) != 0 ) \
val = 1.0f - (val - floored_val); \
else \
val = val - floored_val; \
} \
float inv_hdim = 0.5f * (inv_dim); \
val = fminf(fmaxf(val, inv_hdim), 1.f - inv_hdim); \
} \
val = val * ((crop_vals)[1] - (crop_vals)[0]) + (crop_vals)[0]; \
} \
} while ( 0 )
Note, that this function takes an additional parameter “inv_dim”, which should be the reciproc value of the corresponding dimension. You could use it like this: