No, that is the point, there seems to be none.
No, its always optixGetRayTmax() and that is the same as on the diffuse transmission tests in earlier posts in this thread. And there it seems to work correctly.
Great! So I now know exactly how it has to look like.
No, not yet.
I will try that next.
Here the critical code I use to run the MDL DCs; maybe should I set FLAG_VOLUME ?
// parts of this demo code is taken from OptiX Advanced Samples 2018
// and from the MDL SDK samples;
// its used in my app with MDL SDK 2020.1.2 ABI
// (pre-compiled binaries build 334300.5582, 12 Nov 2020)
// My System: OptiX 7.4.0 SDK CUDA 11.4.3 VS2019 v16.11.13
// Win10PRO 64bit (version 21H1; build 19043.1237) Windows SDK 10.0.19041.0 8GB RAM
// device driver: 512.15 GTX 1050 2GB
// in a closesthit program this function is called:
RT_FUNCTION void do_mdl_handling(MaterialParameter & parameters,
State & state,
PerRayDataUNI* prd,
HitGroupData* sbt_data,
const float3 & tangent_u,
const float3 & tangent_v,
const float3 & text_coord
)
{
unsigned int prd_flags = prd->flags;
// put the BSDF data structs into a union to reduce number of memory writes
union
{
mi::neuraylib::Bsdf_sample_data sample;
mi::neuraylib::Bsdf_evaluate_data<mi::neuraylib::DF_HSM_NONE> evaluate; // required since MDL SDK 2019.2
mi::neuraylib::Bsdf_pdf_data pdf;
mi::neuraylib::Bsdf_auxiliary_data<mi::neuraylib::DF_HSM_NONE> aux_data; // = Bsdf_auxiliary_data;
} data;
// https://raytracing-docs.nvidia.com/mdl/api/html/mi_neuray_example_execution_ptx.html
mi::neuraylib::Resource_data res_data =
{
NULL, // void const *shared_data The shared_data field is currently unused and should always be NULL.
sbt_data->texture_handler // rt_data->texture_handler
};
const char* arg_block = sbt_data->arg_block;
const unsigned int base_MDL_DC_id = sbt_data->mdl_callable_base_index;
// "mdl_material_info.h" clones mi::neuraylib::ITarget_argument_block const *arg_block to "m_arg_block";
// char* get_argument_block_data() returns a CPU pointer of the arg_block;
// get_argument_block_size() returns the size in bytes;
// the block of this size is copied to GPU; arg_block is offset to that data block
optixDirectCall<const int, State*, mi::neuraylib::Resource_data* const, void const *, const char*>(base_MDL_DC_id + MDL_BSDF_INIT, &state, &res_data, /*exception_state=*/ nullptr, arg_block);
// thePrd.wo is same as in MDL: data.sample.k1 = dir_out; // outgoing direction
// thePrd.ior = ior.xy are the current volume's IOR and the surrounding volume's IOR. ( efault: make_float2(1.0f) )
prd->absorption_ior = make_float4(parameters.absorption, parameters.ior);
const float xi0 = rnd(prd->seed);
const float xi1 = rnd(prd->seed);
const float xi2 = rnd(prd->seed);
const float xi3 = rnd(prd->seed);
float3 dir_out = normalize(-optixGetWorldRayDirection());
#if defined(USE_ALBEDO) // NOTE: denoiser uses geometry normal (on start of closesthit)
if (frame == 0) // only on first accumulation frame
{ // aux
if (prd->RayDepth == 0)
{
data.aux_data = {};
data.aux_data.ior1 = make_float3(parameters.ior);
data.aux_data.ior2 = data.aux_data.ior1; // .x = MI_NEURAYLIB_BSDF_USE_MATERIAL_IOR;
data.aux_data.k1 = dir_out; // -WorldRayDirection(); // outgoing direction
// mdl_bsdf_auxiliary(&data.aux_data, &state, &red_data, NULL, arg_block);
optixDirectCall<const int, mi::neuraylib::Bsdf_auxiliary_data<mi::neuraylib::DF_HSM_NONE>*, const State*, mi::neuraylib::Resource_data* const, void const *, const char*>(base_MDL_DC_id + MDL_BSDF_AUXILIARY, &data.aux_data, &state, &res_data, /*exception_state=*/ nullptr, arg_block);
const float3 aux_albedo = data.aux_data.albedo;
// The raygeneration program uses this to write the denoiser's albedo buffer.
prd->albedo = aux_albedo;
prd->flags |= FLAG_ALBEDO_FORCE; // my own flag
} // if (prd->RayDepth == 0)
} // aux if (frame == 0)
#endif// defined(USE_ALBEDO)
const float3 wo = dir_out;
const float3 positive_wo = -wo;
const int is_inside = (prd->flags & FLAG_VOLUME);
const int thin_walled = (prd->flags & FLAG_THINWALLED);
if (is_inside && !thin_walled)
{
data.sample.ior1.x = MI_NEURAYLIB_BSDF_USE_MATERIAL_IOR;
data.sample.ior2 = make_float3(1.0f, 1.0f, 1.0f);
}
else
{
data.sample.ior1 = make_float3(parameters.ior);
data.sample.ior2.x = MI_NEURAYLIB_BSDF_USE_MATERIAL_IOR;
}
data.sample.k1 = dir_out; // outgoing direction
data.sample.xi = make_float4(xi0, xi1, xi2, xi3);
// call MDL sample DC:
optixDirectCall<const int, mi::neuraylib::Bsdf_sample_data*, const State*, mi::neuraylib::Resource_data* const, void const *, const char*>(base_MDL_DC_id + MDL_BSDF_SAMPLE, &data.sample, &state, &res_data, /*exception_state=*/ nullptr, arg_block);
// thePrd.f_over_pdf is same as in MDL: data.sample.bsdf_over_pdf (= bsdf * dot(normal, k2) / pdf )
// thePrd.pdf is same as in MDL: data.sample.pdf (or additionally use "mdl_bsdf_pdf" => data.pdf.pdf )
// thePrd.wi is same as in MDL: data.sample.k2; ///< incoming direction
// thePrd.flags is similar as in MDL: data.sample.event_type
// REMOVED:
//int update_transmission = (int)( thin_walled ? false
// : ((data.sample.event_type & mi::neuraylib::BSDF_EVENT_TRANSMISSION) != 0));
if ((data.sample.event_type & mi::neuraylib:: BSDF_EVENT_SPECULAR) != 0)
{
// BSDF_EVENT_SPECULAR_REFLECTION = BSDF_EVENT_SPECULAR | BSDF_EVENT_REFLECTION,
// BSDF_EVENT_SPECULAR_TRANSMISSION = BSDF_EVENT_SPECULAR | BSDF_EVENT_TRANSMISSION
prd->wi = data.sample.k2; ///< incoming direction
/* // REMOVED
if (dot(prd->wi, state.geom_normal) <= 0.0f) // Do not sample opaque materials below the geometric surface.
{
prd->flags |= FLAG_TERMINATE;
return;
}
*/
prd->f_over_pdf = data.sample.bsdf_over_pdf;
prd->pdf = 1.0f; // data.sample.pdf; // Not 0.0f to make sure the path is not terminated. Otherwise unused for specular events
return;
}
if (data.sample.pdf <= 0.0f)
{
prd->flags |= FLAG_TERMINATE;
return;
}
if ((data.sample.event_type & mi::neuraylib::BSDF_EVENT_GLOSSY) != 0)
{
if ((data.sample.event_type & mi::neuraylib::BSDF_EVENT_GLOSSY_TRANSMISSION) == mi::neuraylib::BSDF_EVENT_GLOSSY_TRANSMISSION)
{
/* // REMOVED: this caused some of the black parts !
if (dot(prd->wi, state.geom_normal) <= 0.0f) // Do not sample opaque materials below the geometric surface.
{
prd->flags |= FLAG_TERMINATE;
return;
}
*/
prd->wi = data.sample.k2; ///< incoming direction
prd->f_over_pdf = data.sample.bsdf_over_pdf;
prd->pdf = data.sample.pdf; // 1.0f // Not 0.0f to make sure the path is not terminated. Otherwise unused for specular events
// ADDED, was missing before!
prd->flags |= FLAG_TRANSMISSION;
return;
}
prd->flags |= FLAG_DIFFUSE;
}
else if ((data.sample.event_type & mi::neuraylib::BSDF_EVENT_DIFFUSE) != 0)
{
if ((data.sample.event_type & mi::neuraylib::BSDF_EVENT_DIFFUSE_TRANSMISSION) != 0)
{
// REMOVED:
// prd->flags |= FLAG_THINWALLED;
// ADDED:
if (!thin_walled) prd->flags |= FLAG_TRANSMISSION;
}
prd->flags |= FLAG_DIFFUSE;
}
// ===========================================================================
prd->f_over_pdf = data.sample.bsdf_over_pdf;
prd->pdf = data.sample.pdf;
prd->wi = data.sample.k2; ///< incoming direction
// REMOVED:
// if (update_transmission) prd->flags |= FLAG_TRANSMISSION;
// USE_NEXT_EVENT_ESTIMATION:
if (data.sample.event_type != mi::neuraylib::BSDF_EVENT_ABSORB)
{
const unsigned int prd_flags = prd->flags;
if ( (prd_flags & FLAG_DIFFUSE) && 0 < sysNumLights )
{
LightSample lightSample; // Sample one of many lights.
const float2 sample = rng2(prd->seed); // Use higher dimension samples for the position. (Irrelevant for the LCG).
const float3 pos = prd->pos;
lightSample.index = clamp(static_cast<int>(floorf(rng(prd->seed) * sysNumLights)), 0, sysNumLights - 1);
const LightType lightType = (sysLightDefinitions[lightSample.index].type & 0x000000F);
optixDirectCall<const int, float3 const&, const float2, LightSample&>(BASE_LIGHT_ID + lightType, pos, sample, lightSample);
if (0.0f < lightSample.pdf) // Useful light sample?
{
// lightSample.direction =wiL is same as in MDL: data.evaluate.k2 = dir; // incoming direction
// Evaluate the BSDF in the light sample direction. Normally cheaper than shooting rays.
// Returns BSDF f in .xyz and the BSDF pdf in .w
float4 bsdf_pdf;
data.evaluate.k2 = lightSample.direction; // incoming direction
// call MDL eval DC:
optixDirectCall<const int, mi::neuraylib::Bsdf_evaluate_data<mi::neuraylib::DF_HSM_NONE>*, State* const, mi::neuraylib::Resource_data* const, void const *, const char*>(base_MDL_DC_id + MDL_BSDF_EVAL, &data.evaluate, &state, &res_data, /*exception_state=*/ nullptr, arg_block);
// f = make_float3(bsdf_pdf) is same as in MDL: data.evaluate.bsdf
// pfd = bsdf_pdf.w is same as in MDL: data.evaluate.pdf
bsdf_pdf = make_float4((data.evaluate.bsdf_diffuse + data.evaluate.bsdf_glossy), data.evaluate.pdf); // since MDL SDK 2019.2
if (0.0f < bsdf_pdf.w && isNotNull(make_float3(bsdf_pdf)))
{
OptixTraversableHandle handle = params.handle;
OptixRayFlags rayflags = ShadowRayFlags;
const float Ldist = lightSample.distance - sysSceneEpsilon;
mTraceShadow(handle,prd->pos,lightSample.direction,Ldist,prd,rayflags); // defines int "visible"
if (visible)
{
if (prd_flags & FLAG_VOLUME) // Supporting nested materials includes having lights inside a volume.
{
// Calculate the transmittance along the light sample's distance in case it's inside a volume.
// The light must be in the same volume or it would have been shadowed!
lightSample.emission *= expf(-lightSample.distance * prd->extinction);
}
const float misWeight = powerHeuristic(lightSample.pdf, bsdf_pdf.w);
prd->radiance += make_float3(bsdf_pdf) * lightSample.emission * (misWeight * dot(lightSample.direction, state.normal) / lightSample.pdf);
ensure_valid_floats(prd);
} // if (prdShadow.visible)
} // if (0.0f < bsdf_pdf.w && isNotNull(make_float3(bsdf_pdf)))
} // if (0.0f < lightSample.pdf) // Useful light sample?
} // if ((thePrd.flags & FLAG_DIFFUSE) && 0 < sysNumLights)
} // if (data.sample.event_type != mi::neuraylib::BSDF_EVENT_ABSORB)
}