From ab3c2e687db852dba7c686d6ed097e5f83d5beda Mon Sep 17 00:00:00 2001 From: n8vm Date: Wed, 22 Jul 2020 10:31:15 -0600 Subject: [PATCH 01/25] some progress on adding aovs to the render_data function --- src/visii/devicecode/disney_bsdf.h | 111 +++++++++++++++--- src/visii/devicecode/launch_params.h | 9 ++ src/visii/devicecode/path_tracer.cu | 165 ++++++++++++++++++++++----- src/visii/visii.cpp | 30 ++++- 4 files changed, 267 insertions(+), 48 deletions(-) diff --git a/src/visii/devicecode/disney_bsdf.h b/src/visii/devicecode/disney_bsdf.h index e1e4af6a..01c28946 100644 --- a/src/visii/devicecode/disney_bsdf.h +++ b/src/visii/devicecode/disney_bsdf.h @@ -280,6 +280,12 @@ __device__ float gtr_2_aniso_pdf(const float3 &w_o, const float3 &w_i, const flo return d * cos_theta_h / (4.f * dot(w_o, w_h)); } +__device__ float3 disney_diffuse_color(const DisneyMaterial &mat, const float3 &n, + const float3 &w_o, const float3 &w_i) +{ + return mat.base_color; +} + __device__ float3 disney_diffuse(const DisneyMaterial &mat, const float3 &n, const float3 &w_o, const float3 &w_i) { @@ -290,7 +296,7 @@ __device__ float3 disney_diffuse(const DisneyMaterial &mat, const float3 &n, float fd90 = 0.5f + 2.f * mat.roughness * i_dot_h * i_dot_h; float fi = schlick_weight(n_dot_i); float fo = schlick_weight(n_dot_o); - return mat.base_color * M_1_PI * lerp(1.f, fd90, fi) * lerp(1.f, fd90, fo); + return disney_diffuse_color(mat, n, w_o, w_i) * M_1_PI * lerp(1.f, fd90, fi) * lerp(1.f, fd90, fo); } __device__ float3 disney_subsurface(const DisneyMaterial &mat, const float3 &n, @@ -305,7 +311,7 @@ __device__ float3 disney_subsurface(const DisneyMaterial &mat, const float3 &n, float Fss = lerp(1.0, Fss90, FL) * lerp(1.0, Fss90, FV); float ss = 1.25 * (Fss * (1. / (n_dot_i + n_dot_o) - .5) + .5); - return (1./M_PI) * ss * mat.base_color; + return disney_diffuse_color(mat, n, w_o, w_i) * M_1_PI * ss; } // Eavg in the algorithm is fitted into this @@ -393,6 +399,20 @@ __device__ float F(float3 i, float3 m, float eta_t, float eta_i) return f; } +__device__ float3 disney_microfacet_reflection_color(const DisneyMaterial &mat, const float3 &n, + const float3 &w_o, const float3 &w_i) +{ + float3 w_h = normalize(w_i + w_o); + float lum = luminance(mat.base_color); + float3 tint = lum > 0.f ? mat.base_color / lum : make_float3(1.f); + float3 spec = lerp(mat.specular * 0.08f * lerp(make_float3(1.f), tint, mat.specular_tint), mat.base_color, mat.metallic); + + float alpha = max(MIN_ALPHA, mat.roughness * mat.roughness); + float3 f = lerp(spec, make_float3(1.f), schlick_weight(dot(w_i, w_h))); + float g = smith_shadowing_ggx(dot(n, w_i), alpha) * smith_shadowing_ggx(dot(n, w_o), alpha); + return f * g; +} + __device__ float3 disney_microfacet_isotropic(const DisneyMaterial &mat, const float3 &n, const float3 &w_o, const float3 &w_i) { @@ -408,6 +428,12 @@ __device__ float3 disney_microfacet_isotropic(const DisneyMaterial &mat, const f return d * f * g; } +__device__ float3 disney_microfacet_transmission_color(const DisneyMaterial &mat, const float3 &n, + const float3 &w_o, const float3 &w_i) +{ + return mat.base_color; +} + __device__ float3 disney_microfacet_transmission_isotropic(const DisneyMaterial &mat, const float3 &n, const float3 &w_o, const float3 &w_i) { @@ -506,7 +532,8 @@ __device__ float3 disney_sheen(const DisneyMaterial &mat, const float3 &n, __device__ float3 disney_brdf(const DisneyMaterial &mat, const float3 &n, const float3 &w_o, const float3 &w_i, const float3 &v_x, const float3 &v_y, - cudaTextureObject_t GGX_E_LOOKUP, cudaTextureObject_t GGX_E_AVG_LOOKUP + cudaTextureObject_t GGX_E_LOOKUP, cudaTextureObject_t GGX_E_AVG_LOOKUP, + int forced_bsdf ) { @@ -515,6 +542,14 @@ __device__ float3 disney_brdf(const DisneyMaterial &mat, const float3 &n, if (mat.specular_transmission > 0.f) { float3 spec_trans = disney_microfacet_transmission_isotropic(mat, n, w_o, w_i); + spec_trans = spec_trans * (1.f - mat.metallic) * mat.specular_transmission; + + // If transmission BSDF is forced + if (forced_bsdf == 3) { + float3 color = disney_microfacet_transmission_color(mat, n, w_o, w_i); + return spec_trans / color; + } + return spec_trans * (1.f - mat.metallic) * mat.specular_transmission; } @@ -522,6 +557,9 @@ __device__ float3 disney_brdf(const DisneyMaterial &mat, const float3 &n, return make_float3(0.f); } + // If forcing transmission, stop here. + if (forced_bsdf == 3) return make_float3(0.f); + float coat = disney_clear_coat(mat, n, w_o, w_i); float3 sheen = disney_sheen(mat, n, w_o, w_i); float3 diffuse = disney_diffuse(mat, n, w_o, w_i); @@ -535,13 +573,30 @@ __device__ float3 disney_brdf(const DisneyMaterial &mat, const float3 &n, gloss = disney_microfacet_anisotropic(mat, n, w_o, w_i, v_x, v_y); gloss = gloss + disney_multiscatter(mat, n, w_o, w_i, GGX_E_LOOKUP, GGX_E_AVG_LOOKUP); } + + // If diffuse BRDF is forced + if (forced_bsdf == 0) { + float3 color = disney_diffuse_color(mat, n, w_o, w_i); + return (lerp(diffuse, subsurface, mat.flatness) + * (1.f - mat.metallic) + * (1.f - mat.specular_transmission) + * fabs(dot(w_i, n))) / color; + } + + // If glossy BRDF is forced + if ((forced_bsdf == 1) || (forced_bsdf == 2)) { + float3 color = disney_microfacet_reflection_color(mat, n, w_o, w_i); + return ((sheen + gloss + coat) * fabs(dot(w_i, n))) / color; + } + return (lerp(diffuse, subsurface, mat.flatness) * (1.f - mat.metallic) * (1.f - mat.specular_transmission) + sheen + gloss + coat) * fabs(dot(w_i, n)); } __device__ float disney_pdf(const DisneyMaterial &mat, const float3 &n, - const float3 &w_o, const float3 &w_i, const float3 &v_x, const float3 &v_y + const float3 &w_o, const float3 &w_i, const float3 &v_x, const float3 &v_y, + int forced_bsdf ) { bool entering = dot(w_o, n) > 0.f; bool sameHemisphere = same_hemisphere(w_o, w_i, n); @@ -580,6 +635,20 @@ __device__ float disney_pdf(const DisneyMaterial &mat, const float3 &n, float metallic_kludge = max(mat.metallic - mat.roughness * 10.f, 0.f); float transmission_kludge = mat.specular_transmission; n_comp -= lerp(transmission_kludge, metallic_kludge, mat.metallic); + + if (forced_bsdf == 0) { + return diffuse; + } + if (forced_bsdf == 1) { + return microfacet; + } + if (forced_bsdf == 2) { + return clear_coat; + } + if (forced_bsdf == 3) { + return microfacet_transmission; + } + return (diffuse + microfacet + microfacet_transmission + clear_coat) / n_comp; } @@ -588,26 +657,32 @@ __device__ float disney_pdf(const DisneyMaterial &mat, const float3 &n, */ __device__ float3 sample_disney_brdf(const DisneyMaterial &mat, const float3 &n, const float3 &w_o, const float3 &v_x, const float3 &v_y, LCGRand &rng, - float3 &w_i, float &pdf, bool &is_specular, + float3 &w_i, float &pdf, int &sampled_bsdf, int forced_bsdf, cudaTextureObject_t GGX_E_LOOKUP, cudaTextureObject_t GGX_E_AVG_LOOKUP) { bool entering = dot(w_o, n) > 0.f; int component = 0; - if (mat.specular_transmission == 0.f) { - component = lcg_randomf(rng) * 3.f; - component = glm::clamp(component, 0, 2); - } else - { - if (entering) { - component = lcg_randomf(rng) * 4.f; - component = glm::clamp(component, 0, 3); + if ((forced_bsdf < 0) || (forced_bsdf > 3)) { + if (mat.specular_transmission == 0.f) { + component = lcg_randomf(rng) * 3.f; + component = glm::clamp(component, 0, 2); + } else + { + if (entering) { + component = lcg_randomf(rng) * 4.f; + component = glm::clamp(component, 0, 3); + } + // HACK, forcing only refractive brdf when entering surface + else component = 3; } - // HACK, forcing only refractive brdf when entering surface - else component = 3; + } + else { + component = forced_bsdf; } - is_specular = ((component != 0) && (component != 3)); + // is_specular = ((component != 0) && (component != 3)); + sampled_bsdf = component; float2 samples = make_float2(lcg_randomf(rng), lcg_randomf(rng)); if (component == 0) { @@ -662,9 +737,9 @@ __device__ float3 sample_disney_brdf(const DisneyMaterial &mat, const float3 &n, } // return make_float3(1.f); // HACK } - pdf = disney_pdf(mat, n, w_o, w_i, v_x, v_y); + pdf = disney_pdf(mat, n, w_o, w_i, v_x, v_y, forced_bsdf); - float3 brdf = disney_brdf(mat, n, w_o, w_i, v_x, v_y, GGX_E_LOOKUP, GGX_E_AVG_LOOKUP); + float3 brdf = disney_brdf(mat, n, w_o, w_i, v_x, v_y, GGX_E_LOOKUP, GGX_E_AVG_LOOKUP, forced_bsdf); return brdf; } diff --git a/src/visii/devicecode/launch_params.h b/src/visii/devicecode/launch_params.h index 6fb39eab..c9450cce 100644 --- a/src/visii/devicecode/launch_params.h +++ b/src/visii/devicecode/launch_params.h @@ -65,4 +65,13 @@ enum RenderDataFlags : uint32_t { ENTITY_ID = 4, DENOISE_NORMAL = 5, DENOISE_ALBEDO = 6, + DIFFUSE_COLOR = 7, + DIFFUSE_DIRECT_LIGHTING = 8, + DIFFUSE_INDIRECT_LIGHTING = 9, + GLOSSY_COLOR = 10, + GLOSSY_DIRECT_LIGHTING = 11, + GLOSSY_INDIRECT_LIGHTING = 12, + TRANSMISSION_COLOR = 13, + TRANSMISSION_DIRECT_LIGHTING = 14, + TRANSMISSION_INDIRECT_LIGHTING = 15 }; \ No newline at end of file diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index 5a616100..d0d451cc 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -210,7 +210,71 @@ void initializeRenderData(float3 &renderData) } __device__ -void saveRenderData(float3 &renderData, int bounce, float depth, float3 w_p, float3 w_n, int entity_id) +void saveLightingColorRenderData ( + float3 &renderData, int bounce, + float3 w_n, float3 w_o, float3 w_i, + DisneyMaterial &mat +) +{ + if (optixLaunchParams.renderDataMode == RenderDataFlags::NONE) return; + if (bounce != optixLaunchParams.renderDataBounce) return; + + // Note, dillum and iillum are expected to change outside this function depending on the + // render data flags. + if (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_COLOR) { + renderData = disney_diffuse_color(mat, w_n, w_o, w_i); + } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_COLOR) { + renderData = disney_microfacet_reflection_color(mat, w_n, w_o, w_i); + } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_COLOR) { + renderData = disney_microfacet_transmission_color(mat, w_n, w_o, w_i); + } +} + +__device__ +void saveLightingIrradianceRenderData( + float3 &renderData, int bounce, + float3 dillum, float3 iillum, + int sampledBsdf) +{ + if (optixLaunchParams.renderDataMode == RenderDataFlags::NONE) return; + if (bounce != optixLaunchParams.renderDataBounce) return; + + // Note, dillum and iillum are expected to change outside this function depending on the + // render data flags. + if (sampledBsdf == 0) { + if (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_DIRECT_LIGHTING) { + renderData = dillum; + } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_INDIRECT_LIGHTING) { + renderData = iillum; + } + } + if ((sampledBsdf == 1) || (sampledBsdf == 2)) { + if (optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_DIRECT_LIGHTING) { + renderData = dillum; + } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_INDIRECT_LIGHTING) { + renderData = iillum; + } + } + if (sampledBsdf == 3) { + if (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING) { + renderData = dillum; + } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_INDIRECT_LIGHTING) { + renderData = iillum; + } + } +} + +__device__ +void saveGeometricRenderData( + float3 &renderData, + int bounce, float depth, + float3 w_p, float3 w_n, float3 w_o, + int entity_id, DisneyMaterial &mat) { if (optixLaunchParams.renderDataMode == RenderDataFlags::NONE) return; if (bounce != optixLaunchParams.renderDataBounce) return; @@ -277,8 +341,24 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() DisneyMaterial mat; int bounce = 0; int visibilitySkips = 0; + + // direct here is used for final image clamping float3 directIllum = make_float3(0.f); float3 illum = make_float3(0.f); + + // used for render metadata stuff. + float3 rdIllum = make_float3(0.f); + float3 rdDirectIllum = make_float3(0.f); + float3 rdIndirectIllum = make_float3(0.f); + int32_t rdSampledBsdf = -1; + int32_t rdForcedBsdf = -1; + if ((optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_DIRECT_LIGHTING) || + (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_DIRECT_LIGHTING)) rdForcedBsdf = 0; + if ((optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_DIRECT_LIGHTING) || + (optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_DIRECT_LIGHTING)) rdForcedBsdf = 1; + if ((optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING) || + (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING)) rdForcedBsdf = 3; + float3 path_throughput = make_float3(1.f); uint16_t ray_count = 0; float roughnessMinimum = 0.f; @@ -387,8 +467,8 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() v_z = faceNormalForward(w_o, v_gz, v_z); } - // For segmentations, metadata extraction for applications like denoising or ML training - saveRenderData(renderData, bounce, payload.tHit, hit_p, v_z, entityID); + // For segmentations, geometric metadata extraction dependent on the hit object + saveGeometricRenderData(renderData, bounce, payload.tHit, hit_p, v_z, w_o, entityID, mat); // If this is the first hit, keep track of primary albedo and normal for denoising. if (bounce == 0) { @@ -428,6 +508,9 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // n_l = -n_l; // } + // note, rdForcedBsdf is -1 by default + int forcedBsdf = (bounce == optixLaunchParams.renderDataBounce) ? rdForcedBsdf : -1; + // first, sample the light source by importance sampling the light do { if (numLights == 0) break; @@ -494,7 +577,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() if ((light_pdf > EPSILON) && (dotNWi > EPSILON)) { float3 light_dir = make_float3(dir.x, dir.y, dir.z); light_dir = normalize(light_dir); - float bsdf_pdf = disney_pdf(mat, n_l, w_o, light_dir, v_x, v_y); + float bsdf_pdf = disney_pdf(mat, n_l, w_o, light_dir, v_x, v_y, forcedBsdf); if (bsdf_pdf > EPSILON) { RayPayload payload; owl::Ray ray; @@ -510,7 +593,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() bool visible = ((entityID == sampledLightID) || (entityID == -1)); if (visible) { float w = power_heuristic(1.f, light_pdf, 1.f, bsdf_pdf); - float3 bsdf = disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, optixLaunchParams.GGX_E_LOOKUP, optixLaunchParams.GGX_E_AVG_LOOKUP); + float3 bsdf = disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, optixLaunchParams.GGX_E_LOOKUP, optixLaunchParams.GGX_E_AVG_LOOKUP, forcedBsdf); float3 Li = lightEmission * w / light_pdf; irradiance = (bsdf * Li * fabs(dotNWi)); } @@ -522,17 +605,17 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // next, sample a light source by importance sampling the BDRF float3 w_i; float bsdf_pdf; - bool sampledSpecular; - float3 bsdf = sample_disney_brdf(mat, v_z, w_o, v_x, v_y, rng, w_i, bsdf_pdf, sampledSpecular, optixLaunchParams.GGX_E_LOOKUP, optixLaunchParams.GGX_E_AVG_LOOKUP); + int sampledBsdf = -1; + float3 bsdf = sample_disney_brdf(mat, v_z, w_o, v_x, v_y, rng, w_i, bsdf_pdf, + sampledBsdf, forcedBsdf, optixLaunchParams.GGX_E_LOOKUP, optixLaunchParams.GGX_E_AVG_LOOKUP); + + // terminate if the bsdf probability is impossible, or if the bsdf filters out all light if (bsdf_pdf < EPSILON || all_zero(bsdf)) { break; } // trace the next ray along that sampled BRDF direction - if (dot(w_o, v_z) < 0.f) { - v_z = -v_z; - } - ray.origin = hit_p;// + v_z * .1; + ray.origin = hit_p; ray.direction = w_i; ray.tmin = EPSILON * 100.f; payload.tHit = -1.f; @@ -575,16 +658,33 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() } // accumulate any radiance (ie path_throughput * irradiance), and update the path throughput using the sampled BRDF - illum = illum + path_throughput * irradiance; + float3 contribution = path_throughput * irradiance; + illum = illum + contribution; + // if (bounce >= optixLaunchParams.renderDataBounce) + rdIllum = rdIllum + contribution; path_throughput = path_throughput * bsdf / bsdf_pdf; // If ray misses, interpret normal as "miss color" assigned by miss program and move on to the next sample if (payload.tHit <= 0.f) { + irradiance = irradiance + missColor(ray) * optixLaunchParams.domeLightIntensity; illum = illum + path_throughput * missColor(ray) * optixLaunchParams.domeLightIntensity; + // if (bounce >= optixLaunchParams.renderDataBounce) + { + rdIllum = rdIllum + path_throughput * missColor(ray) * optixLaunchParams.domeLightIntensity; + } } - + + // For segmentations, lighting metadata extraction dependent on sampling the BSDF + saveLightingColorRenderData(renderData, bounce, v_z, w_o, w_i, mat); + if (bounce == 0) { directIllum = illum; + rdDirectIllum = illum; + rdSampledBsdf = sampledBsdf; + } + + if (bounce == /*optixLaunchParams.renderDataBounce*/ 0) { + // rdIllum = rdDirectIllum; } if ((payload.tHit <= 0.0f) || (path_throughput.x < EPSILON && path_throughput.y < EPSILON && path_throughput.z < EPSILON)) { @@ -607,6 +707,11 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() glm::vec3 dillum = vec3(directIllum.x, directIllum.y, directIllum.z); glm::vec3 iillum = gillum - dillum; + // For segmentations, indirect/direct lighting metadata extraction + float3 rdgillum = rdIllum; + rdIndirectIllum = rdgillum;// - rdDirectIllum; + saveLightingIrradianceRenderData(renderData, bounce, rdDirectIllum, rdIndirectIllum, rdSampledBsdf); + if (optixLaunchParams.indirectClamp > 0.f) iillum = clamp(iillum, vec3(0.f), vec3(optixLaunchParams.indirectClamp)); if (optixLaunchParams.directClamp > 0.f) @@ -646,12 +751,24 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // color.y = linear_to_srgb(color.y); // color.z = linear_to_srgb(color.z); - optixLaunchParams.frameBuffer[fbOfs] = vec4( - color.x, - color.y, - color.z, - 1.0f - ); + if (optixLaunchParams.renderDataMode == RenderDataFlags::NONE) + { + optixLaunchParams.frameBuffer[fbOfs] = vec4( + color.x, + color.y, + color.z, + 1.0f + ); + } + // Override framebuffer output if user requested to render metadata + else + { + vec3 oldRenderData = vec3(optixLaunchParams.frameBuffer[fbOfs]); + vec3 newRenderData = make_vec3(renderData); + vec3 accumData = (newRenderData + float(optixLaunchParams.frameID) * oldRenderData) / float(optixLaunchParams.frameID + 1); + optixLaunchParams.frameBuffer[fbOfs] = vec4( accumData.x, accumData.y, accumData.z, 1.0f); + } + vec4 oldAlbedo = optixLaunchParams.albedoBuffer[fbOfs]; vec4 oldNormal = optixLaunchParams.normalBuffer[fbOfs]; if (any(isnan(oldAlbedo))) oldAlbedo = vec4(1.f); @@ -664,13 +781,5 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() optixLaunchParams.albedoBuffer[fbOfs] = accumAlbedo; optixLaunchParams.normalBuffer[fbOfs] = accumNormal; - // Override framebuffer output if user requested to render metadata - if (optixLaunchParams.renderDataMode != RenderDataFlags::NONE) { - accumNormal = abs(accumNormal + vec4(1.f)); - if (optixLaunchParams.renderDataMode == RenderDataFlags::DENOISE_NORMAL) - renderData = make_float3(accumNormal.x, accumNormal.y, accumNormal.z); - if (optixLaunchParams.renderDataMode == RenderDataFlags::DENOISE_ALBEDO) - renderData = make_float3(accumAlbedo.x, accumAlbedo.y, accumAlbedo.z); - optixLaunchParams.frameBuffer[fbOfs] = vec4( renderData.x, renderData.y, renderData.z, 1.0f); - } + } diff --git a/src/visii/visii.cpp b/src/visii/visii.cpp index c867a555..8f3ac91b 100644 --- a/src/visii/visii.cpp +++ b/src/visii/visii.cpp @@ -1302,10 +1302,36 @@ std::vector renderData(uint32_t width, uint32_t height, uint32_t startFra else if (option == std::string("denoise_albedo")) { OptixData.LP.renderDataMode = RenderDataFlags::DENOISE_ALBEDO; } + else if (option == std::string("diffuse_color")) { + OptixData.LP.renderDataMode = RenderDataFlags::DIFFUSE_COLOR; + } + else if (option == std::string("diffuse_direct_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::DIFFUSE_DIRECT_LIGHTING; + } + else if (option == std::string("diffuse_indirect_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::DIFFUSE_INDIRECT_LIGHTING; + } + else if (option == std::string("glossy_color")) { + OptixData.LP.renderDataMode = RenderDataFlags::GLOSSY_COLOR; + } + else if (option == std::string("glossy_direct_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::GLOSSY_DIRECT_LIGHTING; + } + else if (option == std::string("glossy_indirect_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::GLOSSY_INDIRECT_LIGHTING; + } + else if (option == std::string("transmission_color")) { + OptixData.LP.renderDataMode = RenderDataFlags::TRANSMISSION_COLOR; + } + else if (option == std::string("transmission_direct_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING; + } + else if (option == std::string("transmission_indirect_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::TRANSMISSION_INDIRECT_LIGHTING; + } else { throw std::runtime_error(std::string("Error, unknown option : \"") + _option + std::string("\". ") - + std::string("Available options are \"none\", \"depth\", \"position\", ") - + std::string("\"normal\", \"denoise_normal\", \"denoise_albedo\", and \"entity_id\"")); + + std::string("See documentation for available options")); } resizeOptixFrameBuffer(width, height); From d77450d682d8ec108e762a09473bb0482f88df70 Mon Sep 17 00:00:00 2001 From: n8vm Date: Sun, 26 Jul 2020 19:05:34 -0600 Subject: [PATCH 02/25] sync --- tests/test_area_light_noise.py | 203 +++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) diff --git a/tests/test_area_light_noise.py b/tests/test_area_light_noise.py index 71323412..c790c942 100644 --- a/tests/test_area_light_noise.py +++ b/tests/test_area_light_noise.py @@ -1,5 +1,10 @@ #%% +<<<<<<< Updated upstream import sys, os, math +======= +import sys, os, math, colorsys +os.environ["CUDA_VISIBLE_DEVICES"] = "0" +>>>>>>> Stashed changes os.add_dll_directory(os.path.join(os.getcwd(), '..', 'install')) sys.path.append(os.path.join(os.getcwd(), "..", "install")) @@ -28,8 +33,23 @@ def moveCamera(x=3,y=3,z=2): interact(moveCamera, x=(-10, 10, .001), y=(-10, 10, .001), z=(-10, 10, .001)) #%% +<<<<<<< Updated upstream tex = v.texture.create_from_image("texture", "../data/abandoned_tank_farm_01_1k.hdr") v.set_dome_light_texture(tex) +======= +def moveCameraNext(x=0,y=3,z=2): + camera_entity.get_transform().next_look_at( + v.vec3(0,0,0.0), + v.vec3(0,0,1), + v.vec3(x,y,z), + ) + # camera_entity.get_transform().set_position(0, 0.0, x) +interact(moveCameraNext, x=(-10, 10, .001), y=(-10, 10, .001), z=(-10, 10, .001)) + +#%% +# tex = v.texture.create_from_image("texture", "../data/dome.hdr") +# v.set_dome_light_texture(tex) +>>>>>>> Stashed changes #%% floor = v.entity.create( @@ -60,6 +80,7 @@ def moveCamera(x=3,y=3,z=2): mesh1.get_transform().set_position(v.vec3(0,0,1.0)) #%% +<<<<<<< Updated upstream areaLight1 = v.entity.create( name="areaLight1", light = v.light.create("areaLight1"), @@ -118,6 +139,53 @@ def changeSubsurface(subsurface=0): def changeTransmissionRoughess(transmission_roughness=0): mesh1.get_material().set_transmission_roughness(transmission_roughness) mesh2.get_material().set_transmission_roughness(transmission_roughness) +======= +def changeColor(hue=0, sat=0, val=1): + rgb = colorsys.hsv_to_rgb(hue, sat, val) + outer.get_material().set_base_color(v.vec3(rgb[0], rgb[1], rgb[2])) +def changeRoughness(roughness=1): outer.get_material().set_roughness(roughness) +def changeTransmission(transmission=0): outer.get_material().set_transmission(transmission) +def changeIor(ior=1.57): outer.get_material().set_ior(ior) +def changeSheen(sheen=0): outer.get_material().set_sheen(sheen) +def changeClearCoat(clearcoat=0): outer.get_material().set_clearcoat(clearcoat) +def changeClearCoatRoughness(clearcoat_roughness=0): outer.get_material().set_clearcoat_roughness(clearcoat_roughness) +def changeMetallic(metallic=0): outer.get_material().set_metallic(metallic) +def changeSpecularTint(specular_tint=0): outer.get_material().set_specular_tint(specular_tint) +def changeSpecular(specular=1): outer.get_material().set_specular(specular) +def changeSubsurface(subsurface=0): outer.get_material().set_subsurface(subsurface) +def changeTransmissionRoughess(transmission_roughness=0): outer.get_material().set_transmission_roughness(transmission_roughness) +def changeAnisotropy(anisotropy=0): outer.get_material().set_anisotropic(anisotropy) +interact(changeColor, hue=(0.0, 1.0, .001), sat=(0.0, 1.0, .001), val=(0.0, 1.0, .001)) +interact(changeRoughness, roughness=(0.0, 1.0, .001)) +interact(changeTransmission, transmission=(0.0, 1.0, .001)) +interact(changeIor, ior=(0.0, 2.0, .001)) +interact(changeSheen, sheen=(0.0, 1.0, .001)) +interact(changeClearCoat, clearcoat=(0.0, 1.0, .001)) +interact(changeClearCoatRoughness, clearcoat_roughness=(0.0, 1.0, .001)) +interact(changeMetallic, metallic=(0.0, 1.0, .001)) +interact(changeSpecularTint, specular_tint=(0.0, 1.0, .001)) +interact(changeSpecular, specular=(0.0, 2.0, .001)) +interact(changeSubsurface, subsurface=(0.0, 1.0, .001)) +interact(changeTransmissionRoughess, transmission_roughness=(0.0, 1.0, .001)) +interact(changeAnisotropy, anisotropy=(0.0, 1.0, .001)) +#%% +def changeColor(hue=0, sat=0, val=1): + rgb = colorsys.hsv_to_rgb(hue, sat, val) + inner.get_material().set_base_color(v.vec3(rgb[0], rgb[1], rgb[2])) +def changeRoughness(roughness=1): inner.get_material().set_roughness(roughness) +def changeTransmission(transmission=0): inner.get_material().set_transmission(transmission) +def changeIor(ior=1.57): inner.get_material().set_ior(ior) +def changeSheen(sheen=0): inner.get_material().set_sheen(sheen) +def changeClearCoat(clearcoat=0): inner.get_material().set_clearcoat(clearcoat) +def changeClearCoatRoughness(clearcoat_roughness=0): inner.get_material().set_clearcoat_roughness(clearcoat_roughness) +def changeMetallic(metallic=0): inner.get_material().set_metallic(metallic) +def changeSpecularTint(specular_tint=0): inner.get_material().set_specular_tint(specular_tint) +def changeSpecular(specular=1): inner.get_material().set_specular(specular) +def changeSubsurface(subsurface=0): inner.get_material().set_subsurface(subsurface) +def changeTransmissionRoughess(transmission_roughness=0): inner.get_material().set_transmission_roughness(transmission_roughness) +def changeAnisotropy(anisotropy=0): inner.get_material().set_anisotropic(anisotropy) +interact(changeColor, hue=(0.0, 1.0, .001), sat=(0.0, 1.0, .001), val=(0.0, 1.0, .001)) +>>>>>>> Stashed changes interact(changeRoughness, roughness=(0.0, 1.0, .001)) interact(changeTransmission, transmission=(0.0, 1.0, .001)) interact(changeIor, ior=(0.0, 2.0, .001)) @@ -129,11 +197,66 @@ def changeTransmissionRoughess(transmission_roughness=0): interact(changeSpecular, specular=(0.0, 2.0, .001)) interact(changeSubsurface, subsurface=(0.0, 1.0, .001)) interact(changeTransmissionRoughess, transmission_roughness=(0.0, 1.0, .001)) +<<<<<<< Updated upstream #%% def changeDomeLightIntensity(dome_intensity=0): v.set_dome_light_intensity(dome_intensity) interact(changeDomeLightIntensity, dome_intensity=(0.0, 1.0, .001)) #%% areaLight1.get_light().set_intensity(10000.) +======= +interact(changeAnisotropy, anisotropy=(0.0, 1.0, .001)) +interact(changeColor, hue=(0.0, 1.0, .001), sat=(0.0, 1.0, .001), val=(0.0, 1.0, .001)) + + +#%% +def changeLinearVelocity(lx=0, ly=0, lz=0): + inner.get_transform().set_linear_velocity(v.vec3(lx,ly,lz)) + outer.get_transform().set_linear_velocity(v.vec3(lx,ly,lz)) +interact(changeLinearVelocity, lx=(-1.0, 1.0, .001), ly=(-1.0, 1.0, .001), lz=(-1.0, 1.0, .001)) + +def changeScalarVelocity(sx=0, sy=0, sz=0): + inner.get_transform().set_scalar_velocity(v.vec3(sx,sy,sz)) + outer.get_transform().set_scalar_velocity(v.vec3(sx,sy,sz)) +interact(changeScalarVelocity, sx=(-1.0, 1.0, .001), sy=(-1.0, 1.0, .001), sz=(-1.0, 1.0, .001)) + +def changeAngularVelocity(ax=0, ay=0, az=0): + q = v.quat(1,0,0,0) + q = v.angleAxis(ax, v.vec3(1,0,0)) * q + q = v.angleAxis(ay, v.vec3(0,1,0)) * q + q = v.angleAxis(az, v.vec3(0,0,1)) * q + inner.get_transform().set_angular_velocity(q) + outer.get_transform().set_angular_velocity(q) +interact(changeAngularVelocity, ax=(-1.0, 1.0, .001), ay=(-1.0, 1.0, .001), az=(-1.0, 1.0, .001)) + +def changePosition(x=0, y=0, z=0): + inner.get_transform().set_position(v.vec3(x,y,z)) + outer.get_transform().set_position(v.vec3(x,y,z)) +interact(changePosition, x=(-1.0, 1.0, .001), y=(-1.0, 1.0, .001), z=(-1.0, 1.0, .001)) + +def changeScale(sx=1, sy=1, sz=1): + inner.get_transform().set_scale(v.vec3(sx,sy,sz)) + outer.get_transform().set_scale(v.vec3(sx,sy,sz)) +interact(changeScale, sx=(-1.0, 1.0, .001), sy=(-1.0, 1.0, .001), sz=(-1.0, 1.0, .001)) + +def changeRotation(ax=3.14 * .5, ay=0, az=0): + q = v.quat(1,0,0,0) + q = v.angleAxis(ax, v.vec3(1,0,0)) * q + q = v.angleAxis(ay, v.vec3(0,1,0)) * q + q = v.angleAxis(az, v.vec3(0,0,1)) * q + inner.get_transform().set_rotation(q) + outer.get_transform().set_rotation(q) +interact(changeRotation, ax=(-3.14, 3.14, .001), ay=(-3.14, 3.14, .001), az=(-3.14, 3.14, .001)) + +# v.sample_time_interval(v.vec2(1)) +# v.sample_pixel_area(v.vec2(.5), v.vec2(.5)) +#%% +def changeDomeLightIntensity(dome_intensity=1): v.set_dome_light_intensity(dome_intensity) +interact(changeDomeLightIntensity, dome_intensity=(0.0, 4.0, .001)) +#%% +def changeLightIntensity(intensity=100): light.get_light().set_intensity(intensity) +interact(changeLightIntensity, intensity=(0.0, 1000.0, .001)) + +>>>>>>> Stashed changes #%% def moveLight(x = 0, y = 0, z = 3): areaLight1.get_transform().set_position(v.vec3(x,y,z)) interact(moveLight, x=(0.0, 5.0, .001), y=(0.0, 5.0, .001), z=(-5.0, 5.0, .001)) @@ -265,3 +388,83 @@ def rotateLight(rx = 0, ry = 0., rz = 0): # %% +<<<<<<< Updated upstream +======= +glasses = v.entity.create( + name = "glasses", + mesh = v.mesh.create_from_obj(name = "glasses", path="C:/Users/natevm/3D Objects/glasses/LE_V1_0131_Ikea_Glass_Pokal.obj"), + material = v.material.create(name = "glasses", base_color = v.vec3(1), roughness = 0, transmission = 1), + transform = v.transform.create(name = "glasses") +) + +# %% +glasses.get_transform().set_position(v.vec3(0,0,0.1)) +glasses.get_transform().set_rotation(v.angleAxis(3.14 * .5, v.vec3(1,0,0))) +glasses.get_transform().set_scale(v.vec3(.2)) +glasses.get_material().set_base_color(v.vec3(1, 1, 1)) +# %% +mesh1.get_transform().set_position(v.vec3(-8, 2, 1)) + +# %% +floor.get_material().set_roughness(1.0) +floor.get_material().set_metallic(0) + + + +# %% +mesh2.get_material().set_normal_map_texture(normtex) +floor.get_material().set_normal_map_texture(normtex) + + +# %% +v.set_indirect_lighting_clamp(0.001) + +# %% +mesh2.get_transform().set_rotation(v.angleAxis(3.14, v.vec3(1,0,0))) + +# %% +floor.get_material().clear_normal_map_texture() + +# %% +inner.set_light(light.get_light()) + +# %% +inner.clear_light() + +# %% +v.set_direct_lighting_clamp(10.0) +v.set_indirect_lighting_clamp(10.0) +# %% +orm = v.texture.create_from_image("ORM", "../data/RustedMetal_ORM.png", linear=True) + +# %% +norm = v.texture.create_from_image("N", "../data/RustedMetal_N.png", linear=True) + + +# %% +base = v.texture.create_from_image("Base", "../data/RustedMetal_BaseColor.png", linear=True) + +# %% +outer.get_material().set_base_color_texture(base) +outer.get_material().set_normal_map_texture(norm2) +outer.get_material().set_roughness_texture(orm, channel=1) +outer.get_material().set_metallic_texture(orm, channel=2) + +# %% + +# %% + +# %% +outer.get_material().clear_normal_map_texture() + +# %% +norm2 = v.texture.create_from_image("N2", "../data/normal.png", linear=True) + +# %% +norm2 = v.texture.create_from_image("N4", "../data/RustedMetal_N.png", linear=True) + +# %% +outer.get_material().set_normal_map_texture(norm2) + +# %% +>>>>>>> Stashed changes From b3de17b7fb0aa568d2704e6a01031b7d685f11b7 Mon Sep 17 00:00:00 2001 From: n8vm Date: Mon, 27 Jul 2020 11:07:42 -0600 Subject: [PATCH 03/25] Improving specular color noise --- src/visii/devicecode/disney_bsdf.h | 9 +- src/visii/devicecode/launch_params.h | 1 + src/visii/devicecode/path_tracer.cu | 60 ++----- src/visii/visii.cpp | 69 ++++++++ tests/test_area_light_noise.py | 249 ++++++++------------------- 5 files changed, 164 insertions(+), 224 deletions(-) diff --git a/src/visii/devicecode/disney_bsdf.h b/src/visii/devicecode/disney_bsdf.h index 6e844e9f..00cf32f8 100644 --- a/src/visii/devicecode/disney_bsdf.h +++ b/src/visii/devicecode/disney_bsdf.h @@ -408,9 +408,9 @@ __device__ float3 disney_microfacet_reflection_color(const DisneyMaterial &mat, float3 spec = lerp(mat.specular * 0.08f * lerp(make_float3(1.f), tint, mat.specular_tint), mat.base_color, mat.metallic); float alpha = max(MIN_ALPHA, mat.roughness * mat.roughness); - float3 f = lerp(spec, make_float3(1.f), schlick_weight(dot(w_i, w_h))); - float g = smith_shadowing_ggx(dot(n, w_i), alpha) * smith_shadowing_ggx(dot(n, w_o), alpha); - return f * g; + float3 f = lerp(spec, make_float3(1.f), schlick_weight(dot(w_o, n))); + // float3 f = lerp(spec, make_float3(1.f), schlick_weight(dot(w_i, w_h))); + return f; } __device__ float3 disney_microfacet_isotropic(const DisneyMaterial &mat, const float3 &n, @@ -423,7 +423,8 @@ __device__ float3 disney_microfacet_isotropic(const DisneyMaterial &mat, const f float alpha = max(MIN_ALPHA, mat.roughness * mat.roughness); float d = gtr_2(dot(n, w_h), alpha); - float3 f = lerp(spec, make_float3(1.f), schlick_weight(dot(w_i, w_h))); + // float3 f = lerp(spec, make_float3(1.f), schlick_weight(dot(w_i, w_h))); // seems to be noisy + float3 f = lerp(spec, make_float3(1.f), schlick_weight(dot(w_o, n))); float g = smith_shadowing_ggx(dot(n, w_i), alpha) * smith_shadowing_ggx(dot(n, w_o), alpha); return d * f * g; } diff --git a/src/visii/devicecode/launch_params.h b/src/visii/devicecode/launch_params.h index 6dd8a6e6..d18e8479 100644 --- a/src/visii/devicecode/launch_params.h +++ b/src/visii/devicecode/launch_params.h @@ -85,6 +85,7 @@ enum RenderDataFlags : uint32_t { TRANSMISSION_COLOR = 15, TRANSMISSION_DIRECT_LIGHTING = 16, TRANSMISSION_INDIRECT_LIGHTING = 17 + RAY_DIRECTION = 18, }; // #define REPROJECT true diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index 3a6cad04..2717d1b7 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -168,14 +168,13 @@ float sampleTime(float xi) { } inline __device__ -owl::Ray generateRay(const CameraStruct &camera, const TransformStruct &transform, ivec2 pixelID, ivec2 frameSize, LCGRand &rng) +owl::Ray generateRay(const CameraStruct &camera, const TransformStruct &transform, ivec2 pixelID, ivec2 frameSize, LCGRand &rng, float time) { /* Generate camera rays */ glm::quat r0 = glm::quat_cast(optixLaunchParams.viewT0); glm::quat r1 = glm::quat_cast(optixLaunchParams.viewT1); glm::vec4 p0 = glm::column(optixLaunchParams.viewT0, 3); glm::vec4 p1 = glm::column(optixLaunchParams.viewT1, 3); - float time = sampleTime(lcg_randomf(rng)); glm::vec4 pos = glm::mix(p0, p1, time); glm::quat rot = glm::slerp(r0, r1, time); @@ -315,7 +314,8 @@ void saveGeometricRenderData( float3 &renderData, int bounce, float depth, float3 w_p, float3 w_n, float3 w_o, - int entity_id, DisneyMaterial &mat) + int entity_id, float3 diffuse_mvec, + DisneyMaterial &mat) { if (optixLaunchParams.renderDataMode == RenderDataFlags::NONE) return; if (bounce != optixLaunchParams.renderDataBounce) return; @@ -359,6 +359,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() auto pixelID = ivec2(owl::getLaunchIndex()[0], owl::getLaunchIndex()[1]); auto fbOfs = pixelID.x+optixLaunchParams.frameSize.x* ((optixLaunchParams.frameSize.y - 1) - pixelID.y); LCGRand rng = get_rng(optixLaunchParams.frameID + optixLaunchParams.seed * 10007); + float time = sampleTime(lcg_randomf(rng)); // If no camera is in use, just display some random noise... EntityStruct camera_entity; @@ -387,7 +388,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() { // Trace an initial ray through the scene - owl::Ray ray = generateRay(camera, camera_transform, pixelID, optixLaunchParams.frameSize, rng); + owl::Ray ray = generateRay(camera, camera_transform, pixelID, optixLaunchParams.frameSize, rng, time); DisneyMaterial mat; int bounce = 0; @@ -415,7 +416,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() float roughnessMinimum = 0.f; RayPayload payload; payload.tHit = -1.f; - ray.time = sampleTime(lcg_randomf(rng)); + ray.time = time; owl::traceRay( /*accel to trace against*/ optixLaunchParams.world, /*the ray to trace*/ ray, /*prd*/ payload); @@ -438,7 +439,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() if ((bounce == 0) && ((entity.visibilityFlags & ENTITY_VISIBILITY_CAMERA_RAYS) == 0)) { ray.origin = ray.origin + ray.direction * (payload.tHit + EPSILON); payload.tHit = -1.f; - ray.time = sampleTime(lcg_randomf(rng)); + ray.time = time; owl::traceRay( optixLaunchParams.world, ray, payload); visibilitySkips++; if (visibilitySkips > 10) break; // avoid locking up. @@ -542,13 +543,8 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() v_z = faceNormalForward(w_o, v_gz, v_z); } -<<<<<<< HEAD // For segmentations, geometric metadata extraction dependent on the hit object - saveGeometricRenderData(renderData, bounce, payload.tHit, hit_p, v_z, w_o, entityID, mat); -======= - // For segmentations, metadata extraction for applications like denoising or ML training - saveRenderData(renderData, bounce, payload.tHit, hit_p, v_z, entityID, diffuseMotion, mat.base_color); ->>>>>>> development + saveGeometricRenderData(renderData, bounce, payload.tHit, hit_p, v_z, w_o, entityID, diffuseMotion, mat); // If this is the first hit, keep track of primary albedo and normal for denoising. if (bounce == 0) { @@ -666,7 +662,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() ray.origin = hit_p; ray.direction = light_dir; payload.tHit = -1.f; - ray.time = sampleTime(lcg_randomf(rng)); + ray.time = time; owl::traceRay( optixLaunchParams.world, ray, payload, occlusion_flags); if (payload.instanceID == -1) continue; int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; @@ -689,6 +685,9 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() float3 bsdf = sample_disney_brdf(mat, v_z, w_o, v_x, v_y, rng, w_i, bsdf_pdf, sampledBsdf, forcedBsdf, optixLaunchParams.GGX_E_LOOKUP, optixLaunchParams.GGX_E_AVG_LOOKUP); + // For segmentations, lighting metadata extraction dependent on sampling the BSDF + saveLightingColorRenderData(renderData, bounce, v_z, w_o, w_i, mat); + // terminate if the bsdf probability is impossible, or if the bsdf filters out all light if (bsdf_pdf < EPSILON || all_zero(bsdf)) { break; @@ -755,7 +754,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() } // For segmentations, lighting metadata extraction dependent on sampling the BSDF - saveLightingColorRenderData(renderData, bounce, v_z, w_o, w_i, mat); + // saveLightingColorRenderData(renderData, bounce, v_z, w_o, w_i, mat); if (bounce == 0) { directIllum = illum; @@ -821,34 +820,6 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() ); float3 color = make_float3(accum_color); -<<<<<<< HEAD - - // color = uncharted_2_tonemap(color * exposure); - // color = color * (1.0f / uncharted_2_tonemap(make_float3(11.2f))); - - // color.x = linear_to_srgb(color.x); - // color.y = linear_to_srgb(color.y); - // color.z = linear_to_srgb(color.z); - - if (optixLaunchParams.renderDataMode == RenderDataFlags::NONE) - { - optixLaunchParams.frameBuffer[fbOfs] = vec4( - color.x, - color.y, - color.z, - 1.0f - ); - } - // Override framebuffer output if user requested to render metadata - else - { - vec3 oldRenderData = vec3(optixLaunchParams.frameBuffer[fbOfs]); - vec3 newRenderData = make_vec3(renderData); - vec3 accumData = (newRenderData + float(optixLaunchParams.frameID) * oldRenderData) / float(optixLaunchParams.frameID + 1); - optixLaunchParams.frameBuffer[fbOfs] = vec4( accumData.x, accumData.y, accumData.z, 1.0f); - } - -======= optixLaunchParams.frameBuffer[fbOfs] = vec4( color.x, color.y, @@ -856,7 +827,6 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() 1.0f ); ->>>>>>> development vec4 oldAlbedo = optixLaunchParams.albedoBuffer[fbOfs]; vec4 oldNormal = optixLaunchParams.normalBuffer[fbOfs]; if (any(isnan(oldAlbedo))) oldAlbedo = vec4(1.f); @@ -869,12 +839,8 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() optixLaunchParams.albedoBuffer[fbOfs] = accumAlbedo; optixLaunchParams.normalBuffer[fbOfs] = accumNormal; -<<<<<<< HEAD - -======= // Override framebuffer output if user requested to render metadata if (optixLaunchParams.renderDataMode != RenderDataFlags::NONE) { optixLaunchParams.frameBuffer[fbOfs] = vec4( renderData.x, renderData.y, renderData.z, 1.0f); } ->>>>>>> development } diff --git a/src/visii/visii.cpp b/src/visii/visii.cpp index 7242db94..c3bcfa9b 100644 --- a/src/visii/visii.cpp +++ b/src/visii/visii.cpp @@ -1348,6 +1348,9 @@ std::vector renderData(uint32_t width, uint32_t height, uint32_t startFra else if (option == std::string("depth")) { OptixData.LP.renderDataMode = RenderDataFlags::DEPTH; } + else if (option == std::string("ray_direction")) { + OptixData.LP.renderDataMode = RenderDataFlags::RAY_DIRECTION; + } else if (option == std::string("position")) { OptixData.LP.renderDataMode = RenderDataFlags::POSITION; } @@ -1695,5 +1698,71 @@ void deinitialize() } void __test__(std::vector args) { + if (args.size() != 1) return; + + std::string option = args[0]; + if (option == std::string("none")) { + OptixData.LP.renderDataMode = RenderDataFlags::NONE; + } + else if (option == std::string("depth")) { + OptixData.LP.renderDataMode = RenderDataFlags::DEPTH; + } + else if (option == std::string("ray_direction")) { + OptixData.LP.renderDataMode = RenderDataFlags::RAY_DIRECTION; + } + else if (option == std::string("position")) { + OptixData.LP.renderDataMode = RenderDataFlags::POSITION; + } + else if (option == std::string("normal")) { + OptixData.LP.renderDataMode = RenderDataFlags::NORMAL; + } + else if (option == std::string("entity_id")) { + OptixData.LP.renderDataMode = RenderDataFlags::ENTITY_ID; + } + else if (option == std::string("base_color")) { + OptixData.LP.renderDataMode = RenderDataFlags::BASE_COLOR; + } + else if (option == std::string("denoise_normal")) { + OptixData.LP.renderDataMode = RenderDataFlags::DENOISE_NORMAL; + } + else if (option == std::string("denoise_albedo")) { + OptixData.LP.renderDataMode = RenderDataFlags::DENOISE_ALBEDO; + } + else if (option == std::string("diffuse_color")) { + OptixData.LP.renderDataMode = RenderDataFlags::DIFFUSE_COLOR; + } + else if (option == std::string("diffuse_direct_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::DIFFUSE_DIRECT_LIGHTING; + } + else if (option == std::string("diffuse_indirect_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::DIFFUSE_INDIRECT_LIGHTING; + } + else if (option == std::string("glossy_color")) { + OptixData.LP.renderDataMode = RenderDataFlags::GLOSSY_COLOR; + } + else if (option == std::string("glossy_direct_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::GLOSSY_DIRECT_LIGHTING; + } + else if (option == std::string("glossy_indirect_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::GLOSSY_INDIRECT_LIGHTING; + } + else if (option == std::string("transmission_color")) { + OptixData.LP.renderDataMode = RenderDataFlags::TRANSMISSION_COLOR; + } + else if (option == std::string("transmission_direct_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING; + } + else if (option == std::string("transmission_indirect_lighting")) { + OptixData.LP.renderDataMode = RenderDataFlags::TRANSMISSION_INDIRECT_LIGHTING; + } + else if (option == std::string("diffuse_motion_vectors")) { + OptixData.LP.renderDataMode = RenderDataFlags::DIFFUSE_MOTION_VECTORS; + } + else { + throw std::runtime_error(std::string("Error, unknown option : \"") + option + std::string("\". ") + + std::string("See documentation for available options")); + } + + resetAccumulation(); } \ No newline at end of file diff --git a/tests/test_area_light_noise.py b/tests/test_area_light_noise.py index c790c942..6d00f0ae 100644 --- a/tests/test_area_light_noise.py +++ b/tests/test_area_light_noise.py @@ -1,10 +1,7 @@ #%% -<<<<<<< Updated upstream -import sys, os, math -======= import sys, os, math, colorsys os.environ["CUDA_VISIBLE_DEVICES"] = "0" ->>>>>>> Stashed changes +import sys, os, math, colorsys os.add_dll_directory(os.path.join(os.getcwd(), '..', 'install')) sys.path.append(os.path.join(os.getcwd(), "..", "install")) @@ -23,138 +20,70 @@ #%% from ipywidgets import interact -def moveCamera(x=3,y=3,z=2): +def moveCamera(x=0,y=3,z=2): camera_entity.get_transform().look_at( - v.vec3(0,0,2.0), + v.vec3(0,0,0.0), v.vec3(0,0,1), v.vec3(x,y,z), ) # camera_entity.get_transform().set_position(0, 0.0, x) interact(moveCamera, x=(-10, 10, .001), y=(-10, 10, .001), z=(-10, 10, .001)) +camera_entity.get_camera().use_perspective_from_fov(field_of_view = 0.785398, aspect = 1080.0/1080.0) + #%% -<<<<<<< Updated upstream -tex = v.texture.create_from_image("texture", "../data/abandoned_tank_farm_01_1k.hdr") +tex = v.texture.create_from_image("texture", "../data/dome.hdr") v.set_dome_light_texture(tex) -======= -def moveCameraNext(x=0,y=3,z=2): - camera_entity.get_transform().next_look_at( - v.vec3(0,0,0.0), - v.vec3(0,0,1), - v.vec3(x,y,z), - ) - # camera_entity.get_transform().set_position(0, 0.0, x) -interact(moveCameraNext, x=(-10, 10, .001), y=(-10, 10, .001), z=(-10, 10, .001)) + #%% # tex = v.texture.create_from_image("texture", "../data/dome.hdr") # v.set_dome_light_texture(tex) ->>>>>>> Stashed changes + #%% -floor = v.entity.create( - name="floor", - mesh = v.mesh.create_plane("floor"), - transform = v.transform.create("floor"), - material = v.material.create("floor") -) -#%% -mesh1 = v.entity.create( - name="mesh1", - mesh = v.mesh.create_from_obj("mesh2", "../data/dragon.obj"), - transform = v.transform.create("mesh1"), - material = v.material.create("mesh1") +entities_obj = v.import_obj( + "knob", # prefix name + 'C:/Users/natevm/3D Objects/mori_knob/mori_knob_subdiv.obj', #obj path + 'C:/Users/natevm/3D Objects/mori_knob/', # mtl folder + v.vec3(0,0,0), # translation + v.vec3(1), # scale here + v.angleAxis(3.14 * .5, v.vec3(1,0,0)) #rotation here ) #%% -mesh2 = v.entity.create( - name="mesh2", - mesh = v.mesh.create_sphere("sphere2"), - transform = v.transform.create("mesh2"), - material = v.material.create("mesh2") -) +# Light +light = entities_obj[0] +light.set_light(v.light.create("areaLight1"),) -# %% -mesh1.get_transform().set_scale(v.vec3(4)) -mesh1.get_transform().set_rotation(v.angleAxis(1.57, v.vec3(1,0,0))) -mesh1.get_transform().set_position(v.vec3(0,0,1.0)) +#%% Light +floor = entities_obj[1] -#%% -<<<<<<< Updated upstream -areaLight1 = v.entity.create( - name="areaLight1", - light = v.light.create("areaLight1"), - transform = v.transform.create("areaLight1"), - mesh = v.mesh.create_sphere("areaLight1"), -) -# %% -areaLight1.get_transform().set_scale(v.vec3(.25)) -#%% -floor.get_transform().set_scale(v.vec3(1000)) -mesh1.get_transform().set_scale(v.vec3(.5)) -areaLight1.get_transform().set_position(v.vec3(0, 0, 4)) -areaLight1.get_transform().set_scale(v.vec3(.5)) -floor.get_material().set_roughness(1.0) -mesh1.get_material().set_base_color(v.vec3(1.0, 1.0, 1.0)) -mesh2.get_material().set_base_color(v.vec3(1.0, 1.0, 1.0)) -mesh1.get_transform().set_position(v.vec3(-1.0, 1.0, 0.0)) -mesh2.get_transform().set_position(v.vec3(-1.0, 3.0, 1.0)) +#%% LTE Logo +lteLogo = entities_obj[2] -mesh1.get_transform().set_scale(v.vec3(4)) -mesh1.get_transform().set_rotation(v.angleAxis(1.57, v.vec3(1,0,0))) -mesh1.get_transform().set_position(v.vec3(0,0,1.0)) +#%% outer +outer = entities_obj[3] + +#%% inner +inner = entities_obj[4] #%% -#%% -def changeRoughness(roughness=0): - mesh1.get_material().set_roughness(roughness) - mesh2.get_material().set_roughness(roughness) -def changeTransmission(transmission=1): - mesh1.get_material().set_transmission(transmission) - mesh2.get_material().set_transmission(transmission) -def changeIor(ior=1.57): - mesh1.get_material().set_ior(ior) - mesh2.get_material().set_ior(ior) -def changeSheen(sheen=0): - mesh1.get_material().set_sheen(sheen) - mesh2.get_material().set_sheen(sheen) -def changeClearCoat(clearcoat=0): - mesh1.get_material().set_clearcoat(clearcoat) - mesh2.get_material().set_clearcoat(clearcoat) -def changeClearCoatRoughness(clearcoat_roughness=0): - mesh1.get_material().set_clearcoat_roughness(clearcoat_roughness) - mesh2.get_material().set_clearcoat_roughness(clearcoat_roughness) -def changeMetallic(metallic=0): - mesh1.get_material().set_metallic(metallic) - mesh2.get_material().set_metallic(metallic) -def changeSpecularTint(specular_tint=0): - mesh1.get_material().set_specular_tint(specular_tint) - mesh2.get_material().set_specular_tint(specular_tint) -def changeSpecular(specular=1): - mesh1.get_material().set_specular(specular) - mesh2.get_material().set_specular(specular) -def changeSubsurface(subsurface=0): - mesh1.get_material().set_subsurface(subsurface) - mesh2.get_material().set_subsurface(subsurface) -def changeTransmissionRoughess(transmission_roughness=0): - mesh1.get_material().set_transmission_roughness(transmission_roughness) - mesh2.get_material().set_transmission_roughness(transmission_roughness) -======= def changeColor(hue=0, sat=0, val=1): rgb = colorsys.hsv_to_rgb(hue, sat, val) - outer.get_material().set_base_color(v.vec3(rgb[0], rgb[1], rgb[2])) -def changeRoughness(roughness=1): outer.get_material().set_roughness(roughness) -def changeTransmission(transmission=0): outer.get_material().set_transmission(transmission) -def changeIor(ior=1.57): outer.get_material().set_ior(ior) -def changeSheen(sheen=0): outer.get_material().set_sheen(sheen) -def changeClearCoat(clearcoat=0): outer.get_material().set_clearcoat(clearcoat) -def changeClearCoatRoughness(clearcoat_roughness=0): outer.get_material().set_clearcoat_roughness(clearcoat_roughness) -def changeMetallic(metallic=0): outer.get_material().set_metallic(metallic) -def changeSpecularTint(specular_tint=0): outer.get_material().set_specular_tint(specular_tint) -def changeSpecular(specular=1): outer.get_material().set_specular(specular) -def changeSubsurface(subsurface=0): outer.get_material().set_subsurface(subsurface) -def changeTransmissionRoughess(transmission_roughness=0): outer.get_material().set_transmission_roughness(transmission_roughness) -def changeAnisotropy(anisotropy=0): outer.get_material().set_anisotropic(anisotropy) + inner.get_material().set_base_color(v.vec3(rgb[0], rgb[1], rgb[2])) +def changeRoughness(roughness=0): inner.get_material().set_roughness(roughness) +def changeTransmission(transmission=0): inner.get_material().set_transmission(transmission) +def changeIor(ior=1.57): inner.get_material().set_ior(ior) +def changeSheen(sheen=0): inner.get_material().set_sheen(sheen) +def changeClearCoat(clearcoat=0): inner.get_material().set_clearcoat(clearcoat) +def changeClearCoatRoughness(clearcoat_roughness=0): inner.get_material().set_clearcoat_roughness(clearcoat_roughness) +def changeMetallic(metallic=1): inner.get_material().set_metallic(metallic) +def changeSpecularTint(specular_tint=0): inner.get_material().set_specular_tint(specular_tint) +def changeSpecular(specular=1): inner.get_material().set_specular(specular) +def changeSubsurface(subsurface=0): inner.get_material().set_subsurface(subsurface) +def changeTransmissionRoughess(transmission_roughness=0): inner.get_material().set_transmission_roughness(transmission_roughness) +def changeAnisotropy(anisotropy=0): inner.get_material().set_anisotropic(anisotropy) interact(changeColor, hue=(0.0, 1.0, .001), sat=(0.0, 1.0, .001), val=(0.0, 1.0, .001)) interact(changeRoughness, roughness=(0.0, 1.0, .001)) interact(changeTransmission, transmission=(0.0, 1.0, .001)) @@ -171,21 +100,20 @@ def changeAnisotropy(anisotropy=0): outer.get_material().set_anisotropic(anisotr #%% def changeColor(hue=0, sat=0, val=1): rgb = colorsys.hsv_to_rgb(hue, sat, val) - inner.get_material().set_base_color(v.vec3(rgb[0], rgb[1], rgb[2])) -def changeRoughness(roughness=1): inner.get_material().set_roughness(roughness) -def changeTransmission(transmission=0): inner.get_material().set_transmission(transmission) -def changeIor(ior=1.57): inner.get_material().set_ior(ior) -def changeSheen(sheen=0): inner.get_material().set_sheen(sheen) -def changeClearCoat(clearcoat=0): inner.get_material().set_clearcoat(clearcoat) -def changeClearCoatRoughness(clearcoat_roughness=0): inner.get_material().set_clearcoat_roughness(clearcoat_roughness) -def changeMetallic(metallic=0): inner.get_material().set_metallic(metallic) -def changeSpecularTint(specular_tint=0): inner.get_material().set_specular_tint(specular_tint) -def changeSpecular(specular=1): inner.get_material().set_specular(specular) -def changeSubsurface(subsurface=0): inner.get_material().set_subsurface(subsurface) -def changeTransmissionRoughess(transmission_roughness=0): inner.get_material().set_transmission_roughness(transmission_roughness) -def changeAnisotropy(anisotropy=0): inner.get_material().set_anisotropic(anisotropy) + outer.get_material().set_base_color(v.vec3(rgb[0], rgb[1], rgb[2])) +def changeRoughness(roughness=1): outer.get_material().set_roughness(roughness) +def changeTransmission(transmission=0): outer.get_material().set_transmission(transmission) +def changeIor(ior=1.57): outer.get_material().set_ior(ior) +def changeSheen(sheen=0): outer.get_material().set_sheen(sheen) +def changeClearCoat(clearcoat=0): outer.get_material().set_clearcoat(clearcoat) +def changeClearCoatRoughness(clearcoat_roughness=0): outer.get_material().set_clearcoat_roughness(clearcoat_roughness) +def changeMetallic(metallic=0): outer.get_material().set_metallic(metallic) +def changeSpecularTint(specular_tint=0): outer.get_material().set_specular_tint(specular_tint) +def changeSpecular(specular=1): outer.get_material().set_specular(specular) +def changeSubsurface(subsurface=0): outer.get_material().set_subsurface(subsurface) +def changeTransmissionRoughess(transmission_roughness=0): outer.get_material().set_transmission_roughness(transmission_roughness) +def changeAnisotropy(anisotropy=0): outer.get_material().set_anisotropic(anisotropy) interact(changeColor, hue=(0.0, 1.0, .001), sat=(0.0, 1.0, .001), val=(0.0, 1.0, .001)) ->>>>>>> Stashed changes interact(changeRoughness, roughness=(0.0, 1.0, .001)) interact(changeTransmission, transmission=(0.0, 1.0, .001)) interact(changeIor, ior=(0.0, 2.0, .001)) @@ -197,17 +125,7 @@ def changeAnisotropy(anisotropy=0): inner.get_material().set_anisotropic(anisotr interact(changeSpecular, specular=(0.0, 2.0, .001)) interact(changeSubsurface, subsurface=(0.0, 1.0, .001)) interact(changeTransmissionRoughess, transmission_roughness=(0.0, 1.0, .001)) -<<<<<<< Updated upstream -#%% -def changeDomeLightIntensity(dome_intensity=0): v.set_dome_light_intensity(dome_intensity) -interact(changeDomeLightIntensity, dome_intensity=(0.0, 1.0, .001)) -#%% -areaLight1.get_light().set_intensity(10000.) -======= interact(changeAnisotropy, anisotropy=(0.0, 1.0, .001)) -interact(changeColor, hue=(0.0, 1.0, .001), sat=(0.0, 1.0, .001), val=(0.0, 1.0, .001)) - - #%% def changeLinearVelocity(lx=0, ly=0, lz=0): inner.get_transform().set_linear_velocity(v.vec3(lx,ly,lz)) @@ -228,27 +146,6 @@ def changeAngularVelocity(ax=0, ay=0, az=0): outer.get_transform().set_angular_velocity(q) interact(changeAngularVelocity, ax=(-1.0, 1.0, .001), ay=(-1.0, 1.0, .001), az=(-1.0, 1.0, .001)) -def changePosition(x=0, y=0, z=0): - inner.get_transform().set_position(v.vec3(x,y,z)) - outer.get_transform().set_position(v.vec3(x,y,z)) -interact(changePosition, x=(-1.0, 1.0, .001), y=(-1.0, 1.0, .001), z=(-1.0, 1.0, .001)) - -def changeScale(sx=1, sy=1, sz=1): - inner.get_transform().set_scale(v.vec3(sx,sy,sz)) - outer.get_transform().set_scale(v.vec3(sx,sy,sz)) -interact(changeScale, sx=(-1.0, 1.0, .001), sy=(-1.0, 1.0, .001), sz=(-1.0, 1.0, .001)) - -def changeRotation(ax=3.14 * .5, ay=0, az=0): - q = v.quat(1,0,0,0) - q = v.angleAxis(ax, v.vec3(1,0,0)) * q - q = v.angleAxis(ay, v.vec3(0,1,0)) * q - q = v.angleAxis(az, v.vec3(0,0,1)) * q - inner.get_transform().set_rotation(q) - outer.get_transform().set_rotation(q) -interact(changeRotation, ax=(-3.14, 3.14, .001), ay=(-3.14, 3.14, .001), az=(-3.14, 3.14, .001)) - -# v.sample_time_interval(v.vec2(1)) -# v.sample_pixel_area(v.vec2(.5), v.vec2(.5)) #%% def changeDomeLightIntensity(dome_intensity=1): v.set_dome_light_intensity(dome_intensity) interact(changeDomeLightIntensity, dome_intensity=(0.0, 4.0, .001)) @@ -256,25 +153,25 @@ def changeDomeLightIntensity(dome_intensity=1): v.set_dome_light_intensity(dome_ def changeLightIntensity(intensity=100): light.get_light().set_intensity(intensity) interact(changeLightIntensity, intensity=(0.0, 1000.0, .001)) ->>>>>>> Stashed changes #%% -def moveLight(x = 0, y = 0, z = 3): areaLight1.get_transform().set_position(v.vec3(x,y,z)) -interact(moveLight, x=(0.0, 5.0, .001), y=(0.0, 5.0, .001), z=(-5.0, 5.0, .001)) -def scaleLight(sx = 1, sy = 1., sz = 1): areaLight1.get_transform().set_scale(v.vec3(sx, sy, sz)) +def moveLight(x = 0, y = 0, z = 3): light.get_transform().set_position(v.vec3(x,y,z)) +interact(moveLight, x=(-5.0, 5.0, .001), y=(-5.0, 5.0, .001), z=(-5.0, 5.0, .001)) +def scaleLight(sx = 1, sy = 1., sz = 1): light.get_transform().set_scale(v.vec3(sx, sy, sz)) interact(scaleLight, sx=(0.0001, 1.0, .001), sy=(0.0001, 1.0, .001), sz=(0.0001, 1.0, .001)) -def rotateLight(rx = 0, ry = 0., rz = 0): - areaLight1.get_transform().set_rotation(v.angleAxis(rx, v.vec3(1,0,0))) - areaLight1.get_transform().add_rotation(v.angleAxis(ry, v.vec3(0,1,0))) - areaLight1.get_transform().add_rotation(v.angleAxis(rz, v.vec3(0,0,1))) +def rotateLight(rx = 1.57, ry = 0., rz = 0): + light.get_transform().set_rotation(v.angleAxis(rx, v.vec3(1,0,0))) + light.get_transform().add_rotation(v.angleAxis(ry, v.vec3(0,1,0))) + light.get_transform().add_rotation(v.angleAxis(rz, v.vec3(0,0,1))) interact(rotateLight, rx=(-3.14, 3.14, .001), ry=(-3.14, 3.14, .001), rz=(-3.14, 3.14, .001)) -areaLight1.get_transform().set_scale(v.vec3(.25)) -floor.get_transform().set_scale(v.vec3(100)) -areaLight1.get_light().set_temperature(4000) +# light.get_transform().set_scale(v.vec3(.25)) +# floor.get_transform().set_scale(v.vec3(100)) +light.get_light().set_temperature(8000) # %% +light.set_visibility(False) # %% -v.render_to_png(512,512,1024,"area_light_3.png") +v.render_to_png(1080,1080,1024,"owl09.png") # %% v.enable_denoiser() @@ -325,7 +222,16 @@ def rotateLight(rx = 0, ry = 0., rz = 0): areaLight1.set_mesh(teapot) # %% -tex2 = v.texture.create_from_image("grid", "../data/grid.jpg") +tex2 = v.texture.create_from_image("grid", "../data/UV_Grid_Lrg.jpg") + +#%% +areaLight1.get_light().set_color_texture(tex2) + +#%% +tex3 = v.texture.create_from_image("grid2", "../data/UV_Grid_Sm.jpg") + +#%% +areaLight1.get_light().set_color_texture(tex3) # %% mat = v.material.create("test") @@ -388,8 +294,6 @@ def rotateLight(rx = 0, ry = 0., rz = 0): # %% -<<<<<<< Updated upstream -======= glasses = v.entity.create( name = "glasses", mesh = v.mesh.create_from_obj(name = "glasses", path="C:/Users/natevm/3D Objects/glasses/LE_V1_0131_Ikea_Glass_Pokal.obj"), @@ -446,7 +350,7 @@ def rotateLight(rx = 0, ry = 0., rz = 0): # %% outer.get_material().set_base_color_texture(base) -outer.get_material().set_normal_map_texture(norm2) +outer.get_material().set_normal_map_texture(norm) outer.get_material().set_roughness_texture(orm, channel=1) outer.get_material().set_metallic_texture(orm, channel=2) @@ -467,4 +371,3 @@ def rotateLight(rx = 0, ry = 0., rz = 0): outer.get_material().set_normal_map_texture(norm2) # %% ->>>>>>> Stashed changes From d7c3ce3e04206542bbf45c3830cd22a18411246b Mon Sep 17 00:00:00 2001 From: Jonathan Tremblay Date: Mon, 27 Jul 2020 10:27:01 -0700 Subject: [PATCH 04/25] adding normal map example --- examples/14.normal_map.py | 99 ++++++++++++++++++++++++++++++++++++ examples/download_content.sh | 3 +- 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 examples/14.normal_map.py diff --git a/examples/14.normal_map.py b/examples/14.normal_map.py new file mode 100644 index 00000000..3b2f01b7 --- /dev/null +++ b/examples/14.normal_map.py @@ -0,0 +1,99 @@ +import visii +import noise +import random +import argparse +import numpy as np + +parser = argparse.ArgumentParser() + +parser.add_argument('--spp', + default=100, + type=int, + help = "number of sample per pixel, higher the more costly") +parser.add_argument('--width', + default=500, + type=int, + help = 'image output width') +parser.add_argument('--height', + default=500, + type=int, + help = 'image output height') +parser.add_argument('--noise', + action='store_true', + default=False, + help = "if added the output of the ray tracing is not sent to optix's denoiser") +parser.add_argument('--out', + default='tmp.png', + help = "output filename") + +opt = parser.parse_args() + +# # # # # # # # # # # # # # # # # # # # # # # # # +visii.initialize_headless() + +if not opt.noise is True: + visii.enable_denoiser() + +camera = visii.entity.create( + name = "camera", + transform = visii.transform.create("camera"), + camera = visii.camera.create_perspective_from_fov( + name = "camera", + field_of_view = 0.785398, + aspect = float(opt.width)/float(opt.height) + ) +) + +camera.get_transform().look_at( + visii.vec3(0,0,0), # look at (world coordinate) + visii.vec3(0,0,1), # up vector + visii.vec3(-2,0,2), # camera_origin +) +visii.set_camera_entity(camera) + +# # # # # # # # # # # # # # # # # # # # # # # # # + +visii.set_dome_light_intensity(1) + +# Lets set some objects in the scene +entity = visii.entity.create( + name = "floor", + mesh = visii.mesh.create_plane("mesh_floor"), + transform = visii.transform.create("transform_floor"), + material = visii.material.create("material_floor") +) + + +entity.get_transform().set_scale(visii.vec3(2)) + +mat = visii.material.get("material_floor") +mat.set_metallic(1) +mat.set_roughness(0) + +mat.set_roughness_texture(noise) + +# # # # # # # # # # # # # # # # # # # # # # # # # + +# load the texture +normal_tex = visii.texture.create_from_image("normal",'content/normal_map.png') +mat.set_normal_map_texture(normal_tex) + + +# # # # # # # # # # # # # # # # # # # # # # # # # + + +visii.render_to_png( + width=int(opt.width), + height=int(opt.height), + samples_per_pixel=int(opt.spp), + image_path=f"{opt.out}" +) +visii.render_to_hdr( + width=int(opt.width), + height=int(opt.height), + samples_per_pixel=int(opt.spp), + image_path=f"{(opt.out).replace('png', 'hdr')}" +) + +# let's clean up the GPU +visii.cleanup() \ No newline at end of file diff --git a/examples/download_content.sh b/examples/download_content.sh index 16a8ca18..3657642c 100644 --- a/examples/download_content.sh +++ b/examples/download_content.sh @@ -12,4 +12,5 @@ wget https://www.dropbox.com/s/8nj82vxvxwvnttt/salle_de_bain_separated.zip unzip salle_de_bain_separated.zip rm salle_de_bain_separated.zip -wget https://www.dropbox.com/s/p2xius4kd4olqg3/gradient.png \ No newline at end of file +wget https://www.dropbox.com/s/p2xius4kd4olqg3/gradient.png +wget https://www.dropbox.com/s/ktjyndsai8qxb4q/normal_map.png From ddc359be56666cf2af8cdfa55b28118d9afa3030 Mon Sep 17 00:00:00 2001 From: n8vm Date: Mon, 27 Jul 2020 11:31:22 -0600 Subject: [PATCH 05/25] Adding ray_direction as a possible option for render data --- src/visii/devicecode/launch_params.h | 2 +- src/visii/devicecode/path_tracer.cu | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/visii/devicecode/launch_params.h b/src/visii/devicecode/launch_params.h index d18e8479..1cdb31fa 100644 --- a/src/visii/devicecode/launch_params.h +++ b/src/visii/devicecode/launch_params.h @@ -84,7 +84,7 @@ enum RenderDataFlags : uint32_t { GLOSSY_INDIRECT_LIGHTING = 14, TRANSMISSION_COLOR = 15, TRANSMISSION_DIRECT_LIGHTING = 16, - TRANSMISSION_INDIRECT_LIGHTING = 17 + TRANSMISSION_INDIRECT_LIGHTING = 17, RAY_DIRECTION = 18, }; diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index 2717d1b7..f91e360b 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -338,6 +338,9 @@ void saveGeometricRenderData( else if (optixLaunchParams.renderDataMode == RenderDataFlags::BASE_COLOR) { renderData = mat.base_color; } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::RAY_DIRECTION) { + renderData = -w_o; + } } __device__ From 2a4161cde83dcf468342fcd8cc2d4c93db8bb22a Mon Sep 17 00:00:00 2001 From: n8vm Date: Mon, 27 Jul 2020 12:25:28 -0600 Subject: [PATCH 06/25] some bsdf refactoring to make extracting color easier --- src/visii/devicecode/disney_bsdf.h | 102 ++++++++++++++++------------ src/visii/devicecode/path_tracer.cu | 35 ++++++---- 2 files changed, 77 insertions(+), 60 deletions(-) diff --git a/src/visii/devicecode/disney_bsdf.h b/src/visii/devicecode/disney_bsdf.h index 00cf32f8..0a1317ab 100644 --- a/src/visii/devicecode/disney_bsdf.h +++ b/src/visii/devicecode/disney_bsdf.h @@ -435,8 +435,8 @@ __device__ float3 disney_microfacet_transmission_color(const DisneyMaterial &mat return mat.base_color; } -__device__ float3 disney_microfacet_transmission_isotropic(const DisneyMaterial &mat, const float3 &n, - const float3 &w_o, const float3 &w_i) +__device__ void disney_microfacet_transmission_isotropic(const DisneyMaterial &mat, const float3 &n, + const float3 &w_o, const float3 &w_i, float &bsdf, float3 &color) { float eta_o, eta_i; @@ -458,7 +458,10 @@ __device__ float3 disney_microfacet_transmission_isotropic(const DisneyMaterial float d = gtr_2(cos_theta_h, alpha); float3 f = lerp(spec, make_float3(1.f), 1.0f - schlick_weight(dot(w_i, w_ht))); float g = smith_shadowing_ggx(abs(dot(n, w_i)), alpha) * smith_shadowing_ggx(abs(dot(n, w_o)), alpha); - return mat.base_color * d;// * f;// * g; // * f * g; + + bsdf = d; + color = mat.base_color; + return;// * f;// * g; // * f * g; @@ -531,35 +534,35 @@ __device__ float3 disney_sheen(const DisneyMaterial &mat, const float3 &n, return f * mat.sheen * sheen_color; } -__device__ float3 disney_brdf(const DisneyMaterial &mat, const float3 &n, +// when a BSDF is forced, we'll try to separate the color out of the bsdf filtered value. +// this isn't always possible though, since sheen, gloss, and clearcoat might all have +// unique colors, and combine together to make one single glossy color. +__device__ void disney_brdf(const DisneyMaterial &mat, const float3 &n, const float3 &w_o, const float3 &w_i, const float3 &v_x, const float3 &v_y, - cudaTextureObject_t GGX_E_LOOKUP, cudaTextureObject_t GGX_E_AVG_LOOKUP, - int forced_bsdf - ) -{ + float3 &bsdf, float3 &color, int forced_bsdf +) { + // initialize color and bsdf value to black for now. + color = make_float3(0.f); + bsdf = make_float3(0.f); if (!same_hemisphere(w_o, w_i, n)) { // transmissive objects refract when back of surface is visible. if (mat.specular_transmission > 0.f) { - float3 spec_trans = disney_microfacet_transmission_isotropic(mat, n, w_o, w_i); + float spec_trans; float3 trans_color; + disney_microfacet_transmission_isotropic(mat, n, w_o, w_i, spec_trans, trans_color); spec_trans = spec_trans * (1.f - mat.metallic) * mat.specular_transmission; - - // If transmission BSDF is forced - if (forced_bsdf == 3) { - float3 color = disney_microfacet_transmission_color(mat, n, w_o, w_i); - return spec_trans / color; - } - - return spec_trans * (1.f - mat.metallic) * mat.specular_transmission; + color = trans_color; + bsdf = make_float3(spec_trans); + return; } // non-transmissive objects appear black when back of surface is visible. - return make_float3(0.f); + return; } // If forcing transmission, stop here. - if (forced_bsdf == 3) return make_float3(0.f); + if (forced_bsdf == 3) return; float coat = disney_clear_coat(mat, n, w_o, w_i); float3 sheen = disney_sheen(mat, n, w_o, w_i); @@ -568,37 +571,41 @@ __device__ float3 disney_brdf(const DisneyMaterial &mat, const float3 &n, float3 gloss; if (mat.anisotropy == 0.f) { gloss = disney_microfacet_isotropic(mat, n, w_o, w_i); - gloss = gloss + disney_multiscatter(mat, n, w_o, w_i, GGX_E_LOOKUP, GGX_E_AVG_LOOKUP); + // gloss = gloss + disney_multiscatter(mat, n, w_o, w_i, GGX_E_LOOKUP, GGX_E_AVG_LOOKUP); } else { gloss = disney_microfacet_anisotropic(mat, n, w_o, w_i, v_x, v_y); - gloss = gloss + disney_multiscatter(mat, n, w_o, w_i, GGX_E_LOOKUP, GGX_E_AVG_LOOKUP); + // gloss = gloss + disney_multiscatter(mat, n, w_o, w_i, GGX_E_LOOKUP, GGX_E_AVG_LOOKUP); } // If diffuse BRDF is forced if (forced_bsdf == 0) { - float3 color = disney_diffuse_color(mat, n, w_o, w_i); - return (lerp(diffuse, subsurface, mat.flatness) + color = disney_diffuse_color(mat, n, w_o, w_i); + bsdf = (lerp(diffuse, subsurface, mat.flatness) * (1.f - mat.metallic) * (1.f - mat.specular_transmission) * fabs(dot(w_i, n))) / color; + return; } // If glossy BRDF is forced if ((forced_bsdf == 1) || (forced_bsdf == 2)) { - float3 color = disney_microfacet_reflection_color(mat, n, w_o, w_i); - return ((sheen + gloss + coat) * fabs(dot(w_i, n))) / color; + color = disney_microfacet_reflection_color(mat, n, w_o, w_i); + bsdf = ((sheen + gloss + coat) * fabs(dot(w_i, n))) / color; + return; } - return - (lerp(diffuse, subsurface, mat.flatness) * (1.f - mat.metallic) * (1.f - mat.specular_transmission) - + sheen + gloss + coat) * fabs(dot(w_i, n)); + bsdf = (lerp(diffuse, subsurface, mat.flatness) * (1.f - mat.metallic) * (1.f - mat.specular_transmission) + + sheen + gloss + coat) * fabs(dot(w_i, n)); + color = make_float3(1); } -__device__ float disney_pdf(const DisneyMaterial &mat, const float3 &n, +__device__ void disney_pdf(const DisneyMaterial &mat, const float3 &n, const float3 &w_o, const float3 &w_i, const float3 &v_x, const float3 &v_y, - int forced_bsdf + float &pdf, int forced_bsdf ) { + pdf = 0.f; + bool entering = dot(w_o, n) > 0.f; bool sameHemisphere = same_hemisphere(w_o, w_i, n); @@ -638,28 +645,28 @@ __device__ float disney_pdf(const DisneyMaterial &mat, const float3 &n, n_comp -= lerp(transmission_kludge, metallic_kludge, mat.metallic); if (forced_bsdf == 0) { - return diffuse; + pdf = diffuse; return; } if (forced_bsdf == 1) { - return microfacet; + pdf = microfacet; return; } if (forced_bsdf == 2) { - return clear_coat; + pdf = clear_coat; return; } if (forced_bsdf == 3) { - return microfacet_transmission; + pdf = microfacet_transmission; return; } - return (diffuse + microfacet + microfacet_transmission + clear_coat) / n_comp; + pdf = (diffuse + microfacet + microfacet_transmission + clear_coat) / n_comp; } /* Sample a component of the Disney BRDF, returns the sampled BRDF color, * ray reflection direction (w_i) and sample PDF. */ -__device__ float3 sample_disney_brdf(const DisneyMaterial &mat, const float3 &n, +__device__ void sample_disney_brdf(const DisneyMaterial &mat, const float3 &n, const float3 &w_o, const float3 &v_x, const float3 &v_y, LCGRand &rng, - float3 &w_i, float &pdf, int &sampled_bsdf, int forced_bsdf, - cudaTextureObject_t GGX_E_LOOKUP, cudaTextureObject_t GGX_E_AVG_LOOKUP) + float3 &w_i, float &pdf, int &sampled_bsdf, float3 &bsdf, float3 &color, + int forced_bsdf) { bool entering = dot(w_o, n) > 0.f; @@ -679,6 +686,7 @@ __device__ float3 sample_disney_brdf(const DisneyMaterial &mat, const float3 &n, } } else { + // possible bug here related to above hack and transmissive surfaces with total internal reflections component = forced_bsdf; } @@ -705,7 +713,9 @@ __device__ float3 sample_disney_brdf(const DisneyMaterial &mat, const float3 &n, if (!same_hemisphere(w_o, w_i, n)) { pdf = 0.f; w_i = make_float3(0.f); - return make_float3(0.f); + color = make_float3(0.f); + bsdf = make_float3(0.f); + return; } } else if (component == 2) { // Sample clear coat component @@ -717,7 +727,9 @@ __device__ float3 sample_disney_brdf(const DisneyMaterial &mat, const float3 &n, if (!same_hemisphere(w_o, w_i, n)) { pdf = 0.f; w_i = make_float3(0.f); - return make_float3(0.f); + color = make_float3(0.f); + bsdf = make_float3(0.f); + return; } } else { // Sample microfacet transmission component @@ -734,13 +746,13 @@ __device__ float3 sample_disney_brdf(const DisneyMaterial &mat, const float3 &n, if (all_zero(w_i)) { w_i = reflect(-w_o, (entering) ? w_h : -w_h); pdf = 1.f; - return mat.base_color; + color = mat.base_color; + bsdf = make_float3(1.f); + return; } // return make_float3(1.f); // HACK } - pdf = disney_pdf(mat, n, w_o, w_i, v_x, v_y, forced_bsdf); - - float3 brdf = disney_brdf(mat, n, w_o, w_i, v_x, v_y, GGX_E_LOOKUP, GGX_E_AVG_LOOKUP, forced_bsdf); - return brdf; + disney_pdf(mat, n, w_o, w_i, v_x, v_y, pdf, forced_bsdf); + disney_brdf(mat, n, w_o, w_i, v_x, v_y, bsdf, color, forced_bsdf); } diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index f91e360b..16aad453 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -656,7 +656,8 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() if ((light_pdf > EPSILON) && (dotNWi > EPSILON)) { float3 light_dir = make_float3(dir.x, dir.y, dir.z); light_dir = normalize(light_dir); - float bsdf_pdf = disney_pdf(mat, n_l, w_o, light_dir, v_x, v_y, forcedBsdf); + float bsdf_pdf; + disney_pdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf_pdf, forcedBsdf); if (bsdf_pdf > EPSILON) { RayPayload payload; owl::Ray ray; @@ -672,9 +673,10 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() bool visible = ((entityID == sampledLightID) || (entityID == -1)); if (visible) { float w = power_heuristic(1.f, light_pdf, 1.f, bsdf_pdf); - float3 bsdf = disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, optixLaunchParams.GGX_E_LOOKUP, optixLaunchParams.GGX_E_AVG_LOOKUP, forcedBsdf); + float3 bsdf, bsdf_color; + disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); float3 Li = lightEmission * w / light_pdf; - irradiance = (bsdf * Li * fabs(dotNWi)); + irradiance = (bsdf * bsdf_color * Li * fabs(dotNWi)); } } } @@ -685,14 +687,14 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() float3 w_i; float bsdf_pdf; int sampledBsdf = -1; - float3 bsdf = sample_disney_brdf(mat, v_z, w_o, v_x, v_y, rng, w_i, bsdf_pdf, - sampledBsdf, forcedBsdf, optixLaunchParams.GGX_E_LOOKUP, optixLaunchParams.GGX_E_AVG_LOOKUP); + float3 bsdf, bsdf_color; + sample_disney_brdf(mat, v_z, w_o, v_x, v_y, rng, w_i, bsdf_pdf, sampledBsdf, bsdf, bsdf_color, forcedBsdf); // For segmentations, lighting metadata extraction dependent on sampling the BSDF saveLightingColorRenderData(renderData, bounce, v_z, w_o, w_i, mat); // terminate if the bsdf probability is impossible, or if the bsdf filters out all light - if (bsdf_pdf < EPSILON || all_zero(bsdf)) { + if (bsdf_pdf < EPSILON || all_zero(bsdf) || all_zero(bsdf_color)) { break; } @@ -734,7 +736,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() if (dotNWi > 0.f){ float w = power_heuristic(1.f, bsdf_pdf, 1.f, light_pdf); float3 Li = lightEmission * w / bsdf_pdf; - irradiance = irradiance + (bsdf * Li * fabs(dotNWi)); // missing r^2 falloff? + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); // missing r^2 falloff? } } } @@ -743,25 +745,28 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() float3 contribution = path_throughput * irradiance; illum = illum + contribution; // if (bounce >= optixLaunchParams.renderDataBounce) - rdIllum = rdIllum + contribution; - path_throughput = path_throughput * bsdf / bsdf_pdf; + if (bounce == 0) { + rdIllum = rdIllum + irradiance; + } else { + rdIllum = rdIllum + contribution; + } + path_throughput = (path_throughput * bsdf * bsdf_color) / bsdf_pdf; // If ray misses, interpret normal as "miss color" assigned by miss program and move on to the next sample if (payload.tHit <= 0.f) { irradiance = irradiance + missColor(ray) * optixLaunchParams.domeLightIntensity; illum = illum + path_throughput * missColor(ray) * optixLaunchParams.domeLightIntensity; - // if (bounce >= optixLaunchParams.renderDataBounce) - { + if (bounce == 0) { + rdIllum = rdIllum + missColor(ray) * optixLaunchParams.domeLightIntensity; + } + else { rdIllum = rdIllum + path_throughput * missColor(ray) * optixLaunchParams.domeLightIntensity; } } - // For segmentations, lighting metadata extraction dependent on sampling the BSDF - // saveLightingColorRenderData(renderData, bounce, v_z, w_o, w_i, mat); - if (bounce == 0) { directIllum = illum; - rdDirectIllum = illum; + rdDirectIllum = rdIllum; rdSampledBsdf = sampledBsdf; } From 7c84b1798ece8cc3937f0b577b79353269a88916 Mon Sep 17 00:00:00 2001 From: n8vm Date: Mon, 27 Jul 2020 12:33:14 -0600 Subject: [PATCH 07/25] adding a to_mat4 to cleanup some code --- src/visii/devicecode/float3.h | 11 +++++++++++ src/visii/devicecode/path_tracer.cu | 20 ++++---------------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/visii/devicecode/float3.h b/src/visii/devicecode/float3.h index 71760f36..749478ae 100644 --- a/src/visii/devicecode/float3.h +++ b/src/visii/devicecode/float3.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include "types.h" __device__ float4 make_float4(float c) { @@ -66,6 +67,16 @@ __device__ glm::vec2 make_vec2(float2 v) { return glm::vec2(v.x, v.y); } +__device__ glm::mat4 to_mat4(float xfm_[12]) +{ + glm::mat4 xfm; + xfm = glm::column(xfm, 0, vec4(xfm_[0], xfm_[4], xfm_[8], 0.0f)); + xfm = glm::column(xfm, 1, vec4(xfm_[1], xfm_[5], xfm_[9], 0.0f)); + xfm = glm::column(xfm, 2, vec4(xfm_[2], xfm_[6], xfm_[10], 0.0f)); + xfm = glm::column(xfm, 3, vec4(xfm_[3], xfm_[7], xfm_[11], 1.0f)); + return xfm; +} + __device__ float length(const float3 &v) { return sqrt(v.x * v.x + v.y * v.y + v.z * v.z); } diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index 16aad453..4677c453 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -474,21 +474,9 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() loadMeshNormalData(entity.mesh_id, indices, payload.barycentrics, uv, v_z); loadDisneyMaterial(entityMaterial, make_vec2(uv), mat, roughnessMinimum); - glm::mat4 xfm; - xfm = glm::column(xfm, 0, vec4(payload.localToWorld[0], payload.localToWorld[4], payload.localToWorld[8], 0.0f)); - xfm = glm::column(xfm, 1, vec4(payload.localToWorld[1], payload.localToWorld[5], payload.localToWorld[9], 0.0f)); - xfm = glm::column(xfm, 2, vec4(payload.localToWorld[2], payload.localToWorld[6], payload.localToWorld[10], 0.0f)); - xfm = glm::column(xfm, 3, vec4(payload.localToWorld[3], payload.localToWorld[7], payload.localToWorld[11], 1.0f)); - glm::mat4 xfmt0; - xfmt0 = glm::column(xfmt0, 0, vec4(payload.localToWorldT0[0], payload.localToWorldT0[4], payload.localToWorldT0[8], 0.0f)); - xfmt0 = glm::column(xfmt0, 1, vec4(payload.localToWorldT0[1], payload.localToWorldT0[5], payload.localToWorldT0[9], 0.0f)); - xfmt0 = glm::column(xfmt0, 2, vec4(payload.localToWorldT0[2], payload.localToWorldT0[6], payload.localToWorldT0[10], 0.0f)); - xfmt0 = glm::column(xfmt0, 3, vec4(payload.localToWorldT0[3], payload.localToWorldT0[7], payload.localToWorldT0[11], 1.0f)); - glm::mat4 xfmt1; - xfmt1 = glm::column(xfmt1, 0, vec4(payload.localToWorldT1[0], payload.localToWorldT1[4], payload.localToWorldT1[8], 0.0f)); - xfmt1 = glm::column(xfmt1, 1, vec4(payload.localToWorldT1[1], payload.localToWorldT1[5], payload.localToWorldT1[9], 0.0f)); - xfmt1 = glm::column(xfmt1, 2, vec4(payload.localToWorldT1[2], payload.localToWorldT1[6], payload.localToWorldT1[10], 0.0f)); - xfmt1 = glm::column(xfmt1, 3, vec4(payload.localToWorldT1[3], payload.localToWorldT1[7], payload.localToWorldT1[11], 1.0f)); + glm::mat4 xfm = to_mat4(payload.localToWorld); + glm::mat4 xfmt0 = to_mat4(payload.localToWorldT0); + glm::mat4 xfmt1 = to_mat4(payload.localToWorldT1); glm::mat3 nxfm = transpose(glm::inverse(glm::mat3(xfm))); // If the material has a normal map, load it. @@ -796,7 +784,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // For segmentations, indirect/direct lighting metadata extraction float3 rdgillum = rdIllum; - rdIndirectIllum = rdgillum;// - rdDirectIllum; + rdIndirectIllum = rdgillum - rdDirectIllum; saveLightingIrradianceRenderData(renderData, bounce, rdDirectIllum, rdIndirectIllum, rdSampledBsdf); if (optixLaunchParams.indirectClamp > 0.f) From 58f43b75f49ba1aed1361d9d1b545ddc91b71cf7 Mon Sep 17 00:00:00 2001 From: jtremblay Date: Mon, 27 Jul 2020 11:37:35 -0700 Subject: [PATCH 08/25] adding a normal example --- examples/14.normal_map.py | 45 +++++++++++++++++++++++++++++------- examples/download_content.sh | 3 ++- examples/readme.md | 11 +++++---- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/examples/14.normal_map.py b/examples/14.normal_map.py index 3b2f01b7..9c7ee1df 100644 --- a/examples/14.normal_map.py +++ b/examples/14.normal_map.py @@ -47,13 +47,39 @@ camera.get_transform().look_at( visii.vec3(0,0,0), # look at (world coordinate) visii.vec3(0,0,1), # up vector - visii.vec3(-2,0,2), # camera_origin + visii.vec3(0,0,3), # camera_origin ) visii.set_camera_entity(camera) # # # # # # # # # # # # # # # # # # # # # # # # # -visii.set_dome_light_intensity(1) +visii.set_dome_light_intensity(0) + +# third light +obj_entity = visii.entity.create( + name="light", + mesh = visii.mesh.create_plane('light'), + transform = visii.transform.create("light"), +) +obj_entity.set_light( + visii.light.create('light') +) +obj_entity.get_light().set_intensity(10000) + +obj_entity.get_light().set_temperature(5000) + +obj_entity.get_transform().set_scale( + visii.vec3(0.2) +) +obj_entity.get_transform().set_position( + visii.vec3(1,0,2) +) +obj_entity.get_transform().look_at( + at = visii.vec3(0,0,0), # look at (world coordinate) + up = visii.vec3(0,0,1), # up vector +) +obj_entity.get_transform().add_rotation(visii.quat(0,0,1,0)) + # Lets set some objects in the scene entity = visii.entity.create( @@ -67,16 +93,19 @@ entity.get_transform().set_scale(visii.vec3(2)) mat = visii.material.get("material_floor") -mat.set_metallic(1) -mat.set_roughness(0) - -mat.set_roughness_texture(noise) +mat.set_metallic(0) +mat.set_roughness(1) # # # # # # # # # # # # # # # # # # # # # # # # # # load the texture -normal_tex = visii.texture.create_from_image("normal",'content/normal_map.png') +color_tex = visii.texture.create_from_image("color",'content/Bricks051_2K_Color.jpg') +normal_tex = visii.texture.create_from_image("normal",'content/Bricks051_2K_Normal.jpg') +rough_tex = visii.texture.create_from_image("rough",'content/Bricks051_2K_Roughness.jpg') + +mat.set_base_color_texture(color_tex) mat.set_normal_map_texture(normal_tex) +mat.set_roughness_texture(rough_tex) # # # # # # # # # # # # # # # # # # # # # # # # # @@ -96,4 +125,4 @@ ) # let's clean up the GPU -visii.cleanup() \ No newline at end of file +visii.deinitialize() \ No newline at end of file diff --git a/examples/download_content.sh b/examples/download_content.sh index 3657642c..a1d5490e 100644 --- a/examples/download_content.sh +++ b/examples/download_content.sh @@ -13,4 +13,5 @@ unzip salle_de_bain_separated.zip rm salle_de_bain_separated.zip wget https://www.dropbox.com/s/p2xius4kd4olqg3/gradient.png -wget https://www.dropbox.com/s/ktjyndsai8qxb4q/normal_map.png +wget https://www.dropbox.com/s/bxbkzmuy2mviyzb/Bricks051_2K-JPG.zip +unzip Bricks051_2K-JPG.zip \ No newline at end of file diff --git a/examples/readme.md b/examples/readme.md index 8658852d..ecebac76 100644 --- a/examples/readme.md +++ b/examples/readme.md @@ -88,10 +88,13 @@ A common technique for denoising ray traced images is to use "temporal reproject Here, we use diffuse motion vectors to reproject an image from frame to frame, accounting for disocclusions. +## 14.normal_map.py +A simple script that loads a texture, normal and roughness map and apply them to a flat surface. + ## Notes -All these examples were developed and tested on Ubuntu 18.04 with cuda 10.2, NVIDIA drivers -440.100 and using a NVIDIA RTX 2080 ti. +All these examples were developed and tested on Ubuntu 18.04 with cuda 11.0, NVIDIA drivers +450.36.06 and using a NVIDIA TITAN RTX . -## TODO -- exporting data is missing segmentation id for objects \ No newline at end of file + \ No newline at end of file From f1babfc2d336eefc6fc655d0cd6689ad36640e87 Mon Sep 17 00:00:00 2001 From: n8vm Date: Tue, 28 Jul 2020 11:21:50 -0600 Subject: [PATCH 09/25] Updating OWL to support texture addressing --- externals/owl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/owl b/externals/owl index 80cca512..81236d3e 160000 --- a/externals/owl +++ b/externals/owl @@ -1 +1 @@ -Subproject commit 80cca5120806fb063d9d620a3d2657ad65e2795e +Subproject commit 81236d3e423e0b7465d853dfcec3955db12bf6a1 From 68f216ad8cc21258a7034a2b1ed4bc4e29c3f2c5 Mon Sep 17 00:00:00 2001 From: n8vm Date: Tue, 28 Jul 2020 11:30:35 -0600 Subject: [PATCH 10/25] Updating code with changes to addressing in OWL --- src/visii/devicecode/disney_bsdf.h | 31 +++---- src/visii/devicecode/path_tracer.cu | 122 ++++++++++++++++------------ src/visii/visii.cpp | 24 ++---- 3 files changed, 93 insertions(+), 84 deletions(-) diff --git a/src/visii/devicecode/disney_bsdf.h b/src/visii/devicecode/disney_bsdf.h index 0a1317ab..30f84328 100644 --- a/src/visii/devicecode/disney_bsdf.h +++ b/src/visii/devicecode/disney_bsdf.h @@ -286,8 +286,8 @@ __device__ float3 disney_diffuse_color(const DisneyMaterial &mat, const float3 & return mat.base_color; } -__device__ float3 disney_diffuse(const DisneyMaterial &mat, const float3 &n, - const float3 &w_o, const float3 &w_i) +__device__ void disney_diffuse(const DisneyMaterial &mat, const float3 &n, + const float3 &w_o, const float3 &w_i, float3 &bsdf, float3 &color) { float3 w_h = normalize(w_i + w_o); float n_dot_o = fabs(dot(w_o, n)); @@ -296,11 +296,12 @@ __device__ float3 disney_diffuse(const DisneyMaterial &mat, const float3 &n, float fd90 = 0.5f + 2.f * mat.roughness * i_dot_h * i_dot_h; float fi = schlick_weight(n_dot_i); float fo = schlick_weight(n_dot_o); - return disney_diffuse_color(mat, n, w_o, w_i) * M_1_PI * lerp(1.f, fd90, fi) * lerp(1.f, fd90, fo); + color = disney_diffuse_color(mat, n, w_o, w_i); + bsdf = make_float3(M_1_PI * lerp(1.f, fd90, fi) * lerp(1.f, fd90, fo)); } -__device__ float3 disney_subsurface(const DisneyMaterial &mat, const float3 &n, - const float3 &w_o, const float3 &w_i) { +__device__ void disney_subsurface(const DisneyMaterial &mat, const float3 &n, + const float3 &w_o, const float3 &w_i, float3 &bsdf, float3 &color) { float3 w_h = normalize(w_i + w_o); float n_dot_o = fabs(dot(w_o, n)); float n_dot_i = fabs(dot(w_i, n)); @@ -310,8 +311,8 @@ __device__ float3 disney_subsurface(const DisneyMaterial &mat, const float3 &n, float Fss90 = i_dot_h*i_dot_h * mat.roughness; float Fss = lerp(1.0, Fss90, FL) * lerp(1.0, Fss90, FV); float ss = 1.25 * (Fss * (1. / (n_dot_i + n_dot_o) - .5) + .5); - - return disney_diffuse_color(mat, n, w_o, w_i) * M_1_PI * ss; + color = disney_diffuse_color(mat, n, w_o, w_i); + bsdf = make_float3(M_1_PI * ss); } // Eavg in the algorithm is fitted into this @@ -566,8 +567,10 @@ __device__ void disney_brdf(const DisneyMaterial &mat, const float3 &n, float coat = disney_clear_coat(mat, n, w_o, w_i); float3 sheen = disney_sheen(mat, n, w_o, w_i); - float3 diffuse = disney_diffuse(mat, n, w_o, w_i); - float3 subsurface = disney_subsurface(mat, n, w_o, w_i); + float3 diffuse_bsdf, diffuse_color; + disney_diffuse(mat, n, w_o, w_i, diffuse_bsdf, diffuse_color); + float3 subsurface_bsdf, subsurface_color; + disney_subsurface(mat, n, w_o, w_i, subsurface_bsdf, subsurface_color); float3 gloss; if (mat.anisotropy == 0.f) { gloss = disney_microfacet_isotropic(mat, n, w_o, w_i); @@ -580,11 +583,11 @@ __device__ void disney_brdf(const DisneyMaterial &mat, const float3 &n, // If diffuse BRDF is forced if (forced_bsdf == 0) { - color = disney_diffuse_color(mat, n, w_o, w_i); - bsdf = (lerp(diffuse, subsurface, mat.flatness) + color = diffuse_color; + bsdf = (lerp(diffuse_bsdf, subsurface_bsdf, mat.flatness) * (1.f - mat.metallic) * (1.f - mat.specular_transmission) - * fabs(dot(w_i, n))) / color; + * fabs(dot(w_i, n))); return; } @@ -595,7 +598,7 @@ __device__ void disney_brdf(const DisneyMaterial &mat, const float3 &n, return; } - bsdf = (lerp(diffuse, subsurface, mat.flatness) * (1.f - mat.metallic) * (1.f - mat.specular_transmission) + bsdf = (lerp(diffuse_bsdf * diffuse_color, subsurface_bsdf * subsurface_color, mat.flatness) * (1.f - mat.metallic) * (1.f - mat.specular_transmission) + sheen + gloss + coat) * fabs(dot(w_i, n)); color = make_float3(1); } @@ -605,7 +608,7 @@ __device__ void disney_pdf(const DisneyMaterial &mat, const float3 &n, float &pdf, int forced_bsdf ) { pdf = 0.f; - + bool entering = dot(w_o, n) > 0.f; bool sameHemisphere = same_hemisphere(w_o, w_i, n); diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index 4677c453..7abda0d6 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -283,29 +283,23 @@ void saveLightingIrradianceRenderData( // Note, dillum and iillum are expected to change outside this function depending on the // render data flags. - if (sampledBsdf == 0) { - if (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_DIRECT_LIGHTING) { - renderData = dillum; - } - else if (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_INDIRECT_LIGHTING) { - renderData = iillum; - } + if (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_DIRECT_LIGHTING) { + renderData = dillum; } - if ((sampledBsdf == 1) || (sampledBsdf == 2)) { - if (optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_DIRECT_LIGHTING) { - renderData = dillum; - } - else if (optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_INDIRECT_LIGHTING) { - renderData = iillum; - } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_INDIRECT_LIGHTING) { + renderData = iillum; } - if (sampledBsdf == 3) { - if (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING) { - renderData = dillum; - } - else if (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_INDIRECT_LIGHTING) { - renderData = iillum; - } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_DIRECT_LIGHTING) { + renderData = dillum; + } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_INDIRECT_LIGHTING) { + renderData = iillum; + } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING) { + renderData = dillum; + } + else if (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_INDIRECT_LIGHTING) { + renderData = iillum; } } @@ -360,6 +354,8 @@ float3 faceNormalForward(const float3 &w_o, const float3 &gn, const float3 &n) OPTIX_RAYGEN_PROGRAM(rayGen)() { auto pixelID = ivec2(owl::getLaunchIndex()[0], owl::getLaunchIndex()[1]); + ivec2 centerPixel = ivec2(optixLaunchParams.frameSize.x / 2, optixLaunchParams.frameSize.y / 2); + bool isCenter = glm::all(glm::equal(pixelID, centerPixel)); auto fbOfs = pixelID.x+optixLaunchParams.frameSize.x* ((optixLaunchParams.frameSize.y - 1) - pixelID.y); LCGRand rng = get_rng(optixLaunchParams.frameID + optixLaunchParams.seed * 10007); float time = sampleTime(lcg_randomf(rng)); @@ -386,9 +382,9 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // For potentially several samples per pixel... // Update: for machine learning applications, it's important there be only 1SPP. // Metadata like depth or IDs dont work with multiple SPP. - #define SPP 1 - for (uint32_t rid = 0; rid < SPP; ++rid) - { + // #define SPP 1 + // for (uint32_t rid = 0; rid < SPP; ++rid) + // { // Trace an initial ray through the scene owl::Ray ray = generateRay(camera, camera_transform, pixelID, optixLaunchParams.frameSize, rng, time); @@ -402,9 +398,9 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() float3 illum = make_float3(0.f); // used for render metadata stuff. - float3 rdIllum = make_float3(0.f); - float3 rdDirectIllum = make_float3(0.f); - float3 rdIndirectIllum = make_float3(0.f); + float3 aovIllum = make_float3(0.f); + float3 aovDirectIllum = make_float3(0.f); + float3 aovIndirectIllum = make_float3(0.f); int32_t rdSampledBsdf = -1; int32_t rdForcedBsdf = -1; if ((optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_DIRECT_LIGHTING) || @@ -414,7 +410,8 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() if ((optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING) || (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING)) rdForcedBsdf = 3; - float3 path_throughput = make_float3(1.f); + float3 pathThroughput = make_float3(1.f); + float3 aovPathThroughput = make_float3(1.f); uint16_t ray_count = 0; float roughnessMinimum = 0.f; RayPayload payload; @@ -576,7 +573,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // } // note, rdForcedBsdf is -1 by default - int forcedBsdf = (bounce == optixLaunchParams.renderDataBounce) ? rdForcedBsdf : -1; + int forcedBsdf = rdForcedBsdf;//(bounce == optixLaunchParams.renderDataBounce) ? rdForcedBsdf : -1; // first, sample the light source by importance sampling the light do { @@ -729,41 +726,48 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() } } - // accumulate any radiance (ie path_throughput * irradiance), and update the path throughput using the sampled BRDF - float3 contribution = path_throughput * irradiance; + // accumulate any radiance (ie pathThroughput * irradiance), and update the path throughput using the sampled BRDF + float3 contribution = pathThroughput * irradiance; illum = illum + contribution; + aovIllum = aovIllum + contribution; // if (bounce >= optixLaunchParams.renderDataBounce) - if (bounce == 0) { - rdIllum = rdIllum + irradiance; - } else { - rdIllum = rdIllum + contribution; - } - path_throughput = (path_throughput * bsdf * bsdf_color) / bsdf_pdf; + + pathThroughput = (pathThroughput * bsdf * bsdf_color) / bsdf_pdf; + + aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; + // if (bounce == 0) { + // } else { + // aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; + // // aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; + // } // If ray misses, interpret normal as "miss color" assigned by miss program and move on to the next sample if (payload.tHit <= 0.f) { irradiance = irradiance + missColor(ray) * optixLaunchParams.domeLightIntensity; - illum = illum + path_throughput * missColor(ray) * optixLaunchParams.domeLightIntensity; + illum = illum + pathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; if (bounce == 0) { - rdIllum = rdIllum + missColor(ray) * optixLaunchParams.domeLightIntensity; - } - else { - rdIllum = rdIllum + path_throughput * missColor(ray) * optixLaunchParams.domeLightIntensity; + aovIllum = aovIllum + aovPathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; + } else { + aovIllum = aovIllum + aovPathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; } } if (bounce == 0) { + // aovPathThroughput = aovPathThroughput * bsdf_color; directIllum = illum; - rdDirectIllum = rdIllum; + aovDirectIllum = aovIllum; rdSampledBsdf = sampledBsdf; } - if (bounce == /*optixLaunchParams.renderDataBounce*/ 0) { - // rdIllum = rdDirectIllum; + if (rdForcedBsdf != -1) { + if ((payload.tHit <= 0.0f) || (aovPathThroughput.x < EPSILON && aovPathThroughput.y < EPSILON && aovPathThroughput.z < EPSILON)) { + break; + } } - - if ((payload.tHit <= 0.0f) || (path_throughput.x < EPSILON && path_throughput.y < EPSILON && path_throughput.z < EPSILON)) { - break; + else { + if ((payload.tHit <= 0.0f) || (pathThroughput.x < EPSILON && pathThroughput.y < EPSILON && pathThroughput.z < EPSILON)) { + break; + } } // // Do path regularization to reduce fireflies @@ -783,9 +787,19 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() glm::vec3 iillum = gillum - dillum; // For segmentations, indirect/direct lighting metadata extraction - float3 rdgillum = rdIllum; - rdIndirectIllum = rdgillum - rdDirectIllum; - saveLightingIrradianceRenderData(renderData, bounce, rdDirectIllum, rdIndirectIllum, rdSampledBsdf); + float3 aovGIllum = aovIllum; + aovIndirectIllum = aovGIllum - aovDirectIllum; + + // if (isCenter) { + // printf("aov gillum: %f %f %f\n", aovGIllum.x, aovGIllum.y, aovGIllum.z); + // printf("aov dillum: %f %f %f\n", aovDirectIllum.x, aovDirectIllum.y, aovDirectIllum.z); + // printf("aov iillum: %f %f %f\n", aovIndirectIllum.x, aovIndirectIllum.y, aovIndirectIllum.z); + + // printf("gillum: %f %f %f\n", gillum.x, gillum.y, gillum.z); + // printf("dillum: %f %f %f\n", dillum.x, dillum.y, dillum.z); + // printf("iillum: %f %f %f\n", iillum.x, iillum.y, iillum.z); + // } + saveLightingIrradianceRenderData(renderData, bounce, aovDirectIllum, aovIndirectIllum, rdSampledBsdf); if (optixLaunchParams.indirectClamp > 0.f) iillum = clamp(iillum, vec3(0.f), vec3(optixLaunchParams.indirectClamp)); @@ -800,9 +814,9 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() illum = make_float3(gillum.r, gillum.g, gillum.b); // accumulate the illumination from this sample into what will be an average illumination from all samples in this pixel - accum_illum = accum_illum + illum; - } - accum_illum = accum_illum / float(SPP); + accum_illum = illum; + // } + // accum_illum = accum_illum / float(SPP); /* Write to AOVs, progressively refining results */ diff --git a/src/visii/visii.cpp b/src/visii/visii.cpp index c3bcfa9b..83518006 100644 --- a/src/visii/visii.cpp +++ b/src/visii/visii.cpp @@ -216,16 +216,6 @@ OWLModule moduleCreate(OWLContext context, const char* ptxCode) return owlModuleCreate(context, ptxCode); } -OWLTexture texture2DCreate(OWLContext context, OWLTexelFormat format, size_t sizeX, size_t sizeY, const void* texels, OWLTextureFilterMode mode) -{ - return owlTexture2DCreate(context, format, sizeX, sizeY, texels, mode, 0); -} - -CUtexObject textureGetObject(OWLTexture texture, int deviceID) -{ - return owlTextureGetObject(texture, deviceID); -} - OWLBuffer managedMemoryBufferCreate(OWLContext context, OWLDataType type, size_t count, void* init) { return owlManagedMemoryBufferCreate(context, type, count, init); @@ -660,16 +650,18 @@ void initializeOptix(bool headless) launchParamsSetRaw(OD.launchParams, "environmentMapID", &OD.LP.environmentMapID); launchParamsSetRaw(OD.launchParams, "environmentMapRotation", &OD.LP.environmentMapRotation); - OWLTexture GGX_E_AVG_LOOKUP = texture2DCreate(OD.context, + OWLTexture GGX_E_AVG_LOOKUP = owlTexture2DCreate(OD.context, OWL_TEXEL_FORMAT_R32F, GGX_E_avg_size,1, GGX_E_avg, - OWL_TEXTURE_LINEAR); - OWLTexture GGX_E_LOOKUP = texture2DCreate(OD.context, + OWL_TEXTURE_LINEAR, + OWL_TEXTURE_CLAMP); + OWLTexture GGX_E_LOOKUP = owlTexture2DCreate(OD.context, OWL_TEXEL_FORMAT_R32F, GGX_E_size[0],GGX_E_size[1], GGX_E, - OWL_TEXTURE_LINEAR); + OWL_TEXTURE_LINEAR, + OWL_TEXTURE_CLAMP); launchParamsSetTexture(OD.launchParams, "GGX_E_AVG_LOOKUP", GGX_E_AVG_LOOKUP); launchParamsSetTexture(OD.launchParams, "GGX_E_LOOKUP", GGX_E_LOOKUP); @@ -926,10 +918,10 @@ void updateComponents() if (!textures[tid].isDirty()) continue; if (OD.textureObjects[tid]) { owlTexture2DDestroy(OD.textureObjects[tid]); OD.textureObjects[tid] = nullptr; } if (!textures[tid].isInitialized()) continue; - OD.textureObjects[tid] = texture2DCreate( + OD.textureObjects[tid] = owlTexture2DCreate( OD.context, OWL_TEXEL_FORMAT_RGBA32F, textures[tid].getWidth(), textures[tid].getHeight(), textures[tid].getTexels().data(), - OWL_TEXTURE_LINEAR); + OWL_TEXTURE_LINEAR, OWL_TEXTURE_WRAP); } bufferUpload(OD.textureObjectsBuffer, OD.textureObjects); From 2bdb3a233f5e1f58f140e2e9c0e716c0fa2bd008 Mon Sep 17 00:00:00 2001 From: n8vm Date: Tue, 28 Jul 2020 15:16:54 -0600 Subject: [PATCH 11/25] now directly sampling dome light. still need to add importance sampling --- src/visii/devicecode/path_tracer.cu | 304 ++++++++++++++++------------ src/visii/visii.cpp | 55 +++++ 2 files changed, 230 insertions(+), 129 deletions(-) diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index 7abda0d6..73e60120 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -421,16 +421,21 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() /*the ray to trace*/ ray, /*prd*/ payload); - // If ray misses - if (payload.tHit <= 0.f) { - illum = missColor(ray) * optixLaunchParams.domeLightIntensity; - primaryNormal = make_float3(0.f, 0.f, 1.f); - primaryAlbedo = illum; - directIllum = illum; - } - // If we hit something, shade each hit point on a path using NEE with MIS - else do { + // else + do + { + // If ray misses + if (payload.tHit <= 0.f) { + illum = illum + pathThroughput * (missColor(ray) * optixLaunchParams.domeLightIntensity); + if (bounce == 0) { + primaryNormal = make_float3(0.f, 0.f, 1.f); + primaryAlbedo = illum; + directIllum = illum; + } + break; + } + // Load common position, vectors, and material data used for shading... const int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; EntityStruct entity = optixLaunchParams.entities[entityID]; @@ -556,7 +561,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() } // Sample a light source - uint32_t sampledLightID = -1; + uint32_t sampledLightID; int numLights = optixLaunchParams.numLightEntities; // float3 lightEmission = make_float3(0.f); float3 irradiance = make_float3(0.f); @@ -577,91 +582,120 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // first, sample the light source by importance sampling the light do { - if (numLights == 0) break; - - // Disable NEE for transmission events - // bool entering = dot(w_o, v_z) < 0.f; - // if (entering) break; - + uint32_t random_id = uint32_t(min(lcg_randomf(rng) * numLights+1, float(numLights))); - uint32_t random_id = uint32_t(min(lcg_randomf(rng) * numLights, float(numLights - 1))); - random_id = min(random_id, numLights - 1); - sampledLightID = optixLaunchParams.lightEntities[random_id]; - light_entity = optixLaunchParams.entities[sampledLightID]; + // sample background + if (random_id == numLights) { + sampledLightID = -1; + const uint32_t occlusion_flags = OPTIX_RAY_FLAG_DISABLE_ANYHIT | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; + const float3 hemi_dir = normalize(cos_sample_hemisphere(make_float2(lcg_randomf(rng), lcg_randomf(rng)))); + float3 light_dir = make_float3(normalize(tbn * normalize(make_vec3(hemi_dir))) ); + light_pdf = 1.f; + float dotNWi = fabs(dot(light_dir, v_z)); // for now, making all lights double sided. + + float bsdf_pdf; + disney_pdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf_pdf, forcedBsdf); + if (bsdf_pdf > EPSILON) { + RayPayload payload; + owl::Ray ray; + ray.tmin = EPSILON * 10.f; + ray.tmax = 1e20f; + ray.origin = hit_p; + ray.direction = light_dir; + payload.tHit = -1.f; + ray.time = time; + owl::traceRay( optixLaunchParams.world, ray, payload, occlusion_flags); + int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; + bool visible = (payload.instanceID == -1); + if (visible) { + float w = power_heuristic(1.f, light_pdf, 1.f, bsdf_pdf); + float3 bsdf, bsdf_color; + disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); + float3 Li = (missColor(ray) * optixLaunchParams.domeLightIntensity) * w / light_pdf; + irradiance = (bsdf * bsdf_color * Li * fabs(dotNWi)); + } + } + } + // sample light sources + else { + random_id = min(random_id, numLights - 1); + sampledLightID = optixLaunchParams.lightEntities[random_id]; + light_entity = optixLaunchParams.entities[sampledLightID]; + + // shouldn't happen, but just in case... + if ((light_entity.light_id < 0) || (light_entity.light_id > MAX_LIGHTS)) break; + if ((light_entity.transform_id < 0) || (light_entity.transform_id > MAX_TRANSFORMS)) break; - // shouldn't happen, but just in case... - if ((light_entity.light_id < 0) || (light_entity.light_id > MAX_LIGHTS)) break; - if ((light_entity.transform_id < 0) || (light_entity.transform_id > MAX_TRANSFORMS)) break; - - light_light = optixLaunchParams.lights[light_entity.light_id]; - TransformStruct transform = optixLaunchParams.transforms[light_entity.transform_id]; - MeshStruct mesh; + light_light = optixLaunchParams.lights[light_entity.light_id]; + TransformStruct transform = optixLaunchParams.transforms[light_entity.transform_id]; + MeshStruct mesh; + + bool is_area_light = false; + if ((light_entity.mesh_id >= 0) && (light_entity.mesh_id < MAX_MESHES)) { + mesh = optixLaunchParams.meshes[light_entity.mesh_id]; + is_area_light = true; + }; + + const uint32_t occlusion_flags = OPTIX_RAY_FLAG_DISABLE_ANYHIT; + // | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; + // | OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT; - bool is_area_light = false; - if ((light_entity.mesh_id >= 0) && (light_entity.mesh_id < MAX_MESHES)) { - mesh = optixLaunchParams.meshes[light_entity.mesh_id]; - is_area_light = true; - }; - - const uint32_t occlusion_flags = OPTIX_RAY_FLAG_DISABLE_ANYHIT; - // | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; - // | OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT; - - if (!is_area_light) break; + if (!is_area_light) break; - uint32_t random_tri_id = uint32_t(min(lcg_randomf(rng) * mesh.numTris, float(mesh.numTris - 1))); - owl::device::Buffer *indexLists = (owl::device::Buffer *)optixLaunchParams.indexLists.data; - ivec3 *indices = (ivec3*) indexLists[light_entity.mesh_id].data; - ivec3 triIndex = indices[random_tri_id]; - - // Sample the light to compute an incident light ray to this point - { - owl::device::Buffer *vertexLists = (owl::device::Buffer *)optixLaunchParams.vertexLists.data; - owl::device::Buffer *texCoordLists = (owl::device::Buffer *)optixLaunchParams.texCoordLists.data; - vec4 *vertices = (vec4*) vertexLists[light_entity.mesh_id].data; - vec2 *texCoords = (vec2*) texCoordLists[light_entity.mesh_id].data; - vec3 dir; - vec2 uv; - vec3 pos = vec3(hit_p.x, hit_p.y, hit_p.z); - vec3 v1 = transform.localToWorld * vertices[triIndex.x]; - vec3 v2 = transform.localToWorld * vertices[triIndex.y]; - vec3 v3 = transform.localToWorld * vertices[triIndex.z]; - vec2 uv1 = texCoords[triIndex.x]; - vec2 uv2 = texCoords[triIndex.y]; - vec2 uv3 = texCoords[triIndex.z]; - vec3 N = normalize(cross( normalize(v2 - v1), normalize(v3 - v1))); - sampleTriangle(pos, N, v1, v2, v3, uv1, uv2, uv3, lcg_randomf(rng), lcg_randomf(rng), dir, light_pdf, uv); - vec3 normal = glm::vec3(n_l.x, n_l.y, n_l.z); - float dotNWi = fabs(dot(dir, normal)); // for now, making all lights double sided. - light_pdf = abs(light_pdf); + uint32_t random_tri_id = uint32_t(min(lcg_randomf(rng) * mesh.numTris, float(mesh.numTris - 1))); + owl::device::Buffer *indexLists = (owl::device::Buffer *)optixLaunchParams.indexLists.data; + ivec3 *indices = (ivec3*) indexLists[light_entity.mesh_id].data; + ivec3 triIndex = indices[random_tri_id]; - float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); - float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, uv, make_vec4(default_light_emission))) * light_light.intensity; - - if ((light_pdf > EPSILON) && (dotNWi > EPSILON)) { - float3 light_dir = make_float3(dir.x, dir.y, dir.z); - light_dir = normalize(light_dir); - float bsdf_pdf; - disney_pdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf_pdf, forcedBsdf); - if (bsdf_pdf > EPSILON) { - RayPayload payload; - owl::Ray ray; - ray.tmin = EPSILON * 10.f; - ray.tmax = 1e20f; - ray.origin = hit_p; - ray.direction = light_dir; - payload.tHit = -1.f; - ray.time = time; - owl::traceRay( optixLaunchParams.world, ray, payload, occlusion_flags); - if (payload.instanceID == -1) continue; - int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; - bool visible = ((entityID == sampledLightID) || (entityID == -1)); - if (visible) { - float w = power_heuristic(1.f, light_pdf, 1.f, bsdf_pdf); - float3 bsdf, bsdf_color; - disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); - float3 Li = lightEmission * w / light_pdf; - irradiance = (bsdf * bsdf_color * Li * fabs(dotNWi)); + // Sample the light to compute an incident light ray to this point + { + owl::device::Buffer *vertexLists = (owl::device::Buffer *)optixLaunchParams.vertexLists.data; + owl::device::Buffer *texCoordLists = (owl::device::Buffer *)optixLaunchParams.texCoordLists.data; + vec4 *vertices = (vec4*) vertexLists[light_entity.mesh_id].data; + vec2 *texCoords = (vec2*) texCoordLists[light_entity.mesh_id].data; + vec3 dir; + vec2 uv; + vec3 pos = vec3(hit_p.x, hit_p.y, hit_p.z); + vec3 v1 = transform.localToWorld * vertices[triIndex.x]; + vec3 v2 = transform.localToWorld * vertices[triIndex.y]; + vec3 v3 = transform.localToWorld * vertices[triIndex.z]; + vec2 uv1 = texCoords[triIndex.x]; + vec2 uv2 = texCoords[triIndex.y]; + vec2 uv3 = texCoords[triIndex.z]; + vec3 N = normalize(cross( normalize(v2 - v1), normalize(v3 - v1))); + sampleTriangle(pos, N, v1, v2, v3, uv1, uv2, uv3, lcg_randomf(rng), lcg_randomf(rng), dir, light_pdf, uv); + vec3 normal = glm::vec3(n_l.x, n_l.y, n_l.z); + float dotNWi = fabs(dot(dir, normal)); // for now, making all lights double sided. + light_pdf = abs(light_pdf); + + float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); + float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, uv, make_vec4(default_light_emission))) * light_light.intensity; + + if ((light_pdf > EPSILON) && (dotNWi > EPSILON)) { + float3 light_dir = make_float3(dir.x, dir.y, dir.z); + light_dir = normalize(light_dir); + float bsdf_pdf; + disney_pdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf_pdf, forcedBsdf); + if (bsdf_pdf > EPSILON) { + RayPayload payload; + owl::Ray ray; + ray.tmin = EPSILON * 10.f; + ray.tmax = 1e20f; + ray.origin = hit_p; + ray.direction = light_dir; + payload.tHit = -1.f; + ray.time = time; + owl::traceRay( optixLaunchParams.world, ray, payload, occlusion_flags); + if (payload.instanceID == -1) continue; + int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; + bool visible = ((entityID == sampledLightID) || (entityID == -1)); + if (visible) { + float w = power_heuristic(1.f, light_pdf, 1.f, bsdf_pdf); + float3 bsdf, bsdf_color; + disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); + float3 Li = lightEmission * w / light_pdf; + irradiance = (bsdf * bsdf_color * Li * fabs(dotNWi)); + } } } } @@ -687,6 +721,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() ray.origin = hit_p; ray.direction = w_i; ray.tmin = EPSILON * 100.f; + payload.instanceID = -1; payload.tHit = -1.f; ray.time = sampleTime(lcg_randomf(rng)); owl::traceRay(optixLaunchParams.world, ray, payload); @@ -694,34 +729,45 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() if (light_pdf > EPSILON) { // if by sampling the brdf we also hit the light source... - if (payload.instanceID == -1) continue; - int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; - bool visible = (entityID == sampledLightID); - if (visible) { - int3 indices; float3 p, p_e1, p_e2; float3 v_gz; float2 uv, uv_e1, uv_e2; - loadMeshTriIndices(light_entity.mesh_id, payload.primitiveID, indices); - loadMeshVertexData(light_entity.mesh_id, indices, payload.barycentrics, p, v_gz, p_e1, p_e2); - loadMeshUVData(light_entity.mesh_id, indices, payload.barycentrics, uv, uv_e1, uv_e2); - - // Transform data into world space - glm::mat4 xfm; - xfm = glm::column(xfm, 0, vec4(payload.localToWorld[0], payload.localToWorld[4], payload.localToWorld[8], 0.0f)); - xfm = glm::column(xfm, 1, vec4(payload.localToWorld[1], payload.localToWorld[5], payload.localToWorld[9], 0.0f)); - xfm = glm::column(xfm, 2, vec4(payload.localToWorld[2], payload.localToWorld[6], payload.localToWorld[10], 0.0f)); - xfm = glm::column(xfm, 3, vec4(payload.localToWorld[3], payload.localToWorld[7], payload.localToWorld[11], 1.0f)); - glm::mat3 nxfm = transpose(glm::inverse(glm::mat3(xfm))); - p = make_float3(xfm * make_vec4(p, 1.0f)); - v_gz = make_float3(normalize(nxfm * normalize(make_vec3(v_gz)))); - - float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); - float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, make_vec2(uv), make_vec4(default_light_emission))) * light_light.intensity; - - float dist = distance(vec3(p.x, p.y, p.z), vec3(ray.origin.x, ray.origin.y, ray.origin.z)); // should I be using this? + if ((payload.instanceID == -1) && (sampledLightID == -1)) { + // Case where we hit the background, and also previously sampled the background float dotNWi = fabs(dot(-v_gz, ray.direction)); // for now, making all lights double sided. - if (dotNWi > 0.f){ + if (dotNWi > 0.f) { float w = power_heuristic(1.f, bsdf_pdf, 1.f, light_pdf); - float3 Li = lightEmission * w / bsdf_pdf; - irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); // missing r^2 falloff? + float3 Li = (missColor(ray) * optixLaunchParams.domeLightIntensity) * w / bsdf_pdf; + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); + } + } + else { + int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; + bool visible = (entityID == sampledLightID); + // We hit the light we sampled previously + if (visible) { + int3 indices; float3 p, p_e1, p_e2; float3 v_gz; float2 uv, uv_e1, uv_e2; + loadMeshTriIndices(light_entity.mesh_id, payload.primitiveID, indices); + loadMeshVertexData(light_entity.mesh_id, indices, payload.barycentrics, p, v_gz, p_e1, p_e2); + loadMeshUVData(light_entity.mesh_id, indices, payload.barycentrics, uv, uv_e1, uv_e2); + + // Transform data into world space + glm::mat4 xfm; + xfm = glm::column(xfm, 0, vec4(payload.localToWorld[0], payload.localToWorld[4], payload.localToWorld[8], 0.0f)); + xfm = glm::column(xfm, 1, vec4(payload.localToWorld[1], payload.localToWorld[5], payload.localToWorld[9], 0.0f)); + xfm = glm::column(xfm, 2, vec4(payload.localToWorld[2], payload.localToWorld[6], payload.localToWorld[10], 0.0f)); + xfm = glm::column(xfm, 3, vec4(payload.localToWorld[3], payload.localToWorld[7], payload.localToWorld[11], 1.0f)); + glm::mat3 nxfm = transpose(glm::inverse(glm::mat3(xfm))); + p = make_float3(xfm * make_vec4(p, 1.0f)); + v_gz = make_float3(normalize(nxfm * normalize(make_vec3(v_gz)))); + + float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); + float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, make_vec2(uv), make_vec4(default_light_emission))) * light_light.intensity; + + float dist = distance(vec3(p.x, p.y, p.z), vec3(ray.origin.x, ray.origin.y, ray.origin.z)); // should I be using this? + float dotNWi = fabs(dot(-v_gz, ray.direction)); // for now, making all lights double sided. + if (dotNWi > 0.f){ + float w = power_heuristic(1.f, bsdf_pdf, 1.f, light_pdf); + float3 Li = lightEmission * w / bsdf_pdf; + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); // missing r^2 falloff? + } } } } @@ -733,7 +779,6 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // if (bounce >= optixLaunchParams.renderDataBounce) pathThroughput = (pathThroughput * bsdf * bsdf_color) / bsdf_pdf; - aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; // if (bounce == 0) { // } else { @@ -741,16 +786,17 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // // aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; // } - // If ray misses, interpret normal as "miss color" assigned by miss program and move on to the next sample - if (payload.tHit <= 0.f) { - irradiance = irradiance + missColor(ray) * optixLaunchParams.domeLightIntensity; - illum = illum + pathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; - if (bounce == 0) { - aovIllum = aovIllum + aovPathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; - } else { - aovIllum = aovIllum + aovPathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; - } - } + // If ray misses, and we didn't previously explicitly sample the backgroound light, + // interpret normal as "miss color" assigned by miss program and move on to the next sample + // if ((payload.tHit <= 0.f)) && (sampledLightID != -1)) { + // irradiance = irradiance + missColor(ray) * optixLaunchParams.domeLightIntensity; + // illum = illum + pathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; + // if (bounce == 0) { + // aovIllum = aovIllum + aovPathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; + // } else { + // aovIllum = aovIllum + aovPathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; + // } + // } if (bounce == 0) { // aovPathThroughput = aovPathThroughput * bsdf_color; @@ -760,12 +806,12 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() } if (rdForcedBsdf != -1) { - if ((payload.tHit <= 0.0f) || (aovPathThroughput.x < EPSILON && aovPathThroughput.y < EPSILON && aovPathThroughput.z < EPSILON)) { + if (aovPathThroughput.x < EPSILON && aovPathThroughput.y < EPSILON && aovPathThroughput.z < EPSILON) { break; } } else { - if ((payload.tHit <= 0.0f) || (pathThroughput.x < EPSILON && pathThroughput.y < EPSILON && pathThroughput.z < EPSILON)) { + if (pathThroughput.x < EPSILON && pathThroughput.y < EPSILON && pathThroughput.z < EPSILON) { break; } } diff --git a/src/visii/visii.cpp b/src/visii/visii.cpp index 83518006..95ee36ae 100644 --- a/src/visii/visii.cpp +++ b/src/visii/visii.cpp @@ -408,6 +408,61 @@ void setDomeLightTexture(Texture* texture) { // OptixData.domeLightTexture = texture; OptixData.LP.environmentMapID = texture->getId(); + std::vector texels = texture->getTexels(); + int width = texture->getWidth(); + int height = texture->getHeight(); + + // why do i need to do this? + // if (width < 32) width = 32; + // if (height < 32) height = 32; + + float invWidth = 1.f / float(width); + float invHeight = 1.f / float(height); + float invjacobian = width * height / float(4 * M_PI); + + auto rows = std::vector(height); + auto cols = std::vector(width * height); + for (int y = 0, i = 0; y < height; y++) { + for (int x = 0; x < width; x++, i++) { + cols[i] = std::max(texels[i].r, std::max(texels[i].g, texels[i].b)) + ((x > 0) ? cols[i - 1] : 0.f); + } + rows[y] = cols[i - 1] + ((y > 0) ? rows[y - 1] : 0.0f); + // normalize the pdf for this scanline (if it was non-zero) + if (cols[i - 1] > 0) { + for (int x = 0; x < width; x++) { + cols[i - width + x] /= cols[i - 1]; + } + } + } + + // normalize the pdf across all scanlines + for (int y = 0; y < height; y++) + rows[y] /= rows[height - 1]; + + // both eval and sample below return a "weight" that is + // value[i] / row*col_pdf, so might as well bake it into the table + for (int y = 0, i = 0; y < height; y++) { + float row_pdf = rows[y] - (y > 0 ? rows[y - 1] : 0.0f); + for (int x = 0; x < width; x++, i++) { + float col_pdf = cols[i] - (x > 0 ? cols[i - 1] : 0.0f); + texels[i].r /= row_pdf * col_pdf * invjacobian; + texels[i].g /= row_pdf * col_pdf * invjacobian; + texels[i].b /= row_pdf * col_pdf * invjacobian; + } + } + + #if 1 // DEBUG: visualize importance table + // using namespace OIIO; + // ImageOutput* out = ImageOutput::create("bg.exr"); + // ImageSpec spec(res, res, 3, TypeDesc::TypeFloat); + // if (out && out->open("bg.exr", spec)) + // out->write_image(TypeDesc::TypeFloat, &values[0]); + // delete out; + + stbi_flip_vertically_on_write(true); + stbi_write_hdr("test.hdr", width, height, /* num channels*/ 4, (float*)texels.data()); + #endif + resetAccumulation(); } From 5111a94eb494aa15bdffa8f1444c2fca8b564bb8 Mon Sep 17 00:00:00 2001 From: n8vm Date: Wed, 29 Jul 2020 17:33:54 -0600 Subject: [PATCH 12/25] Dome light importance sampling works. Directional lights seem broken --- src/visii/devicecode/launch_params.h | 4 + src/visii/devicecode/path_tracer.cu | 165 ++++++++++++- src/visii/visii.cpp | 342 ++++++++++++++------------- 3 files changed, 335 insertions(+), 176 deletions(-) diff --git a/src/visii/devicecode/launch_params.h b/src/visii/devicecode/launch_params.h index 1cdb31fa..28aee8ad 100644 --- a/src/visii/devicecode/launch_params.h +++ b/src/visii/devicecode/launch_params.h @@ -56,6 +56,10 @@ struct LaunchParams { int32_t environmentMapID = -1; glm::quat environmentMapRotation = glm::quat(1,0,0,0); + float* environmentMapRows = nullptr; + float* environmentMapCols = nullptr; + int environmentMapWidth = 0; + int environmentMapHeight = 0; cudaTextureObject_t *textureObjects = nullptr; cudaTextureObject_t GGX_E_AVG_LOOKUP; diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index 73e60120..c6963586 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -20,23 +20,95 @@ struct RayPayload { float localToWorldT1[12]; }; -inline __device__ -vec2 toSpherical(vec3 dir) { - dir = normalize(dir); - float u = atan(dir.z, dir.x) / (2.0f * 3.1415926535897932384626433832795f) + .5f; - float v = asin(dir.y) / 3.1415926535897932384626433832795f + .5f; - return vec2(u, (1.0f - v)); +__device__ +vec2 toUV(vec3 n) +{ + n.z = -n.z; + n.x = -n.x; + vec2 uv; + + uv.x = atan(-n.x, n.y); + uv.x = (uv.x + M_PI / 2.0) / (M_PI * 2.0) + M_PI * (28.670 / 360.0); + + uv.y = acos(n.z) / M_PI; + + return uv; } +// Uv range: [0, 1] +__device__ +vec3 toPolar(vec2 uv) +{ + float theta = 2.0 * M_PI * uv.x + - M_PI / 2.0; + float phi = M_PI * uv.y; + + vec3 n; + n.x = cos(theta) * sin(phi); + n.y = sin(theta) * sin(phi); + n.z = cos(phi); + + //n = normalize(n); + n.z = -n.z; + n.x = -n.x; + return n; +} + +// inline __device__ +// vec2 toSpherical(vec3 dir) { +// dir = normalize(dir); +// float u = atan(dir.z, dir.x) / (2.0f * 3.1415926535897932384626433832795f) + .5f; +// float v = asin(dir.y) / 3.1415926535897932384626433832795f + .5f; +// return vec2(u, (1.0f - v)); +// } + +// inline __device__ +// vec3 toDirectional(vec2 coords) { +// dir = normalize(dir); +// float u = atan(dir.z, dir.x) / (2.0f * 3.1415926535897932384626433832795f) + .5f; +// float v = asin(dir.y) / 3.1415926535897932384626433832795f + .5f; +// return vec2(u, (1.0f - v)); +// } + +// Dual2 map(float x, float y) const { +// // pixel coordinates of entry (x,y) +// Dual2 u = Dual2(x, 1, 0) * invres; +// Dual2 v = Dual2(y, 0, 1) * invres; +// Dual2 theta = u * float(2 * M_PI); +// Dual2 st, ct; +// fast_sincos(theta, &st, &ct); +// Dual2 cos_phi = 1.0f - 2.0f * v; +// Dual2 sin_phi = sqrt(1.0f - cos_phi * cos_phi); +// return make_Vec3(sin_phi * ct, +// sin_phi * st, +// cos_phi); +// } + inline __device__ float3 missColor(const owl::Ray &ray) { - auto pixelID = owl::getLaunchIndex(); - vec3 rayDir = optixLaunchParams.environmentMapRotation * make_vec3(normalize(ray.direction)); if (optixLaunchParams.environmentMapID != -1) { - vec2 tc = toSpherical(vec3(rayDir.x, -rayDir.z, rayDir.y)); + vec2 tc = toUV(vec3(rayDir.x, rayDir.y, rayDir.z)); + cudaTextureObject_t tex = optixLaunchParams.textureObjects[optixLaunchParams.environmentMapID]; + if (!tex) return make_float3(1.f, 0.f, 1.f); + + float4 texColor = tex2D(tex, tc.x,tc.y); + return make_float3(texColor); + } + + float t = 0.5f*(rayDir.z + 1.0f); + float3 c = (1.0f - t) * make_float3(pow(vec3(1.0f), vec3(2.2f))) + t * make_float3( pow(vec3(0.5f, 0.7f, 1.0f), vec3(2.2f)) ); + return c; +} + +inline __device__ +float3 missColor(const float3 dir) +{ + vec3 rayDir = optixLaunchParams.environmentMapRotation * make_vec3(normalize(dir)); + if (optixLaunchParams.environmentMapID != -1) + { + vec2 tc = toUV(vec3(rayDir.x, rayDir.y, rayDir.z)); cudaTextureObject_t tex = optixLaunchParams.textureObjects[optixLaunchParams.environmentMapID]; if (!tex) return make_float3(1.f, 0.f, 1.f); @@ -351,6 +423,50 @@ float3 faceNormalForward(const float3 &w_o, const float3 &gn, const float3 &n) return new_n; } +__device__ +const float* upper_bound (const float* first, const float* last, const float& val) +{ + const float* it; +// iterator_traits::difference_type count, step; + int count, step; +// count = std::distance(first,last); + count = (last-first); + while (count > 0) + { + it = first; + step=count/2; + // std::advance (it,step); + it = it + step; + if ( ! (val < *it)) // or: if (!comp(val,*it)), for version (2) + { + first=++it; + count-=step+1; + } + else count=step; + } + return first; +} + +__device__ float sample_cdf(const float* data, unsigned int n, float x, unsigned int *idx, float* pdf) +{ + // OSL_DASSERT(x >= 0); + // OSL_DASSERT(x < 1); + *idx = upper_bound(data, data + n, x) - data; + // OSL_DASSERT(*idx < n); + // OSL_DASSERT(x < data[*idx]); + float scaled_sample; + if (*idx == 0) { + *pdf = data[0]; + scaled_sample = x / data[0]; + } else { + // OSL_DASSERT(x >= data[*idx - 1]); + *pdf = data[*idx] - data[*idx - 1]; + scaled_sample = (x - data[*idx - 1]) / (data[*idx] - data[*idx - 1]); + } + // keep result in [0,1) + return min(scaled_sample, 0.99999994f); +} + OPTIX_RAYGEN_PROGRAM(rayGen)() { auto pixelID = ivec2(owl::getLaunchIndex()[0], owl::getLaunchIndex()[1]); @@ -588,9 +704,32 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() if (random_id == numLights) { sampledLightID = -1; const uint32_t occlusion_flags = OPTIX_RAY_FLAG_DISABLE_ANYHIT | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; - const float3 hemi_dir = normalize(cos_sample_hemisphere(make_float2(lcg_randomf(rng), lcg_randomf(rng)))); - float3 light_dir = make_float3(normalize(tbn * normalize(make_vec3(hemi_dir))) ); - light_pdf = 1.f; + float3 light_dir; + + if ((optixLaunchParams.environmentMapWidth != 0) && (optixLaunchParams.environmentMapHeight != 0)) { + // Vec3fa color = m_background->sample(dg, wi, tMax, RandomSampler_get2D(sampler)); + float rx = lcg_randomf(rng); + float ry = lcg_randomf(rng); + float* rows = optixLaunchParams.environmentMapRows; + float* cols = optixLaunchParams.environmentMapCols; + int width = optixLaunchParams.environmentMapWidth; + int height = optixLaunchParams.environmentMapHeight; + float invjacobian = width * height / float(4 * M_PI); + float row_pdf, col_pdf; + unsigned x, y; + ry = sample_cdf(rows, height, ry, &y, &row_pdf); + rx = sample_cdf(cols + y * width, width, rx, &x, &col_pdf); + // y = height - y; + light_dir = make_float3(toPolar(vec2((x/* + rx*/) / float(width), (y/* + ry*/)/float(height)))); + light_pdf = row_pdf * col_pdf * invjacobian; + } + else + { + const float3 hemi_dir = normalize(cos_sample_hemisphere(make_float2(lcg_randomf(rng), lcg_randomf(rng)))); + light_dir = make_float3(normalize(tbn * normalize(make_vec3(hemi_dir))) ); + light_pdf = 1.f; + } + float dotNWi = fabs(dot(light_dir, v_z)); // for now, making all lights double sided. float bsdf_pdf; @@ -607,6 +746,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() owl::traceRay( optixLaunchParams.world, ray, payload, occlusion_flags); int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; bool visible = (payload.instanceID == -1); + if (visible) { float w = power_heuristic(1.f, light_pdf, 1.f, bsdf_pdf); float3 bsdf, bsdf_color; @@ -840,7 +980,6 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // printf("aov gillum: %f %f %f\n", aovGIllum.x, aovGIllum.y, aovGIllum.z); // printf("aov dillum: %f %f %f\n", aovDirectIllum.x, aovDirectIllum.y, aovDirectIllum.z); // printf("aov iillum: %f %f %f\n", aovIndirectIllum.x, aovIndirectIllum.y, aovIndirectIllum.z); - // printf("gillum: %f %f %f\n", gillum.x, gillum.y, gillum.z); // printf("dillum: %f %f %f\n", dillum.x, dillum.y, dillum.z); // printf("iillum: %f %f %f\n", iillum.x, iillum.y, iillum.z); diff --git a/src/visii/visii.cpp b/src/visii/visii.cpp index 95ee36ae..6c92d645 100644 --- a/src/visii/visii.cpp +++ b/src/visii/visii.cpp @@ -1,5 +1,7 @@ #include +#include + #include #include #include @@ -111,7 +113,11 @@ static struct OptixData { Texture* domeLightTexture = nullptr; + OWLBuffer environmentMapRowsBuffer; + OWLBuffer environmentMapColsBuffer; + OWLBuffer placeholder; + } OptixData; static struct ViSII { @@ -383,134 +389,6 @@ void synchronizeDevices() cudaSetDevice(0); } -void setCameraEntity(Entity* camera_entity) -{ - if (!camera_entity) { - OptixData.LP.cameraEntity = EntityStruct(); - OptixData.LP.cameraEntity.initialized = false; - resetAccumulation(); - } - else { - if (!camera_entity->isInitialized()) throw std::runtime_error("Error: camera entity is uninitialized"); - OptixData.LP.cameraEntity = camera_entity->getStruct(); - } - resetAccumulation(); -} - -void setDomeLightIntensity(float intensity) -{ - intensity = std::max(float(intensity), float(0.f)); - OptixData.LP.domeLightIntensity = intensity; - resetAccumulation(); -} - -void setDomeLightTexture(Texture* texture) -{ - // OptixData.domeLightTexture = texture; - OptixData.LP.environmentMapID = texture->getId(); - std::vector texels = texture->getTexels(); - int width = texture->getWidth(); - int height = texture->getHeight(); - - // why do i need to do this? - // if (width < 32) width = 32; - // if (height < 32) height = 32; - - float invWidth = 1.f / float(width); - float invHeight = 1.f / float(height); - float invjacobian = width * height / float(4 * M_PI); - - auto rows = std::vector(height); - auto cols = std::vector(width * height); - for (int y = 0, i = 0; y < height; y++) { - for (int x = 0; x < width; x++, i++) { - cols[i] = std::max(texels[i].r, std::max(texels[i].g, texels[i].b)) + ((x > 0) ? cols[i - 1] : 0.f); - } - rows[y] = cols[i - 1] + ((y > 0) ? rows[y - 1] : 0.0f); - // normalize the pdf for this scanline (if it was non-zero) - if (cols[i - 1] > 0) { - for (int x = 0; x < width; x++) { - cols[i - width + x] /= cols[i - 1]; - } - } - } - - // normalize the pdf across all scanlines - for (int y = 0; y < height; y++) - rows[y] /= rows[height - 1]; - - // both eval and sample below return a "weight" that is - // value[i] / row*col_pdf, so might as well bake it into the table - for (int y = 0, i = 0; y < height; y++) { - float row_pdf = rows[y] - (y > 0 ? rows[y - 1] : 0.0f); - for (int x = 0; x < width; x++, i++) { - float col_pdf = cols[i] - (x > 0 ? cols[i - 1] : 0.0f); - texels[i].r /= row_pdf * col_pdf * invjacobian; - texels[i].g /= row_pdf * col_pdf * invjacobian; - texels[i].b /= row_pdf * col_pdf * invjacobian; - } - } - - #if 1 // DEBUG: visualize importance table - // using namespace OIIO; - // ImageOutput* out = ImageOutput::create("bg.exr"); - // ImageSpec spec(res, res, 3, TypeDesc::TypeFloat); - // if (out && out->open("bg.exr", spec)) - // out->write_image(TypeDesc::TypeFloat, &values[0]); - // delete out; - - stbi_flip_vertically_on_write(true); - stbi_write_hdr("test.hdr", width, height, /* num channels*/ 4, (float*)texels.data()); - #endif - - resetAccumulation(); -} - -void setDomeLightRotation(glm::quat rotation) -{ - OptixData.LP.environmentMapRotation = rotation; - resetAccumulation(); -} - -void setIndirectLightingClamp(float clamp) -{ - clamp = std::max(float(clamp), float(0.f)); - OptixData.LP.indirectClamp = clamp; - resetAccumulation(); - launchParamsSetRaw(OptixData.launchParams, "indirectClamp", &OptixData.LP.indirectClamp); -} - -void setDirectLightingClamp(float clamp) -{ - clamp = std::max(float(clamp), float(0.f)); - OptixData.LP.directClamp = clamp; - resetAccumulation(); - launchParamsSetRaw(OptixData.launchParams, "directClamp", &OptixData.LP.directClamp); -} - -void setMaxBounceDepth(uint32_t depth) -{ - OptixData.LP.maxBounceDepth = depth; - resetAccumulation(); - launchParamsSetRaw(OptixData.launchParams, "maxBounceDepth", &OptixData.LP.maxBounceDepth); -} - -void samplePixelArea(vec2 xSampleInterval, vec2 ySampleInterval) -{ - OptixData.LP.xPixelSamplingInterval = xSampleInterval; - OptixData.LP.yPixelSamplingInterval = ySampleInterval; - resetAccumulation(); - launchParamsSetRaw(OptixData.launchParams, "xPixelSamplingInterval", &OptixData.LP.xPixelSamplingInterval); - launchParamsSetRaw(OptixData.launchParams, "yPixelSamplingInterval", &OptixData.LP.yPixelSamplingInterval); -} - -void sampleTimeInterval(vec2 sampleTimeInterval) -{ - OptixData.LP.timeSamplingInterval = sampleTimeInterval; - resetAccumulation(); - launchParamsSetRaw(OptixData.launchParams, "timeSamplingInterval", &OptixData.LP.timeSamplingInterval); -} - void initializeFrameBuffer(int fbWidth, int fbHeight) { fbWidth = glm::max(fbWidth, 1); fbHeight = glm::max(fbHeight, 1); @@ -638,6 +516,10 @@ void initializeOptix(bool headless) { "viewT1", OWL_USER_TYPE(glm::mat4), OWL_OFFSETOF(LaunchParams, viewT1)}, { "environmentMapID", OWL_USER_TYPE(uint32_t), OWL_OFFSETOF(LaunchParams, environmentMapID)}, { "environmentMapRotation", OWL_USER_TYPE(glm::quat), OWL_OFFSETOF(LaunchParams, environmentMapRotation)}, + { "environmentMapRows", OWL_BUFPTR, OWL_OFFSETOF(LaunchParams, environmentMapRows)}, + { "environmentMapCols", OWL_BUFPTR, OWL_OFFSETOF(LaunchParams, environmentMapCols)}, + { "environmentMapWidth", OWL_USER_TYPE(uint32_t), OWL_OFFSETOF(LaunchParams, environmentMapWidth)}, + { "environmentMapHeight", OWL_USER_TYPE(uint32_t), OWL_OFFSETOF(LaunchParams, environmentMapHeight)}, { "textureObjects", OWL_BUFPTR, OWL_OFFSETOF(LaunchParams, textureObjects)}, { "GGX_E_AVG_LOOKUP", OWL_TEXTURE, OWL_OFFSETOF(LaunchParams, GGX_E_AVG_LOOKUP)}, { "GGX_E_LOOKUP", OWL_TEXTURE, OWL_OFFSETOF(LaunchParams, GGX_E_LOOKUP)}, @@ -704,6 +586,12 @@ void initializeOptix(bool headless) OD.LP.environmentMapRotation = glm::quat(1,0,0,0); launchParamsSetRaw(OD.launchParams, "environmentMapID", &OD.LP.environmentMapID); launchParamsSetRaw(OD.launchParams, "environmentMapRotation", &OD.LP.environmentMapRotation); + + launchParamsSetBuffer(OD.launchParams, "environmentMapRows", OD.environmentMapRowsBuffer); + launchParamsSetBuffer(OD.launchParams, "environmentMapCols", OD.environmentMapColsBuffer); + launchParamsSetRaw(OD.launchParams, "environmentMapWidth", &OD.LP.environmentMapWidth); + launchParamsSetRaw(OD.launchParams, "environmentMapHeight", &OD.LP.environmentMapHeight); + OWLTexture GGX_E_AVG_LOOKUP = owlTexture2DCreate(OD.context, OWL_TEXEL_FORMAT_R32F, @@ -813,6 +701,161 @@ void initializeImgui() ImGui_ImplOpenGL3_Init(glsl_version); } +std::future enqueueCommand(std::function function) +{ + if (ViSII.render_thread_id != std::this_thread::get_id()) + std::lock_guard lock(ViSII.qMutex); + + ViSII::Command c; + c.function = function; + c.promise = std::make_shared>(); + auto new_future = c.promise->get_future(); + ViSII.commandQueue.push(c); + // cv.notify_one(); + return new_future; +} + +void processCommandQueue() +{ + std::lock_guard lock(ViSII.qMutex); + while (!ViSII.commandQueue.empty()) { + auto item = ViSII.commandQueue.front(); + item.function(); + try { + item.promise->set_value(); + } + catch (std::future_error& e) { + if (e.code() == std::make_error_condition(std::future_errc::promise_already_satisfied)) + std::cout << "ViSII: [promise already satisfied]\n"; + else + std::cout << "ViSII: [unknown exception]\n"; + } + ViSII.commandQueue.pop(); + } +} + +void setCameraEntity(Entity* camera_entity) +{ + if (!camera_entity) { + OptixData.LP.cameraEntity = EntityStruct(); + OptixData.LP.cameraEntity.initialized = false; + resetAccumulation(); + } + else { + if (!camera_entity->isInitialized()) throw std::runtime_error("Error: camera entity is uninitialized"); + OptixData.LP.cameraEntity = camera_entity->getStruct(); + } + resetAccumulation(); +} + +void setDomeLightIntensity(float intensity) +{ + intensity = std::max(float(intensity), float(0.f)); + OptixData.LP.domeLightIntensity = intensity; + resetAccumulation(); +} + +void setDomeLightTexture(Texture* texture) +{ + auto func = [texture] () { + OptixData.LP.environmentMapID = texture->getId(); + std::vector texels = texture->getTexels(); + int width = texture->getWidth(); + int height = texture->getHeight(); + + float invWidth = 1.f / float(width); + float invHeight = 1.f / float(height); + float invjacobian = width * height / float(4 * M_PI); + + auto rows = std::vector(height); + auto cols = std::vector(width * height); + for (int y = 0, i = 0; y < height; y++) { + for (int x = 0; x < width; x++, i++) { + cols[i] = std::max(texels[i].r, std::max(texels[i].g, texels[i].b)) + ((x > 0) ? cols[i - 1] : 0.f); + } + rows[y] = cols[i - 1] + ((y > 0) ? rows[y - 1] : 0.0f); + // normalize the pdf for this scanline (if it was non-zero) + if (cols[i - 1] > 0) { + for (int x = 0; x < width; x++) { + cols[i - width + x] /= cols[i - 1]; + } + } + } + + // normalize the pdf across all scanlines + for (int y = 0; y < height; y++) + rows[y] /= rows[height - 1]; + + // both eval and sample below return a "weight" that is + // value[i] / row*col_pdf, so might as well bake it into the table + for (int y = 0, i = 0; y < height; y++) { + float row_pdf = rows[y] - (y > 0 ? rows[y - 1] : 0.0f); + for (int x = 0; x < width; x++, i++) { + float col_pdf = cols[i] - (x > 0 ? cols[i - 1] : 0.0f); + texels[i].r /= row_pdf * col_pdf * invjacobian; + texels[i].g /= row_pdf * col_pdf * invjacobian; + texels[i].b /= row_pdf * col_pdf * invjacobian; + } + } + + if (OptixData.environmentMapRowsBuffer) owlBufferRelease(OptixData.environmentMapRowsBuffer); + if (OptixData.environmentMapColsBuffer) owlBufferRelease(OptixData.environmentMapColsBuffer); + OptixData.environmentMapRowsBuffer = owlDeviceBufferCreate(OptixData.context, OWL_USER_TYPE(float), height, rows.data()); + OptixData.environmentMapColsBuffer = owlDeviceBufferCreate(OptixData.context, OWL_USER_TYPE(float), width * height, cols.data()); + OptixData.LP.environmentMapWidth = width; + OptixData.LP.environmentMapHeight = height; + resetAccumulation(); + }; + + auto future = enqueueCommand(func); + future.wait(); +} + +void setDomeLightRotation(glm::quat rotation) +{ + OptixData.LP.environmentMapRotation = rotation; + resetAccumulation(); +} + +void setIndirectLightingClamp(float clamp) +{ + clamp = std::max(float(clamp), float(0.f)); + OptixData.LP.indirectClamp = clamp; + resetAccumulation(); + launchParamsSetRaw(OptixData.launchParams, "indirectClamp", &OptixData.LP.indirectClamp); +} + +void setDirectLightingClamp(float clamp) +{ + clamp = std::max(float(clamp), float(0.f)); + OptixData.LP.directClamp = clamp; + resetAccumulation(); + launchParamsSetRaw(OptixData.launchParams, "directClamp", &OptixData.LP.directClamp); +} + +void setMaxBounceDepth(uint32_t depth) +{ + OptixData.LP.maxBounceDepth = depth; + resetAccumulation(); + launchParamsSetRaw(OptixData.launchParams, "maxBounceDepth", &OptixData.LP.maxBounceDepth); +} + +void samplePixelArea(vec2 xSampleInterval, vec2 ySampleInterval) +{ + OptixData.LP.xPixelSamplingInterval = xSampleInterval; + OptixData.LP.yPixelSamplingInterval = ySampleInterval; + resetAccumulation(); + launchParamsSetRaw(OptixData.launchParams, "xPixelSamplingInterval", &OptixData.LP.xPixelSamplingInterval); + launchParamsSetRaw(OptixData.launchParams, "yPixelSamplingInterval", &OptixData.LP.yPixelSamplingInterval); +} + +void sampleTimeInterval(vec2 sampleTimeInterval) +{ + OptixData.LP.timeSamplingInterval = sampleTimeInterval; + resetAccumulation(); + launchParamsSetRaw(OptixData.launchParams, "timeSamplingInterval", &OptixData.LP.timeSamplingInterval); +} + void updateComponents() { auto &OD = OptixData; @@ -1035,14 +1078,20 @@ void updateLaunchParams() launchParamsSetRaw(OptixData.launchParams, "frameSize", &OptixData.LP.frameSize); launchParamsSetRaw(OptixData.launchParams, "cameraEntity", &OptixData.LP.cameraEntity); launchParamsSetRaw(OptixData.launchParams, "domeLightIntensity", &OptixData.LP.domeLightIntensity); - launchParamsSetRaw(OptixData.launchParams, "environmentMapID", &OptixData.LP.environmentMapID); - launchParamsSetRaw(OptixData.launchParams, "environmentMapRotation", &OptixData.LP.environmentMapRotation); launchParamsSetRaw(OptixData.launchParams, "renderDataMode", &OptixData.LP.renderDataMode); launchParamsSetRaw(OptixData.launchParams, "renderDataBounce", &OptixData.LP.renderDataBounce); launchParamsSetRaw(OptixData.launchParams, "seed", &OptixData.LP.seed); launchParamsSetRaw(OptixData.launchParams, "proj", &OptixData.LP.proj); launchParamsSetRaw(OptixData.launchParams, "viewT0", &OptixData.LP.viewT0); launchParamsSetRaw(OptixData.launchParams, "viewT1", &OptixData.LP.viewT1); + + launchParamsSetRaw(OptixData.launchParams, "environmentMapID", &OptixData.LP.environmentMapID); + launchParamsSetRaw(OptixData.launchParams, "environmentMapRotation", &OptixData.LP.environmentMapRotation); + launchParamsSetBuffer(OptixData.launchParams, "environmentMapRows", OptixData.environmentMapRowsBuffer); + launchParamsSetBuffer(OptixData.launchParams, "environmentMapCols", OptixData.environmentMapColsBuffer); + launchParamsSetRaw(OptixData.launchParams, "environmentMapWidth", &OptixData.LP.environmentMapWidth); + launchParamsSetRaw(OptixData.launchParams, "environmentMapHeight", &OptixData.LP.environmentMapHeight); + OptixData.LP.frameID ++; } @@ -1198,39 +1247,6 @@ void drawGUI() // } } -std::future enqueueCommand(std::function function) -{ - if (ViSII.render_thread_id != std::this_thread::get_id()) - std::lock_guard lock(ViSII.qMutex); - - ViSII::Command c; - c.function = function; - c.promise = std::make_shared>(); - auto new_future = c.promise->get_future(); - ViSII.commandQueue.push(c); - // cv.notify_one(); - return new_future; -} - -void processCommandQueue() -{ - std::lock_guard lock(ViSII.qMutex); - while (!ViSII.commandQueue.empty()) { - auto item = ViSII.commandQueue.front(); - item.function(); - try { - item.promise->set_value(); - } - catch (std::future_error& e) { - if (e.code() == std::make_error_condition(std::future_errc::promise_already_satisfied)) - std::cout << "ViSII: [promise already satisfied]\n"; - else - std::cout << "ViSII: [unknown exception]\n"; - } - ViSII.commandQueue.pop(); - } -} - void resizeWindow(uint32_t width, uint32_t height) { width = (width <= 0) ? 1 : width; From fe5cecbcbf5002d4d0ab367cc7dc4ab535b13c7e Mon Sep 17 00:00:00 2001 From: n8vm Date: Wed, 29 Jul 2020 18:37:59 -0600 Subject: [PATCH 13/25] Fixed bug where direct lights werent being sampled --- src/visii/devicecode/path_tracer.cu | 27 +++++++++------------------ src/visii/visii.cpp | 2 +- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index c6963586..7357a8f7 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -677,7 +677,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() } // Sample a light source - uint32_t sampledLightID; + int32_t sampledLightID = -1; int numLights = optixLaunchParams.numLightEntities; // float3 lightEmission = make_float3(0.f); float3 irradiance = make_float3(0.f); @@ -698,8 +698,8 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // first, sample the light source by importance sampling the light do { - uint32_t random_id = uint32_t(min(lcg_randomf(rng) * numLights+1, float(numLights))); - + uint32_t random_id = uint32_t(min(lcg_randomf(rng) * (numLights+1), float(numLights))); + // sample background if (random_id == numLights) { sampledLightID = -1; @@ -757,7 +757,9 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() } } // sample light sources - else { + else + { + if (numLights == 0) break; random_id = min(random_id, numLights - 1); sampledLightID = optixLaunchParams.lightEntities[random_id]; light_entity = optixLaunchParams.entities[sampledLightID]; @@ -810,7 +812,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, uv, make_vec4(default_light_emission))) * light_light.intensity; - + if ((light_pdf > EPSILON) && (dotNWi > EPSILON)) { float3 light_dir = make_float3(dir.x, dir.y, dir.z); light_dir = normalize(light_dir); @@ -878,7 +880,8 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); } } - else { + else if (payload.instanceID != -1) { + // Case where we hit the light, and also previously sampled the same light int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; bool visible = (entityID == sampledLightID); // We hit the light we sampled previously @@ -926,18 +929,6 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // // aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; // } - // If ray misses, and we didn't previously explicitly sample the backgroound light, - // interpret normal as "miss color" assigned by miss program and move on to the next sample - // if ((payload.tHit <= 0.f)) && (sampledLightID != -1)) { - // irradiance = irradiance + missColor(ray) * optixLaunchParams.domeLightIntensity; - // illum = illum + pathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; - // if (bounce == 0) { - // aovIllum = aovIllum + aovPathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; - // } else { - // aovIllum = aovIllum + aovPathThroughput * missColor(ray) * optixLaunchParams.domeLightIntensity; - // } - // } - if (bounce == 0) { // aovPathThroughput = aovPathThroughput * bsdf_color; directIllum = illum; diff --git a/src/visii/visii.cpp b/src/visii/visii.cpp index 6c92d645..76004936 100644 --- a/src/visii/visii.cpp +++ b/src/visii/visii.cpp @@ -803,7 +803,7 @@ void setDomeLightTexture(Texture* texture) OptixData.environmentMapRowsBuffer = owlDeviceBufferCreate(OptixData.context, OWL_USER_TYPE(float), height, rows.data()); OptixData.environmentMapColsBuffer = owlDeviceBufferCreate(OptixData.context, OWL_USER_TYPE(float), width * height, cols.data()); OptixData.LP.environmentMapWidth = width; - OptixData.LP.environmentMapHeight = height; + OptixData.LP.environmentMapHeight = height; resetAccumulation(); }; From 0eea69f8032c6fe54ea97f5535db83f170d2f9a3 Mon Sep 17 00:00:00 2001 From: n8vm Date: Thu, 30 Jul 2020 09:37:22 -0600 Subject: [PATCH 14/25] Adding the ability to take multiple light samples per path vertex --- include/visii/visii.h | 8 ++ src/visii/devicecode/launch_params.h | 3 + src/visii/devicecode/path_tracer.cu | 163 ++++++++++++++------------- src/visii/visii.cpp | 27 ++++- 4 files changed, 118 insertions(+), 83 deletions(-) diff --git a/include/visii/visii.h b/include/visii/visii.h index 0b72c0a3..d241e1b4 100644 --- a/include/visii/visii.h +++ b/include/visii/visii.h @@ -90,6 +90,14 @@ void setDirectLightingClamp(float clamp); */ void setMaxBounceDepth(uint32_t depth); +/** + * Sets the number of light samples to take per path vertex. A higher number of samples will reduce noise per frame, but + * also reduces frames per second. + * + * @param count The number of light samples to take per path vertex. Currently constrained to a maximum of 10 samples per vertex. + */ +void setLightSampleCount(uint32_t count); + /** * Sets the region of the pixel where rays should sample. By default, rays sample the entire * pixel area between [0,1]. Rays can instead sample a specific location of the pixel, like the pixel center, diff --git a/src/visii/devicecode/launch_params.h b/src/visii/devicecode/launch_params.h index 28aee8ad..abf10d14 100644 --- a/src/visii/devicecode/launch_params.h +++ b/src/visii/devicecode/launch_params.h @@ -29,6 +29,7 @@ struct LaunchParams { float directClamp = 100.f; float indirectClamp = 100.f; uint32_t maxBounceDepth = 10; + uint32_t numLightSamples = 2; uint32_t seed = 0; vec2 xPixelSamplingInterval = vec2(0.f,1.f); vec2 yPixelSamplingInterval = vec2(0.f,1.f); @@ -92,4 +93,6 @@ enum RenderDataFlags : uint32_t { RAY_DIRECTION = 18, }; +#define MAX_LIGHT_SAMPLES 10 + // #define REPROJECT true diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index 7357a8f7..e344d6fc 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -677,11 +677,12 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() } // Sample a light source - int32_t sampledLightID = -1; + int32_t sampledLightIDs[MAX_LIGHT_SAMPLES] = {-2}; + float lightPDFs[MAX_LIGHT_SAMPLES] = {0.f}; + int numLights = optixLaunchParams.numLightEntities; - // float3 lightEmission = make_float3(0.f); float3 irradiance = make_float3(0.f); - float light_pdf = 0.f; + // float3 lightEmission = make_float3(0.f); EntityStruct light_entity; MaterialStruct light_material; @@ -697,14 +698,15 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() int forcedBsdf = rdForcedBsdf;//(bounce == optixLaunchParams.renderDataBounce) ? rdForcedBsdf : -1; // first, sample the light source by importance sampling the light - do { - uint32_t random_id = uint32_t(min(lcg_randomf(rng) * (numLights+1), float(numLights))); + for (uint32_t lid = 0; lid < optixLaunchParams.numLightSamples; ++lid) + { + uint32_t randomID = uint32_t(min(lcg_randomf(rng) * (numLights+1), float(numLights))); // sample background - if (random_id == numLights) { - sampledLightID = -1; - const uint32_t occlusion_flags = OPTIX_RAY_FLAG_DISABLE_ANYHIT | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; - float3 light_dir; + if (randomID == numLights) { + sampledLightIDs[lid] = -1; + const uint32_t occlusionFlags = OPTIX_RAY_FLAG_DISABLE_ANYHIT | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; + float3 lightDir; if ((optixLaunchParams.environmentMapWidth != 0) && (optixLaunchParams.environmentMapHeight != 0)) { // Vec3fa color = m_background->sample(dg, wi, tMax, RandomSampler_get2D(sampler)); @@ -720,53 +722,53 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() ry = sample_cdf(rows, height, ry, &y, &row_pdf); rx = sample_cdf(cols + y * width, width, rx, &x, &col_pdf); // y = height - y; - light_dir = make_float3(toPolar(vec2((x/* + rx*/) / float(width), (y/* + ry*/)/float(height)))); - light_pdf = row_pdf * col_pdf * invjacobian; + lightDir = make_float3(toPolar(vec2((x/* + rx*/) / float(width), (y/* + ry*/)/float(height)))); + lightPDFs[lid] = row_pdf * col_pdf * invjacobian; } else { const float3 hemi_dir = normalize(cos_sample_hemisphere(make_float2(lcg_randomf(rng), lcg_randomf(rng)))); - light_dir = make_float3(normalize(tbn * normalize(make_vec3(hemi_dir))) ); - light_pdf = 1.f; + lightDir = make_float3(normalize(tbn * normalize(make_vec3(hemi_dir))) ); + lightPDFs[lid] = 1.f; } - float dotNWi = fabs(dot(light_dir, v_z)); // for now, making all lights double sided. + float dotNWi = fabs(dot(lightDir, v_z)); // for now, making all lights double sided. - float bsdf_pdf; - disney_pdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf_pdf, forcedBsdf); - if (bsdf_pdf > EPSILON) { + float bsdfPDF; + disney_pdf(mat, n_l, w_o, lightDir, v_x, v_y, bsdfPDF, forcedBsdf); + if (bsdfPDF > EPSILON) { RayPayload payload; owl::Ray ray; ray.tmin = EPSILON * 10.f; ray.tmax = 1e20f; ray.origin = hit_p; - ray.direction = light_dir; + ray.direction = lightDir; payload.tHit = -1.f; ray.time = time; - owl::traceRay( optixLaunchParams.world, ray, payload, occlusion_flags); + owl::traceRay( optixLaunchParams.world, ray, payload, occlusionFlags); int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; bool visible = (payload.instanceID == -1); if (visible) { - float w = power_heuristic(1.f, light_pdf, 1.f, bsdf_pdf); + float w = power_heuristic(1.f, lightPDFs[lid], 1.f, bsdfPDF); float3 bsdf, bsdf_color; - disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); - float3 Li = (missColor(ray) * optixLaunchParams.domeLightIntensity) * w / light_pdf; - irradiance = (bsdf * bsdf_color * Li * fabs(dotNWi)); + disney_brdf(mat, n_l, w_o, lightDir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); + float3 Li = (missColor(ray) * optixLaunchParams.domeLightIntensity) * w / lightPDFs[lid]; + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); } } } // sample light sources else { - if (numLights == 0) break; - random_id = min(random_id, numLights - 1); - sampledLightID = optixLaunchParams.lightEntities[random_id]; - light_entity = optixLaunchParams.entities[sampledLightID]; + if (numLights == 0) continue; + randomID = min(randomID, numLights - 1); + sampledLightIDs[lid] = optixLaunchParams.lightEntities[randomID]; + light_entity = optixLaunchParams.entities[sampledLightIDs[lid]]; // shouldn't happen, but just in case... - if ((light_entity.light_id < 0) || (light_entity.light_id > MAX_LIGHTS)) break; - if ((light_entity.transform_id < 0) || (light_entity.transform_id > MAX_TRANSFORMS)) break; + if ((light_entity.light_id < 0) || (light_entity.light_id > MAX_LIGHTS)) continue; + if ((light_entity.transform_id < 0) || (light_entity.transform_id > MAX_TRANSFORMS)) continue; light_light = optixLaunchParams.lights[light_entity.light_id]; TransformStruct transform = optixLaunchParams.transforms[light_entity.transform_id]; @@ -782,7 +784,7 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; // | OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT; - if (!is_area_light) break; + if (!is_area_light) continue; uint32_t random_tri_id = uint32_t(min(lcg_randomf(rng) * mesh.numTris, float(mesh.numTris - 1))); owl::device::Buffer *indexLists = (owl::device::Buffer *)optixLaunchParams.indexLists.data; @@ -805,15 +807,15 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() vec2 uv2 = texCoords[triIndex.y]; vec2 uv3 = texCoords[triIndex.z]; vec3 N = normalize(cross( normalize(v2 - v1), normalize(v3 - v1))); - sampleTriangle(pos, N, v1, v2, v3, uv1, uv2, uv3, lcg_randomf(rng), lcg_randomf(rng), dir, light_pdf, uv); + sampleTriangle(pos, N, v1, v2, v3, uv1, uv2, uv3, lcg_randomf(rng), lcg_randomf(rng), dir, lightPDFs[lid], uv); vec3 normal = glm::vec3(n_l.x, n_l.y, n_l.z); float dotNWi = fabs(dot(dir, normal)); // for now, making all lights double sided. - light_pdf = abs(light_pdf); + lightPDFs[lid] = abs(lightPDFs[lid]); float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, uv, make_vec4(default_light_emission))) * light_light.intensity; - if ((light_pdf > EPSILON) && (dotNWi > EPSILON)) { + if ((lightPDFs[lid] > EPSILON) && (dotNWi > EPSILON)) { float3 light_dir = make_float3(dir.x, dir.y, dir.z); light_dir = normalize(light_dir); float bsdf_pdf; @@ -830,19 +832,19 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() owl::traceRay( optixLaunchParams.world, ray, payload, occlusion_flags); if (payload.instanceID == -1) continue; int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; - bool visible = ((entityID == sampledLightID) || (entityID == -1)); + bool visible = ((entityID == sampledLightIDs[lid]) || (entityID == -1)); if (visible) { - float w = power_heuristic(1.f, light_pdf, 1.f, bsdf_pdf); + float w = power_heuristic(1.f, lightPDFs[lid], 1.f, bsdf_pdf); float3 bsdf, bsdf_color; disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); - float3 Li = lightEmission * w / light_pdf; - irradiance = (bsdf * bsdf_color * Li * fabs(dotNWi)); + float3 Li = lightEmission * w / lightPDFs[lid]; + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); } } } } } - } while (false); + } // next, sample a light source by importance sampling the BDRF float3 w_i; @@ -868,53 +870,58 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() ray.time = sampleTime(lcg_randomf(rng)); owl::traceRay(optixLaunchParams.world, ray, payload); - if (light_pdf > EPSILON) + for (uint32_t lid = 0; lid < optixLaunchParams.numLightSamples; ++lid) { - // if by sampling the brdf we also hit the light source... - if ((payload.instanceID == -1) && (sampledLightID == -1)) { - // Case where we hit the background, and also previously sampled the background - float dotNWi = fabs(dot(-v_gz, ray.direction)); // for now, making all lights double sided. - if (dotNWi > 0.f) { - float w = power_heuristic(1.f, bsdf_pdf, 1.f, light_pdf); - float3 Li = (missColor(ray) * optixLaunchParams.domeLightIntensity) * w / bsdf_pdf; - irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); - } - } - else if (payload.instanceID != -1) { - // Case where we hit the light, and also previously sampled the same light - int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; - bool visible = (entityID == sampledLightID); - // We hit the light we sampled previously - if (visible) { - int3 indices; float3 p, p_e1, p_e2; float3 v_gz; float2 uv, uv_e1, uv_e2; - loadMeshTriIndices(light_entity.mesh_id, payload.primitiveID, indices); - loadMeshVertexData(light_entity.mesh_id, indices, payload.barycentrics, p, v_gz, p_e1, p_e2); - loadMeshUVData(light_entity.mesh_id, indices, payload.barycentrics, uv, uv_e1, uv_e2); - - // Transform data into world space - glm::mat4 xfm; - xfm = glm::column(xfm, 0, vec4(payload.localToWorld[0], payload.localToWorld[4], payload.localToWorld[8], 0.0f)); - xfm = glm::column(xfm, 1, vec4(payload.localToWorld[1], payload.localToWorld[5], payload.localToWorld[9], 0.0f)); - xfm = glm::column(xfm, 2, vec4(payload.localToWorld[2], payload.localToWorld[6], payload.localToWorld[10], 0.0f)); - xfm = glm::column(xfm, 3, vec4(payload.localToWorld[3], payload.localToWorld[7], payload.localToWorld[11], 1.0f)); - glm::mat3 nxfm = transpose(glm::inverse(glm::mat3(xfm))); - p = make_float3(xfm * make_vec4(p, 1.0f)); - v_gz = make_float3(normalize(nxfm * normalize(make_vec3(v_gz)))); - - float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); - float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, make_vec2(uv), make_vec4(default_light_emission))) * light_light.intensity; - - float dist = distance(vec3(p.x, p.y, p.z), vec3(ray.origin.x, ray.origin.y, ray.origin.z)); // should I be using this? + if (lightPDFs[lid] > EPSILON) + { + // if by sampling the brdf we also hit the light source... + if ((payload.instanceID == -1) && (sampledLightIDs[lid] == -1)) { + // Case where we hit the background, and also previously sampled the background float dotNWi = fabs(dot(-v_gz, ray.direction)); // for now, making all lights double sided. - if (dotNWi > 0.f){ - float w = power_heuristic(1.f, bsdf_pdf, 1.f, light_pdf); - float3 Li = lightEmission * w / bsdf_pdf; - irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); // missing r^2 falloff? + if (dotNWi > 0.f) { + float w = power_heuristic(1.f, bsdf_pdf, 1.f, lightPDFs[lid]); + float3 Li = (missColor(ray) * optixLaunchParams.domeLightIntensity) * w / bsdf_pdf; + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); + } + } + else if (payload.instanceID != -1) { + // Case where we hit the light, and also previously sampled the same light + int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; + bool visible = (entityID == sampledLightIDs[lid]); + // We hit the light we sampled previously + if (visible) { + int3 indices; float3 p, p_e1, p_e2; float3 v_gz; float2 uv, uv_e1, uv_e2; + loadMeshTriIndices(light_entity.mesh_id, payload.primitiveID, indices); + loadMeshVertexData(light_entity.mesh_id, indices, payload.barycentrics, p, v_gz, p_e1, p_e2); + loadMeshUVData(light_entity.mesh_id, indices, payload.barycentrics, uv, uv_e1, uv_e2); + + // Transform data into world space + glm::mat4 xfm; + xfm = glm::column(xfm, 0, vec4(payload.localToWorld[0], payload.localToWorld[4], payload.localToWorld[8], 0.0f)); + xfm = glm::column(xfm, 1, vec4(payload.localToWorld[1], payload.localToWorld[5], payload.localToWorld[9], 0.0f)); + xfm = glm::column(xfm, 2, vec4(payload.localToWorld[2], payload.localToWorld[6], payload.localToWorld[10], 0.0f)); + xfm = glm::column(xfm, 3, vec4(payload.localToWorld[3], payload.localToWorld[7], payload.localToWorld[11], 1.0f)); + glm::mat3 nxfm = transpose(glm::inverse(glm::mat3(xfm))); + p = make_float3(xfm * make_vec4(p, 1.0f)); + v_gz = make_float3(normalize(nxfm * normalize(make_vec3(v_gz)))); + + float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); + float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, make_vec2(uv), make_vec4(default_light_emission))) * light_light.intensity; + + float dist = distance(vec3(p.x, p.y, p.z), vec3(ray.origin.x, ray.origin.y, ray.origin.z)); // should I be using this? + float dotNWi = fabs(dot(-v_gz, ray.direction)); // for now, making all lights double sided. + if (dotNWi > 0.f){ + float w = power_heuristic(1.f, bsdf_pdf, 1.f, lightPDFs[lid]); + float3 Li = lightEmission * w / bsdf_pdf; + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); // missing r^2 falloff? + } } } } } + irradiance = irradiance / float(optixLaunchParams.numLightSamples); + // accumulate any radiance (ie pathThroughput * irradiance), and update the path throughput using the sampled BRDF float3 contribution = pathThroughput * irradiance; illum = illum + contribution; diff --git a/src/visii/visii.cpp b/src/visii/visii.cpp index 76004936..0a3b6d7e 100644 --- a/src/visii/visii.cpp +++ b/src/visii/visii.cpp @@ -507,6 +507,7 @@ void initializeOptix(bool headless) { "directClamp", OWL_USER_TYPE(float), OWL_OFFSETOF(LaunchParams, directClamp)}, { "indirectClamp", OWL_USER_TYPE(float), OWL_OFFSETOF(LaunchParams, indirectClamp)}, { "maxBounceDepth", OWL_USER_TYPE(uint32_t), OWL_OFFSETOF(LaunchParams, maxBounceDepth)}, + { "numLightSamples", OWL_USER_TYPE(uint32_t), OWL_OFFSETOF(LaunchParams, numLightSamples)}, { "seed", OWL_USER_TYPE(uint32_t), OWL_OFFSETOF(LaunchParams, seed)}, { "xPixelSamplingInterval", OWL_USER_TYPE(glm::vec2), OWL_OFFSETOF(LaunchParams, xPixelSamplingInterval)}, { "yPixelSamplingInterval", OWL_USER_TYPE(glm::vec2), OWL_OFFSETOF(LaunchParams, yPixelSamplingInterval)}, @@ -614,6 +615,7 @@ void initializeOptix(bool headless) launchParamsSetRaw(OD.launchParams, "directClamp", &OD.LP.directClamp); launchParamsSetRaw(OD.launchParams, "indirectClamp", &OD.LP.indirectClamp); launchParamsSetRaw(OD.launchParams, "maxBounceDepth", &OD.LP.maxBounceDepth); + launchParamsSetRaw(OD.launchParams, "numLightSamples", &OD.LP.numLightSamples); launchParamsSetRaw(OD.launchParams, "seed", &OD.LP.seed); launchParamsSetRaw(OD.launchParams, "xPixelSamplingInterval", &OD.LP.xPixelSamplingInterval); launchParamsSetRaw(OD.launchParams, "yPixelSamplingInterval", &OD.LP.yPixelSamplingInterval); @@ -821,39 +823,54 @@ void setIndirectLightingClamp(float clamp) { clamp = std::max(float(clamp), float(0.f)); OptixData.LP.indirectClamp = clamp; - resetAccumulation(); launchParamsSetRaw(OptixData.launchParams, "indirectClamp", &OptixData.LP.indirectClamp); + resetAccumulation(); } void setDirectLightingClamp(float clamp) { clamp = std::max(float(clamp), float(0.f)); OptixData.LP.directClamp = clamp; - resetAccumulation(); launchParamsSetRaw(OptixData.launchParams, "directClamp", &OptixData.LP.directClamp); + resetAccumulation(); } void setMaxBounceDepth(uint32_t depth) { OptixData.LP.maxBounceDepth = depth; - resetAccumulation(); launchParamsSetRaw(OptixData.launchParams, "maxBounceDepth", &OptixData.LP.maxBounceDepth); + resetAccumulation(); +} + +void setLightSampleCount(uint32_t count) +{ + if (count > MAX_LIGHT_SAMPLES) + throw std::runtime_error( + std::string("Error: max number of light samples is ") + + std::to_string(MAX_LIGHT_SAMPLES)); + if (count == 0) + throw std::runtime_error( + std::string("Error: number of light samples must be between 1 and ") + + std::to_string(MAX_LIGHT_SAMPLES)); + OptixData.LP.numLightSamples = count; + launchParamsSetRaw(OptixData.launchParams, "numLightSamples", &OptixData.LP.numLightSamples); + resetAccumulation(); } void samplePixelArea(vec2 xSampleInterval, vec2 ySampleInterval) { OptixData.LP.xPixelSamplingInterval = xSampleInterval; OptixData.LP.yPixelSamplingInterval = ySampleInterval; - resetAccumulation(); launchParamsSetRaw(OptixData.launchParams, "xPixelSamplingInterval", &OptixData.LP.xPixelSamplingInterval); launchParamsSetRaw(OptixData.launchParams, "yPixelSamplingInterval", &OptixData.LP.yPixelSamplingInterval); + resetAccumulation(); } void sampleTimeInterval(vec2 sampleTimeInterval) { OptixData.LP.timeSamplingInterval = sampleTimeInterval; - resetAccumulation(); launchParamsSetRaw(OptixData.launchParams, "timeSamplingInterval", &OptixData.LP.timeSamplingInterval); + resetAccumulation(); } void updateComponents() From ec915f92ddd01bc4d9d921415d2e283e806118cb Mon Sep 17 00:00:00 2001 From: Jonathan Tremblay Date: Fri, 31 Jul 2020 14:39:00 -0700 Subject: [PATCH 15/25] example for a camera interactive --- examples/15.camera_control.py | 222 ++++++++++++++++++++++++++++++++++ examples/readme.md | 3 + 2 files changed, 225 insertions(+) create mode 100644 examples/15.camera_control.py diff --git a/examples/15.camera_control.py b/examples/15.camera_control.py new file mode 100644 index 00000000..54abb65f --- /dev/null +++ b/examples/15.camera_control.py @@ -0,0 +1,222 @@ +import visii +import noise +import random +import argparse +import numpy as np + +parser = argparse.ArgumentParser() + +parser.add_argument('--spp', + default=400, + type=int, + help = "number of sample per pixel, higher the more costly") +parser.add_argument('--width', + default=1000, + type=int, + help = 'image output width') +parser.add_argument('--height', + default=1000, + type=int, + help = 'image output height') +parser.add_argument('--noise', + action='store_true', + default=False, + help = "if added the output of the ray tracing is not sent to optix's denoiser") +parser.add_argument('--out', + default='tmp.png', + help = "output filename") + +opt = parser.parse_args() + +# # # # # # # # # # # # # # # # # # # # # # # # # +visii.initialize_interactive() +visii.resize_window(1000,1000) +visii.set_max_bounce_depth(2) +visii.set_dome_light_intensity(0) +# # # # # # # # # # # # # # # # # # # # # # # # # + + +game_running = True +rotate_camera = False +speed_camera = 0.1 +camera_movement_pos_old = [200,200] +camera_movement_pos_now = [200,200] + +x_rot = 0 +y_rot = 0 + +# # # # # # # # # # # # # # # # # # # # # # # # # + +if not opt.noise is True: + visii.enable_denoiser() + +camera = visii.entity.create( + name = "camera", + transform = visii.transform.create("camera"), + camera = visii.camera.create_perspective_from_fov( + name = "camera", + field_of_view = 0.785398, + aspect = float(opt.width)/float(opt.height) + ) +) + +camera.get_transform().look_at( + at = visii.vec3(1,-1.5,1.8) + visii.vec3(0,1,0), # look at (world coordinate) + up = visii.vec3(0,0,1), # up vector + eye = visii.vec3(1,-1.5,1.8) +) + +init_rot = camera.get_transform().get_rotation() + +rot = visii.angleAxis( + x_rot, + visii.vec3(0,1,0) +) +rot = rot * visii.angleAxis( + y_rot, + visii.vec3(1,0,0) +) +camera.get_transform().add_rotation(rot) + +visii.set_camera_entity(camera) + +# # # # # # # # # # # # # # # # # # # # # # # # # + +# This function loads the +sdb = visii.import_obj( + "sdb", # prefix name + 'content/salle_de_bain_separated/salle_de_bain_separated.obj', #obj path + 'content/salle_de_bain_separated/', # mtl folder + visii.vec3(0,0,1), # translation + visii.vec3(0.1), # scale here + visii.angleAxis(3.14 * .5, visii.vec3(1,0,0)) #rotation here +) + +mirror = visii.material.get('sdbMirror') + +mirror.set_roughness(0) +mirror.set_metallic(1) +mirror.set_base_color(visii.vec3(1)) + +for i_s, s in enumerate(sdb): + if "light" in s.get_name().lower(): + s.set_light(visii.light.create('light')) + s.get_light().set_intensity(50) + s.get_light().set_temperature(5000) + s.clear_material() + +# # # # # # # # # # # # # # # # # # # # # # # # # +import pygame +pygame.init() +screen = pygame.display.set_mode((400, 400)) + +while game_running: + + # visii camera matrix + cam_matrix = camera.get_transform().get_local_to_world_matrix() + to_add = visii.vec4(0,0,0,0) + + for event in pygame.event.get(): + print(event) + + # Game is running check for quit + if event.type == pygame.QUIT: + game_running = False + if event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE: + game_running = False + # camera control + # Forward and backward + if event.key == pygame.K_w: + print('hello') + to_add[2] = 1 * speed_camera * -1 + if event.key == pygame.K_s: + to_add[2] = 1 * speed_camera + + # left and right + if event.key == pygame.K_a: + to_add[0] = 1 * speed_camera * -1 + if event.key == pygame.K_d: + to_add[0] = 1 * speed_camera + + # up and down + if event.key == pygame.K_q: + to_add[1] = 1 * speed_camera * -1 + if event.key == pygame.K_e: + to_add[1] = 1 * speed_camera + + # change speed movement + if event.key == pygame.K_UP: + speed_camera *= 0.5 + print('decrease speed camera') + if event.key == pygame.K_DOWN: + speed_camera /= 0.5 + print('increase speed camera') + + # camera rotation + if event.type == pygame.MOUSEMOTION and rotate_camera: + print('cam is moving') + camera_movement_pos_old = camera_movement_pos_now + camera_movement_pos_now = event.pos + + if event.type == pygame.MOUSEBUTTONDOWN: + if event.button == 1: # left click grows radius + rotate_camera = True + print('rotation') + + if event.type == pygame.MOUSEBUTTONUP: + if event.button == 1: # left click grows radius + rotate_camera = False + print('no rotation') + camera_movement_pos_old = [200,200] + camera_movement_pos_now = [200,200] + + # set mouse in the middle when moving + + if rotate_camera: + x_rot -= (camera_movement_pos_old[0] - camera_movement_pos_now[0]) * 0.0001 + y_rot -= (camera_movement_pos_old[1] - camera_movement_pos_now[1]) * 0.0001 + + # camera.get_transform().set_rotation(init_rot) + + rot_x_to_apply = visii.angleAxis( + x_rot, + # camera.get_transform().get_up() + visii.vec3(0,1,0) + ) + # camera.get_transform().add_rotation(rot) + + + rot_y_to_apply = visii.angleAxis( + y_rot, + # camera.get_transform().get_right() + visii.vec3(1,0,0) + ) + # camera.get_transform().look_at( + # at = camera.get_transform().get_position() + visii.vec3(0,1,0), # look at (world coordinate) + # up = visii.vec3(0,0,1), # up vector + # ) + + camera.get_transform().set_rotation(init_rot* rot_x_to_apply * rot_y_to_apply) + + # camera.get_transform().set_rotation(rot * init_rot) + + pygame.mouse.set_pos([200,200]) + + # control the camera + if to_add[0]**2 > 0.001 or \ + to_add[1]**2 > 0.001 or \ + to_add[2]**2 > 0.001: + + to_add_world = cam_matrix * to_add + + camera.get_transform().add_position( + visii.vec3( + to_add_world[0], + to_add_world[1], + to_add_world[2] + ) + ) + +# let's clean up the GPU +visii.deinitialize() \ No newline at end of file diff --git a/examples/readme.md b/examples/readme.md index ecebac76..a069e154 100644 --- a/examples/readme.md +++ b/examples/readme.md @@ -91,6 +91,9 @@ for disocclusions. ## 14.normal_map.py A simple script that loads a texture, normal and roughness map and apply them to a flat surface. +## 15.camera_control.py +An interactive demo for controlling the camera similar to to a first person shooter control using `w,a,s,d` and `q` and `e` for up and down. Using the left click on the mouse you can rotate the camera. + ## Notes All these examples were developed and tested on Ubuntu 18.04 with cuda 11.0, NVIDIA drivers 450.36.06 and using a NVIDIA TITAN RTX . From d569c27cf111584752547aed47449aa07cda0589 Mon Sep 17 00:00:00 2001 From: n8vm Date: Sat, 1 Aug 2020 13:11:15 -0600 Subject: [PATCH 16/25] Adding support for absolute motion blur in addition to relative motion blur --- include/visii/transform.h | 328 +++++---- include/visii/transform_struct.h | 5 +- src/visii/devicecode/launch_params.h | 2 +- src/visii/devicecode/lights.h | 62 +- src/visii/devicecode/path_tracer.cu | 961 +++++++++++++-------------- src/visii/transform.cpp | 439 +++++++----- src/visii/visii.cpp | 12 +- 7 files changed, 945 insertions(+), 864 deletions(-) diff --git a/include/visii/transform.h b/include/visii/transform.h index bad12503..839078cd 100644 --- a/include/visii/transform.h +++ b/include/visii/transform.h @@ -27,12 +27,17 @@ using namespace std; /** * The "Transform" component places an entity into the scene. * These transform components represent a scale, a rotation, and a translation, in that order. + * These transform components also keep track of the previous frame scale, rotation, and translation, which + * can optionally be used for creating motion blur and for temporal effects like reprojection. */ class Transform : public StaticFactory { friend class StaticFactory; friend class Entity; + private: + bool useRelativeMotionBlur = true; + /* Scene graph information */ int32_t parent = -1; std::set children; @@ -42,51 +47,68 @@ class Transform : public StaticFactory vec3 position = vec3(0.0); quat rotation = quat(1.0f, 0.0f, 0.0f, 0.0f); - vec3 linearVelocity = vec3(0.0); - quat angularVelocity = quat(1.f,0.f,0.f,0.f); - vec3 scalarVelocity = vec3(0.0); + vec3 prevScale = vec3(1.0); + vec3 prevPosition = vec3(0.0); + quat prevRotation = quat(1.0f, 0.0f, 0.0f, 0.0f); + + vec3 linearMotion = vec3(0.0); + quat angularMotion = quat(1.f,0.f,0.f,0.f); + vec3 scalarMotion = vec3(0.0); + + // vec3 right = vec3(1.0, 0.0, 0.0); + // vec3 up = vec3(0.0, 1.0, 0.0); + // vec3 forward = vec3(0.0, 0.0, 1.0); - vec3 right = vec3(1.0, 0.0, 0.0); - vec3 up = vec3(0.0, 1.0, 0.0); - vec3 forward = vec3(0.0, 0.0, 1.0); + // vec3 prevRight = vec3(1.0, 0.0, 0.0); + // vec3 prevUp = vec3(0.0, 1.0, 0.0); + // vec3 prevForward = vec3(0.0, 0.0, 1.0); mat4 localToParentTransform = mat4(1); - mat4 localToParentRotation = mat4(1); - mat4 localToParentTranslation = mat4(1); - mat4 localToParentScale = mat4(1); + // mat4 localToParentRotation = mat4(1); + // mat4 localToParentTranslation = mat4(1); + // mat4 localToParentScale = mat4(1); - mat4 parentToLocalTransform = mat4(1); - mat4 parentToLocalRotation = mat4(1); - mat4 parentToLocalTranslation = mat4(1); - mat4 parentToLocalScale = mat4(1); + // mat4 parentToLocalTransform = mat4(1); + // mat4 parentToLocalRotation = mat4(1); + // mat4 parentToLocalTranslation = mat4(1); + // mat4 parentToLocalScale = mat4(1); mat4 localToParentMatrix = mat4(1); mat4 parentToLocalMatrix = mat4(1); - mat4 nextLocalToParentTranslation = mat4(1); - mat4 nextLocalToParentRotation = mat4(1); - mat4 nextLocalToParentScale = mat4(1); + mat4 prevLocalToParentTransform = mat4(1); + // mat4 prevLocalToParentTranslation = mat4(1); + // mat4 prevLocalToParentRotation = mat4(1); + // mat4 prevLocalToParentScale = mat4(1); - mat4 nextParentToLocalTranslation = mat4(1); - mat4 nextParentToLocalRotation = mat4(1); - mat4 nextParentToLocalScale = mat4(1); + // mat4 prevParentToLocalTransform = mat4(1); + // mat4 prevParentToLocalTranslation = mat4(1); + // mat4 prevParentToLocalRotation = mat4(1); + // mat4 prevParentToLocalScale = mat4(1); - mat4 nextLocalToParentMatrix = mat4(1); - mat4 nextParentToLocalMatrix = mat4(1); + mat4 prevLocalToParentMatrix = mat4(1); + mat4 prevParentToLocalMatrix = mat4(1); /* Local <=> World */ mat4 localToWorldMatrix = mat4(1); mat4 worldToLocalMatrix = mat4(1); - mat4 nextLocalToWorldMatrix = mat4(1); - mat4 nextWorldToLocalMatrix = mat4(1); + + mat4 prevLocalToWorldMatrix = mat4(1); + mat4 prevWorldToLocalMatrix = mat4(1); // from local to world decomposition. // May only approximate the localToWorldMatrix - glm::vec3 worldScale; - glm::quat worldRotation; - glm::vec3 worldTranslation; - glm::vec3 worldSkew; - glm::vec4 worldPerspective; + // glm::vec3 worldScale; + // glm::quat worldRotation; + // glm::vec3 worldTranslation; + // glm::vec3 worldSkew; + // glm::vec4 worldPerspective; + + // glm::vec3 prevWorldScale; + // glm::quat prevWorldRotation; + // glm::vec3 prevWorldTranslation; + // glm::vec3 prevWorldSkew; + // glm::vec4 prevWorldPerspective; // float interpolation = 1.0; @@ -121,8 +143,8 @@ class Transform : public StaticFactory /* traverses from the current transform up through its ancestors, computing a final world to local matrix */ - glm::mat4 computeWorldToLocalMatrix(); - glm::mat4 computeNextWorldToLocalMatrix(); + glm::mat4 computeWorldToLocalMatrix(bool previous); + // glm::mat4 computePrevWorldToLocalMatrix(bool previous); Transform(); Transform(std::string name, uint32_t id); @@ -215,18 +237,20 @@ class Transform : public StaticFactory * The returned vector has the same length as the input direction. * * @param direction The direction to apply the transform to. + * @param previous If true, uses the previous transform as the transform to apply. * @return The transformed direction. */ - vec3 transformDirection(vec3 direction); + vec3 transformDirection(vec3 direction, bool previous = false); /** * Transforms position from local to parent. Note, affected by scale. * The opposite conversion, from parent to local, can be done with Transform.inverse_transform_point * * @param point The point to apply the transform to. + * @param previous If true, uses the previous transform as the transform to apply. * @return The transformed point. */ - vec3 transformPoint(vec3 point); + vec3 transformPoint(vec3 point, bool previous = false); /** * Transforms vector from local to parent. @@ -234,9 +258,10 @@ class Transform : public StaticFactory * The returned vector may have a different length that the input vector. * * @param vector The vector to apply the transform to. + * @param previous If true, uses the previous transform as the transform to apply. * @return The transformed vector. */ - vec3 transformVector(vec3 vector); + vec3 transformVector(vec3 vector, bool previous = false); /** * Transforms a direction from parent space to local space. @@ -244,9 +269,10 @@ class Transform : public StaticFactory * This operation is unaffected by scale. * * @param point The direction to apply the inverse transform to. + * @param previous If true, uses the previous transform as the transform to apply. * @return The transformed direction. */ - vec3 inverseTransformDirection(vec3 direction); + vec3 inverseTransformDirection(vec3 direction, bool previous = false); /** * Transforms position from parent space to local space. @@ -254,9 +280,10 @@ class Transform : public StaticFactory * Note, affected by scale. * * @param point The point to apply the inverse transform to. + * @param previous If true, uses the previous transform as the transform to apply. * @return The transformed point. */ - vec3 inverseTransformPoint(vec3 point); + vec3 inverseTransformPoint(vec3 point, bool previous = false); /** * Transforms a vector from parent space to local space. @@ -264,9 +291,10 @@ class Transform : public StaticFactory * This operation is affected by scale. * * @param point The vector to apply the inverse transform to. + * @param previous If true, uses the previous transform as the transform to apply. * @return The transformed vector. */ - vec3 inverseTransformVector(vec3 vector); + vec3 inverseTransformVector(vec3 vector, bool previous = false); /** * Rotates the transform so the forward vector points at the target's current position. @@ -276,11 +304,12 @@ class Transform : public StaticFactory * @param at The position to point the transform towards * @param up The unit direction pointing upwards * @param eye (optional) The position to place the object + * @param previous If true, edits the previous translation and/or rotation. */ - void lookAt(vec3 at, vec3 up, vec3 eye = vec3(NAN)); + void lookAt(vec3 at, vec3 up, vec3 eye = vec3(NAN), bool previous = false); // /** - // * For motion blur. Rotates the next transform so the forward vector points at the target's current position. + // * For motion blur. Rotates the prev transform so the forward vector points at the target's current position. // * Then it rotates the transform to point its up direction vector in the direction hinted at // * by the parentUp vector. // * @@ -288,7 +317,7 @@ class Transform : public StaticFactory // * @param up The unit direction pointing upwards // * @param eye (optional) The position to place the object // */ - // void nextLookAt(vec3 at, vec3 up, vec3 eye = vec3(NAN)); + // void prevLookAt(vec3 at, vec3 up, vec3 eye = vec3(NAN)); // /** // Applies a rotation of eulerAngles.z degrees around the z axis, eulerAngles.x degrees around @@ -314,9 +343,10 @@ class Transform : public StaticFactory * This modifies both the position and rotation of the transform. * * @param point The pivot point in space to rotate around. - * @param quaternion The quaternion to use for rotation. + * @param quaternion The quaternion to use for rotation. + * @param previous If true, edits the previous translation and rotation. */ - void rotateAround(vec3 point, glm::quat quaternion); + void rotateAround(vec3 point, glm::quat quaternion, bool previous = false); /** * Sets an optional additional transform, useful for representing normally unsupported transformations @@ -324,18 +354,23 @@ class Transform : public StaticFactory * * @param transformation a 4 by 4 column major transformation matrix * @param decompose attempts to use singular value decomposition to decompose the provided transform into a translation, rotation, and scale + * @param previous If true, edits the previous translation, rotation, and scale. */ - void setTransform(glm::mat4 transformation, bool decompose = true); + void setTransform(glm::mat4 transformation, bool decompose = true, bool previous = false); - /** @return A quaternion rotating the transform from local to parent */ - quat getRotation(); + /** + * @param previous If true, returns the previous rotation. + * @return A quaternion rotating the transform from local to parent + */ + quat getRotation(bool previous = false); /** * Sets the rotation of the transform from local to parent via a quaternion * * @param newRotation The new rotation quaternion to set the current transform quaternion to. + * @param previous If true, edits the previous rotation. */ - void setRotation(quat newRotation); + void setRotation(quat newRotation, bool previous = false); // /** // * Sets the rotation of the transform from local to parent using an axis @@ -351,8 +386,9 @@ class Transform : public StaticFactory * via a quaternion. * * @param additionalRotation The rotation quaternion apply to the existing transform quaternion. + * @param previous If true, edits the previous rotation. */ - void addRotation(quat additionalRotation); + void addRotation(quat additionalRotation, bool previous = false); // /** // * Adds a rotation to the existing transform rotation from local to parent @@ -364,33 +400,47 @@ class Transform : public StaticFactory // */ // void addRotation(float angle, vec3 axis); - /** @returns a position vector describing where this transform will be translated to in its parent space. */ - vec3 getPosition(); + /** + * @param previous If true, returns the previous position. + * @returns a position vector describing where this transform will be translated to in its parent space. + */ + vec3 getPosition(bool previous = false); - /** @returns a vector pointing right relative to the current transform placed in its parent's space. */ - vec3 getRight(); + /** + * @param previous If true, returns the previous right vector. + * @returns a vector pointing right relative to the current transform placed in its parent's space. + */ + vec3 getRight(bool previous = false); - /** @returns a vector pointing up relative to the current transform placed in its parent's space. */ - vec3 getUp(); + /** + * @param previous If true, returns the previous up vector. + * @returns a vector pointing up relative to the current transform placed in its parent's space. + */ + vec3 getUp(bool previous = false); - /** @returns a vector pointing forward relative to the current transform placed in its parent's space. */ - vec3 getForward(); + /** + * @param previous If true, returns the previous forward vector. + * @returns a vector pointing forward relative to the current transform placed in its parent's space. + */ + vec3 getForward(bool previous = false); /** * Sets the position vector describing where this transform should be translated to when placed in its * parent space. * * @param newPosition The new position to set the current transform position to. + * @param previous If true, edits the previous position. */ - void setPosition(vec3 newPosition); + void setPosition(vec3 newPosition, bool previous = false); /** * Adds to the current the position vector describing where this transform should be translated to * when placed in its parent space. * * @param additionalPosition The position (interpreted as a vector) to add onto the current transform position. + * @param previous If true, edits the previous position. */ - void addPosition(vec3 additionalPosition); + void addPosition(vec3 additionalPosition, bool previous = false); // /** // * Sets the position vector describing where this transform should be translated to when placed in its @@ -413,18 +463,20 @@ class Transform : public StaticFactory // void addPosition(float dx, float dy, float dz); /** + * @param previous If true, returns the previous scale. * @returns the scale of this transform from local to parent space along its right, up, and forward * directions respectively */ - vec3 getScale(); + vec3 getScale(bool previous = false); /** * Sets the scale of this transform from local to parent space along its right, up, and forward * directions respectively. * * @param newScale The new scale to set the current transform scale to. + * @param previous If true, edits the previous scale. */ - void setScale(vec3 newScale); + void setScale(vec3 newScale, bool previous = false); // /** // * Sets the scale of this transform from local to parent space along its right, up, and forward @@ -439,8 +491,9 @@ class Transform : public StaticFactory * and forward directions respectively * * @param additionalScale The scale to add onto the current transform scale. + * @param previous If true, edits the previous scale. */ - void addScale(vec3 additionalScale); + void addScale(vec3 additionalScale, bool previous = false); // /** // * Sets the scale of this transform from local to parent space along its right, up, and forward @@ -498,64 +551,66 @@ class Transform : public StaticFactory void setScalarVelocity(vec3 velocity, float frames_per_second = 1.0f, float mix = 0.0f); /** + * @param previous If true, returns the previous parent-to-local matrix. * @returns the final matrix transforming this object from it's parent coordinate space to it's * local coordinate space */ - glm::mat4 getParentToLocalMatrix(); + glm::mat4 getParentToLocalMatrix(bool previous = false); - /** - * @returns the final matrix transforming this object from it's parent coordinate space to it's - * local coordinate space, accounting for linear and angular velocities. - */ - glm::mat4 getNextParentToLocalMatrix(); + // /** + // * @returns the final matrix transforming this object from it's parent coordinate space to it's + // * local coordinate space, accounting for linear and angular velocities. + // */ + // glm::mat4 getPrevParentToLocalMatrix(bool previous = false); /** + * @param previous If true, returns the previous local-to-parent matrix. * @returns the final matrix transforming this object from it's local coordinate space to it's * parents coordinate space */ - glm::mat4 getLocalToParentMatrix(); - - /** - * @returns the final matrix transforming this object from it's local coordinate space to it's - * parents coordinate space, accounting for linear and angular velocities. - */ - glm::mat4 getNextLocalToParentMatrix(); + glm::mat4 getLocalToParentMatrix(bool previous = false); /** + * @param previous If true, returns the previous local-to-parent translation matrix. * @returns the final matrix translating this object from it's local coordinate space to it's * parent coordinate space */ - glm::mat4 getLocalToParentTranslationMatrix(); + glm::mat4 getLocalToParentTranslationMatrix(bool previous = false); /** + * @param previous If true, returns the previous local-to-parent scale matrix. * @returns the final matrix translating this object from it's local coordinate space to it's * parent coordinate space */ - glm::mat4 getLocalToParentScaleMatrix(); + glm::mat4 getLocalToParentScaleMatrix(bool previous = false); /** + * @param previous If true, returns the previous local-to-parent rotation matrix. * @returns the final matrix rotating this object in it's local coordinate space to it's * parent coordinate space */ - glm::mat4 getLocalToParentRotationMatrix(); + glm::mat4 getLocalToParentRotationMatrix(bool previous = false); /** + * @param previous If true, returns the previous parent-to-local translation matrix. * @returns the final matrix translating this object from it's parent coordinate space to it's * local coordinate space */ - glm::mat4 getParentToLocalTranslationMatrix(); + glm::mat4 getParentToLocalTranslationMatrix(bool previous = false); /** + * @param previous If true, returns the previous parent-to-local scale matrix. * @returns the final matrix scaling this object from it's parent coordinate space to it's * local coordinate space */ - glm::mat4 getParentToLocalScaleMatrix(); + glm::mat4 getParentToLocalScaleMatrix(bool previous = false); /** + * @param previous If true, returns the previous parent-to-local rotation matrix. * @returns the final matrix rotating this object from it's parent coordinate space to it's * local coordinate space * */ - glm::mat4 getParentToLocalRotationMatrix(); + glm::mat4 getParentToLocalRotationMatrix(bool previous = false); /** * Set the parent of this transform, whose transformation will be applied after the current @@ -584,82 +639,81 @@ class Transform : public StaticFactory void removeChild(Transform* child); /** + * @param previous If true, returns the previous world-to-local matrix. * @returns a matrix transforming this component from world space to its local space, taking all * parent transforms into account. */ - glm::mat4 getWorldToLocalMatrix(); + glm::mat4 getWorldToLocalMatrix(bool previous = false); /** + * @param previous If true, returns the previous local-to-world matrix. * @returns a matrix transforming this component from its local space to world space, taking all * parent transforms into account. */ - glm::mat4 getLocalToWorldMatrix(); + glm::mat4 getLocalToWorldMatrix(bool previous = false); - /** - * @returns a matrix transforming this component from world space to its local space, taking all - * parent transforms into account, in addition to any linear and angular velocities. - */ - glm::mat4 getNextWorldToLocalMatrix(); - - /** - * @returns a matrix transforming this component from its local space to world space, taking all - * parent transforms into account, in addition to any linear and angular velocities. - */ - glm::mat4 getNextLocalToWorldMatrix(); - - /** - * @returns a (possibly approximate) scale scaling the current transform from - * local space to world space, taking all parent transforms into account - */ - glm::vec3 getWorldScale(); + // /** + // * @param previous If true, returns the previous world space scale. + // * @returns a (possibly approximate) scale scaling the current transform from + // * local space to world space, taking all parent transforms into account + // */ + // glm::vec3 getWorldScale(bool previous = false); - /** - * @returns a (possibly approximate) rotation rotating the current transform from - * local space to world space, taking all parent transforms into account - */ - glm::quat getWorldRotation(); + // /** + // * @param previous If true, returns the previous world space rotation. + // * @returns a (possibly approximate) rotation rotating the current transform from + // * local space to world space, taking all parent transforms into account + // */ + // glm::quat getWorldRotation(bool previous = false); - /** - * @returns a (possibly approximate) translation moving the current transform from - * local space to world space, taking all parent transforms into account - */ - glm::vec3 getWorldTranslation(); + // /** + // * @param previous If true, returns the previous world space translation. + // * @returns a (possibly approximate) translation moving the current transform from + // * local space to world space, taking all parent transforms into account + // */ + // glm::vec3 getWorldTranslation(bool previous = false); - /** - * @returns a (possibly approximate) rotation matrix rotating the current transform from - * local space to world space, taking all parent transforms into account - */ - glm::mat4 getWorldToLocalRotationMatrix(); + // /** + // * @param previous If true, returns the previous world-to-local rotation matrix. + // * @returns a (possibly approximate) rotation matrix rotating the current transform from + // * local space to world space, taking all parent transforms into account + // */ + // glm::mat4 getWorldToLocalRotationMatrix(bool previous = false); - /** - * @returns a (possibly approximate) rotation matrix rotating the current transform from - * world space to local space, taking all parent transforms into account - */ - glm::mat4 getLocalToWorldRotationMatrix(); + // /** + // * @param previous If true, returns the previous local-to-world rotation matrix. + // * @returns a (possibly approximate) rotation matrix rotating the current transform from + // * world space to local space, taking all parent transforms into account + // */ + // glm::mat4 getLocalToWorldRotationMatrix(bool previous = false); - /** - * @returns a (possibly approximate) translation matrix translating the current transform from - * local space to world space, taking all parent transforms into account - */ - glm::mat4 getWorldToLocalTranslationMatrix(); + // /** + // * @param previous If true, returns the previous world-to-local translation matrix. + // * @returns a (possibly approximate) translation matrix translating the current transform from + // * local space to world space, taking all parent transforms into account + // */ + // glm::mat4 getWorldToLocalTranslationMatrix(bool previous = false); - /** - * @returns a (possibly approximate) translation matrix rotating the current transform from - * world space to local space - */ - glm::mat4 getLocalToWorldTranslationMatrix(); + // /** + // * @param previous If true, returns the previous local-to-world translation matrix. + // * @returns a (possibly approximate) translation matrix rotating the current transform from + // * world space to local space + // */ + // glm::mat4 getLocalToWorldTranslationMatrix(bool previous = false); - /** - * @returns a (possibly approximate) scale matrix scaling the current transform from - * local space to world space, taking all parent transforms into account - */ - glm::mat4 getWorldToLocalScaleMatrix(); + // /** + // * @param previous If true, returns the previous world-to-local scale matrix. + // * @returns a (possibly approximate) scale matrix scaling the current transform from + // * local space to world space, taking all parent transforms into account + // */ + // glm::mat4 getWorldToLocalScaleMatrix(bool previous = false); - /** - * @returns a (possibly approximate) scale matrix scaling the current transform from - * world space to local space, taking all parent transforms into account - */ - glm::mat4 getLocalToWorldScaleMatrix(); + // /** + // * @param previous If true, returns the previous local-to-world scale matrix. + // * @returns a (possibly approximate) scale matrix scaling the current transform from + // * world space to local space, taking all parent transforms into account + // */ + // glm::mat4 getLocalToWorldScaleMatrix(bool previous = false); /** @returns a struct with only essential data */ TransformStruct &getStruct(); diff --git a/include/visii/transform_struct.h b/include/visii/transform_struct.h index 7e7e1678..55d0af45 100644 --- a/include/visii/transform_struct.h +++ b/include/visii/transform_struct.h @@ -1,7 +1,7 @@ /* File shared by both host and device */ #pragma once -#define MAX_TRANSFORMS 100000 +#define MAX_TRANSFORMS 1000000 #include using namespace glm; @@ -18,8 +18,7 @@ struct TransformStruct // mat4 localToWorldRotation; // mat4 worldToLocalTranslation; // mat4 localToWorldTranslation; - - + /* 128 bytes, for temporal reprojection */ // mat4 worldToLocalPrev; // mat4 localToWorldPrev; diff --git a/src/visii/devicecode/launch_params.h b/src/visii/devicecode/launch_params.h index abf10d14..34d29892 100644 --- a/src/visii/devicecode/launch_params.h +++ b/src/visii/devicecode/launch_params.h @@ -29,7 +29,7 @@ struct LaunchParams { float directClamp = 100.f; float indirectClamp = 100.f; uint32_t maxBounceDepth = 10; - uint32_t numLightSamples = 2; + uint32_t numLightSamples = 1; uint32_t seed = 0; vec2 xPixelSamplingInterval = vec2(0.f,1.f); vec2 yPixelSamplingInterval = vec2(0.f,1.f); diff --git a/src/visii/devicecode/lights.h b/src/visii/devicecode/lights.h index 480c009e..de57789c 100644 --- a/src/visii/devicecode/lights.h +++ b/src/visii/devicecode/lights.h @@ -165,27 +165,6 @@ void sampleDirectLight( vec3 pos, vec3 &dir, float &pdf ) { - // pick one of the three AABB orientations to sample from. - // glm::mat4 rotation, rotationInv; - // ivec4 q[2]; - - // vec3 p[8] = { - // vec3(bbmin.x, bbmin.y, bbmin.z), - // vec3(bbmax.x, bbmin.y, bbmin.z), - // vec3(bbmin.x, bbmax.y, bbmin.z), - // vec3(bbmax.x, bbmax.y, bbmin.z), - // vec3(bbmin.x, bbmin.y, bbmax.z), - // vec3(bbmax.x, bbmin.y, bbmax.z), - // vec3(bbmin.x, bbmax.y, bbmax.z), - // vec3(bbmax.x, bbmax.y, bbmax.z) - // }; - // { - // vec3 n = cross(normalize(e1), normalize(e2)); - // if (abs(dot(n, pos - s)) < EPSILON) { - // return; - // } - // } - pos = vec3( lightTransformInv * vec4(pos, 1.0) ); normal = vec3( lightTransformInv * vec4(normal, 0.0) ); bool minCloser = (distance(bbmin , pos) < distance(bbmax , pos)); @@ -248,8 +227,6 @@ void sampleDirectLightPDF( vec3 pos, pdf = 1.0f / squad.S; } - - //Gram-Schmidt method __device__ vec3 orthogonalize(const vec3 &a, const vec3 &b) { @@ -365,3 +342,42 @@ void sampleTriangle(const vec3 &pos, const vec3 &n, float aCosThere = max(0.0, fabs(dot(-dir,n))); pdf = PdfAtoW( pdfA, d2, aCosThere ); } + +__device__ +const float* upper_bound (const float* first, const float* last, const float& val) +{ + const float* it; +// iterator_traits::difference_type count, step; + int count, step; +// count = std::distance(first,last); + count = (last-first); + while (count > 0) + { + it = first; + step=count/2; + // std::advance (it,step); + it = it + step; + if ( ! (val < *it)) // or: if (!comp(val,*it)), for version (2) + { + first=++it; + count-=step+1; + } + else count=step; + } + return first; +} + +__device__ float sample_cdf(const float* data, unsigned int n, float x, unsigned int *idx, float* pdf) +{ + *idx = upper_bound(data, data + n, x) - data; + float scaled_sample; + if (*idx == 0) { + *pdf = data[0]; + scaled_sample = x / data[0]; + } else { + *pdf = data[*idx] - data[*idx - 1]; + scaled_sample = (x - data[*idx - 1]) / (data[*idx] - data[*idx - 1]); + } + // keep result in [0,1) + return min(scaled_sample, 0.99999994f); +} \ No newline at end of file diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index e344d6fc..b5507010 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -423,586 +423,517 @@ float3 faceNormalForward(const float3 &w_o, const float3 &gn, const float3 &n) return new_n; } -__device__ -const float* upper_bound (const float* first, const float* last, const float& val) -{ - const float* it; -// iterator_traits::difference_type count, step; - int count, step; -// count = std::distance(first,last); - count = (last-first); - while (count > 0) - { - it = first; - step=count/2; - // std::advance (it,step); - it = it + step; - if ( ! (val < *it)) // or: if (!comp(val,*it)), for version (2) - { - first=++it; - count-=step+1; - } - else count=step; - } - return first; -} - -__device__ float sample_cdf(const float* data, unsigned int n, float x, unsigned int *idx, float* pdf) -{ - // OSL_DASSERT(x >= 0); - // OSL_DASSERT(x < 1); - *idx = upper_bound(data, data + n, x) - data; - // OSL_DASSERT(*idx < n); - // OSL_DASSERT(x < data[*idx]); - float scaled_sample; - if (*idx == 0) { - *pdf = data[0]; - scaled_sample = x / data[0]; - } else { - // OSL_DASSERT(x >= data[*idx - 1]); - *pdf = data[*idx] - data[*idx - 1]; - scaled_sample = (x - data[*idx - 1]) / (data[*idx] - data[*idx - 1]); - } - // keep result in [0,1) - return min(scaled_sample, 0.99999994f); -} - OPTIX_RAYGEN_PROGRAM(rayGen)() { auto pixelID = ivec2(owl::getLaunchIndex()[0], owl::getLaunchIndex()[1]); - ivec2 centerPixel = ivec2(optixLaunchParams.frameSize.x / 2, optixLaunchParams.frameSize.y / 2); - bool isCenter = glm::all(glm::equal(pixelID, centerPixel)); - auto fbOfs = pixelID.x+optixLaunchParams.frameSize.x* ((optixLaunchParams.frameSize.y - 1) - pixelID.y); + bool isCenter = glm::all(glm::equal(pixelID, ivec2(optixLaunchParams.frameSize.x / 2, optixLaunchParams.frameSize.y / 2))); LCGRand rng = get_rng(optixLaunchParams.frameID + optixLaunchParams.seed * 10007); float time = sampleTime(lcg_randomf(rng)); // If no camera is in use, just display some random noise... - EntityStruct camera_entity; - TransformStruct camera_transform; - CameraStruct camera; - if (!loadCamera(camera_entity, camera, camera_transform)) { - optixLaunchParams.frameBuffer[fbOfs] = vec4(lcg_randomf(rng), lcg_randomf(rng), lcg_randomf(rng), 1.f); - return; + owl::Ray ray; + + { + EntityStruct camera_entity; + TransformStruct camera_transform; + CameraStruct camera; + if (!loadCamera(camera_entity, camera, camera_transform)) { + auto fbOfs = pixelID.x+optixLaunchParams.frameSize.x * ((optixLaunchParams.frameSize.y - 1) - pixelID.y); + optixLaunchParams.frameBuffer[fbOfs] = vec4(lcg_randomf(rng), lcg_randomf(rng), lcg_randomf(rng), 1.f); + return; + } + + // Trace an initial ray through the scene + ray = generateRay(camera, camera_transform, pixelID, optixLaunchParams.frameSize, rng, time); } - mat4 VP = camera.proj * camera_transform.worldToLocal; - float3 accum_illum = make_float3(0.f); - float3 primaryAlbedo = make_float3(0.f); - float3 primaryNormal = make_float3(0.f); - float3 primaryDiffuseMotion = make_float3(0.f); - + float3 pathThroughput = make_float3(1.f); + // float3 aovPathThroughput = make_float3(1.f); float3 renderData = make_float3(0.f); initializeRenderData(renderData); + + uint8_t bounce = 0; + uint8_t visibilitySkips = 0; + + // direct here is used for final image clamping + float3 directIllum = make_float3(0.f); + float3 illum = make_float3(0.f); + + // used for render metadata stuff. + // float3 aovIllum = make_float3(0.f); + // float3 aovDirectIllum = make_float3(0.f); + // float3 aovIndirectIllum = make_float3(0.f); + // int8_t rdSampledBsdf = -1, rdForcedBsdf = -1; + // if ((optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_DIRECT_LIGHTING) || + // (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_DIRECT_LIGHTING)) rdForcedBsdf = 0; + // if ((optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_DIRECT_LIGHTING) || + // (optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_DIRECT_LIGHTING)) rdForcedBsdf = 1; + // if ((optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING) || + // (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING)) rdForcedBsdf = 3; - // For potentially several samples per pixel... - // Update: for machine learning applications, it's important there be only 1SPP. - // Metadata like depth or IDs dont work with multiple SPP. - // #define SPP 1 - // for (uint32_t rid = 0; rid < SPP; ++rid) - // { + + // uint16_t ray_count = 0; + // float roughnessMinimum = 0.f; + RayPayload payload; + payload.tHit = -1.f; + ray.time = time; + owl::traceRay( /*accel to trace against*/ optixLaunchParams.world, + /*the ray to trace*/ ray, + /*prd*/ payload); + + // Shade each hit point on a path using NEE with MIS + do { + // If ray misses + if (payload.tHit <= 0.f) { + illum = illum + pathThroughput * (missColor(ray) * optixLaunchParams.domeLightIntensity); + if (bounce == 0) { + // primaryNormal = make_float3(0.f, 0.f, 1.f); + // primaryAlbedo = illum; + directIllum = illum; + } + break; + } - // Trace an initial ray through the scene - owl::Ray ray = generateRay(camera, camera_transform, pixelID, optixLaunchParams.frameSize, rng, time); - - DisneyMaterial mat; - int bounce = 0; - int visibilitySkips = 0; - - // direct here is used for final image clamping - float3 directIllum = make_float3(0.f); - float3 illum = make_float3(0.f); - - // used for render metadata stuff. - float3 aovIllum = make_float3(0.f); - float3 aovDirectIllum = make_float3(0.f); - float3 aovIndirectIllum = make_float3(0.f); - int32_t rdSampledBsdf = -1; - int32_t rdForcedBsdf = -1; - if ((optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_DIRECT_LIGHTING) || - (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_DIRECT_LIGHTING)) rdForcedBsdf = 0; - if ((optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_DIRECT_LIGHTING) || - (optixLaunchParams.renderDataMode == RenderDataFlags::GLOSSY_DIRECT_LIGHTING)) rdForcedBsdf = 1; - if ((optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING) || - (optixLaunchParams.renderDataMode == RenderDataFlags::TRANSMISSION_DIRECT_LIGHTING)) rdForcedBsdf = 3; - - float3 pathThroughput = make_float3(1.f); - float3 aovPathThroughput = make_float3(1.f); - uint16_t ray_count = 0; - float roughnessMinimum = 0.f; - RayPayload payload; - payload.tHit = -1.f; - ray.time = time; - owl::traceRay( /*accel to trace against*/ optixLaunchParams.world, - /*the ray to trace*/ ray, - /*prd*/ payload); + // Otherwise, load common position, vectors, and material data used for shading... + const int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; + EntityStruct entity = optixLaunchParams.entities[entityID]; + + // Skip forward if the hit object is invisible for this ray type + if ((bounce == 0) && ((entity.visibilityFlags & ENTITY_VISIBILITY_CAMERA_RAYS) == 0)) { + ray.origin = ray.origin + ray.direction * (payload.tHit + EPSILON); + payload.tHit = -1.f; + ray.time = time; + owl::traceRay( optixLaunchParams.world, ray, payload); + visibilitySkips++; + if (visibilitySkips > 10) break; // avoid locking up. - // If we hit something, shade each hit point on a path using NEE with MIS - // else - do - { // If ray misses if (payload.tHit <= 0.f) { - illum = illum + pathThroughput * (missColor(ray) * optixLaunchParams.domeLightIntensity); - if (bounce == 0) { - primaryNormal = make_float3(0.f, 0.f, 1.f); - primaryAlbedo = illum; - directIllum = illum; - } - break; - } - - // Load common position, vectors, and material data used for shading... - const int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; - EntityStruct entity = optixLaunchParams.entities[entityID]; - - // Skip forward if the hit object is invisible for this ray type - if ((bounce == 0) && ((entity.visibilityFlags & ENTITY_VISIBILITY_CAMERA_RAYS) == 0)) { - ray.origin = ray.origin + ray.direction * (payload.tHit + EPSILON); - payload.tHit = -1.f; - ray.time = time; - owl::traceRay( optixLaunchParams.world, ray, payload); - visibilitySkips++; - if (visibilitySkips > 10) break; // avoid locking up. - - // If ray misses - if (payload.tHit <= 0.f) { - illum = missColor(ray) * optixLaunchParams.domeLightIntensity; - primaryNormal = make_float3(0.f, 0.f, 1.f); - primaryAlbedo = illum; - directIllum = illum; - } - continue; + illum = missColor(ray) * optixLaunchParams.domeLightIntensity; + // primaryNormal = make_float3(0.f, 0.f, 1.f); + // primaryAlbedo = illum; + directIllum = illum; } + continue; + } - TransformStruct entityTransform = optixLaunchParams.transforms[entity.transform_id]; - MaterialStruct entityMaterial; LightStruct entityLight; - if (entity.material_id >= 0 && entity.material_id < MAX_MATERIALS) { - entityMaterial = optixLaunchParams.materials[entity.material_id]; - } - - const float3 w_o = -ray.direction; - float3 hit_p = ray.origin + payload.tHit * ray.direction; - float3 mp, p, pt0, pt1, v_x, v_y, v_z, v_gz, p_e1, p_e2; float2 uv, uv_e1, uv_e2; int3 indices; - bool shouldNormalFaceForward = (entityMaterial.transmission == 0.f); - - loadMeshTriIndices(entity.mesh_id, payload.primitiveID, indices); - loadMeshVertexData(entity.mesh_id, indices, payload.barycentrics, mp, v_gz, p_e1, p_e2); - loadMeshUVData(entity.mesh_id, indices, payload.barycentrics, uv, uv_e1, uv_e2); - loadMeshNormalData(entity.mesh_id, indices, payload.barycentrics, uv, v_z); - loadDisneyMaterial(entityMaterial, make_vec2(uv), mat, roughnessMinimum); + DisneyMaterial mat; MaterialStruct entityMaterial; LightStruct entityLight; + if (entity.material_id >= 0 && entity.material_id < MAX_MATERIALS) { + entityMaterial = optixLaunchParams.materials[entity.material_id]; + } + + const float3 w_o = -ray.direction; + float3 hit_p = ray.origin + payload.tHit * ray.direction; + float3 mp, p, v_x, v_y, v_z, v_gz, p_e1, p_e2; + float2 uv, uv_e1, uv_e2; + int3 indices; + float3 diffuseMotion; + bool shouldNormalFaceForward = (entityMaterial.transmission == 0.f); + + loadMeshTriIndices(entity.mesh_id, payload.primitiveID, indices); + loadMeshVertexData(entity.mesh_id, indices, payload.barycentrics, mp, v_gz, p_e1, p_e2); + loadMeshUVData(entity.mesh_id, indices, payload.barycentrics, uv, uv_e1, uv_e2); + loadMeshNormalData(entity.mesh_id, indices, payload.barycentrics, uv, v_z); + loadDisneyMaterial(entityMaterial, make_vec2(uv), mat, MIN_ROUGHNESS); + + { + float f = 1.0f / (uv_e1.x * uv_e2.y - uv_e2.x * uv_e1.y); + v_x.x = f * (uv_e2.y * p_e1.x - uv_e1.y * p_e2.x); + v_x.y = f * (uv_e2.y * p_e1.y - uv_e1.y * p_e2.y); + v_x.z = f * (uv_e2.y * p_e1.z - uv_e1.y * p_e2.z); + v_x = normalize(v_x); + v_z = normalize(v_z); + } + // Transform data into world space + { glm::mat4 xfm = to_mat4(payload.localToWorld); glm::mat4 xfmt0 = to_mat4(payload.localToWorldT0); glm::mat4 xfmt1 = to_mat4(payload.localToWorldT1); glm::mat3 nxfm = transpose(glm::inverse(glm::mat3(xfm))); - - // If the material has a normal map, load it. - float f = 1.0f / (uv_e1.x * uv_e2.y - uv_e2.x * uv_e1.y); - vec3 tangent, binormal; - tangent.x = f * (uv_e2.y * p_e1.x - uv_e1.y * p_e2.x); - tangent.y = f * (uv_e2.y * p_e1.y - uv_e1.y * p_e2.y); - tangent.z = f * (uv_e2.y * p_e1.z - uv_e1.y * p_e2.z); - tangent = normalize(tangent); - v_z = normalize(v_z); - - // Transform data into world space p = make_float3(xfm * make_vec4(mp, 1.0f)); vec4 tmp1 = optixLaunchParams.proj * optixLaunchParams.viewT0 * xfmt0 * make_vec4(mp, 1.0f); - pt0 = make_float3(tmp1 / tmp1.w) * .5f; - + float3 pt0 = make_float3(tmp1 / tmp1.w) * .5f; vec4 tmp2 = optixLaunchParams.proj * optixLaunchParams.viewT1 * xfmt1 * make_vec4(mp, 1.0f); - pt1 = make_float3(tmp2 / tmp2.w) * .5f; - - float3 diffuseMotion = pt1 - pt0; - // diffuseMotion = make_float3(diffuseMotion.x, diffuseMotion.z, diffuseMotion.y); - if (bounce == 0) primaryDiffuseMotion = diffuseMotion; - // float3 test = make_float3(abs(make_vec3(diffuseMotion))); - // test.z = 0.f; - // illum = test; - // break; - + float3 pt1 = make_float3(tmp2 / tmp2.w) * .5f; + diffuseMotion = pt1 - pt0; hit_p = p; v_gz = make_float3(normalize(nxfm * make_vec3(v_gz))); v_z = make_float3(normalize(nxfm * make_vec3(v_z))); - v_x = make_float3(normalize(nxfm * tangent)); + v_x = make_float3(normalize(nxfm * make_vec3(v_x))); v_y = cross(v_z, v_x); v_x = cross(v_y, v_z); - - if ( - all(lessThan(abs(make_vec3(v_x)), vec3(EPSILON))) || - all(lessThan(abs(make_vec3(v_y)), vec3(EPSILON))) || - any(isnan(make_vec3(v_x))) || - any(isnan(make_vec3(v_y))) - ) { - ortho_basis(v_x, v_y, v_z); - } - + } + + if ( + all(lessThan(abs(make_vec3(v_x)), vec3(EPSILON))) || + all(lessThan(abs(make_vec3(v_y)), vec3(EPSILON))) || + any(isnan(make_vec3(v_x))) || + any(isnan(make_vec3(v_y))) + ) { + ortho_basis(v_x, v_y, v_z); + } + + { glm::mat3 tbn; tbn = glm::column(tbn, 0, make_vec3(v_x) ); tbn = glm::column(tbn, 1, make_vec3(v_y) ); - tbn = glm::column(tbn, 2, make_vec3(v_z) ); - + tbn = glm::column(tbn, 2, make_vec3(v_z) ); float3 dN = make_float3(sampleTexture(entityMaterial.normal_map_texture_id, make_vec2(uv), vec4(0.5f, .5f, 1.f, 0.f))); dN = (dN * make_float3(2.0f)) - make_float3(1.f); - v_z = make_float3(normalize(tbn * normalize(make_vec3(dN))) ); + } - if (shouldNormalFaceForward) { - v_z = faceNormalForward(w_o, v_gz, v_z); - } + if (shouldNormalFaceForward) { + v_z = faceNormalForward(w_o, v_gz, v_z); + } - // For segmentations, geometric metadata extraction dependent on the hit object - saveGeometricRenderData(renderData, bounce, payload.tHit, hit_p, v_z, w_o, entityID, diffuseMotion, mat); - - // If this is the first hit, keep track of primary albedo and normal for denoising. - if (bounce == 0) { - primaryNormal = v_z; - primaryAlbedo = mat.base_color; - } + // For segmentations, geometric metadata extraction dependent on the hit object + saveGeometricRenderData(renderData, bounce, payload.tHit, hit_p, v_z, w_o, entityID, diffuseMotion, mat); + + // If this is the first hit, keep track of primary albedo and normal for denoising. + // if (bounce == 0) { + // primaryNormal = v_z; + // primaryAlbedo = mat.base_color; + // } - // If the entity we hit is a light, terminate the path. - // First hits are colored by the light. All other light hits are handled by NEE/MIS - if (entity.light_id >= 0 && entity.light_id < MAX_LIGHTS) { - if (bounce == 0) - { - entityLight = optixLaunchParams.lights[entity.light_id]; - float3 light_emission; - if (entityLight.color_texture_id == -1) light_emission = make_float3(entityLight.r, entityLight.g, entityLight.b) * entityLight.intensity; - else light_emission = make_float3(sampleTexture(entityLight.color_texture_id, make_vec2(uv), vec4(entityLight.r, entityLight.g, entityLight.b, 1.f))); // * intensity; temporarily commenting out to show texture for bright lights in LDR - illum = light_emission; - directIllum = illum; - } - break; + // If the entity we hit is a light, terminate the path. + // First hits are colored by the light. All other light hits are handled by NEE/MIS + if (entity.light_id >= 0 && entity.light_id < MAX_LIGHTS) { + if (bounce == 0) + { + entityLight = optixLaunchParams.lights[entity.light_id]; + float3 light_emission; + if (entityLight.color_texture_id == -1) light_emission = make_float3(entityLight.r, entityLight.g, entityLight.b) * entityLight.intensity; + else light_emission = make_float3(sampleTexture(entityLight.color_texture_id, make_vec2(uv), vec4(entityLight.r, entityLight.g, entityLight.b, 1.f))); // * intensity; temporarily commenting out to show texture for bright lights in LDR + illum = light_emission; + directIllum = illum; } - - // Sample a light source - int32_t sampledLightIDs[MAX_LIGHT_SAMPLES] = {-2}; - float lightPDFs[MAX_LIGHT_SAMPLES] = {0.f}; - - int numLights = optixLaunchParams.numLightEntities; - float3 irradiance = make_float3(0.f); - // float3 lightEmission = make_float3(0.f); - - EntityStruct light_entity; - MaterialStruct light_material; - LightStruct light_light; - light_material.base_color_texture_id = -1; - - float3 n_l = v_z; //faceNormalForward(w_o, v_gz, v_z); - // if (dot(w_o, n_l) < 0.f) { - // n_l = -n_l; - // } - - // note, rdForcedBsdf is -1 by default - int forcedBsdf = rdForcedBsdf;//(bounce == optixLaunchParams.renderDataBounce) ? rdForcedBsdf : -1; + break; + } + + // Sample a light source + int32_t sampledLightIDs[MAX_LIGHT_SAMPLES] = {-2}; + float lightPDFs[MAX_LIGHT_SAMPLES] = {0.f}; + + int numLights = optixLaunchParams.numLightEntities; + float3 irradiance = make_float3(0.f); + // float3 lightEmission = make_float3(0.f); + + EntityStruct light_entity; + MaterialStruct light_material; + LightStruct light_light; + light_material.base_color_texture_id = -1; + + float3 n_l = v_z; //faceNormalForward(w_o, v_gz, v_z); + // if (dot(w_o, n_l) < 0.f) { + // n_l = -n_l; + // } - // first, sample the light source by importance sampling the light - for (uint32_t lid = 0; lid < optixLaunchParams.numLightSamples; ++lid) - { - uint32_t randomID = uint32_t(min(lcg_randomf(rng) * (numLights+1), float(numLights))); - - // sample background - if (randomID == numLights) { - sampledLightIDs[lid] = -1; - const uint32_t occlusionFlags = OPTIX_RAY_FLAG_DISABLE_ANYHIT | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; - float3 lightDir; - - if ((optixLaunchParams.environmentMapWidth != 0) && (optixLaunchParams.environmentMapHeight != 0)) { - // Vec3fa color = m_background->sample(dg, wi, tMax, RandomSampler_get2D(sampler)); - float rx = lcg_randomf(rng); - float ry = lcg_randomf(rng); - float* rows = optixLaunchParams.environmentMapRows; - float* cols = optixLaunchParams.environmentMapCols; - int width = optixLaunchParams.environmentMapWidth; - int height = optixLaunchParams.environmentMapHeight; - float invjacobian = width * height / float(4 * M_PI); - float row_pdf, col_pdf; - unsigned x, y; - ry = sample_cdf(rows, height, ry, &y, &row_pdf); - rx = sample_cdf(cols + y * width, width, rx, &x, &col_pdf); - // y = height - y; - lightDir = make_float3(toPolar(vec2((x/* + rx*/) / float(width), (y/* + ry*/)/float(height)))); - lightPDFs[lid] = row_pdf * col_pdf * invjacobian; - } - else - { - const float3 hemi_dir = normalize(cos_sample_hemisphere(make_float2(lcg_randomf(rng), lcg_randomf(rng)))); - lightDir = make_float3(normalize(tbn * normalize(make_vec3(hemi_dir))) ); - lightPDFs[lid] = 1.f; - } + // note, rdForcedBsdf is -1 by default + int forcedBsdf = -1;//rdForcedBsdf;//(bounce == optixLaunchParams.renderDataBounce) ? rdForcedBsdf : -1; + + // first, sample the light source by importance sampling the light + for (uint32_t lid = 0; lid < optixLaunchParams.numLightSamples; ++lid) + { + uint32_t randomID = uint32_t(min(lcg_randomf(rng) * (numLights+1), float(numLights))); + + // sample background + if (randomID == numLights) { + sampledLightIDs[lid] = -1; + const uint32_t occlusionFlags = OPTIX_RAY_FLAG_DISABLE_ANYHIT | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; + float3 lightDir; + + if ((optixLaunchParams.environmentMapWidth != 0) && (optixLaunchParams.environmentMapHeight != 0)) { + // Vec3fa color = m_background->sample(dg, wi, tMax, RandomSampler_get2D(sampler)); + float rx = lcg_randomf(rng); + float ry = lcg_randomf(rng); + float* rows = optixLaunchParams.environmentMapRows; + float* cols = optixLaunchParams.environmentMapCols; + int width = optixLaunchParams.environmentMapWidth; + int height = optixLaunchParams.environmentMapHeight; + float invjacobian = width * height / float(4 * M_PI); + float row_pdf, col_pdf; + unsigned x, y; + ry = sample_cdf(rows, height, ry, &y, &row_pdf); + rx = sample_cdf(cols + y * width, width, rx, &x, &col_pdf); + // y = height - y; + lightDir = make_float3(toPolar(vec2((x + rx) / float(width), (y + ry)/float(height)))); + lightPDFs[lid] = row_pdf * col_pdf * invjacobian; + } + else + { + glm::mat3 tbn; + tbn = glm::column(tbn, 0, make_vec3(v_x) ); + tbn = glm::column(tbn, 1, make_vec3(v_y) ); + tbn = glm::column(tbn, 2, make_vec3(v_z) ); + const float3 hemi_dir = normalize(cos_sample_hemisphere(make_float2(lcg_randomf(rng), lcg_randomf(rng)))); + lightDir = make_float3(normalize(tbn * normalize(make_vec3(hemi_dir))) ); + lightPDFs[lid] = 1.f; + } - float dotNWi = fabs(dot(lightDir, v_z)); // for now, making all lights double sided. - - float bsdfPDF; - disney_pdf(mat, n_l, w_o, lightDir, v_x, v_y, bsdfPDF, forcedBsdf); - if (bsdfPDF > EPSILON) { - RayPayload payload; - owl::Ray ray; - ray.tmin = EPSILON * 10.f; - ray.tmax = 1e20f; - ray.origin = hit_p; - ray.direction = lightDir; - payload.tHit = -1.f; - ray.time = time; - owl::traceRay( optixLaunchParams.world, ray, payload, occlusionFlags); - int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; - bool visible = (payload.instanceID == -1); - - if (visible) { - float w = power_heuristic(1.f, lightPDFs[lid], 1.f, bsdfPDF); - float3 bsdf, bsdf_color; - disney_brdf(mat, n_l, w_o, lightDir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); - float3 Li = (missColor(ray) * optixLaunchParams.domeLightIntensity) * w / lightPDFs[lid]; - irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); - } + float dotNWi = fabs(dot(lightDir, v_z)); // for now, making all lights double sided. + + float bsdfPDF; + disney_pdf(mat, n_l, w_o, lightDir, v_x, v_y, bsdfPDF, forcedBsdf); + if (bsdfPDF > EPSILON) { + RayPayload payload; + owl::Ray ray; + ray.tmin = EPSILON * 10.f; + ray.tmax = 1e20f; + ray.origin = hit_p; + ray.direction = lightDir; + payload.tHit = -1.f; + ray.time = time; + owl::traceRay( optixLaunchParams.world, ray, payload, occlusionFlags); + int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; + bool visible = (payload.instanceID == -1); + + if (visible) { + float w = power_heuristic(1.f, lightPDFs[lid], 1.f, bsdfPDF); + float3 bsdf, bsdf_color; + disney_brdf(mat, n_l, w_o, lightDir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); + float3 Li = (missColor(ray) * optixLaunchParams.domeLightIntensity) * w / lightPDFs[lid]; + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); } } - // sample light sources - else - { - if (numLights == 0) continue; - randomID = min(randomID, numLights - 1); - sampledLightIDs[lid] = optixLaunchParams.lightEntities[randomID]; - light_entity = optixLaunchParams.entities[sampledLightIDs[lid]]; - - // shouldn't happen, but just in case... - if ((light_entity.light_id < 0) || (light_entity.light_id > MAX_LIGHTS)) continue; - if ((light_entity.transform_id < 0) || (light_entity.transform_id > MAX_TRANSFORMS)) continue; + } + // sample light sources + else + { + if (numLights == 0) continue; + randomID = min(randomID, numLights - 1); + sampledLightIDs[lid] = optixLaunchParams.lightEntities[randomID]; + light_entity = optixLaunchParams.entities[sampledLightIDs[lid]]; - light_light = optixLaunchParams.lights[light_entity.light_id]; - TransformStruct transform = optixLaunchParams.transforms[light_entity.transform_id]; - MeshStruct mesh; - - bool is_area_light = false; - if ((light_entity.mesh_id >= 0) && (light_entity.mesh_id < MAX_MESHES)) { - mesh = optixLaunchParams.meshes[light_entity.mesh_id]; - is_area_light = true; - }; - - const uint32_t occlusion_flags = OPTIX_RAY_FLAG_DISABLE_ANYHIT; - // | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; - // | OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT; + // shouldn't happen, but just in case... + if ((light_entity.light_id < 0) || (light_entity.light_id > MAX_LIGHTS)) continue; + if ((light_entity.transform_id < 0) || (light_entity.transform_id > MAX_TRANSFORMS)) continue; + + light_light = optixLaunchParams.lights[light_entity.light_id]; + TransformStruct transform = optixLaunchParams.transforms[light_entity.transform_id]; + MeshStruct mesh; - if (!is_area_light) continue; + bool is_area_light = false; + if ((light_entity.mesh_id >= 0) && (light_entity.mesh_id < MAX_MESHES)) { + mesh = optixLaunchParams.meshes[light_entity.mesh_id]; + is_area_light = true; + }; + + const uint32_t occlusion_flags = OPTIX_RAY_FLAG_DISABLE_ANYHIT; + // | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; + // | OPTIX_RAY_FLAG_DISABLE_CLOSESTHIT; + + if (!is_area_light) continue; - uint32_t random_tri_id = uint32_t(min(lcg_randomf(rng) * mesh.numTris, float(mesh.numTris - 1))); - owl::device::Buffer *indexLists = (owl::device::Buffer *)optixLaunchParams.indexLists.data; - ivec3 *indices = (ivec3*) indexLists[light_entity.mesh_id].data; - ivec3 triIndex = indices[random_tri_id]; + uint32_t random_tri_id = uint32_t(min(lcg_randomf(rng) * mesh.numTris, float(mesh.numTris - 1))); + owl::device::Buffer *indexLists = (owl::device::Buffer *)optixLaunchParams.indexLists.data; + ivec3 *indices = (ivec3*) indexLists[light_entity.mesh_id].data; + ivec3 triIndex = indices[random_tri_id]; + + // Sample the light to compute an incident light ray to this point + { + owl::device::Buffer *vertexLists = (owl::device::Buffer *)optixLaunchParams.vertexLists.data; + owl::device::Buffer *texCoordLists = (owl::device::Buffer *)optixLaunchParams.texCoordLists.data; + vec4 *vertices = (vec4*) vertexLists[light_entity.mesh_id].data; + vec2 *texCoords = (vec2*) texCoordLists[light_entity.mesh_id].data; + vec3 dir; + vec2 uv; + vec3 pos = vec3(hit_p.x, hit_p.y, hit_p.z); + vec3 v1 = transform.localToWorld * vertices[triIndex.x]; + vec3 v2 = transform.localToWorld * vertices[triIndex.y]; + vec3 v3 = transform.localToWorld * vertices[triIndex.z]; + vec2 uv1 = texCoords[triIndex.x]; + vec2 uv2 = texCoords[triIndex.y]; + vec2 uv3 = texCoords[triIndex.z]; + vec3 N = normalize(cross( normalize(v2 - v1), normalize(v3 - v1))); + sampleTriangle(pos, N, v1, v2, v3, uv1, uv2, uv3, lcg_randomf(rng), lcg_randomf(rng), dir, lightPDFs[lid], uv); + vec3 normal = glm::vec3(n_l.x, n_l.y, n_l.z); + float dotNWi = fabs(dot(dir, normal)); // for now, making all lights double sided. + lightPDFs[lid] = abs(lightPDFs[lid]); - // Sample the light to compute an incident light ray to this point - { - owl::device::Buffer *vertexLists = (owl::device::Buffer *)optixLaunchParams.vertexLists.data; - owl::device::Buffer *texCoordLists = (owl::device::Buffer *)optixLaunchParams.texCoordLists.data; - vec4 *vertices = (vec4*) vertexLists[light_entity.mesh_id].data; - vec2 *texCoords = (vec2*) texCoordLists[light_entity.mesh_id].data; - vec3 dir; - vec2 uv; - vec3 pos = vec3(hit_p.x, hit_p.y, hit_p.z); - vec3 v1 = transform.localToWorld * vertices[triIndex.x]; - vec3 v2 = transform.localToWorld * vertices[triIndex.y]; - vec3 v3 = transform.localToWorld * vertices[triIndex.z]; - vec2 uv1 = texCoords[triIndex.x]; - vec2 uv2 = texCoords[triIndex.y]; - vec2 uv3 = texCoords[triIndex.z]; - vec3 N = normalize(cross( normalize(v2 - v1), normalize(v3 - v1))); - sampleTriangle(pos, N, v1, v2, v3, uv1, uv2, uv3, lcg_randomf(rng), lcg_randomf(rng), dir, lightPDFs[lid], uv); - vec3 normal = glm::vec3(n_l.x, n_l.y, n_l.z); - float dotNWi = fabs(dot(dir, normal)); // for now, making all lights double sided. - lightPDFs[lid] = abs(lightPDFs[lid]); - - float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); - float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, uv, make_vec4(default_light_emission))) * light_light.intensity; - - if ((lightPDFs[lid] > EPSILON) && (dotNWi > EPSILON)) { - float3 light_dir = make_float3(dir.x, dir.y, dir.z); - light_dir = normalize(light_dir); - float bsdf_pdf; - disney_pdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf_pdf, forcedBsdf); - if (bsdf_pdf > EPSILON) { - RayPayload payload; - owl::Ray ray; - ray.tmin = EPSILON * 10.f; - ray.tmax = 1e20f; - ray.origin = hit_p; - ray.direction = light_dir; - payload.tHit = -1.f; - ray.time = time; - owl::traceRay( optixLaunchParams.world, ray, payload, occlusion_flags); - if (payload.instanceID == -1) continue; - int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; - bool visible = ((entityID == sampledLightIDs[lid]) || (entityID == -1)); - if (visible) { - float w = power_heuristic(1.f, lightPDFs[lid], 1.f, bsdf_pdf); - float3 bsdf, bsdf_color; - disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); - float3 Li = lightEmission * w / lightPDFs[lid]; - irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); - } + float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); + float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, uv, make_vec4(default_light_emission))) * light_light.intensity; + + if ((lightPDFs[lid] > EPSILON) && (dotNWi > EPSILON)) { + float3 light_dir = make_float3(dir.x, dir.y, dir.z); + light_dir = normalize(light_dir); + float bsdf_pdf; + disney_pdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf_pdf, forcedBsdf); + if (bsdf_pdf > EPSILON) { + RayPayload payload; + owl::Ray ray; + ray.tmin = EPSILON * 10.f; + ray.tmax = 1e20f; + ray.origin = hit_p; + ray.direction = light_dir; + payload.tHit = -1.f; + ray.time = time; + owl::traceRay( optixLaunchParams.world, ray, payload, occlusion_flags); + if (payload.instanceID == -1) continue; + int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; + bool visible = ((entityID == sampledLightIDs[lid]) || (entityID == -1)); + if (visible) { + float w = power_heuristic(1.f, lightPDFs[lid], 1.f, bsdf_pdf); + float3 bsdf, bsdf_color; + disney_brdf(mat, n_l, w_o, light_dir, v_x, v_y, bsdf, bsdf_color, forcedBsdf); + float3 Li = lightEmission * w / lightPDFs[lid]; + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); } } } } } + } + + // next, sample a light source by importance sampling the BDRF + float3 w_i; + float bsdf_pdf; + int sampledBsdf = -1; + float3 bsdf, bsdf_color; + sample_disney_brdf(mat, v_z, w_o, v_x, v_y, rng, w_i, bsdf_pdf, sampledBsdf, bsdf, bsdf_color, forcedBsdf); + + // For segmentations, lighting metadata extraction dependent on sampling the BSDF + saveLightingColorRenderData(renderData, bounce, v_z, w_o, w_i, mat); + + // terminate if the bsdf probability is impossible, or if the bsdf filters out all light + if (bsdf_pdf < EPSILON || all_zero(bsdf) || all_zero(bsdf_color)) { + break; + } + + // trace the next ray along that sampled BRDF direction + ray.origin = hit_p; + ray.direction = w_i; + ray.tmin = EPSILON * 100.f; + payload.instanceID = -1; + payload.tHit = -1.f; + ray.time = sampleTime(lcg_randomf(rng)); + owl::traceRay(optixLaunchParams.world, ray, payload); - // next, sample a light source by importance sampling the BDRF - float3 w_i; - float bsdf_pdf; - int sampledBsdf = -1; - float3 bsdf, bsdf_color; - sample_disney_brdf(mat, v_z, w_o, v_x, v_y, rng, w_i, bsdf_pdf, sampledBsdf, bsdf, bsdf_color, forcedBsdf); - - // For segmentations, lighting metadata extraction dependent on sampling the BSDF - saveLightingColorRenderData(renderData, bounce, v_z, w_o, w_i, mat); - - // terminate if the bsdf probability is impossible, or if the bsdf filters out all light - if (bsdf_pdf < EPSILON || all_zero(bsdf) || all_zero(bsdf_color)) { - break; - } - - // trace the next ray along that sampled BRDF direction - ray.origin = hit_p; - ray.direction = w_i; - ray.tmin = EPSILON * 100.f; - payload.instanceID = -1; - payload.tHit = -1.f; - ray.time = sampleTime(lcg_randomf(rng)); - owl::traceRay(optixLaunchParams.world, ray, payload); - - for (uint32_t lid = 0; lid < optixLaunchParams.numLightSamples; ++lid) + for (uint32_t lid = 0; lid < optixLaunchParams.numLightSamples; ++lid) + { + if (lightPDFs[lid] > EPSILON) { - if (lightPDFs[lid] > EPSILON) - { - // if by sampling the brdf we also hit the light source... - if ((payload.instanceID == -1) && (sampledLightIDs[lid] == -1)) { - // Case where we hit the background, and also previously sampled the background + // if by sampling the brdf we also hit the light source... + if ((payload.instanceID == -1) && (sampledLightIDs[lid] == -1)) { + // Case where we hit the background, and also previously sampled the background + float dotNWi = fabs(dot(-v_gz, ray.direction)); // for now, making all lights double sided. + if (dotNWi > 0.f) { + float w = power_heuristic(1.f, bsdf_pdf, 1.f, lightPDFs[lid]); + float3 Li = (missColor(ray) * optixLaunchParams.domeLightIntensity) * w / bsdf_pdf; + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); + } + } + else if (payload.instanceID != -1) { + // Case where we hit the light, and also previously sampled the same light + int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; + bool visible = (entityID == sampledLightIDs[lid]); + // We hit the light we sampled previously + if (visible) { + int3 indices; float3 p, p_e1, p_e2; float3 v_gz; float2 uv, uv_e1, uv_e2; + loadMeshTriIndices(light_entity.mesh_id, payload.primitiveID, indices); + loadMeshVertexData(light_entity.mesh_id, indices, payload.barycentrics, p, v_gz, p_e1, p_e2); + loadMeshUVData(light_entity.mesh_id, indices, payload.barycentrics, uv, uv_e1, uv_e2); + + // Transform data into world space + glm::mat4 xfm; + xfm = glm::column(xfm, 0, vec4(payload.localToWorld[0], payload.localToWorld[4], payload.localToWorld[8], 0.0f)); + xfm = glm::column(xfm, 1, vec4(payload.localToWorld[1], payload.localToWorld[5], payload.localToWorld[9], 0.0f)); + xfm = glm::column(xfm, 2, vec4(payload.localToWorld[2], payload.localToWorld[6], payload.localToWorld[10], 0.0f)); + xfm = glm::column(xfm, 3, vec4(payload.localToWorld[3], payload.localToWorld[7], payload.localToWorld[11], 1.0f)); + glm::mat3 nxfm = transpose(glm::inverse(glm::mat3(xfm))); + p = make_float3(xfm * make_vec4(p, 1.0f)); + v_gz = make_float3(normalize(nxfm * normalize(make_vec3(v_gz)))); + + float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); + float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, make_vec2(uv), make_vec4(default_light_emission))) * light_light.intensity; + + float dist = distance(vec3(p.x, p.y, p.z), vec3(ray.origin.x, ray.origin.y, ray.origin.z)); // should I be using this? float dotNWi = fabs(dot(-v_gz, ray.direction)); // for now, making all lights double sided. - if (dotNWi > 0.f) { + if (dotNWi > 0.f){ float w = power_heuristic(1.f, bsdf_pdf, 1.f, lightPDFs[lid]); - float3 Li = (missColor(ray) * optixLaunchParams.domeLightIntensity) * w / bsdf_pdf; - irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); - } - } - else if (payload.instanceID != -1) { - // Case where we hit the light, and also previously sampled the same light - int entityID = optixLaunchParams.instanceToEntityMap[payload.instanceID]; - bool visible = (entityID == sampledLightIDs[lid]); - // We hit the light we sampled previously - if (visible) { - int3 indices; float3 p, p_e1, p_e2; float3 v_gz; float2 uv, uv_e1, uv_e2; - loadMeshTriIndices(light_entity.mesh_id, payload.primitiveID, indices); - loadMeshVertexData(light_entity.mesh_id, indices, payload.barycentrics, p, v_gz, p_e1, p_e2); - loadMeshUVData(light_entity.mesh_id, indices, payload.barycentrics, uv, uv_e1, uv_e2); - - // Transform data into world space - glm::mat4 xfm; - xfm = glm::column(xfm, 0, vec4(payload.localToWorld[0], payload.localToWorld[4], payload.localToWorld[8], 0.0f)); - xfm = glm::column(xfm, 1, vec4(payload.localToWorld[1], payload.localToWorld[5], payload.localToWorld[9], 0.0f)); - xfm = glm::column(xfm, 2, vec4(payload.localToWorld[2], payload.localToWorld[6], payload.localToWorld[10], 0.0f)); - xfm = glm::column(xfm, 3, vec4(payload.localToWorld[3], payload.localToWorld[7], payload.localToWorld[11], 1.0f)); - glm::mat3 nxfm = transpose(glm::inverse(glm::mat3(xfm))); - p = make_float3(xfm * make_vec4(p, 1.0f)); - v_gz = make_float3(normalize(nxfm * normalize(make_vec3(v_gz)))); - - float4 default_light_emission = make_float4(light_light.r, light_light.g, light_light.b, 0.f); - float3 lightEmission = make_float3(sampleTexture(light_light.color_texture_id, make_vec2(uv), make_vec4(default_light_emission))) * light_light.intensity; - - float dist = distance(vec3(p.x, p.y, p.z), vec3(ray.origin.x, ray.origin.y, ray.origin.z)); // should I be using this? - float dotNWi = fabs(dot(-v_gz, ray.direction)); // for now, making all lights double sided. - if (dotNWi > 0.f){ - float w = power_heuristic(1.f, bsdf_pdf, 1.f, lightPDFs[lid]); - float3 Li = lightEmission * w / bsdf_pdf; - irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); // missing r^2 falloff? - } + float3 Li = lightEmission * w / bsdf_pdf; + irradiance = irradiance + (bsdf * bsdf_color * Li * fabs(dotNWi)); // missing r^2 falloff? } } } } + } - irradiance = irradiance / float(optixLaunchParams.numLightSamples); + irradiance = irradiance / float(optixLaunchParams.numLightSamples); - // accumulate any radiance (ie pathThroughput * irradiance), and update the path throughput using the sampled BRDF - float3 contribution = pathThroughput * irradiance; - illum = illum + contribution; - aovIllum = aovIllum + contribution; - // if (bounce >= optixLaunchParams.renderDataBounce) - - pathThroughput = (pathThroughput * bsdf * bsdf_color) / bsdf_pdf; - aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; - // if (bounce == 0) { - // } else { - // aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; - // // aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; - // } - - if (bounce == 0) { - // aovPathThroughput = aovPathThroughput * bsdf_color; - directIllum = illum; - aovDirectIllum = aovIllum; - rdSampledBsdf = sampledBsdf; - } + // accumulate any radiance (ie pathThroughput * irradiance), and update the path throughput using the sampled BRDF + float3 contribution = pathThroughput * irradiance; + illum = illum + contribution; + // aovIllum = aovIllum + contribution; + // if (bounce >= optixLaunchParams.renderDataBounce) + + pathThroughput = (pathThroughput * bsdf * bsdf_color) / bsdf_pdf; + // aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; + // if (bounce == 0) { + // } else { + // aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; + // // aovPathThroughput = (aovPathThroughput * bsdf * bsdf_color) / bsdf_pdf; + // } - if (rdForcedBsdf != -1) { - if (aovPathThroughput.x < EPSILON && aovPathThroughput.y < EPSILON && aovPathThroughput.z < EPSILON) { - break; - } - } - else { - if (pathThroughput.x < EPSILON && pathThroughput.y < EPSILON && pathThroughput.z < EPSILON) { - break; - } + if (bounce == 0) { + // aovPathThroughput = aovPathThroughput * bsdf_color; + directIllum = illum; + // aovDirectIllum = aovIllum; + // rdSampledBsdf = sampledBsdf; + } + + // if (rdForcedBsdf != -1) { + // if (aovPathThroughput.x < EPSILON && aovPathThroughput.y < EPSILON && aovPathThroughput.z < EPSILON) { + // break; + // } + // } + // else + { + if (pathThroughput.x < EPSILON && pathThroughput.y < EPSILON && pathThroughput.z < EPSILON) { + break; } + } - // // Do path regularization to reduce fireflies - // // Note, .35f was chosen emperically, but could be exposed as a parameter later on. - // EDIT: finding that path regularization doesn't generalize well with transmissive objects... - // if (sampledSpecular) { - // roughnessMinimum = min((roughnessMinimum + .35f), 1.f); - // } - - // if the bounce count is less than the max bounce count, potentially add on radiance from the next hit location. - ++bounce; - } while (bounce < optixLaunchParams.maxBounceDepth); - - // clamp out any extreme fireflies - glm::vec3 gillum = vec3(illum.x, illum.y, illum.z); - glm::vec3 dillum = vec3(directIllum.x, directIllum.y, directIllum.z); - glm::vec3 iillum = gillum - dillum; - - // For segmentations, indirect/direct lighting metadata extraction - float3 aovGIllum = aovIllum; - aovIndirectIllum = aovGIllum - aovDirectIllum; - - // if (isCenter) { - // printf("aov gillum: %f %f %f\n", aovGIllum.x, aovGIllum.y, aovGIllum.z); - // printf("aov dillum: %f %f %f\n", aovDirectIllum.x, aovDirectIllum.y, aovDirectIllum.z); - // printf("aov iillum: %f %f %f\n", aovIndirectIllum.x, aovIndirectIllum.y, aovIndirectIllum.z); - // printf("gillum: %f %f %f\n", gillum.x, gillum.y, gillum.z); - // printf("dillum: %f %f %f\n", dillum.x, dillum.y, dillum.z); - // printf("iillum: %f %f %f\n", iillum.x, iillum.y, iillum.z); + // // Do path regularization to reduce fireflies + // // Note, .35f was chosen emperically, but could be exposed as a parameter later on. + // EDIT: finding that path regularization doesn't generalize well with transmissive objects... + // if (sampledSpecular) { + // roughnessMinimum = min((roughnessMinimum + .35f), 1.f); // } - saveLightingIrradianceRenderData(renderData, bounce, aovDirectIllum, aovIndirectIllum, rdSampledBsdf); - if (optixLaunchParams.indirectClamp > 0.f) - iillum = clamp(iillum, vec3(0.f), vec3(optixLaunchParams.indirectClamp)); - if (optixLaunchParams.directClamp > 0.f) - dillum = clamp(dillum, vec3(0.f), vec3(optixLaunchParams.directClamp)); + // if the bounce count is less than the max bounce count, potentially add on radiance from the next hit location. + ++bounce; + } while (bounce < optixLaunchParams.maxBounceDepth); + + // clamp out any extreme fireflies + glm::vec3 gillum = vec3(illum.x, illum.y, illum.z); + glm::vec3 dillum = vec3(directIllum.x, directIllum.y, directIllum.z); + glm::vec3 iillum = gillum - dillum; + + // For segmentations, indirect/direct lighting metadata extraction + // float3 aovGIllum = aovIllum; + // aovIndirectIllum = aovGIllum - aovDirectIllum; + // saveLightingIrradianceRenderData(renderData, bounce, aovDirectIllum, aovIndirectIllum, rdSampledBsdf); - gillum = dillum + iillum; + if (optixLaunchParams.indirectClamp > 0.f) + iillum = clamp(iillum, vec3(0.f), vec3(optixLaunchParams.indirectClamp)); + if (optixLaunchParams.directClamp > 0.f) + dillum = clamp(dillum, vec3(0.f), vec3(optixLaunchParams.directClamp)); - // just in case we get inf's or nans, remove them. - if (glm::any(glm::isnan(gillum))) gillum = vec3(0.f); - if (glm::any(glm::isinf(gillum))) gillum = vec3(0.f); - illum = make_float3(gillum.r, gillum.g, gillum.b); + gillum = dillum + iillum; - // accumulate the illumination from this sample into what will be an average illumination from all samples in this pixel - accum_illum = illum; - // } - // accum_illum = accum_illum / float(SPP); + // just in case we get inf's or nans, remove them. + if (glm::any(glm::isnan(gillum))) gillum = vec3(0.f); + if (glm::any(glm::isinf(gillum))) gillum = vec3(0.f); + illum = make_float3(gillum.r, gillum.g, gillum.b); + // accumulate the illumination from this sample into what will be an average illumination from all samples in this pixel + accum_illum = illum; /* Write to AOVs, progressively refining results */ + auto fbOfs = pixelID.x+optixLaunchParams.frameSize.x * ((optixLaunchParams.frameSize.y - 1) - pixelID.y); float4 &prev_color = (float4&) optixLaunchParams.accumPtr[fbOfs]; float4 accum_color = make_float4((accum_illum + float(optixLaunchParams.frameID) * make_float3(prev_color)) / float(optixLaunchParams.frameID + 1), 1.0f); optixLaunchParams.accumPtr[fbOfs] = vec4( @@ -1020,17 +951,17 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() 1.0f ); - vec4 oldAlbedo = optixLaunchParams.albedoBuffer[fbOfs]; - vec4 oldNormal = optixLaunchParams.normalBuffer[fbOfs]; - if (any(isnan(oldAlbedo))) oldAlbedo = vec4(1.f); - if (any(isnan(oldNormal))) oldNormal = vec4(1.f); - vec4 newAlbedo = vec4(primaryAlbedo.x, primaryAlbedo.y, primaryAlbedo.z, 1.f); - vec4 newNormal = normalize(VP * vec4(primaryNormal.x, primaryNormal.y, primaryNormal.z, 0.f)); - newNormal.a = 1.f; - vec4 accumAlbedo = (newAlbedo + float(optixLaunchParams.frameID) * oldAlbedo) / float(optixLaunchParams.frameID + 1); - vec4 accumNormal = (newNormal + float(optixLaunchParams.frameID) * oldNormal) / float(optixLaunchParams.frameID + 1); - optixLaunchParams.albedoBuffer[fbOfs] = accumAlbedo; - optixLaunchParams.normalBuffer[fbOfs] = accumNormal; + // vec4 oldAlbedo = optixLaunchParams.albedoBuffer[fbOfs]; + // vec4 oldNormal = optixLaunchParams.normalBuffer[fbOfs]; + // if (any(isnan(oldAlbedo))) oldAlbedo = vec4(1.f); + // if (any(isnan(oldNormal))) oldNormal = vec4(1.f); + // vec4 newAlbedo = vec4(primaryAlbedo.x, primaryAlbedo.y, primaryAlbedo.z, 1.f); + // vec4 newNormal = normalize(VP * vec4(primaryNormal.x, primaryNormal.y, primaryNormal.z, 0.f)); + // newNormal.a = 1.f; + // vec4 accumAlbedo = (newAlbedo + float(optixLaunchParams.frameID) * oldAlbedo) / float(optixLaunchParams.frameID + 1); + // vec4 accumNormal = (newNormal + float(optixLaunchParams.frameID) * oldNormal) / float(optixLaunchParams.frameID + 1); + // optixLaunchParams.albedoBuffer[fbOfs] = accumAlbedo; + // optixLaunchParams.normalBuffer[fbOfs] = accumNormal; // Override framebuffer output if user requested to render metadata if (optixLaunchParams.renderDataMode != RenderDataFlags::NONE) { diff --git a/src/visii/transform.cpp b/src/visii/transform.cpp index 339965fb..0009ba6d 100644 --- a/src/visii/transform.cpp +++ b/src/visii/transform.cpp @@ -138,34 +138,34 @@ std::string Transform::toString() return output; } -vec3 Transform::transformDirection(vec3 direction) +vec3 Transform::transformDirection(vec3 direction, bool previous) { - return vec3(localToParentRotation * vec4(direction, 0.0)); + return vec3(getLocalToParentRotationMatrix(previous) * vec4(direction, 0.0)); } -vec3 Transform::transformPoint(vec3 point) +vec3 Transform::transformPoint(vec3 point, bool previous) { - return vec3(localToParentMatrix * vec4(point, 1.0)); + return vec3(getLocalToParentMatrix(previous) * vec4(point, 1.0)); } -vec3 Transform::transformVector(vec3 vector) +vec3 Transform::transformVector(vec3 vector, bool previous) { - return vec3(localToParentMatrix * vec4(vector, 0.0)); + return vec3(getLocalToParentMatrix(previous) * vec4(vector, 0.0)); } -vec3 Transform::inverseTransformDirection(vec3 direction) +vec3 Transform::inverseTransformDirection(vec3 direction, bool previous) { - return vec3(parentToLocalRotation * vec4(direction, 0.0)); + return vec3(getParentToLocalRotationMatrix(previous) * vec4(direction, 0.0)); } -vec3 Transform::inverseTransformPoint(vec3 point) +vec3 Transform::inverseTransformPoint(vec3 point, bool previous) { - return vec3(parentToLocalMatrix * vec4(point, 1.0)); + return vec3(getParentToLocalMatrix(previous) * vec4(point, 1.0)); } -vec3 Transform::inverseTransformVector(vec3 vector) +vec3 Transform::inverseTransformVector(vec3 vector, bool previous) { - return vec3(localToParentMatrix * vec4(vector, 0.0)); + return vec3(getLocalToParentMatrix(previous) * vec4(vector, 0.0)); } glm::quat safeQuatLookAt( @@ -194,17 +194,18 @@ glm::quat safeQuatLookAt( } } -void Transform::lookAt(vec3 at, vec3 up, vec3 eye) +void Transform::lookAt(vec3 at, vec3 up, vec3 eye, bool previous) { + if (previous) useRelativeMotionBlur = false; if (glm::any(glm::isnan(eye))) { - eye = this->position; + eye = (previous) ? this->prevPosition : this->position; } else { - setPosition(eye); + setPosition(eye, previous); } up = normalize(up); glm::vec3 forward = glm::normalize(at - eye); glm::quat rotation = safeQuatLookAt(eye, at, up, up); - setRotation(rotation); + setRotation(rotation, previous); } // void Transform::nextLookAt(vec3 at, vec3 up, vec3 eye) @@ -249,27 +250,36 @@ void Transform::lookAt(vec3 at, vec3 up, vec3 eye) // markDirty(); // } -void Transform::rotateAround(vec3 point, glm::quat rot) +void Transform::rotateAround(vec3 point, glm::quat rot, bool previous) { - glm::vec3 direction = point - getPosition(); - glm::vec3 newPosition = getPosition() + direction; - glm::quat newRotation = rot * getRotation(); + if (previous) useRelativeMotionBlur = false; + glm::vec3 direction = point - getPosition(previous); + glm::vec3 newPosition = getPosition(previous) + direction; + glm::quat newRotation = rot * getRotation(previous); newPosition = newPosition - direction * glm::inverse(rot); - rotation = glm::normalize(newRotation); - localToParentRotation = glm::toMat4(rotation); - parentToLocalRotation = glm::inverse(localToParentRotation); + glm::quat &r = (previous) ? prevRotation : rotation; + glm::vec3 &t = (previous) ? prevPosition : position; - position = newPosition; - localToParentTranslation = glm::translate(glm::mat4(1.0), position); - parentToLocalTranslation = glm::translate(glm::mat4(1.0), -position); + // glm::mat4 <pr = (previous) ? prevLocalToParentRotation : localToParentRotation; + // glm::mat4 &ptlr = (previous) ? prevParentToLocalRotation : parentToLocalRotation; + // glm::mat4 <pt = (previous) ? prevLocalToParentTranslation : localToParentTranslation; + // glm::mat4 &ptlt = (previous) ? prevParentToLocalTranslation : parentToLocalTranslation; + r = glm::normalize(newRotation); + // ltpr = glm::toMat4(rotation); + // ptlr = glm::inverse(ltpr); + + t = newPosition; + // ltpt = glm::translate(glm::mat4(1.0), t); + // ptlt = glm::translate(glm::mat4(1.0), -t); updateMatrix(); markDirty(); } -void Transform::setTransform(glm::mat4 transformation, bool decompose) +void Transform::setTransform(glm::mat4 transformation, bool decompose, bool previous) { + if (previous) useRelativeMotionBlur = false; if (decompose) { glm::vec3 scale; @@ -288,28 +298,37 @@ void Transform::setTransform(glm::mat4 transformation, bool decompose) scale = glm::max(scale, glm::vec3(.0001f)); if (!(glm::any(glm::isnan(translation)))) - setPosition(translation); + setPosition(translation, previous); if (!(glm::any(glm::isnan(scale)))) - setScale(scale); + setScale(scale, previous); if (!(glm::any(glm::isnan(rotation)))) - setRotation(rotation); + setRotation(rotation, previous); } else { - this->localToParentTransform = transformation; - this->parentToLocalTransform = glm::inverse(transformation); + if (previous) { + this->prevLocalToParentTransform = transformation; + // this->prevParentToLocalTransform = glm::inverse(transformation); + } + else { + this->localToParentTransform = transformation; + // this->parentToLocalTransform = glm::inverse(transformation); + } updateMatrix(); } markDirty(); } -quat Transform::getRotation() +quat Transform::getRotation(bool previous) { - return rotation; + if (previous) return prevRotation; + else return rotation; } -void Transform::setRotation(quat newRotation) +void Transform::setRotation(quat newRotation, bool previous) { - rotation = glm::normalize(newRotation); + if (previous) useRelativeMotionBlur = false; + auto &r = (previous) ? prevRotation : rotation; + r = glm::normalize(newRotation); updateRotation(); markDirty(); } @@ -320,9 +339,10 @@ void Transform::setRotation(quat newRotation) // markDirty(); // } -void Transform::addRotation(quat additionalRotation) +void Transform::addRotation(quat additionalRotation, bool previous) { - setRotation(getRotation() * additionalRotation); + if (previous) useRelativeMotionBlur = false; + setRotation(getRotation(previous) * additionalRotation, previous); updateRotation(); markDirty(); } @@ -335,74 +355,88 @@ void Transform::addRotation(quat additionalRotation) void Transform::updateRotation() { - localToParentRotation = glm::toMat4(rotation); - parentToLocalRotation = glm::inverse(localToParentRotation); + // localToParentRotation = glm::toMat4(rotation); + // parentToLocalRotation = glm::inverse(localToParentRotation); - nextLocalToParentRotation = glm::toMat4(angularVelocity * rotation); - nextParentToLocalRotation = glm::inverse(nextLocalToParentRotation); + // if (useRelativeMotionBlur) { + // prevLocalToParentRotation = glm::toMat4(angularVelocity * rotation); + // } else { + // prevLocalToParentRotation = glm::toMat4(prevRotation); + // } + // prevParentToLocalRotation = glm::inverse(prevLocalToParentRotation); updateMatrix(); markDirty(); } -vec3 Transform::getPosition() +vec3 Transform::getPosition(bool previous) { - return position; + if (previous) return prevPosition; + else return position; } -vec3 Transform::getRight() +vec3 Transform::getRight(bool previous) { - return right; + if (previous) return glm::vec3(glm::column(prevLocalToParentMatrix, 0)); + else return glm::vec3(glm::column(localToParentMatrix, 0)); } -vec3 Transform::getUp() +vec3 Transform::getUp(bool previous) { - return up; + if (previous) return glm::vec3(glm::column(prevLocalToParentMatrix, 1)); + else return glm::vec3(glm::column(localToParentMatrix, 1)); } -vec3 Transform::getForward() +vec3 Transform::getForward(bool previous) { - return forward; + if (previous) return glm::vec3(glm::column(prevLocalToParentMatrix, 2)); + else return glm::vec3(glm::column(localToParentMatrix, 2)); } -void Transform::setPosition(vec3 newPosition) +void Transform::setPosition(vec3 newPosition, bool previous) { - position = newPosition; + if (previous) useRelativeMotionBlur = false; + auto &p = (previous) ? prevPosition : position; + p = newPosition; updatePosition(); markDirty(); } -void Transform::addPosition(vec3 additionalPosition) +void Transform::addPosition(vec3 additionalPosition, bool previous) { - setPosition(getPosition() + additionalPosition); + if (previous) useRelativeMotionBlur = false; + setPosition(getPosition(previous) + additionalPosition, previous); updatePosition(); markDirty(); } void Transform::setLinearVelocity(vec3 newLinearVelocity, float framesPerSecond, float mix) { + useRelativeMotionBlur = true; mix = glm::clamp(mix, 0.f, 1.f); newLinearVelocity /= framesPerSecond; - linearVelocity = glm::mix(newLinearVelocity, linearVelocity, mix); + linearMotion = glm::mix(newLinearVelocity, linearMotion, mix); updatePosition(); markDirty(); } void Transform::setAngularVelocity(quat newAngularVelocity, float framesPerSecond, float mix) { + useRelativeMotionBlur = true; mix = glm::clamp(mix, 0.f, 1.f); newAngularVelocity[0] = newAngularVelocity[0] / framesPerSecond; newAngularVelocity[1] = newAngularVelocity[1] / framesPerSecond; newAngularVelocity[2] = newAngularVelocity[2] / framesPerSecond; - angularVelocity = glm::lerp(newAngularVelocity, angularVelocity, mix); + angularMotion = glm::lerp(newAngularVelocity, angularMotion, mix); updateRotation(); markDirty(); } void Transform::setScalarVelocity(vec3 newScalarVelocity, float framesPerSecond, float mix) { + useRelativeMotionBlur = true; mix = glm::clamp(mix, 0.f, 1.f); newScalarVelocity /= framesPerSecond; - scalarVelocity = glm::mix(newScalarVelocity, scalarVelocity, mix); + scalarMotion = glm::mix(newScalarVelocity, scalarMotion, mix); updateScale(); markDirty(); } @@ -421,22 +455,30 @@ void Transform::setScalarVelocity(vec3 newScalarVelocity, float framesPerSecond, void Transform::updatePosition() { - localToParentTranslation = glm::translate(glm::mat4(1.0), position); - parentToLocalTranslation = glm::translate(glm::mat4(1.0), -position); - nextLocalToParentTranslation = glm::translate(glm::mat4(1.0), position + linearVelocity); - nextParentToLocalTranslation = glm::translate(glm::mat4(1.0), -position + linearVelocity); + // localToParentTranslation = glm::translate(glm::mat4(1.0), position); + // parentToLocalTranslation = glm::translate(glm::mat4(1.0), -position); + // if (useRelativeMotionBlur) { + // prevLocalToParentTranslation = glm::translate(glm::mat4(1.0), position + linearVelocity); + // prevParentToLocalTranslation = glm::translate(glm::mat4(1.0), -position + linearVelocity); + // } else { + // prevLocalToParentTranslation = glm::translate(glm::mat4(1.0), prevPosition); + // prevParentToLocalTranslation = glm::translate(glm::mat4(1.0), -prevPosition); + // } updateMatrix(); markDirty(); } -vec3 Transform::getScale() +vec3 Transform::getScale(bool previous) { - return scale; + if (previous) return prevScale; + else return scale; } -void Transform::setScale(vec3 newScale) +void Transform::setScale(vec3 newScale, bool previous) { - scale = newScale; + if (previous) useRelativeMotionBlur = false; + auto &s = (previous) ? prevScale : scale; + s = newScale; updateScale(); markDirty(); } @@ -448,9 +490,10 @@ void Transform::setScale(vec3 newScale) // markDirty(); // } -void Transform::addScale(vec3 additionalScale) +void Transform::addScale(vec3 additionalScale, bool previous) { - setScale(getScale() + additionalScale); + if (previous) useRelativeMotionBlur = false; + setScale(getScale(previous) + additionalScale, previous); updateScale(); markDirty(); } @@ -475,123 +518,154 @@ void Transform::addScale(vec3 additionalScale) void Transform::updateScale() { - localToParentScale = glm::scale(glm::mat4(1.0), scale); - parentToLocalScale = glm::scale(glm::mat4(1.0), glm::vec3(1.0 / scale.x, 1.0 / scale.y, 1.0 / scale.z)); - nextLocalToParentScale = glm::scale(glm::mat4(1.0), scale + scalarVelocity); - nextParentToLocalScale = glm::scale(glm::mat4(1.0), glm::vec3(1.0 / (scale.x + scalarVelocity.x), 1.0 / (scale.y + scalarVelocity.y), 1.0 / (scale.z + scalarVelocity.z))); + // localToParentScale = glm::scale(glm::mat4(1.0), scale); + // parentToLocalScale = glm::scale(glm::mat4(1.0), glm::vec3(1.0 / scale.x, 1.0 / scale.y, 1.0 / scale.z)); + // if (useRelativeMotionBlur) { + // prevLocalToParentScale = glm::scale(glm::mat4(1.0), scale + scalarVelocity); + // prevParentToLocalScale = glm::scale(glm::mat4(1.0), glm::vec3(1.0 / (scale.x + scalarVelocity.x), 1.0 / (scale.y + scalarVelocity.y), 1.0 / (scale.z + scalarVelocity.z))); + // } else { + // prevLocalToParentScale = glm::scale(glm::mat4(1.0), prevScale); + // prevParentToLocalScale = glm::scale(glm::mat4(1.0), glm::vec3(1.0 / prevScale.x, 1.0 / prevScale.y, 1.0 / prevScale.z)); + // } updateMatrix(); markDirty(); } void Transform::updateMatrix() { - localToParentMatrix = (localToParentTransform * localToParentTranslation * localToParentRotation * localToParentScale); - parentToLocalMatrix = (parentToLocalScale * parentToLocalRotation * parentToLocalTranslation * parentToLocalTransform); + localToParentMatrix = (localToParentTransform * getLocalToParentTranslationMatrix(false) * getLocalToParentRotationMatrix(false) * getLocalToParentScaleMatrix(false)); + parentToLocalMatrix = (getParentToLocalScaleMatrix(false) * getParentToLocalRotationMatrix(false) * getParentToLocalTranslationMatrix(false) * glm::inverse(localToParentTransform)); + + prevLocalToParentMatrix = (prevLocalToParentTransform * getLocalToParentTranslationMatrix(true) * getLocalToParentRotationMatrix(true) * getLocalToParentScaleMatrix(true)); + prevParentToLocalMatrix = (getParentToLocalScaleMatrix(true) * getParentToLocalRotationMatrix(true) * getParentToLocalTranslationMatrix(true) * glm::inverse(prevLocalToParentTransform)); - nextLocalToParentMatrix = (localToParentTransform * nextLocalToParentTranslation * nextLocalToParentRotation * nextLocalToParentScale); - nextParentToLocalMatrix = (nextParentToLocalScale * nextParentToLocalRotation * nextParentToLocalTranslation * parentToLocalTransform); + // right = glm::vec3(localToParentMatrix[0]); + // up = glm::vec3(localToParentMatrix[1]); + // forward = glm::vec3(localToParentMatrix[2]); + // position = glm::vec3(localToParentMatrix[3]); - right = glm::vec3(localToParentMatrix[0]); - up = glm::vec3(localToParentMatrix[1]); - forward = glm::vec3(localToParentMatrix[2]); - position = glm::vec3(localToParentMatrix[3]); + // prevRight = glm::vec3(prevLocalToParentMatrix[0]); + // prevUp = glm::vec3(prevLocalToParentMatrix[1]); + // prevForward = glm::vec3(prevLocalToParentMatrix[2]); + // prevPosition = glm::vec3(prevLocalToParentMatrix[3]); updateChildren(); markDirty(); } -glm::mat4 Transform::computeWorldToLocalMatrix() +glm::mat4 Transform::computeWorldToLocalMatrix(bool previous) { glm::mat4 parentMatrix = glm::mat4(1.0); if (parent != -1) { - parentMatrix = transforms[parent].computeWorldToLocalMatrix(); - return getParentToLocalMatrix() * parentMatrix; + parentMatrix = transforms[parent].computeWorldToLocalMatrix(previous); + return getParentToLocalMatrix(previous) * parentMatrix; } - else return getParentToLocalMatrix(); + else return getParentToLocalMatrix(previous); } -glm::mat4 Transform::computeNextWorldToLocalMatrix() -{ - glm::mat4 parentMatrix = glm::mat4(1.0); - if (parent != -1) { - parentMatrix = transforms[parent].computeNextWorldToLocalMatrix(); - return getNextParentToLocalMatrix() * parentMatrix; - } - else return getNextParentToLocalMatrix(); -} +// glm::mat4 Transform::computeNextWorldToLocalMatrix(bool previous) +// { +// glm::mat4 parentMatrix = glm::mat4(1.0); +// if (parent != -1) { +// parentMatrix = transforms[parent].computeNextWorldToLocalMatrix(); +// return getNextParentToLocalMatrix() * parentMatrix; +// } +// else return getNextParentToLocalMatrix(); +// } void Transform::updateWorldMatrix() { if (parent == -1) { worldToLocalMatrix = parentToLocalMatrix; localToWorldMatrix = localToParentMatrix; - nextWorldToLocalMatrix = nextParentToLocalMatrix; - nextLocalToWorldMatrix = nextLocalToParentMatrix; - - worldScale = scale; - worldTranslation = position; - worldRotation = rotation; - worldSkew = glm::vec3(0.f, 0.f, 0.f); - worldPerspective = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f); // not sure what this should default to... + prevWorldToLocalMatrix = prevParentToLocalMatrix; + prevLocalToWorldMatrix = prevLocalToParentMatrix; + + // worldScale = scale; + // worldTranslation = position; + // worldRotation = rotation; + // worldSkew = glm::vec3(0.f, 0.f, 0.f); + // worldPerspective = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f); // not sure what this should default to... + + // prevWorldScale = prevScale; + // prevWorldTranslation = prevPosition; + // prevWorldRotation = prevRotation; + // prevWorldSkew = glm::vec3(0.f, 0.f, 0.f); + // prevWorldPerspective = glm::vec4(1.0f, 1.0f, 1.0f, 1.0f); // not sure what this should default to... } else { - worldToLocalMatrix = computeWorldToLocalMatrix(); - nextWorldToLocalMatrix = computeNextWorldToLocalMatrix(); + worldToLocalMatrix = computeWorldToLocalMatrix(/*previous=*/false); + prevWorldToLocalMatrix = computeWorldToLocalMatrix(/*previous=*/true); localToWorldMatrix = glm::inverse(worldToLocalMatrix); - nextLocalToWorldMatrix = glm::inverse(worldToLocalMatrix); - glm::decompose(localToWorldMatrix, worldScale, worldRotation, worldTranslation, worldSkew, worldPerspective); + prevLocalToWorldMatrix = glm::inverse(prevWorldToLocalMatrix); + // glm::decompose(localToWorldMatrix, worldScale, worldRotation, worldTranslation, worldSkew, worldPerspective); + // glm::decompose(prevLocalToWorldMatrix, prevWorldScale, prevWorldRotation, prevWorldTranslation, prevWorldSkew, prevWorldPerspective); // glm::decompose(nextLocalToWorldMatrix, worldScale, worldRotation, worldTranslation, worldSkew, worldPerspective); } markDirty(); } -glm::mat4 Transform::getParentToLocalMatrix() +glm::mat4 Transform::getParentToLocalMatrix(bool previous) { - return parentToLocalMatrix; + if (previous) return prevParentToLocalMatrix; + else return parentToLocalMatrix; } -glm::mat4 Transform::getNextParentToLocalMatrix() -{ - return nextParentToLocalMatrix; -} +// glm::mat4 Transform::getNextParentToLocalMatrix() +// { +// return nextParentToLocalMatrix; +// } -glm::mat4 Transform::getLocalToParentMatrix() +glm::mat4 Transform::getLocalToParentMatrix(bool previous) { - return localToParentMatrix; + if (previous) return prevLocalToParentMatrix; + else return localToParentMatrix; } -glm::mat4 Transform::getNextLocalToParentMatrix() -{ - return nextLocalToParentMatrix; -} +// glm::mat4 Transform::getNextLocalToParentMatrix() +// { +// return nextLocalToParentMatrix; +// } -glm::mat4 Transform::getLocalToParentTranslationMatrix() +glm::mat4 Transform::getLocalToParentTranslationMatrix(bool previous) { - return localToParentTranslation; + if ((previous) && (useRelativeMotionBlur)) return glm::translate(glm::mat4(1.0), position - linearMotion); + else if (previous) return glm::translate(glm::mat4(1.0), prevPosition); + else return glm::translate(glm::mat4(1.0), position); } -glm::mat4 Transform::getLocalToParentScaleMatrix() +glm::mat4 Transform::getLocalToParentScaleMatrix(bool previous) { - return localToParentScale; + if ((previous) && (useRelativeMotionBlur)) return glm::scale(glm::mat4(1.0), scale - scalarMotion); + else if (previous) return glm::scale(glm::mat4(1.0), prevScale); + else return glm::scale(glm::mat4(1.0), scale); } -glm::mat4 Transform::getLocalToParentRotationMatrix() +glm::mat4 Transform::getLocalToParentRotationMatrix(bool previous) { - return localToParentRotation; + if ((previous) && (useRelativeMotionBlur)) return glm::toMat4(angularMotion * rotation); + else if (previous) return glm::toMat4(prevRotation); + else return glm::toMat4(rotation); } -glm::mat4 Transform::getParentToLocalTranslationMatrix() +glm::mat4 Transform::getParentToLocalTranslationMatrix(bool previous) { - return parentToLocalTranslation; + if ((previous) && (useRelativeMotionBlur)) return glm::translate(glm::mat4(1.0), -(position - linearMotion)); + else if (previous) return glm::translate(glm::mat4(1.0), -prevPosition); + else return glm::translate(glm::mat4(1.0), -position); } -glm::mat4 Transform::getParentToLocalScaleMatrix() +glm::mat4 Transform::getParentToLocalScaleMatrix(bool previous) { - return parentToLocalScale; + if ((previous) && (useRelativeMotionBlur)) return glm::scale(glm::mat4(1.0), glm::vec3(1.0 / (scale - scalarMotion).x, 1.0 / (scale - scalarMotion).y, 1.0 / (scale - scalarMotion).z)); + else if (previous) return glm::scale(glm::mat4(1.0), glm::vec3(1.0 / prevScale.x, 1.0 / prevScale.y, 1.0 / prevScale.z)); + else return glm::scale(glm::mat4(1.0), glm::vec3(1.0 / scale.x, 1.0 / scale.y, 1.0 / scale.z)); } -glm::mat4 Transform::getParentToLocalRotationMatrix() +glm::mat4 Transform::getParentToLocalRotationMatrix(bool previous) { - return parentToLocalRotation; + if ((previous) && (useRelativeMotionBlur)) return glm::toMat4(glm::inverse(angularMotion * rotation)); + else if (previous) return glm::toMat4(glm::inverse(prevRotation)); + else return glm::toMat4(glm::inverse(rotation)); } void Transform::setParent(Transform *parent) { @@ -655,71 +729,78 @@ void Transform::removeChild(Transform *object) { transforms[object->getId()].markDirty(); } -glm::mat4 Transform::getWorldToLocalMatrix() { - return worldToLocalMatrix; +glm::mat4 Transform::getWorldToLocalMatrix(bool previous) { + if (previous) return prevWorldToLocalMatrix; + else return worldToLocalMatrix; } -glm::mat4 Transform::getLocalToWorldMatrix() { - return localToWorldMatrix; +glm::mat4 Transform::getLocalToWorldMatrix(bool previous) { + if (previous) return prevLocalToWorldMatrix; + else return localToWorldMatrix; } -glm::mat4 Transform::getNextWorldToLocalMatrix() { - return nextWorldToLocalMatrix; -} +// glm::mat4 Transform::getNextWorldToLocalMatrix() { +// return nextWorldToLocalMatrix; +// } -glm::mat4 Transform::getNextLocalToWorldMatrix() { - return nextLocalToWorldMatrix; -} +// glm::mat4 Transform::getNextLocalToWorldMatrix() { +// return nextLocalToWorldMatrix; +// } -glm::quat Transform::getWorldRotation() { - return worldRotation; -} +// glm::quat Transform::getWorldRotation(bool previous) { +// if (previous) return prevWorldRotation; +// else return worldRotation; +// } -glm::vec3 Transform::getWorldTranslation() { - return worldTranslation; -} +// glm::vec3 Transform::getWorldTranslation(bool previous) { +// if (previous) return prevWorldTranslation; +// else return worldTranslation; +// } -glm::vec3 Transform::getWorldScale() { - return worldScale; -} +// glm::vec3 Transform::getWorldScale(bool previous) { +// if (previous) return prevWorldScale; +// else return worldScale; +// } -glm::mat4 Transform::getWorldToLocalRotationMatrix() -{ - return glm::toMat4(glm::inverse(worldRotation)); -} +// glm::mat4 Transform::getWorldToLocalRotationMatrix(bool previous) +// { +// return glm::toMat4(glm::inverse(worldRotation)); +// } -glm::mat4 Transform::getLocalToWorldRotationMatrix() -{ - return glm::toMat4(worldRotation); -} +// glm::mat4 Transform::getLocalToWorldRotationMatrix(bool previous) +// { +// if (previous) glm::toMat4(prevWorldRotation); +// return glm::toMat4(worldRotation); +// } -glm::mat4 Transform::getWorldToLocalTranslationMatrix() -{ - glm::mat4 m(1.0); - m = glm::translate(m, -1.0f * worldTranslation); - return m; -} +// glm::mat4 Transform::getWorldToLocalTranslationMatrix(bool previous) +// { +// glm::mat4 m(1.0); +// m = glm::translate(m, -1.0f * (previous) ? prevWorldTranslation : worldTranslation); +// return m; +// } -glm::mat4 Transform::getLocalToWorldTranslationMatrix() -{ - glm::mat4 m(1.0); - m = glm::translate(m, worldTranslation); - return m; -} +// glm::mat4 Transform::getLocalToWorldTranslationMatrix(bool previous) +// { +// glm::mat4 m(1.0); +// m = glm::translate(m, (previous) ? prevWorldTranslation : worldTranslation); +// return m; +// } -glm::mat4 Transform::getWorldToLocalScaleMatrix() -{ - glm::mat4 m(1.0); - m = glm::scale(m, 1.0f / worldScale); - return m; -} +// glm::mat4 Transform::getWorldToLocalScaleMatrix(bool previous) +// { +// glm::mat4 m(1.0); +// m = glm::scale(m, 1.0f / ((previous) ? prevWorldScale : worldScale)); +// return m; +// } + +// glm::mat4 Transform::getLocalToWorldScaleMatrix(bool previous) +// { +// glm::mat4 m(1.0); +// m = glm::scale(m, (previous) ? prevWorldScale : worldScale); +// return m; +// } -glm::mat4 Transform::getLocalToWorldScaleMatrix() -{ - glm::mat4 m(1.0); - m = glm::scale(m, worldScale); - return m; -} void Transform::updateChildren() { diff --git a/src/visii/visii.cpp b/src/visii/visii.cpp index 0a3b6d7e..98399137 100644 --- a/src/visii/visii.cpp +++ b/src/visii/visii.cpp @@ -960,10 +960,10 @@ void updateComponents() OWLGroup blas = OD.meshes[entities[eid].getMesh()->getId()].blas; if (!blas) return; - glm::mat4 localToWorld = entities[eid].getTransform()->getLocalToWorldMatrix(); - glm::mat4 nextLocalToWorld = entities[eid].getTransform()->getNextLocalToWorldMatrix(); - t0InstanceTransforms.push_back(localToWorld); - t1InstanceTransforms.push_back(nextLocalToWorld); + glm::mat4 prevLocalToWorld = entities[eid].getTransform()->getLocalToWorldMatrix(/*previous = */true); + glm::mat4 localToWorld = entities[eid].getTransform()->getLocalToWorldMatrix(/*previous = */false); + t0InstanceTransforms.push_back(prevLocalToWorld); + t1InstanceTransforms.push_back(localToWorld); instances.push_back(blas); instanceToEntityMap.push_back(eid); } @@ -1084,8 +1084,8 @@ void updateComponents() auto transform = Transform::getFront()[OptixData.LP.cameraEntity.transform_id]; auto camera = Camera::getFront()[OptixData.LP.cameraEntity.camera_id]; OptixData.LP.proj = camera.getProjection(); - OptixData.LP.viewT0 = transform.getWorldToLocalMatrix(); - OptixData.LP.viewT1 = transform.getNextWorldToLocalMatrix(); + OptixData.LP.viewT0 = transform.getWorldToLocalMatrix(/*previous = */ true); + OptixData.LP.viewT1 = transform.getWorldToLocalMatrix(/*previous = */ false); } } From 33b8a87484f38c750f899609d0e4ff5a941ea70d Mon Sep 17 00:00:00 2001 From: n8vm Date: Sat, 1 Aug 2020 13:18:04 -0600 Subject: [PATCH 17/25] Added a clear_motion function to reset motion blur --- include/visii/transform.h | 5 +++++ src/visii/transform.cpp | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/include/visii/transform.h b/include/visii/transform.h index 839078cd..8d0325ef 100644 --- a/include/visii/transform.h +++ b/include/visii/transform.h @@ -550,6 +550,11 @@ class Transform : public StaticFactory */ void setScalarVelocity(vec3 velocity, float frames_per_second = 1.0f, float mix = 0.0f); + /** + * Resets any "previous" transform data, effectively clearing any current motion blur. + */ + void clearMotion(); + /** * @param previous If true, returns the previous parent-to-local matrix. * @returns the final matrix transforming this object from it's parent coordinate space to it's diff --git a/src/visii/transform.cpp b/src/visii/transform.cpp index 0009ba6d..772e0bba 100644 --- a/src/visii/transform.cpp +++ b/src/visii/transform.cpp @@ -441,6 +441,16 @@ void Transform::setScalarVelocity(vec3 newScalarVelocity, float framesPerSecond, markDirty(); } +void Transform::clearMotion() +{ + useRelativeMotionBlur = true; + scalarMotion = glm::vec3(0.f); + angularMotion = glm::quat(1.f, 0.f, 0.f, 0.f); + linearMotion = glm::vec3(0.f); + updateMatrix(); + markDirty(); +} + // void Transform::setPosition(float x, float y, float z) // { // setPosition(glm::vec3(x, y, z)); From cc1d0dff52811bd648acff983fcbcfbcf2daeead Mon Sep 17 00:00:00 2001 From: n8vm Date: Sat, 1 Aug 2020 18:57:36 -0600 Subject: [PATCH 18/25] Some optimization to allow for faster transform component updates --- include/visii/transform.h | 22 +++++++--------- src/visii/transform.cpp | 55 +++++++++++++++++++++++++-------------- src/visii/visii.cpp | 22 ++++++++++++++-- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/include/visii/transform.h b/include/visii/transform.h index 8d0325ef..1967235d 100644 --- a/include/visii/transform.h +++ b/include/visii/transform.h @@ -149,11 +149,7 @@ class Transform : public StaticFactory Transform(); Transform(std::string name, uint32_t id); - /* Indicates that one of the components has been edited */ - static bool anyDirty; - - /* Indicates this component has been edited */ - bool dirty = true; + static std::set dirtyTransforms; public: /** @@ -189,6 +185,9 @@ class Transform : public StaticFactory /** @returns the name of this component */ std::string getName(); + /** @returns the unique integer ID for this component */ + int32_t getId(); + /** @returns A map whose key is a transform name and whose value is the ID for that transform */ static std::map getNameToIdMap(); @@ -207,24 +206,21 @@ class Transform : public StaticFactory /** Iterates through all transform components, computing transform metadata for rendering purposes. */ static void updateComponents(); + /** Iterates through all transform components, marking them as clean. */ + static void cleanComponents(); + /** Clears any existing transform components. */ static void clearAll(); - /** @return True if this transform has been modified since the previous frame, and False otherwise */ - bool isDirty() { return dirty; } - /** @return True if any the transform has been modified since the previous frame, and False otherwise */ static bool areAnyDirty(); - /** @return True if the Transform has not been modified since the previous frame, and False otherwise */ - bool isClean() { return !dirty; } + /** @returns a list of transforms that have been modified since the previous frame */ + static std::set getDirtyTransforms(); /** Tags the current component as being modified since the previous frame. */ void markDirty(); - /** Tags the current component as being unmodified since the previous frame. */ - void markClean() { dirty = false; } - /** For internal use. Returns the mutex used to lock transforms for processing by the renderer. */ static std::shared_ptr getEditMutex(); diff --git a/src/visii/transform.cpp b/src/visii/transform.cpp index 772e0bba..0499377d 100644 --- a/src/visii/transform.cpp +++ b/src/visii/transform.cpp @@ -7,7 +7,7 @@ std::map Transform::lookupTable; std::shared_ptr Transform::editMutex; bool Transform::factoryInitialized = false; -bool Transform::anyDirty = true; +std::set Transform::dirtyTransforms; void Transform::initializeFactory() { @@ -26,29 +26,29 @@ bool Transform::isInitialized() return initialized; } -bool Transform::areAnyDirty() +bool Transform::areAnyDirty() { + return dirtyTransforms.size(); +}; + +std::set Transform::getDirtyTransforms() { - return anyDirty; + return dirtyTransforms; } -void Transform::markDirty() { - dirty = true; - anyDirty = true; - auto entityPointers = Entity::getFront(); - for (auto &eid : entities) { - entityPointers[eid].markDirty(); +void Transform::updateComponents() +{ + if (dirtyTransforms.size() == 0) return; + for (auto &t : dirtyTransforms) { + if (!t->isInitialized()) continue; + transformStructs[t->id].worldToLocal = t->getWorldToLocalMatrix(); + transformStructs[t->id].localToWorld = t->getLocalToWorldMatrix(); } -}; +} -void Transform::updateComponents() +void Transform::cleanComponents() { - for (int i = 0; i < MAX_TRANSFORMS; ++i) { - if (!transforms[i].isFactoryInitialized()) continue; - transformStructs[i].worldToLocal = transforms[i].getWorldToLocalMatrix(); - transformStructs[i].localToWorld = transforms[i].getLocalToWorldMatrix(); - transforms[i].markClean(); - }; - anyDirty = false; + if (dirtyTransforms.size() == 0) return; + dirtyTransforms.clear(); } void Transform::clearAll() @@ -68,10 +68,10 @@ Transform* Transform::create(std::string name, vec3 scale, quat rotation, vec3 position) { auto t = StaticFactory::create(editMutex, name, "Transform", lookupTable, transforms, MAX_TRANSFORMS); + dirtyTransforms.insert(t); t->setPosition(position); t->setRotation(rotation); t->setScale(scale); - anyDirty = true; return t; } @@ -85,7 +85,9 @@ Transform* Transform::get(std::string name) { } void Transform::remove(std::string name) { + int32_t oldID = transforms->getId(); StaticFactory::remove(editMutex, name, "Transform", lookupTable, transforms, MAX_TRANSFORMS); + dirtyTransforms.insert(&transforms[oldID]); } TransformStruct* Transform::getFrontStruct() @@ -106,11 +108,24 @@ std::string Transform::getName() return name; } +int32_t Transform::getId() +{ + return id; +} + std::map Transform::getNameToIdMap() { return lookupTable; } +void Transform::markDirty() { + dirtyTransforms.insert(this); + auto entityPointers = Entity::getFront(); + for (auto &eid : entities) { + entityPointers[eid].markDirty(); + } +}; + Transform::Transform() { initialized = false; } @@ -826,4 +841,4 @@ void Transform::updateChildren() TransformStruct &Transform::getStruct() { return transformStructs[id]; -} \ No newline at end of file +} diff --git a/src/visii/visii.cpp b/src/visii/visii.cpp index 98399137..aeb869fd 100644 --- a/src/visii/visii.cpp +++ b/src/visii/visii.cpp @@ -1045,12 +1045,30 @@ void updateComponents() } // Manage transforms - if (Transform::areAnyDirty()) { + auto dirtyTransforms = Transform::getDirtyTransforms(); + if (dirtyTransforms.size() > 0) { auto mutex = Transform::getEditMutex(); std::lock_guard lock(*mutex.get()); Transform::updateComponents(); - bufferUpload(OptixData.transformBuffer, Transform::getFrontStruct()); + + // for each device + for (uint32_t id = 0; id < owlGetDeviceCount(OptixData.context); ++id) + { + cudaSetDevice(id); + + TransformStruct* devTransforms = (TransformStruct*)owlBufferGetPointer(OptixData.transformBuffer, id); + TransformStruct* transformStructs = Transform::getFrontStruct(); + for (auto &t : dirtyTransforms) { + if (!t->isInitialized()) continue; + CUDA_CHECK(cudaMemcpy(&devTransforms[t->getId()], &transformStructs[t->getId()], sizeof(TransformStruct), cudaMemcpyHostToDevice)); + } + } + + cudaSetDevice(0); + + Transform::cleanComponents(); + // bufferUpload(OptixData.transformBuffer, Transform::getFrontStruct()); } // Manage Cameras From de693a89c1f7ea30267fa0b932b9208d8115ff65 Mon Sep 17 00:00:00 2001 From: n8vm Date: Sat, 1 Aug 2020 23:52:47 -0600 Subject: [PATCH 19/25] Fixed an out of bounds bug when importance sampling dome lights --- src/visii/devicecode/path_tracer.cu | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index b5507010..84b56239 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -645,7 +645,11 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() const uint32_t occlusionFlags = OPTIX_RAY_FLAG_DISABLE_ANYHIT | OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; float3 lightDir; - if ((optixLaunchParams.environmentMapWidth != 0) && (optixLaunchParams.environmentMapHeight != 0)) { + if ( + (optixLaunchParams.environmentMapWidth != 0) && (optixLaunchParams.environmentMapHeight != 0) && + (optixLaunchParams.environmentMapRows != nullptr) && (optixLaunchParams.environmentMapCols != nullptr) + ) + { // Vec3fa color = m_background->sample(dg, wi, tMax, RandomSampler_get2D(sampler)); float rx = lcg_randomf(rng); float ry = lcg_randomf(rng); @@ -657,8 +661,8 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() float row_pdf, col_pdf; unsigned x, y; ry = sample_cdf(rows, height, ry, &y, &row_pdf); + y = max(min(y, height - 1), 0); rx = sample_cdf(cols + y * width, width, rx, &x, &col_pdf); - // y = height - y; lightDir = make_float3(toPolar(vec2((x + rx) / float(width), (y + ry)/float(height)))); lightPDFs[lid] = row_pdf * col_pdf * invjacobian; } From 188c39b351e04f6ee7ff65620ced63f205e20300 Mon Sep 17 00:00:00 2001 From: n8vm Date: Sun, 2 Aug 2020 00:54:46 -0600 Subject: [PATCH 20/25] Added motion vectors for background dome light --- include/visii/transform.h | 3 --- src/visii/devicecode/path_tracer.cu | 28 +++++++++++++++++++++++++++ src/visii/transform.cpp | 30 +++++++++++++++++------------ src/visii/visii.cpp | 2 -- 4 files changed, 46 insertions(+), 17 deletions(-) diff --git a/include/visii/transform.h b/include/visii/transform.h index 1967235d..960e8d56 100644 --- a/include/visii/transform.h +++ b/include/visii/transform.h @@ -206,9 +206,6 @@ class Transform : public StaticFactory /** Iterates through all transform components, computing transform metadata for rendering purposes. */ static void updateComponents(); - /** Iterates through all transform components, marking them as clean. */ - static void cleanComponents(); - /** Clears any existing transform components. */ static void clearAll(); diff --git a/src/visii/devicecode/path_tracer.cu b/src/visii/devicecode/path_tracer.cu index 84b56239..16fe43b0 100644 --- a/src/visii/devicecode/path_tracer.cu +++ b/src/visii/devicecode/path_tracer.cu @@ -375,6 +375,21 @@ void saveLightingIrradianceRenderData( } } +__device__ +void saveMissRenderData( + float3 &renderData, + int bounce, + float3 mvec) +{ + if (optixLaunchParams.renderDataMode == RenderDataFlags::NONE) return; + if (bounce != optixLaunchParams.renderDataBounce) return; + + if (optixLaunchParams.renderDataMode == RenderDataFlags::DIFFUSE_MOTION_VECTORS) { + renderData = mvec; + } +} + + __device__ void saveGeometricRenderData( float3 &renderData, @@ -492,6 +507,19 @@ OPTIX_RAYGEN_PROGRAM(rayGen)() // primaryAlbedo = illum; directIllum = illum; } + + const float envDist = 10000.0f; // large value + /* Compute miss motion vector */ + float3 mvec; + // Point far away + float3 pFar = ray.origin + ray.direction * envDist; + // TODO: account for motion from rotating dome light + vec4 tmp1 = optixLaunchParams.proj * optixLaunchParams.viewT0 * /*xfmt0 **/ make_vec4(pFar, 1.0f); + float3 pt0 = make_float3(tmp1 / tmp1.w) * .5f; + vec4 tmp2 = optixLaunchParams.proj * optixLaunchParams.viewT1 * /*xfmt1 **/ make_vec4(pFar, 1.0f); + float3 pt1 = make_float3(tmp2 / tmp2.w) * .5f; + mvec = pt1 - pt0; + saveMissRenderData(renderData, bounce, mvec); break; } diff --git a/src/visii/transform.cpp b/src/visii/transform.cpp index 0499377d..979acfa3 100644 --- a/src/visii/transform.cpp +++ b/src/visii/transform.cpp @@ -8,6 +8,7 @@ std::map Transform::lookupTable; std::shared_ptr Transform::editMutex; bool Transform::factoryInitialized = false; std::set Transform::dirtyTransforms; +static bool mutexAcquired = false; void Transform::initializeFactory() { @@ -43,11 +44,6 @@ void Transform::updateComponents() transformStructs[t->id].worldToLocal = t->getWorldToLocalMatrix(); transformStructs[t->id].localToWorld = t->getLocalToWorldMatrix(); } -} - -void Transform::cleanComponents() -{ - if (dirtyTransforms.size() == 0) return; dirtyTransforms.clear(); } @@ -62,17 +58,24 @@ void Transform::clearAll() } } - /* Static Factory Implementations */ Transform* Transform::create(std::string name, vec3 scale, quat rotation, vec3 position) { - auto t = StaticFactory::create(editMutex, name, "Transform", lookupTable, transforms, MAX_TRANSFORMS); - dirtyTransforms.insert(t); - t->setPosition(position); - t->setRotation(rotation); - t->setScale(scale); - return t; + auto createTransform = [scale, rotation, position] (Transform* transform) { + dirtyTransforms.insert(transform); + transform->setPosition(position); + transform->setRotation(rotation); + transform->setScale(scale); + }; + + try { + return StaticFactory::create(editMutex, name, "Transform", lookupTable, transforms, MAX_TRANSFORMS, createTransform); + } + catch (...) { + StaticFactory::removeIfExists(editMutex, name, "Transform", lookupTable, transforms, MAX_TRANSFORMS); + throw; + } } std::shared_ptr Transform::getEditMutex() @@ -211,6 +214,9 @@ glm::quat safeQuatLookAt( void Transform::lookAt(vec3 at, vec3 up, vec3 eye, bool previous) { + // if (!mutexAcquired) { + // std::lock_guardlock(*editMutex.get()); + // } if (previous) useRelativeMotionBlur = false; if (glm::any(glm::isnan(eye))) { eye = (previous) ? this->prevPosition : this->position; diff --git a/src/visii/visii.cpp b/src/visii/visii.cpp index aeb869fd..d75faa19 100644 --- a/src/visii/visii.cpp +++ b/src/visii/visii.cpp @@ -1066,8 +1066,6 @@ void updateComponents() } cudaSetDevice(0); - - Transform::cleanComponents(); // bufferUpload(OptixData.transformBuffer, Transform::getFrontStruct()); } From 7f9fbe3dca7f5cef0716cfefbbcb76fed93bf1c1 Mon Sep 17 00:00:00 2001 From: n8vm Date: Sun, 2 Aug 2020 01:05:55 -0600 Subject: [PATCH 21/25] Update to reprojection sample to include camera motion, reprojecting background --- examples/13.reprojection.py | 47 ++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/examples/13.reprojection.py b/examples/13.reprojection.py index 7eae504a..65abd0f6 100644 --- a/examples/13.reprojection.py +++ b/examples/13.reprojection.py @@ -1,4 +1,5 @@ import os +import math import visii import noise import random @@ -38,7 +39,6 @@ print(f'created folder {opt.outf}/') # # # # # # # # # # # # # # # # # # # # # # # # # - visii.initialize_headless() camera = visii.entity.create( @@ -51,11 +51,22 @@ ) ) +angle = 0 +camera.get_transform().look_at( + visii.vec3(0,0,.1), # look at (world coordinate) + visii.vec3(0,0,1), # up vector + visii.vec3(math.sin(angle), math.cos(angle),.2), + previous = True +) + +angle = -visii.pi() * .05 camera.get_transform().look_at( - visii.vec3(0,0,0), # look at (world coordinate) + visii.vec3(0,0,.1), # look at (world coordinate) visii.vec3(0,0,1), # up vector - visii.vec3(0,1,1) + visii.vec3(math.sin(angle), math.cos(angle),.2), + previous = False ) + visii.set_camera_entity(camera) # # # # # # # # # # # # # # # # # # # # # # # # # @@ -67,20 +78,8 @@ material = visii.material.create("floor") ) -floor.get_transform().set_scale(visii.vec3(100)) floor.get_material().set_roughness(1.0) -areaLight1 = visii.entity.create( - name="areaLight1", - light = visii.light.create("areaLight1"), - transform = visii.transform.create("areaLight1"), - mesh = visii.mesh.create_teapotahedron("areaLight1"), -) -areaLight1.get_light().set_intensity(10000.) -areaLight1.get_light().set_temperature(8000) -areaLight1.get_transform().set_position( - visii.vec3(0, 0, 5)) - mesh1 = visii.entity.create( name="mesh1", mesh = visii.mesh.create_teapotahedron("mesh1"), @@ -92,17 +91,21 @@ mesh1.get_material().set_base_color( visii.vec3(1.0, 0.0, 0.0)) -mesh1.get_transform().set_position(visii.vec3(-0.05, 0.0, 0)) -mesh1.get_transform().set_scale(visii.vec3(0.1)) -mesh1.get_transform().set_linear_velocity(visii.vec3(0.1, 0.0, 0.0)) +mesh1.get_transform().set_position(visii.vec3(-0.05, 0.0, 0), previous=True) +mesh1.get_transform().set_scale(visii.vec3(0.1), previous = False) +mesh1.get_transform().set_scale(visii.vec3(0.1), previous = True) +mesh1.get_transform().set_position(visii.vec3(0.05, 0.0, 0), previous=False) + +tex = visii.texture.create_from_image("dome", "../data/dome.hdr") +visii.set_dome_light_texture(tex) +visii.set_dome_light_intensity(2) -visii.set_dome_light_intensity(1) visii.set_direct_lighting_clamp(10.0) visii.set_indirect_lighting_clamp(10.0) visii.set_max_bounce_depth(0) visii.sample_pixel_area(visii.vec2(.5), visii.vec2(.5)) -# # # # # # # # # # # # # # # # # # # # # # # # # +# # # # # # # # # # # # # # # # # # # # # # # # # # First, let's render out the scene with motion blur to understand # how the object is moving visii.sample_time_interval(visii.vec2(0.0, 1.0)) @@ -129,7 +132,7 @@ def save_image(data, name): t1_array = visii.render( width=opt.width, height=opt.height, - samples_per_pixel=1, + samples_per_pixel=8, seed = 1 ) t1_array = np.array(t1_array).reshape(opt.height,opt.width,4) @@ -205,4 +208,4 @@ def save_image(data, name): save_image(mixed_img, f"{opt.outf}/mixed_img.png") # let's clean up the GPU -visii.deinitialize() \ No newline at end of file +visii.deinitialize() From b03814b8e1d02ebd8939cb138940bebfcd8fabf0 Mon Sep 17 00:00:00 2001 From: jtremblay Date: Mon, 3 Aug 2020 09:51:21 -0700 Subject: [PATCH 22/25] Update readme.md Added an example of moving the camera around. --- examples/readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/readme.md b/examples/readme.md index a069e154..c0eb83c9 100644 --- a/examples/readme.md +++ b/examples/readme.md @@ -92,7 +92,7 @@ for disocclusions. A simple script that loads a texture, normal and roughness map and apply them to a flat surface. ## 15.camera_control.py -An interactive demo for controlling the camera similar to to a first person shooter control using `w,a,s,d` and `q` and `e` for up and down. Using the left click on the mouse you can rotate the camera. +An interactive demo for controlling the camera similar to to a first person shooter control using `w,a,s,d` and `q` and `e` for up and down. Using the left click on the mouse you can rotate the camera. Here is an [example](https://imgur.com/VYda2UF) of the sort of motion you can generate. ## Notes All these examples were developed and tested on Ubuntu 18.04 with cuda 11.0, NVIDIA drivers @@ -100,4 +100,4 @@ All these examples were developed and tested on Ubuntu 18.04 with cuda 11.0, NVI \ No newline at end of file +- exporting data is missing segmentation id for objects --> From f30e8b567bc5e1977a20d546f52cab6058815f1c Mon Sep 17 00:00:00 2001 From: n8vm Date: Mon, 3 Aug 2020 11:02:24 -0600 Subject: [PATCH 23/25] Updating CI --- .github/workflows/manylinux.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index af013f1e..bbf9e186 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -31,7 +31,7 @@ jobs: - name: Download Dependencies run: | # Add directory containing cmake - export PATH=$PATH:/opt/_internal/cpython-3.8.4/bin/ + export PATH=$PATH:/opt/_internal/cpython-3.8.5/bin/ # list contents of python folder #ls -R /opt/python/${{ matrix.python-version }} @@ -52,7 +52,7 @@ jobs: /opt/python/cp38-cp38/bin/pip install cmake find / -iname "cmake" - /opt/_internal/cpython-3.8.4/bin/cmake --version + /opt/_internal/cpython-3.8.5/bin/cmake --version # Setuptools scm /opt/python/${{ matrix.python-version }}/bin/pip install setuptools_scm @@ -87,7 +87,7 @@ jobs: - name: Configure and install cmake project run: | - export PATH=$PATH:/opt/_internal/cpython-3.8.4/bin/ + export PATH=$PATH:/opt/_internal/cpython-3.8.5/bin/ source /opt/rh/devtoolset-8/enable PY=${{ matrix.python-version }} From 64eff8ece3885f60efab79b0316704313bf37888 Mon Sep 17 00:00:00 2001 From: n8vm Date: Mon, 3 Aug 2020 11:24:40 -0600 Subject: [PATCH 24/25] Making switch from relative to absolute motion blur independent for scale, translation, and rotation --- include/visii/transform.h | 4 +++- src/visii/transform.cpp | 49 ++++++++++++++++++++++++--------------- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/include/visii/transform.h b/include/visii/transform.h index 960e8d56..30e3e188 100644 --- a/include/visii/transform.h +++ b/include/visii/transform.h @@ -36,7 +36,9 @@ class Transform : public StaticFactory friend class Entity; private: - bool useRelativeMotionBlur = true; + bool useRelativeLinearMotionBlur = true; + bool useRelativeAngularMotionBlur = true; + bool useRelativeScalarMotionBlur = true; /* Scene graph information */ int32_t parent = -1; diff --git a/src/visii/transform.cpp b/src/visii/transform.cpp index 979acfa3..6a854edb 100644 --- a/src/visii/transform.cpp +++ b/src/visii/transform.cpp @@ -217,10 +217,15 @@ void Transform::lookAt(vec3 at, vec3 up, vec3 eye, bool previous) // if (!mutexAcquired) { // std::lock_guardlock(*editMutex.get()); // } - if (previous) useRelativeMotionBlur = false; + if (previous) { + useRelativeAngularMotionBlur = false; + } if (glm::any(glm::isnan(eye))) { eye = (previous) ? this->prevPosition : this->position; } else { + if (previous) { + useRelativeLinearMotionBlur = false; + } setPosition(eye, previous); } up = normalize(up); @@ -273,7 +278,7 @@ void Transform::lookAt(vec3 at, vec3 up, vec3 eye, bool previous) void Transform::rotateAround(vec3 point, glm::quat rot, bool previous) { - if (previous) useRelativeMotionBlur = false; + if (previous) useRelativeAngularMotionBlur = false; glm::vec3 direction = point - getPosition(previous); glm::vec3 newPosition = getPosition(previous) + direction; glm::quat newRotation = rot * getRotation(previous); @@ -300,7 +305,11 @@ void Transform::rotateAround(vec3 point, glm::quat rot, bool previous) void Transform::setTransform(glm::mat4 transformation, bool decompose, bool previous) { - if (previous) useRelativeMotionBlur = false; + if (previous) { + useRelativeLinearMotionBlur = false; + useRelativeAngularMotionBlur = false; + useRelativeScalarMotionBlur = false; + } if (decompose) { glm::vec3 scale; @@ -347,7 +356,7 @@ quat Transform::getRotation(bool previous) void Transform::setRotation(quat newRotation, bool previous) { - if (previous) useRelativeMotionBlur = false; + if (previous) useRelativeAngularMotionBlur = false; auto &r = (previous) ? prevRotation : rotation; r = glm::normalize(newRotation); updateRotation(); @@ -362,7 +371,7 @@ void Transform::setRotation(quat newRotation, bool previous) void Transform::addRotation(quat additionalRotation, bool previous) { - if (previous) useRelativeMotionBlur = false; + if (previous) useRelativeAngularMotionBlur = false; setRotation(getRotation(previous) * additionalRotation, previous); updateRotation(); markDirty(); @@ -415,7 +424,7 @@ vec3 Transform::getForward(bool previous) void Transform::setPosition(vec3 newPosition, bool previous) { - if (previous) useRelativeMotionBlur = false; + if (previous) useRelativeLinearMotionBlur = false; auto &p = (previous) ? prevPosition : position; p = newPosition; updatePosition(); @@ -424,7 +433,7 @@ void Transform::setPosition(vec3 newPosition, bool previous) void Transform::addPosition(vec3 additionalPosition, bool previous) { - if (previous) useRelativeMotionBlur = false; + if (previous) useRelativeLinearMotionBlur = false; setPosition(getPosition(previous) + additionalPosition, previous); updatePosition(); markDirty(); @@ -432,7 +441,7 @@ void Transform::addPosition(vec3 additionalPosition, bool previous) void Transform::setLinearVelocity(vec3 newLinearVelocity, float framesPerSecond, float mix) { - useRelativeMotionBlur = true; + useRelativeLinearMotionBlur = true; mix = glm::clamp(mix, 0.f, 1.f); newLinearVelocity /= framesPerSecond; linearMotion = glm::mix(newLinearVelocity, linearMotion, mix); @@ -442,7 +451,7 @@ void Transform::setLinearVelocity(vec3 newLinearVelocity, float framesPerSecond, void Transform::setAngularVelocity(quat newAngularVelocity, float framesPerSecond, float mix) { - useRelativeMotionBlur = true; + useRelativeAngularMotionBlur = true; mix = glm::clamp(mix, 0.f, 1.f); newAngularVelocity[0] = newAngularVelocity[0] / framesPerSecond; newAngularVelocity[1] = newAngularVelocity[1] / framesPerSecond; @@ -454,7 +463,7 @@ void Transform::setAngularVelocity(quat newAngularVelocity, float framesPerSecon void Transform::setScalarVelocity(vec3 newScalarVelocity, float framesPerSecond, float mix) { - useRelativeMotionBlur = true; + useRelativeScalarMotionBlur = true; mix = glm::clamp(mix, 0.f, 1.f); newScalarVelocity /= framesPerSecond; scalarMotion = glm::mix(newScalarVelocity, scalarMotion, mix); @@ -464,7 +473,9 @@ void Transform::setScalarVelocity(vec3 newScalarVelocity, float framesPerSecond, void Transform::clearMotion() { - useRelativeMotionBlur = true; + useRelativeLinearMotionBlur = true; + useRelativeAngularMotionBlur = true; + useRelativeScalarMotionBlur = true; scalarMotion = glm::vec3(0.f); angularMotion = glm::quat(1.f, 0.f, 0.f, 0.f); linearMotion = glm::vec3(0.f); @@ -507,7 +518,7 @@ vec3 Transform::getScale(bool previous) void Transform::setScale(vec3 newScale, bool previous) { - if (previous) useRelativeMotionBlur = false; + if (previous) useRelativeScalarMotionBlur = false; auto &s = (previous) ? prevScale : scale; s = newScale; updateScale(); @@ -523,7 +534,7 @@ void Transform::setScale(vec3 newScale, bool previous) void Transform::addScale(vec3 additionalScale, bool previous) { - if (previous) useRelativeMotionBlur = false; + if (previous) useRelativeScalarMotionBlur = false; setScale(getScale(previous) + additionalScale, previous); updateScale(); markDirty(); @@ -659,42 +670,42 @@ glm::mat4 Transform::getLocalToParentMatrix(bool previous) glm::mat4 Transform::getLocalToParentTranslationMatrix(bool previous) { - if ((previous) && (useRelativeMotionBlur)) return glm::translate(glm::mat4(1.0), position - linearMotion); + if ((previous) && (useRelativeLinearMotionBlur)) return glm::translate(glm::mat4(1.0), position - linearMotion); else if (previous) return glm::translate(glm::mat4(1.0), prevPosition); else return glm::translate(glm::mat4(1.0), position); } glm::mat4 Transform::getLocalToParentScaleMatrix(bool previous) { - if ((previous) && (useRelativeMotionBlur)) return glm::scale(glm::mat4(1.0), scale - scalarMotion); + if ((previous) && (useRelativeScalarMotionBlur)) return glm::scale(glm::mat4(1.0), scale - scalarMotion); else if (previous) return glm::scale(glm::mat4(1.0), prevScale); else return glm::scale(glm::mat4(1.0), scale); } glm::mat4 Transform::getLocalToParentRotationMatrix(bool previous) { - if ((previous) && (useRelativeMotionBlur)) return glm::toMat4(angularMotion * rotation); + if ((previous) && (useRelativeAngularMotionBlur)) return glm::toMat4(angularMotion * rotation); else if (previous) return glm::toMat4(prevRotation); else return glm::toMat4(rotation); } glm::mat4 Transform::getParentToLocalTranslationMatrix(bool previous) { - if ((previous) && (useRelativeMotionBlur)) return glm::translate(glm::mat4(1.0), -(position - linearMotion)); + if ((previous) && (useRelativeLinearMotionBlur)) return glm::translate(glm::mat4(1.0), -(position - linearMotion)); else if (previous) return glm::translate(glm::mat4(1.0), -prevPosition); else return glm::translate(glm::mat4(1.0), -position); } glm::mat4 Transform::getParentToLocalScaleMatrix(bool previous) { - if ((previous) && (useRelativeMotionBlur)) return glm::scale(glm::mat4(1.0), glm::vec3(1.0 / (scale - scalarMotion).x, 1.0 / (scale - scalarMotion).y, 1.0 / (scale - scalarMotion).z)); + if ((previous) && (useRelativeScalarMotionBlur)) return glm::scale(glm::mat4(1.0), glm::vec3(1.0 / (scale - scalarMotion).x, 1.0 / (scale - scalarMotion).y, 1.0 / (scale - scalarMotion).z)); else if (previous) return glm::scale(glm::mat4(1.0), glm::vec3(1.0 / prevScale.x, 1.0 / prevScale.y, 1.0 / prevScale.z)); else return glm::scale(glm::mat4(1.0), glm::vec3(1.0 / scale.x, 1.0 / scale.y, 1.0 / scale.z)); } glm::mat4 Transform::getParentToLocalRotationMatrix(bool previous) { - if ((previous) && (useRelativeMotionBlur)) return glm::toMat4(glm::inverse(angularMotion * rotation)); + if ((previous) && (useRelativeAngularMotionBlur)) return glm::toMat4(glm::inverse(angularMotion * rotation)); else if (previous) return glm::toMat4(glm::inverse(prevRotation)); else return glm::toMat4(glm::inverse(rotation)); } From 1ec574e66088687699426b1d00141c5d8261490e Mon Sep 17 00:00:00 2001 From: Jonathan Tremblay Date: Mon, 3 Aug 2020 10:52:56 -0700 Subject: [PATCH 25/25] running all the examples --- examples/99.run_all.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 examples/99.run_all.py diff --git a/examples/99.run_all.py b/examples/99.run_all.py new file mode 100644 index 00000000..09ab6825 --- /dev/null +++ b/examples/99.run_all.py @@ -0,0 +1,42 @@ +import os +import glob +import shutil +import argparse +import subprocess + +parser = argparse.ArgumentParser() +parser.add_argument('--outf', + default='all_examples', + help = 'folder to output the examples') +opt = parser.parse_args() + +if os.path.isdir(opt.outf): + print(f'folder {opt.outf}/ exists') +else: + os.mkdir(opt.outf) + print(f'created folder {opt.outf}/') + + +for test in sorted(glob.glob("*.py")): + if test == '99.run_all.py' or\ + test == '00.helloworld.py' or\ + test == '15.camera_control.py': + continue + # + print(f'running {test}') + subprocess.call( + [ + "python",test + ] + ) + if "pybullet" in test: + shutil.move('output.mp4',f'{opt.outf}/{test.replace(".py",".mp4")}') + else: + if os.path.exists('tmp.png'): + shutil.move('tmp.png',f'{opt.outf}/{test.replace(".py",".png")}') + if os.path.exists('tmp.hdr'): + shutil.move('tmp.hdr',f'{opt.outf}/{test.replace(".py",".hdr")}') + if os.path.exists('metadata/'): + shutil.move('metadata/',f'{opt.outf}/{test.replace(".py","/")}') + + # break \ No newline at end of file