diff --git a/src/cmake/testing.cmake b/src/cmake/testing.cmake index 5b5b4327d7..05e01fa58b 100644 --- a/src/cmake/testing.cmake +++ b/src/cmake/testing.cmake @@ -362,6 +362,7 @@ macro (osl_add_all_tests) render-cornell render-displacement render-furnace-diffuse + render-mx-anisotropic-vdf render-mx-furnace-burley-diffuse render-mx-furnace-oren-nayar render-mx-furnace-sheen @@ -371,7 +372,9 @@ macro (osl_add_all_tests) render-mx-generalized-schlick render-mx-generalized-schlick-glass render-mx-layer render-mx-sheen - render-microfacet render-oren-nayar + render-mx-medium-vdf + render-mx-medium-vdf-glass + render-microfacet render-oren-nayar render-spi-thinlayer render-uv render-veachmis render-ward render-raytypes diff --git a/src/libbsdl/include/BSDL/tools.h b/src/libbsdl/include/BSDL/tools.h index bbb049f0f2..3af347a1d7 100644 --- a/src/libbsdl/include/BSDL/tools.h +++ b/src/libbsdl/include/BSDL/tools.h @@ -12,6 +12,12 @@ BSDL_ENTER_NAMESPACE +BSDL_INLINE float +MAX(float a, float b) +{ + return std::max(a, b); +} + BSDL_INLINE float MAX_ABS_XYZ(const Imath::V3f& v) { diff --git a/src/testrender/optixraytracer.cpp b/src/testrender/optixraytracer.cpp index 492430712c..cd58bf5de7 100644 --- a/src/testrender/optixraytracer.cpp +++ b/src/testrender/optixraytracer.cpp @@ -1175,7 +1175,7 @@ OptixRaytracer::processPrintfBuffer(void* buffer_data, size_t buffer_size) if (format[j] == '%') { fmt_string = "%"; bool format_end_found = false; - for (size_t i = 0; !format_end_found; i++) { + for (; !format_end_found; ) { j++; fmt_string += format[j]; switch (format[j]) { diff --git a/src/testrender/shading.cpp b/src/testrender/shading.cpp index 96c140f96a..68f222b557 100644 --- a/src/testrender/shading.cpp +++ b/src/testrender/shading.cpp @@ -4,6 +4,7 @@ #include "shading.h" +#include "OSL/oslconfig.h" #include #include "optics.h" #include "sampling.h" @@ -12,6 +13,7 @@ #include #include #include +#include using namespace OSL; @@ -1513,6 +1515,51 @@ struct ZeltnerBurleySheen final : public BSDF, MxSheenParams { } }; +struct HenyeyGreenstein : public bsdl::spi::VolumeLobe { + using Base = bsdl::spi::VolumeLobe; + + OSL_HOSTDEVICE HenyeyGreenstein(const Data& data, const Vec3& wo, + float path_roughness) + : Base(this, + bsdl::BsdfGlobals(wo, + Vec3(0), // Nf + Vec3(0), // Ngf + false, + path_roughness, + 1.0f, // outer_ior + 0), // hero wavelength off + data) + { + } + + OSL_HOSTDEVICE BSDF::Sample eval(const Vec3& wo, const Vec3& wi) const + { + bsdl::Sample s = Base::eval_impl(Base::frame.local(wo), + Base::frame.local(wi)); + return { wi, s.weight.toRGB(0), s.pdf, s.roughness }; + } + OSL_HOSTDEVICE BSDF::Sample sample(const Vec3& wo, float rx, float ry, + float rz) const + { + bsdl::Sample s = Base::sample_impl(Base::frame.local(wo), + { rx, ry, rz }); + return { Base::frame.world(s.wi), s.weight.toRGB(0), s.pdf, + s.roughness }; + } +}; + + +OSL_HOSTDEVICE BSDF::Sample MediumParams::sample_phase_func(const Vec3& wo, float rx, + float ry, float rz) const { + if (is_empty) { + return { Vec3(1.0f), Color3(1.0f), 0.0f, 0.0f }; + } + + HenyeyGreenstein::Data data { medium_g, medium_g, 0.0f }; + HenyeyGreenstein phase_func(data, wo, 0.0f); + return phase_func.sample(wo, rx, ry, rz); +} + OSL_HOSTDEVICE Color3 evaluate_layer_opacity(const ShaderGlobalsType& sg, float path_roughness, const ClosureColor* closure) @@ -1606,8 +1653,8 @@ evaluate_layer_opacity(const ShaderGlobalsType& sg, float path_roughness, OSL_HOSTDEVICE void process_medium_closure(const ShaderGlobalsType& sg, float path_roughness, - ShadingResult& result, const ClosureColor* closure, - const Color3& w) + ShadingResult& result, MediumStack& medium_stack, + const ClosureColor* closure, const Color3& w) { if (!closure) return; @@ -1649,37 +1696,72 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness, const ClosureComponent* comp = closure->as_comp(); Color3 cw = weight * comp->w; const auto& params = *comp->as(); - result.sigma_t = cw * params.extinction; - result.sigma_s = params.albedo * result.sigma_t; - result.medium_g = params.anisotropy; - closure = nullptr; + result.medium_data.sigma_t = cw * params.extinction; + result.medium_data.sigma_s = params.albedo + * result.medium_data.sigma_t; + result.medium_data.medium_g = params.anisotropy; + result.medium_data.priority = 0; // always intersect + + result.medium_data.is_empty = result.medium_data.is_vaccum(); + + closure = nullptr; break; } case MX_MEDIUM_VDF_ID: { const ClosureComponent* comp = closure->as_comp(); Color3 cw = weight * comp->w; const auto& params = *comp->as(); - result.sigma_t = { -OIIO::fast_log(params.transmission_color.x), - -OIIO::fast_log(params.transmission_color.y), - -OIIO::fast_log(params.transmission_color.z) }; - // NOTE: closure weight scales the extinction parameter - result.sigma_t *= cw / params.transmission_depth; - result.sigma_s = params.albedo * result.sigma_t; - result.medium_g = params.anisotropy; - // TODO: properly track a medium stack here ... - result.refraction_ior = sg.backfacing ? 1.0f / params.ior - : params.ior; - result.priority = params.priority; - closure = nullptr; + + // when both albedo and transmission_color are black, this is + // a vacuum medium used only to carry the IOR for dielectric + // surfaces. + bool is_vacuum = is_black(params.albedo) + && is_black(params.transmission_color); + + if (is_vacuum) { + result.medium_data.sigma_t = Color3(0.0f); + result.medium_data.sigma_s = Color3(0.0f); + result.medium_data.is_empty = true; + } else { + const float epsilon = 1e-10f; + result.medium_data.sigma_t = Color3( + -OIIO::fast_log(fmaxf(params.transmission_color.x, epsilon)), + -OIIO::fast_log(fmaxf(params.transmission_color.y, epsilon)), + -OIIO::fast_log(fmaxf(params.transmission_color.z, epsilon)) + ); + + result.medium_data.sigma_t *= cw / params.transmission_depth; + result.medium_data.sigma_s = params.albedo + * result.medium_data.sigma_t; + result.medium_data.is_empty = result.medium_data.is_vaccum(); + } + + result.medium_data.medium_g = params.anisotropy; + + result.medium_data.refraction_ior = sg.backfacing + ? 1.0f / params.ior + : params.ior; + result.medium_data.priority = params.priority; + + closure = nullptr; break; } case MxDielectric::closureid(): { const ClosureComponent* comp = closure->as_comp(); const MxDielectric::Data& params = *comp->as(); if (!is_black(weight * comp->w * params.refr_tint)) { - // TODO: properly track a medium stack here ... - result.refraction_ior = sg.backfacing ? 1.0f / params.IOR - : params.IOR; + float new_ior = sg.backfacing ? 1.0f / params.IOR : params.IOR; + + result.medium_data.refraction_ior = new_ior; + + const MediumParams* current_params + = medium_stack.get_current_params(); + if (current_params + && result.medium_data.priority + <= current_params->priority) { + result.medium_data.refraction_ior + = current_params->refraction_ior; + } } closure = nullptr; break; @@ -1688,13 +1770,23 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness, const ClosureComponent* comp = closure->as_comp(); const auto& params = *comp->as(); if (!is_black(weight * comp->w * params.transmission_tint)) { - // TODO: properly track a medium stack here ... float avg_F0 = clamp((params.f0.x + params.f0.y + params.f0.z) / 3.0f, 0.0f, 0.99f); float sqrt_F0 = sqrtf(avg_F0); float ior = (1 + sqrt_F0) / (1 - sqrt_F0); - result.refraction_ior = sg.backfacing ? 1.0f / ior : ior; + float new_ior = sg.backfacing ? 1.0f / ior : ior; + + result.medium_data.refraction_ior = new_ior; + + const MediumParams* current_params + = medium_stack.get_current_params(); + if (current_params + && result.medium_data.priority + <= current_params->priority) { + result.medium_data.refraction_ior + = current_params->refraction_ior; + } } closure = nullptr; break; @@ -1711,8 +1803,9 @@ process_medium_closure(const ShaderGlobalsType& sg, float path_roughness, // recursively walk through the closure tree, creating bsdfs as we go OSL_HOSTDEVICE void process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness, - ShadingResult& result, const ClosureColor* closure, - const Color3& w, bool light_only) + ShadingResult& result, MediumStack& medium_stack, + const ClosureColor* closure, const Color3& w, + bool light_only) { static const ustringhash uh_ggx("ggx"); static const ustringhash uh_beckmann("beckmann"); @@ -1845,9 +1938,16 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness, case MxDielectric::closureid(): { const MxDielectric::Data& params = *comp->as(); - ok = result.bsdf.add_bsdf(cw, params, -sg.I, - sg.backfacing, - path_roughness); + + if (medium_stack.false_intersection_with( + result.medium_data)) { + ok = result.bsdf.add_bsdf(cw); + } else { + ok = result.bsdf.add_bsdf(cw, params, + -sg.I, + sg.backfacing, + path_roughness); + } break; } case MxConductor::closureid(): { @@ -1860,15 +1960,21 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness, case MX_GENERALIZED_SCHLICK_ID: { const MxGeneralizedSchlickParams& params = *comp->as(); - if (is_black(params.transmission_tint)) - ok = result.bsdf.add_bsdf>(cw, - params, - 1.0f); - else - ok = result.bsdf.add_bsdf>( - cw, params, result.refraction_ior); + + if (medium_stack.false_intersection_with( + result.medium_data)) { + ok = result.bsdf.add_bsdf(cw); + } else { + if (is_black(params.transmission_tint)) { + ok = result.bsdf.add_bsdf>( + cw, params, 1.0f); + } else { + ok = result.bsdf.add_bsdf>( + cw, params, result.medium_data.refraction_ior); + } + } break; }; case MX_TRANSLUCENT_ID: { @@ -1957,11 +2063,14 @@ process_bsdf_closure(const ShaderGlobalsType& sg, float path_roughness, OSL_HOSTDEVICE void process_closure(const ShaderGlobalsType& sg, float path_roughness, - ShadingResult& result, const ClosureColor* Ci, bool light_only) + ShadingResult& result, MediumStack& medium_stack, + const ClosureColor* Ci, bool light_only) { if (!light_only) - process_medium_closure(sg, path_roughness, result, Ci, Color3(1)); - process_bsdf_closure(sg, path_roughness, result, Ci, Color3(1), light_only); + process_medium_closure(sg, path_roughness, result, medium_stack, Ci, + Color3(1)); + process_bsdf_closure(sg, path_roughness, result, medium_stack, Ci, + Color3(1), light_only); } OSL_HOSTDEVICE Vec3 @@ -2022,5 +2131,4 @@ BSDF::sample_vrtl(const Vec3& wo, float rx, float ry, float rz) const return dispatch([&](auto bsdf) { return bsdf.sample(wo, rx, ry, rz); }); } - OSL_NAMESPACE_END diff --git a/src/testrender/shading.h b/src/testrender/shading.h index 45c37103f5..c3b6dec370 100644 --- a/src/testrender/shading.h +++ b/src/testrender/shading.h @@ -13,11 +13,13 @@ #include "bsdl_config.h" #include +#include +#include "bvh.h" #include "optics.h" +#include "raytracer.h" #include "sampling.h" - OSL_NAMESPACE_BEGIN @@ -261,6 +263,7 @@ struct EnergyCompensatedOrenNayar; struct ZeltnerBurleySheen; struct CharlieSheen; struct SpiThinLayer; +struct HenyeyGreenstein; // StaticVirtual generates a switch/case dispatch method for us given // a list of possible subtypes. We just need to forward declare them. @@ -270,9 +273,9 @@ using AbstractBSDF = bsdl::StaticVirtual< MicrofacetBeckmannBoth, MicrofacetGGXRefl, MicrofacetGGXRefr, MicrofacetGGXBoth, MxConductor, MxDielectric, MxBurleyDiffuse, EnergyCompensatedOrenNayar, ZeltnerBurleySheen, CharlieSheen, - MxGeneralizedSchlickOpaque, MxGeneralizedSchlick, SpiThinLayer>; + MxGeneralizedSchlickOpaque, MxGeneralizedSchlick, SpiThinLayer, HenyeyGreenstein>; -// Then we just need to inherit from AbstractBSDF +// Then we just need to inherit from AbstractBSDF or AbstractMedium /// Individual BSDF (diffuse, phong, refraction, etc ...) /// Actual implementations of this class are private @@ -454,22 +457,329 @@ struct CompositeBSDF { int num_bsdfs, num_bytes; }; -struct ShadingResult { - Color3 Le = Color3(0.0f); - CompositeBSDF bsdf = {}; - // medium data - Color3 sigma_s = Color3(0.0f); - Color3 sigma_t = Color3(0.0f); - float medium_g = 0.0f; // volumetric anisotropy +struct MediumParams { + Color3 sigma_t = Color3(0.0f); // extinction coefficient + Color3 sigma_s = Color3(0.0f); // scattering + float medium_g = 0.0f; // volumetric anisotropy float refraction_ior = 1.0f; int priority = 0; + bool is_empty = true; + + OSL_HOSTDEVICE bool is_vaccum() const + { + return sigma_t.x <= 0.0f && sigma_t.y <= 0.0f && sigma_t.z <= 0.0f; + } + + OSL_HOSTDEVICE bool is_special_priority() const { return priority == 0; } + + OSL_HOSTDEVICE BSDF::Sample sample_phase_func(const Vec3& wo, float rx, + float ry, float rz) const; +}; + +struct MediumStack { + OSL_HOSTDEVICE MediumStack() : depth(0), pool_size(0) {} + + OSL_HOSTDEVICE const MediumParams* get_current_params() const + { + if (depth > 0) { + return mediums[0]; + } + return nullptr; + } + + OSL_HOSTDEVICE bool in_medium() const { return depth > 0; } + + OSL_HOSTDEVICE int size() const { return depth; } + + OSL_HOSTDEVICE bool integrate(Ray& r, Sampler& sampler, Intersection& hit, + Color3& path_weight, Color3& path_radiance, + float& bsdf_pdf) + { + if (depth <= 0) { + return false; + } + + if (need_to_compute_current_params) { + // only compute data for overlapping mediums + // if a new medium was added to the stack + MediumParams new_params; + num_overlapping = 0; + + for (int i = 0; i < depth; i++) { + const MediumParams& params_i = *mediums[i]; + + if (i == 0) { + // current params has to have the same priority as mediums[0] + new_params.priority = params_i.priority; + } + if (params_i.priority != new_params.priority) { + continue; + } + overlapping_medium_indices[num_overlapping] = i; + new_params.sigma_t += params_i.sigma_t; + new_params.sigma_s += params_i.sigma_s; + + float avg_sigma_s_i = (params_i.sigma_s.x + + params_i.sigma_s.y + + params_i.sigma_s.z) + / 3.0f; + cdf[num_overlapping] = (num_overlapping > 0 + ? cdf[num_overlapping - 1] + : 0.0f) + + avg_sigma_s_i; + new_params.is_empty &= params_i.is_empty; + num_overlapping++; + } + + if (num_overlapping > 1 && !new_params.is_empty) { + float total_cdf = cdf[num_overlapping - 1]; + if (total_cdf > 0.0f) { + for (int i = 0; i < num_overlapping; i++) { + cdf[i] /= total_cdf; + } + } + } + + current_params = new_params; + need_to_compute_current_params = false; + } + + if (current_params.is_empty) { + return false; + } + + float total_sigma_s = current_params.sigma_s.x + + current_params.sigma_s.y + + current_params.sigma_s.z; + + if (total_sigma_s <= 0.0f) { + // pure absorption: apply transmittance to the surface and continue + Color3 tr = transmittance(current_params.sigma_t, hit.t); + path_weight *= tr; + return false; + } + + Vec3 rand_vol = sampler.get(); + Vec3 rand_channel = sampler.get(); + + // Build per-channel selection weights from sigma_s + float channel_weights[3] = { current_params.sigma_s.x, + current_params.sigma_s.y, + current_params.sigma_s.z }; + + // total_sigma_s is guaranteed > 0 from the early-out above + float inv_total = 1.0f / total_sigma_s; + channel_weights[0] *= inv_total; + channel_weights[1] *= inv_total; + channel_weights[2] *= inv_total; + + // pick a channel using the cdf of channel_weights + int channel; + if (rand_channel.x < channel_weights[0]) { + channel = 0; + } else if (rand_channel.x < channel_weights[0] + channel_weights[1]) { + channel = 1; + } else { + channel = 2; + } + + // sample distance along the ray using the selected channel's sigma_t + float sigma_t_channel = current_params.sigma_t[channel]; + if (sigma_t_channel <= 0.0f) { + // channel has scattering but no extinction + Color3 tr = transmittance(current_params.sigma_t, hit.t); + path_weight *= tr; + return false; + } + + float t_volume = -logf(1.0f - rand_vol.x) / sigma_t_channel; + + bool scatter = t_volume < hit.t; + float t = scatter ? t_volume : hit.t; + + Color3 tr = transmittance(current_params.sigma_t, t); + + Color3 density = scatter ? (current_params.sigma_t * tr) : tr; + float pdf = density.x * channel_weights[0] + + density.y * channel_weights[1] + + density.z * channel_weights[2]; + + if (pdf <= 0.0f) { + return false; + } + + if (scatter) { + path_weight *= (tr * current_params.sigma_s) / pdf; + } else { + path_weight *= (tr / pdf); + return false; + } + + // scattering pick a new direction + r.origin = r.point(t_volume); + + Vec3 rand_phase = sampler.get(); + + int index = 0; + if (num_overlapping > 1) { + Vec3 rand_index = sampler.get(); + + for (index = 0; index < num_overlapping; ++index) { + if (rand_index.x < cdf[index]) { + break; + } + } + } + + index = fmin(index, num_overlapping - 1); + + int medium_index = overlapping_medium_indices[index]; + + BSDF::Sample phase_sample + = mediums[medium_index]->sample_phase_func(-r.direction, + rand_phase.x, + rand_phase.y, + rand_phase.z); + + if (phase_sample.pdf > 0.0f) { + path_weight *= phase_sample.weight; + r.direction = phase_sample.wi; + bsdf_pdf = phase_sample.pdf; + return true; + } + + return false; + } + + OSL_HOSTDEVICE bool add_medium(MediumParams new_params) + { + if (depth >= MaxEntries || pool_size >= MaxPool) + return false; + + MediumParams* p = &pool[pool_size++]; + *p = new_params; + + // find insertion point (sorted by descending priority) + int insert_pos = depth; + for (int i = 0; i < depth; ++i) { + if (new_params.priority > mediums[i]->priority) { + insert_pos = i; + break; + } + } + + // shift pointers to make room + for (int j = depth; j > insert_pos; --j) { + mediums[j] = mediums[j - 1]; + } + + mediums[insert_pos] = p; + entry_order[depth] = p; + + need_to_compute_current_params = true; + depth++; + + return true; + } + + OSL_HOSTDEVICE void pop_medium() + { + if (depth <= 0) + return; + + depth--; + + // find the most recently added medium + MediumParams* p = entry_order[depth]; + int sorted_index = -1; + for (int i = 0; i <= depth; ++i) { + if (mediums[i] == p) { + sorted_index = i; + break; + } + } + + if (sorted_index < 0) + return; // shouldn't happen + + // shift pointers down to fill the gap + for (int j = sorted_index; j < depth; ++j) { + mediums[j] = mediums[j + 1]; + } + + // reclaim pool if this was the last allocated entry + if (p == &pool[pool_size - 1]) + pool_size--; + + need_to_compute_current_params = true; + } + + + OSL_HOSTDEVICE bool + false_intersection_with(const MediumParams& entrant_params) + { + const MediumParams* current = get_current_params(); + if (!current) + return false; + + // special priority will always record an intersection + if (entrant_params.is_special_priority() + && current->is_special_priority()) + return false; + + // same non-special priority: never record an intersection + if (entrant_params.priority == current->priority) + return true; + + return entrant_params.priority > current->priority; + } + + + OSL_HOSTDEVICE Color3 transmittance(const Color3& sigma_t, + float distance) const + { // Beer-Lambert law + return Color3(expf(-sigma_t.x * distance), expf(-sigma_t.y * distance), + expf(-sigma_t.z * distance)); + } + +private: + /// Never try to copy this struct because it would invalidate the medium pointers + OSL_HOSTDEVICE MediumStack(const MediumStack& c); + OSL_HOSTDEVICE MediumStack& operator=(const MediumStack& c); + + enum { MaxEntries = 8 }; + enum { MaxPool = 32 }; + + MediumParams pool[MaxPool]; // stable storage + MediumParams* mediums[MaxEntries]; // sorted by descending priority + MediumParams* entry_order[MaxEntries]; // LIFO order (pointer identity) + + float cdf[MaxEntries]; + int overlapping_medium_indices[MaxEntries]; + + MediumParams current_params; + + int depth; + int pool_size; + int num_overlapping; + + bool need_to_compute_current_params; + }; +struct ShadingResult { + Color3 Le = Color3(0.0f); + CompositeBSDF bsdf = {}; + MediumParams medium_data = {}; +}; + + void register_closures(ShadingSystem* shadingsys); OSL_HOSTDEVICE void process_closure(const OSL::ShaderGlobals& sg, float path_roughness, - ShadingResult& result, const ClosureColor* Ci, bool light_only); + ShadingResult& result, MediumStack& medium_stack, + const ClosureColor* Ci, bool light_only); OSL_HOSTDEVICE Vec3 process_background_closure(const ClosureColor* Ci); diff --git a/src/testrender/simpleraytracer.cpp b/src/testrender/simpleraytracer.cpp index 600d46bdb8..4e5863b781 100644 --- a/src/testrender/simpleraytracer.cpp +++ b/src/testrender/simpleraytracer.cpp @@ -969,6 +969,8 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler, Color3 path_radiance(0, 0, 0); int prev_id = -1; float bsdf_pdf = inf; // camera ray has only one possible direction + MediumStack medium_stack; + for (int b = 0; b <= max_bounces; b++) { ShaderGlobalsType sg; @@ -993,6 +995,10 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler, } break; } + + if (medium_stack.integrate(r, sampler, hit, path_weight, path_radiance, bsdf_pdf)) { + continue; + } // construct a shader globals for the hit point globals_from_hit(sg, r, hit.t, hit.id, hit.u, hit.v); @@ -1032,8 +1038,8 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler, #endif ShadingResult result; bool last_bounce = b == max_bounces; - process_closure(sg, r.roughness, result, (const ClosureColor*)sg.Ci, - last_bounce); + process_closure(sg, r.roughness, result, medium_stack, + (const ClosureColor*)sg.Ci, last_bounce); #ifndef __CUDACC__ const size_t lightprims_size = m_lightprims.size(); @@ -1144,7 +1150,8 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler, #endif ShadingResult light_result; process_closure(light_sg, r.roughness, light_result, - (const ClosureColor*)light_sg.Ci, true); + medium_stack, (const ClosureColor*)light_sg.Ci, + true); // accumulate contribution path_radiance += contrib * light_result.Le; } @@ -1162,8 +1169,18 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler, // Just simply use roughness as spread slope r.spread = std::max(r.spread, p.roughness); r.roughness = p.roughness; - if (!(path_weight.x > 0) && !(path_weight.y > 0) - && !(path_weight.z > 0)) + + bool transmitted = sg.Ng.dot(p.wi) < 0; // has the sammpled sampled dir crossed surface? + + if (transmitted) { + if (!sg.backfacing) { // if entering and crossing surface + medium_stack.add_medium(result.medium_data); + } else { + medium_stack.pop_medium(); + } + } + + if (!(path_weight.x > 0) && !(path_weight.y > 0) && !(path_weight.z > 0)) break; // filter out all 0's or NaNs prev_id = hit.id; r.origin = sg.P; @@ -1172,6 +1189,7 @@ SimpleRaytracer::subpixel_radiance(float x, float y, Sampler& sampler, } + OSL_HOSTDEVICE Color3 SimpleRaytracer::antialias_pixel(int x, int y, ShadingContext* ctx) { diff --git a/src/testshade/optixgridrender.cpp b/src/testshade/optixgridrender.cpp index 86a80cbe05..d1532a1016 100644 --- a/src/testshade/optixgridrender.cpp +++ b/src/testshade/optixgridrender.cpp @@ -1013,7 +1013,7 @@ OptixGridRenderer::processPrintfBuffer(void* buffer_data, size_t buffer_size) if (format[j] == '%') { fmt_string = "%"; bool format_end_found = false; - for (size_t i = 0; !format_end_found; i++) { + for (; !format_end_found; ) { j++; fmt_string += format[j]; switch (format[j]) { diff --git a/testsuite/render-mx-anisotropic-vdf/OPTIX b/testsuite/render-mx-anisotropic-vdf/OPTIX new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testsuite/render-mx-anisotropic-vdf/anisotropic.osl b/testsuite/render-mx-anisotropic-vdf/anisotropic.osl new file mode 100644 index 0000000000..170f2486d8 --- /dev/null +++ b/testsuite/render-mx-anisotropic-vdf/anisotropic.osl @@ -0,0 +1,22 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +volume +anisotropic + [[ string description = "Volume medium material" ]] +( + color albedo = 1.0 + [[ string description = "Scattering color", + float UImin = 0, float UImax = 1 ]], + color extinction = 1.0 + [[ string description = "Transmission color (volume absorption tint)", + float UImin = 0, float UImax = 1 ]], + float anisotropy = 0.0 + [[ string description = "Directionality of scattering (-1=back, 0=isotropic, 1=forward)", + float UImin = -1, float UImax = 1 ]] + ) +{ + Ci = transparent() + anisotropic_vdf(albedo, extinction, anisotropy); +} \ No newline at end of file diff --git a/testsuite/render-mx-anisotropic-vdf/envmap.osl b/testsuite/render-mx-anisotropic-vdf/envmap.osl new file mode 100644 index 0000000000..14f09243b2 --- /dev/null +++ b/testsuite/render-mx-anisotropic-vdf/envmap.osl @@ -0,0 +1,19 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +shader envmap( + color sky = color(0.7,0.8,0.9), + color horizon = color(0.3,0.6,0.9), + color sun = color(0.9,0.8,0.7), + vector sun_dir = vector(0,1,1), + float sun_angle = 5.0) +{ + vector dir = normalize(I); + vector sd = normalize(sun_dir); + color c = mix(horizon, sky, dir.y * dir.y); + float cos_ang = cos(radians(sun_angle / 2)); + if (dot(dir, normalize(sun_dir)) > cos_ang) + c += sun / (1 - cos_ang); // normalize + Ci = c * background(); +} diff --git a/testsuite/render-mx-anisotropic-vdf/matte.osl b/testsuite/render-mx-anisotropic-vdf/matte.osl new file mode 100644 index 0000000000..a8c6f187e4 --- /dev/null +++ b/testsuite/render-mx-anisotropic-vdf/matte.osl @@ -0,0 +1,19 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +surface +matte + [[ string description = "Lambertian diffuse material" ]] +( + float Kd = 1 + [[ string description = "Diffuse scaling", + float UImin = 0, float UIsoftmax = 1 ]], + color Cs = 1 + [[ string description = "Base color", + float UImin = 0, float UImax = 1 ]] + ) +{ + Ci = Kd * Cs * diffuse (N); +} diff --git a/testsuite/render-mx-anisotropic-vdf/ref/out-linux-alt.exr b/testsuite/render-mx-anisotropic-vdf/ref/out-linux-alt.exr new file mode 100644 index 0000000000..212d44cea7 Binary files /dev/null and b/testsuite/render-mx-anisotropic-vdf/ref/out-linux-alt.exr differ diff --git a/testsuite/render-mx-anisotropic-vdf/ref/out-macos-alt.exr b/testsuite/render-mx-anisotropic-vdf/ref/out-macos-alt.exr new file mode 100644 index 0000000000..00c5f841ed Binary files /dev/null and b/testsuite/render-mx-anisotropic-vdf/ref/out-macos-alt.exr differ diff --git a/testsuite/render-mx-anisotropic-vdf/ref/out-optix-alt.exr b/testsuite/render-mx-anisotropic-vdf/ref/out-optix-alt.exr new file mode 100644 index 0000000000..7268d650fe Binary files /dev/null and b/testsuite/render-mx-anisotropic-vdf/ref/out-optix-alt.exr differ diff --git a/testsuite/render-mx-anisotropic-vdf/ref/out.exr b/testsuite/render-mx-anisotropic-vdf/ref/out.exr new file mode 100644 index 0000000000..212d44cea7 Binary files /dev/null and b/testsuite/render-mx-anisotropic-vdf/ref/out.exr differ diff --git a/testsuite/render-mx-anisotropic-vdf/run.py b/testsuite/render-mx-anisotropic-vdf/run.py new file mode 100755 index 0000000000..00fd262d22 --- /dev/null +++ b/testsuite/render-mx-anisotropic-vdf/run.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +failthresh = 0.01 +failpercent = 1 +outputs = [ "out.exr" ] +command = testrender("-v -r 196 196 -aa 64 scene.xml out.exr") diff --git a/testsuite/render-mx-anisotropic-vdf/scene.xml b/testsuite/render-mx-anisotropic-vdf/scene.xml new file mode 100644 index 0000000000..49fd4c7e67 --- /dev/null +++ b/testsuite/render-mx-anisotropic-vdf/scene.xml @@ -0,0 +1,64 @@ + + + + + + vector sun_dir 0.0 0.5 1.0; + shader envmap layer1; + + + + + + + color Cs 0.25 0.25 0.25; + shader matte layer1; + + + + + + param color albedo 0.9 0.1 0.1; + param color extinction 0.1 1.0 1.0; + param float anisotropy 0.0; + shader anisotropic layer1; + + + + + + param color albedo 0.1 0.9 0.1; + param color extinction 1.0 0.5 1.0; + param float anisotropy 0.0; + shader anisotropic layer1; + + + + + + param color albedo 0.1 0.1 0.9; + param color extinction 1.0 1.0 1.0; + param float anisotropy 0.0; + shader anisotropic layer1; + + + + + + param color albedo 0.5 0.5 0.5; + param color extinction 0.5 0.5 0.5; + param float anisotropy -0.7; + shader anisotropic layer1; + + + + + + param color albedo 0.5 0.5 0.5; + param color extinction 0.5 0.5 0.5; + param float anisotropy 0.7; + shader anisotropic layer1; + + + + diff --git a/testsuite/render-mx-dielectric-glass/ref/out-optix-alt.exr b/testsuite/render-mx-dielectric-glass/ref/out-optix-alt.exr index c918a8be17..4628e6a000 100644 Binary files a/testsuite/render-mx-dielectric-glass/ref/out-optix-alt.exr and b/testsuite/render-mx-dielectric-glass/ref/out-optix-alt.exr differ diff --git a/testsuite/render-mx-dielectric-glass/ref/out.exr b/testsuite/render-mx-dielectric-glass/ref/out.exr index df2a39fff8..4986dd85bc 100644 Binary files a/testsuite/render-mx-dielectric-glass/ref/out.exr and b/testsuite/render-mx-dielectric-glass/ref/out.exr differ diff --git a/testsuite/render-mx-generalized-schlick-glass/ref/out-linux-alt.exr b/testsuite/render-mx-generalized-schlick-glass/ref/out-linux-alt.exr index 1cf2687f72..7b2ebe1498 100644 Binary files a/testsuite/render-mx-generalized-schlick-glass/ref/out-linux-alt.exr and b/testsuite/render-mx-generalized-schlick-glass/ref/out-linux-alt.exr differ diff --git a/testsuite/render-mx-generalized-schlick-glass/ref/out-optix-alt.exr b/testsuite/render-mx-generalized-schlick-glass/ref/out-optix-alt.exr index 0cdbd70651..9166e94871 100644 Binary files a/testsuite/render-mx-generalized-schlick-glass/ref/out-optix-alt.exr and b/testsuite/render-mx-generalized-schlick-glass/ref/out-optix-alt.exr differ diff --git a/testsuite/render-mx-generalized-schlick/ref/out-optix-alt.exr b/testsuite/render-mx-generalized-schlick/ref/out-optix-alt.exr index bca59dbd6a..7864ea106e 100644 Binary files a/testsuite/render-mx-generalized-schlick/ref/out-optix-alt.exr and b/testsuite/render-mx-generalized-schlick/ref/out-optix-alt.exr differ diff --git a/testsuite/render-mx-generalized-schlick/ref/out.exr b/testsuite/render-mx-generalized-schlick/ref/out.exr index 46f50adc98..80f759ec5f 100644 Binary files a/testsuite/render-mx-generalized-schlick/ref/out.exr and b/testsuite/render-mx-generalized-schlick/ref/out.exr differ diff --git a/testsuite/render-mx-medium-vdf-glass/emitter.osl b/testsuite/render-mx-medium-vdf-glass/emitter.osl new file mode 100644 index 0000000000..b026b63e0b --- /dev/null +++ b/testsuite/render-mx-medium-vdf-glass/emitter.osl @@ -0,0 +1,23 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +surface +emitter + [[ string description = "Lambertian emitter material" ]] +( + float power = 1 + [[ string description = "Total power of the light", + float UImin = 0 ]], + color Cs = 1 + [[ string description = "Base color", + float UImin = 0, float UImax = 1 ]] + ) +{ + // Because emission() expects a weight in radiance, we must convert by dividing + // the power (in Watts) by the surface area and the factor of PI implied by + // uniform emission over the hemisphere. N.B.: The total power is BEFORE Cs + // filters the color! + Ci = (power / (M_PI * surfacearea())) * Cs * emission(); +} diff --git a/testsuite/render-mx-medium-vdf-glass/glossy.osl b/testsuite/render-mx-medium-vdf-glass/glossy.osl new file mode 100644 index 0000000000..8b1f9a1b52 --- /dev/null +++ b/testsuite/render-mx-medium-vdf-glass/glossy.osl @@ -0,0 +1,35 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +surface +glossy + [[ string description = "Glossy glass material" ]] +( + color Cr = 1.0 + [[ string description = "Reflectance tint", + float UImin = 0, float UImax = 1 ]], + color Ct = 1.0 + [[ string description = "Transmission tint", + float UImin = 0, float UImax = 1 ]], + float ior = 1.5 + [[ string description = "Index of refraction", + float UImin = 1.0, float UImax = 3.0 ]], + float roughness = 0.5 + [[ string description = "Roughness of the surface", + float UImin = 0, float UImax = 1 ]], + float anisotropy = 0.0 + [[ string description = "Anisotropy of the surface", + float UImin = 0, float UImax = 1 ]], + int priority = 0 + [[ string description = "Priority for overlapping mediums. Zero is a special 'off' priority", + float UImin = 0, float UImax = 8 ]], // Same as MaxEntries in MediumStack + ) +{ + float alpha = roughness * roughness; + float alpha_x = alpha * (1.0 - anisotropy); + float alpha_y = alpha; + vector U = normalize(cross(N, dPdv)); + Ci = dielectric_bsdf(N, U, Cr, Ct, alpha_x, alpha_y, ior, "ggx") + + medium_vdf(color(0), 1.0, color(0), 0.0, ior, priority); +} \ No newline at end of file diff --git a/testsuite/render-mx-medium-vdf-glass/matte.osl b/testsuite/render-mx-medium-vdf-glass/matte.osl new file mode 100644 index 0000000000..a8c6f187e4 --- /dev/null +++ b/testsuite/render-mx-medium-vdf-glass/matte.osl @@ -0,0 +1,19 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +surface +matte + [[ string description = "Lambertian diffuse material" ]] +( + float Kd = 1 + [[ string description = "Diffuse scaling", + float UImin = 0, float UIsoftmax = 1 ]], + color Cs = 1 + [[ string description = "Base color", + float UImin = 0, float UImax = 1 ]] + ) +{ + Ci = Kd * Cs * diffuse (N); +} diff --git a/testsuite/render-mx-medium-vdf-glass/ref/out-linux-alt.exr b/testsuite/render-mx-medium-vdf-glass/ref/out-linux-alt.exr new file mode 100755 index 0000000000..0d0a4fe12e Binary files /dev/null and b/testsuite/render-mx-medium-vdf-glass/ref/out-linux-alt.exr differ diff --git a/testsuite/render-mx-medium-vdf-glass/ref/out-macos-alt.exr b/testsuite/render-mx-medium-vdf-glass/ref/out-macos-alt.exr new file mode 100644 index 0000000000..27aa0c657b Binary files /dev/null and b/testsuite/render-mx-medium-vdf-glass/ref/out-macos-alt.exr differ diff --git a/testsuite/render-mx-medium-vdf-glass/ref/out.exr b/testsuite/render-mx-medium-vdf-glass/ref/out.exr new file mode 100755 index 0000000000..0d0a4fe12e Binary files /dev/null and b/testsuite/render-mx-medium-vdf-glass/ref/out.exr differ diff --git a/testsuite/render-mx-medium-vdf-glass/run.py b/testsuite/render-mx-medium-vdf-glass/run.py new file mode 100755 index 0000000000..a69ad2ca3b --- /dev/null +++ b/testsuite/render-mx-medium-vdf-glass/run.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +failthresh = 0.01 +failpercent = 1 +outputs = [ "out.exr" ] +command = testrender("-r 196 196 -aa 32 scene.xml out.exr") diff --git a/testsuite/render-mx-medium-vdf-glass/scene.xml b/testsuite/render-mx-medium-vdf-glass/scene.xml new file mode 100644 index 0000000000..4eeed78189 --- /dev/null +++ b/testsuite/render-mx-medium-vdf-glass/scene.xml @@ -0,0 +1,91 @@ + + + + color Cs 0.75 0.25 0.25; shader matte layer1; + + + color Cs 0.25 0.25 0.75; shader matte layer1; + + + color Cs 0.25 0.25 0.25; shader matte layer1; + + + + + float power 26000; shader emitter layer1 + + + + + color Cr 1.0 1.0 0.0; + float roughness 0.1; + float anisotropy 0.0; + float ior 1.1; + int priority 0; + shader glossy layer1; + + + + + color Cr 1.0 1.0 0.0; + float roughness 0.1; + float anisotropy 0.0; + float ior 1.1; + int priority 0; + shader glossy layer1; + + + + + + color Cr 0.0 1.0 1.0; + float roughness 0.3; + float anisotropy 0.0; + float ior 1.4; + int priority 1; + shader glossy layer1; + + + + + color Cr 0.0 1.0 1.0; + float roughness 0.3; + float anisotropy 0.0; + float ior 1.4; + int priority 1; + shader glossy layer1; + + + + + + color Cr 0.0 0.0 1.0; + float roughness 0.1; + float anisotropy 0.0; + float ior 1.2; + int priority 2; + shader glossy layer1; + + + + + color Cr 0.0 1.0 0.0; + float roughness 0.2; + float anisotropy 0.0; + float ior 1.2; + int priority 1; + shader glossy layer1; + + + + + color Cr 1.0 0.0 0.0; + float roughness 0.3; + float anisotropy 0.0; + float ior 1.2; + int priority 0; + shader glossy layer1; + + + + \ No newline at end of file diff --git a/testsuite/render-mx-medium-vdf/OPTIX b/testsuite/render-mx-medium-vdf/OPTIX new file mode 100644 index 0000000000..e69de29bb2 diff --git a/testsuite/render-mx-medium-vdf/envmap.osl b/testsuite/render-mx-medium-vdf/envmap.osl new file mode 100644 index 0000000000..14f09243b2 --- /dev/null +++ b/testsuite/render-mx-medium-vdf/envmap.osl @@ -0,0 +1,19 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +shader envmap( + color sky = color(0.7,0.8,0.9), + color horizon = color(0.3,0.6,0.9), + color sun = color(0.9,0.8,0.7), + vector sun_dir = vector(0,1,1), + float sun_angle = 5.0) +{ + vector dir = normalize(I); + vector sd = normalize(sun_dir); + color c = mix(horizon, sky, dir.y * dir.y); + float cos_ang = cos(radians(sun_angle / 2)); + if (dot(dir, normalize(sun_dir)) > cos_ang) + c += sun / (1 - cos_ang); // normalize + Ci = c * background(); +} diff --git a/testsuite/render-mx-medium-vdf/matte.osl b/testsuite/render-mx-medium-vdf/matte.osl new file mode 100644 index 0000000000..a8c6f187e4 --- /dev/null +++ b/testsuite/render-mx-medium-vdf/matte.osl @@ -0,0 +1,19 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +surface +matte + [[ string description = "Lambertian diffuse material" ]] +( + float Kd = 1 + [[ string description = "Diffuse scaling", + float UImin = 0, float UIsoftmax = 1 ]], + color Cs = 1 + [[ string description = "Base color", + float UImin = 0, float UImax = 1 ]] + ) +{ + Ci = Kd * Cs * diffuse (N); +} diff --git a/testsuite/render-mx-medium-vdf/medium.osl b/testsuite/render-mx-medium-vdf/medium.osl new file mode 100644 index 0000000000..7b5a125780 --- /dev/null +++ b/testsuite/render-mx-medium-vdf/medium.osl @@ -0,0 +1,31 @@ +// Copyright Contributors to the Open Shading Language project. +// SPDX-License-Identifier: BSD-3-Clause +// https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + + +volume +medium + [[ string description = "Volume medium material" ]] +( + color albedo = 1.0 + [[ string description = "Scattering color", + float UImin = 0, float UImax = 1 ]], + float transmission_depth = 0.5 + [[ string description = "Mean free path (0.0 is black, infinity is transparent)", + float UImin = 0, float UImax = 1 ]], + color transmission_color = 1.0 + [[ string description = "Transmission color (volume absorption tint)", + float UImin = 0, float UImax = 1 ]], + float anisotropy = 0.0 + [[ string description = "Directionality of scattering (-1=back, 0=isotropic, 1=forward)", + float UImin = -1, float UImax = 1 ]], + float ior = 1.0 + [[ string description = "Index of refraction", + float UImin = 0, float UImax = 1 ]], + int priority = 0 + [[ string description = "Priority for overlapping mediums. Zero is a special 'off' priority", + float UImin = 0, float UImax = 8 ]] // Same as MaxEntries in MediumStack +) +{ + Ci = transparent() + medium_vdf(albedo, transmission_depth, transmission_color, anisotropy, ior, priority); +} \ No newline at end of file diff --git a/testsuite/render-mx-medium-vdf/ref/out-linux-alt.exr b/testsuite/render-mx-medium-vdf/ref/out-linux-alt.exr new file mode 100644 index 0000000000..1622a38d0f Binary files /dev/null and b/testsuite/render-mx-medium-vdf/ref/out-linux-alt.exr differ diff --git a/testsuite/render-mx-medium-vdf/ref/out-macos-alt.exr b/testsuite/render-mx-medium-vdf/ref/out-macos-alt.exr new file mode 100644 index 0000000000..7216f090da Binary files /dev/null and b/testsuite/render-mx-medium-vdf/ref/out-macos-alt.exr differ diff --git a/testsuite/render-mx-medium-vdf/ref/out-optix-alt.exr b/testsuite/render-mx-medium-vdf/ref/out-optix-alt.exr new file mode 100644 index 0000000000..7debe160db Binary files /dev/null and b/testsuite/render-mx-medium-vdf/ref/out-optix-alt.exr differ diff --git a/testsuite/render-mx-medium-vdf/ref/out.exr b/testsuite/render-mx-medium-vdf/ref/out.exr new file mode 100644 index 0000000000..1622a38d0f Binary files /dev/null and b/testsuite/render-mx-medium-vdf/ref/out.exr differ diff --git a/testsuite/render-mx-medium-vdf/run.py b/testsuite/render-mx-medium-vdf/run.py new file mode 100755 index 0000000000..00fd262d22 --- /dev/null +++ b/testsuite/render-mx-medium-vdf/run.py @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +# Copyright Contributors to the Open Shading Language project. +# SPDX-License-Identifier: BSD-3-Clause +# https://github.com/AcademySoftwareFoundation/OpenShadingLanguage + +failthresh = 0.01 +failpercent = 1 +outputs = [ "out.exr" ] +command = testrender("-v -r 196 196 -aa 64 scene.xml out.exr") diff --git a/testsuite/render-mx-medium-vdf/scene.xml b/testsuite/render-mx-medium-vdf/scene.xml new file mode 100644 index 0000000000..4f3172f823 --- /dev/null +++ b/testsuite/render-mx-medium-vdf/scene.xml @@ -0,0 +1,78 @@ + + + + + + vector sun_dir 0.0 1.0 0.5; + shader envmap layer1; + + + + + + + color Cs 0.25 0.25 0.25; + shader matte layer1; + + + + + + param color albedo 0.25 0.25 0.25; + param float transmission_depth 0.5; + param color transmission_color 0.98 0.78 0.82; + param float anisotropy 0.0; + param float ior 1.0; + param int priority 1; + shader medium layer1; + + + + + + param color albedo 0.25 0.25 0.25; + param float transmission_depth 0.5; + param color transmission_color 0.99 0.84 0.70; + param float anisotropy 0.0; + param float ior 1.0; + param int priority 1; + shader medium layer1; + + + + + + param color albedo 0.25 0.25 0.25; + param float transmission_depth 0.5; + param color transmission_color 0.98 0.96 0.72; + param float anisotropy 0.0; + param float ior 1.0; + param int priority 1; + shader medium layer1; + + + + + + param color albedo 0.25 0.25 0.25; + param float transmission_depth 0.5; + param color transmission_color 0.76 0.92 0.84; + param float anisotropy 0.0; + param float ior 1.0; + param int priority 1; + shader medium layer1; + + + + + + param color albedo 0.25 0.25 0.25; + param float transmission_depth 0.5; + param color transmission_color 0.78 0.86 0.96; + param float anisotropy 0.0; + param float ior 1.0; + param int priority 1; + shader medium layer1; + + +