Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Furnace test #1259

Merged
merged 5 commits into from
Jul 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions libs/yocto/yocto_modelio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ using std::string_view;
using std::unordered_map;
using std::unordered_set;
using namespace std::string_literals;
using namespace std::string_view_literals;

} // namespace yocto

Expand Down Expand Up @@ -149,15 +150,15 @@ inline void format_value(string& str, const mat4f& value) {
}

// Foramt to file
inline void format_values(string& str, const string& fmt) {
auto pos = fmt.find("{}");
inline void format_values(string& str, string_view fmt) {
auto pos = fmt.find("{}"sv);
if (pos != string::npos) throw std::invalid_argument("bad format string");
str += fmt;
}
template <typename Arg, typename... Args>
inline void format_values(
string& str, const string& fmt, const Arg& arg, const Args&... args) {
auto pos = fmt.find("{}");
string& str, string_view fmt, const Arg& arg, const Args&... args) {
auto pos = fmt.find("{}"sv);
if (pos == string::npos) throw std::invalid_argument("bad format string");
str += fmt.substr(0, pos);
format_value(str, arg);
Expand Down
44 changes: 34 additions & 10 deletions libs/yocto/yocto_shading.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ using std::vector;
// -----------------------------------------------------------------------------
namespace yocto {

// Check if on the same side of the hemisphere
inline bool same_hemisphere(
const vec3f& normal, const vec3f& outgoing, const vec3f& incoming);

// Schlick approximation of the Fresnel term.
inline vec3f fresnel_schlick(
const vec3f& specular, const vec3f& normal, const vec3f& outgoing);
Expand Down Expand Up @@ -288,6 +292,12 @@ inline float sample_phasefunction_pdf(
// -----------------------------------------------------------------------------
namespace yocto {

// Check if on the same side of the hemisphere
inline bool same_hemisphere(
const vec3f& normal, const vec3f& outgoing, const vec3f& incoming) {
return dot(normal, outgoing) * dot(normal, incoming) >= 0;
}

// Schlick approximation of the Fresnel term
inline vec3f fresnel_schlick(
const vec3f& specular, const vec3f& normal, const vec3f& outgoing) {
Expand Down Expand Up @@ -570,12 +580,14 @@ inline vec3f eval_glossy(const vec3f& color, float ior, float roughness,
}

// Sample a specular BRDF lobe.
inline vec3f sample_specular(const vec3f& color, float ior, float roughness,
inline vec3f sample_glossy(const vec3f& color, float ior, float roughness,
const vec3f& normal, const vec3f& outgoing, float rnl, const vec2f& rn) {
auto up_normal = dot(normal, outgoing) <= 0 ? -normal : normal;
if (rnl < fresnel_dielectric(ior, up_normal, outgoing)) {
auto halfway = sample_microfacet(roughness, up_normal, rn);
return reflect(outgoing, halfway);
auto halfway = sample_microfacet(roughness, up_normal, rn);
auto incoming = reflect(outgoing, halfway);
if (!same_hemisphere(up_normal, outgoing, incoming)) return {0, 0, 0};
return incoming;
} else {
return sample_hemisphere_cos(up_normal, rn);
}
Expand Down Expand Up @@ -613,7 +625,9 @@ inline vec3f sample_metallic(const vec3f& color, float roughness,
const vec3f& normal, const vec3f& outgoing, const vec2f& rn) {
auto up_normal = dot(normal, outgoing) <= 0 ? -normal : normal;
auto halfway = sample_microfacet(roughness, up_normal, rn);
return reflect(outgoing, halfway);
auto incoming = reflect(outgoing, halfway);
if (!same_hemisphere(up_normal, outgoing, incoming)) return {0, 0, 0};
return incoming;
}

// Pdf for metal BRDF lobe sampling.
Expand Down Expand Up @@ -733,8 +747,10 @@ inline vec3f sample_gltfpbr(const vec3f& color, float ior, float roughness,
auto reflectivity = lerp(
eta_to_reflectivity(vec3f{ior, ior, ior}), color, metallic);
if (rnl < mean(fresnel_schlick(reflectivity, up_normal, outgoing))) {
auto halfway = sample_microfacet(roughness, up_normal, rn);
return reflect(outgoing, halfway);
auto halfway = sample_microfacet(roughness, up_normal, rn);
auto incoming = reflect(outgoing, halfway);
if (!same_hemisphere(up_normal, outgoing, incoming)) return {0, 0, 0};
return incoming;
} else {
return sample_hemisphere_cos(up_normal, rn);
}
Expand Down Expand Up @@ -787,10 +803,14 @@ inline vec3f sample_transparent(const vec3f& color, float ior, float roughness,
auto up_normal = dot(normal, outgoing) <= 0 ? -normal : normal;
auto halfway = sample_microfacet(roughness, up_normal, rn);
if (rnl < fresnel_dielectric(ior, halfway, outgoing)) {
return reflect(outgoing, halfway);
auto incoming = reflect(outgoing, halfway);
if (!same_hemisphere(up_normal, outgoing, incoming)) return {0, 0, 0};
return incoming;
} else {
auto reflected = reflect(outgoing, halfway);
return -reflect(reflected, up_normal);
auto incoming = -reflect(reflected, up_normal);
if (same_hemisphere(up_normal, outgoing, incoming)) return {0, 0, 0};
return incoming;
}
}

Expand Down Expand Up @@ -885,9 +905,13 @@ inline vec3f sample_refractive(const vec3f& color, float ior, float roughness,
auto up_normal = entering ? normal : -normal;
auto halfway = sample_microfacet(roughness, up_normal, rn);
if (rnl < fresnel_dielectric(entering ? ior : (1 / ior), halfway, outgoing)) {
return reflect(outgoing, halfway);
auto incoming = reflect(outgoing, halfway);
if (!same_hemisphere(up_normal, outgoing, incoming)) return {0, 0, 0};
return incoming;
} else {
return refract(outgoing, halfway, entering ? (1 / ior) : ior);
auto incoming = refract(outgoing, halfway, entering ? (1 / ior) : ior);
if (same_hemisphere(up_normal, outgoing, incoming)) return {0, 0, 0};
return incoming;
}
}

Expand Down
99 changes: 98 additions & 1 deletion libs/yocto/yocto_trace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ static vec3f sample_bsdfcos(const material_point& material, const vec3f& normal,
if (material.type == material_type::matte) {
return sample_matte(material.color, normal, outgoing, rn);
} else if (material.type == material_type::glossy) {
return sample_specular(material.color, material.ior, material.roughness,
return sample_glossy(material.color, material.ior, material.roughness,
normal, outgoing, rnl, rn);
} else if (material.type == material_type::metallic) {
return sample_metallic(
Expand Down Expand Up @@ -1097,6 +1097,100 @@ static trace_result trace_eyelightao(const scene_data& scene,
return {radiance, hit, hit_albedo, hit_normal};
}

// Furnace test.
static trace_result trace_furnace(const scene_model& scene,
const bvh_scene& bvh, const trace_lights& lights, const ray3f& ray_,
rng_state& rng, const trace_params& params) {
// initialize
auto radiance = zero3f;
auto weight = vec3f{1, 1, 1};
auto ray = ray_;
auto hit = false;
auto hit_albedo = vec3f{0, 0, 0};
auto hit_normal = vec3f{0, 0, 0};
auto opbounce = 0;
auto in_volume = false;

// trace path
for (auto bounce = 0; bounce < params.bounces; bounce++) {
// exit loop
if (bounce > 0 && !in_volume) {
radiance += weight * eval_environment(scene, ray.d);
break;
}

// intersect next point
auto intersection = intersect_bvh(bvh, scene, ray);
if (!intersection.hit) {
if (bounce > 0 || !params.envhidden)
radiance += weight * eval_environment(scene, ray.d);
break;
}

// prepare shading point
auto outgoing = -ray.d;
auto instance = scene.instances[intersection.instance];
auto element = intersection.element;
auto uv = intersection.uv;
auto position = eval_position(scene, instance, element, uv);
auto normal = eval_shading_normal(scene, instance, element, uv, outgoing);
auto material = eval_material(scene, instance, element, uv);

// handle opacity
if (material.opacity < 1 && rand1f(rng) >= material.opacity) {
if (opbounce++ > 128) break;
ray = {position + ray.d * 1e-2f, ray.d};
bounce -= 1;
continue;
}

// set hit variables
if (bounce == 0) {
hit = true;
hit_albedo = material.color;
hit_normal = normal;
}

// accumulate emission
radiance += weight * eval_emission(material, normal, outgoing);

// next direction
auto incoming = zero3f;
if (material.roughness != 0) {
incoming = sample_bsdfcos(
material, normal, outgoing, rand1f(rng), rand2f(rng));
if (incoming == vec3f{0, 0, 0}) break;
weight *= eval_bsdfcos(material, normal, outgoing, incoming) /
sample_bsdfcos_pdf(material, normal, outgoing, incoming);
} else {
incoming = sample_delta(material, normal, outgoing, rand1f(rng));
if (incoming == vec3f{0, 0, 0}) break;
weight *= eval_delta(material, normal, outgoing, incoming) /
sample_delta_pdf(material, normal, outgoing, incoming);
}

// check weight
if (weight == zero3f || !isfinite(weight)) break;

// russian roulette
if (bounce > 3) {
auto rr_prob = min((float)0.99, max(weight));
if (rand1f(rng) >= rr_prob) break;
weight *= 1 / rr_prob;
}

// update volume stack
if (dot(normal, outgoing) * dot(normal, incoming) < 0)
in_volume = !in_volume;

// setup next iteration
ray = {position, incoming};
}

// done
return {radiance, hit, hit_albedo, hit_normal};
}

// False color rendering
static trace_result trace_falsecolor(const scene_data& scene,
const bvh_data& bvh, const trace_lights& lights, const ray3f& ray,
Expand Down Expand Up @@ -1190,6 +1284,7 @@ static sampler_func get_trace_sampler_func(const trace_params& params) {
case trace_sampler_type::naive: return trace_naive;
case trace_sampler_type::eyelight: return trace_eyelight;
case trace_sampler_type::eyelightao: return trace_eyelightao;
case trace_sampler_type::furnace: return trace_furnace;
case trace_sampler_type::falsecolor: return trace_falsecolor;
default: {
throw std::runtime_error("sampler unknown");
Expand All @@ -1206,6 +1301,8 @@ bool is_sampler_lit(const trace_params& params) {
case trace_sampler_type::pathmis: return true;
case trace_sampler_type::naive: return true;
case trace_sampler_type::eyelight: return false;
case trace_sampler_type::eyelightao: return false;
case trace_sampler_type::furnace: return true;
case trace_sampler_type::falsecolor: return false;
default: {
throw std::runtime_error("sampler unknown");
Expand Down
4 changes: 3 additions & 1 deletion libs/yocto/yocto_trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ enum struct trace_sampler_type {
naive, // naive path tracing
eyelight, // eyelight rendering
eyelightao, // eyelight with ambient occlusion
furnace, // furnace test
falsecolor, // false color rendering
};
// Type of false color visualization
Expand Down Expand Up @@ -116,7 +117,8 @@ struct trace_params {
};

inline const auto trace_sampler_names = std::vector<std::string>{"path",
"pathdirect", "pathmis", "naive", "eyelight", "eyelightao", "falsecolor"};
"pathdirect", "pathmis", "naive", "eyelight", "eyelightao", "furnace",
"falsecolor"};

inline const auto trace_falsecolor_names = vector<string>{"position", "normal",
"frontfacing", "gnormal", "gfrontfacing", "texcoord", "mtype", "color",
Expand Down
Loading