diff --git a/devices/rtx/device/gpu/gpu_objects.h b/devices/rtx/device/gpu/gpu_objects.h index 21e7c5d85..c8946325e 100644 --- a/devices/rtx/device/gpu/gpu_objects.h +++ b/devices/rtx/device/gpu/gpu_objects.h @@ -612,9 +612,8 @@ struct InstanceVolumeGPUData struct InstanceLightGPUData { - const DeviceObjectIndex *indices; - size_t numLights; - mat4 xfm; + DeviceObjectIndex lightIndex; // Index into registry.lights[] + mat4 xfm; // Transform for this light instance }; // World // @@ -632,7 +631,8 @@ struct WorldGPUData const InstanceLightGPUData *lightInstances; size_t numLightInstances; - DeviceObjectIndex hdri; + const InstanceLightGPUData *hdriLightInstances; + size_t numHdriLightInstances; }; // Renderer // diff --git a/devices/rtx/device/gpu/gpu_util.h b/devices/rtx/device/gpu/gpu_util.h index aaef86abb..2f039d028 100644 --- a/devices/rtx/device/gpu/gpu_util.h +++ b/devices/rtx/device/gpu/gpu_util.h @@ -304,12 +304,28 @@ VISRTX_DEVICE vec4 getBackgroundImage( VISRTX_DEVICE vec4 getBackground( const FrameGPUData &fd, const vec2 &loc, const vec3 &rayDir) { - const LightGPUData *hdri = - fd.world.hdri != -1 ? &fd.registry.lights[fd.world.hdri] : nullptr; - if (hdri && hdri->hdri.visible) - return vec4(sampleHDRI(*hdri, rayDir), 1.f); - else - return getBackgroundImage(fd.renderer, loc); + // Accumulate contributions from all visible HDRI lights + vec3 hdriContribution = vec3(0.f); + bool hasVisibleHDRI = false; + + for (size_t i = 0; i < fd.world.numHdriLightInstances; i++) { + const auto &hdriLight = fd.world.hdriLightInstances[i]; + const auto &light = fd.registry.lights[hdriLight.lightIndex]; + if (light.hdri.visible) { + // Transform ray direction from world space to HDRI local space + // For orthonormal matrices, inverse = transpose + const mat3 xfmInv = glm::transpose(mat3(hdriLight.xfm)); + const vec3 localRayDir = xfmInv * rayDir; + hdriContribution += sampleHDRI(light, localRayDir); + hasVisibleHDRI = true; + } + } + + if (hasVisibleHDRI) + return vec4(hdriContribution, 1.f); + + // No visible HDRI, use background image/color + return getBackgroundImage(fd.renderer, loc); } VISRTX_DEVICE uint32_t computeGeometryPrimId(const SurfaceHit &hit) diff --git a/devices/rtx/device/gpu/renderer/raygen_helpers.h b/devices/rtx/device/gpu/renderer/raygen_helpers.h index 0d00bddf6..d4d5a2d12 100644 --- a/devices/rtx/device/gpu/renderer/raygen_helpers.h +++ b/devices/rtx/device/gpu/renderer/raygen_helpers.h @@ -35,6 +35,7 @@ #include "gpu/intersectRay.h" #include "gpu/renderer/common.h" #include "gpu/shadingState.h" +#include "gpu/volumeIntegration.h" // Shared helper functions for ray generation across renderers diff --git a/devices/rtx/device/material/shaders/MDLShader_ptx.cu b/devices/rtx/device/material/shaders/MDLShader_ptx.cu index b812e320b..cef1e7083 100644 --- a/devices/rtx/device/material/shaders/MDLShader_ptx.cu +++ b/devices/rtx/device/material/shaders/MDLShader_ptx.cu @@ -273,7 +273,8 @@ vec3 __direct_callable__evaluateTransmission( const MDLShadingState *shadingState) { return mdlTransmission( - &shadingState->state, &shadingState->resData, shadingState->argBlock); + &shadingState->state, &shadingState->resData, shadingState->argBlock) + * 0.85f; } VISRTX_CALLABLE diff --git a/devices/rtx/device/renderer/DirectLight_ptx.cu b/devices/rtx/device/renderer/DirectLight_ptx.cu index 32c3196c4..d52b0b9a6 100644 --- a/devices/rtx/device/renderer/DirectLight_ptx.cu +++ b/devices/rtx/device/renderer/DirectLight_ptx.cu @@ -39,11 +39,11 @@ #include "gpu/gpu_math.h" #include "gpu/gpu_objects.h" #include "gpu/intersectRay.h" +#include "gpu/renderer/common.h" +#include "gpu/renderer/raygen_helpers.h" #include "gpu/sampleLight.h" #include "gpu/shadingState.h" #include "gpu/shading_api.h" -#include "gpu/renderer/common.h" -#include "gpu/renderer/raygen_helpers.h" namespace visrtx { @@ -53,43 +53,41 @@ DECLARE_FRAME_DATA(frameData) struct DirectLightShadingPolicy { - static VISRTX_DEVICE vec4 shadeSurface(const MaterialShadingState &shadingState, - ScreenSample &ss, - const Ray &ray, - const SurfaceHit &hit) -{ - const auto &rendererParams = frameData.renderer; - const auto &directLightParams = rendererParams.params.directLight; - - auto &world = frameData.world; - - // Compute ambient light contribution // - const float aoFactor = directLightParams.aoSamples > 0 - ? computeAO(ss, - ray, - hit, - rendererParams.occlusionDistance, - directLightParams.aoSamples, - &surfaceAttenuation) - : 1.f; - - vec3 contrib = materialEvaluateEmission(shadingState, -ray.dir); - - // Handle ambient light contribution - if (rendererParams.ambientIntensity > 0.0f) { - contrib += rendererParams.ambientColor * rendererParams.ambientIntensity - * materialEvaluateTint(shadingState); - } - - // Handle all lights contributions - for (size_t i = 0; i < world.numLightInstances; i++) { - auto *inst = world.lightInstances + i; - if (!inst) - continue; + static VISRTX_DEVICE vec4 shadeSurface( + const MaterialShadingState &shadingState, + ScreenSample &ss, + const Ray &ray, + const SurfaceHit &hit) + { + const auto &rendererParams = frameData.renderer; + const auto &directLightParams = rendererParams.params.directLight; + + auto &world = frameData.world; + + // Compute ambient light contribution // + const float aoFactor = directLightParams.aoSamples > 0 + ? computeAO(ss, + ray, + hit, + rendererParams.occlusionDistance, + directLightParams.aoSamples, + &surfaceAttenuation) + : 1.f; + + vec3 contrib = materialEvaluateEmission(shadingState, -ray.dir); + + // Handle ambient light contribution + if (rendererParams.ambientIntensity > 0.0f) { + contrib += rendererParams.ambientColor * rendererParams.ambientIntensity + * materialEvaluateTint(shadingState); + } - for (size_t l = 0; l < inst->numLights; l++) { + // Handle all lights contributions + for (size_t i = 0; i < world.numLightInstances; i++) { + const auto &light = world.lightInstances[i]; const auto lightSample = - sampleLight(ss, hit, inst->indices[l], inst->xfm); + sampleLight(ss, hit, light.lightIndex, light.xfm); + if (lightSample.pdf == 0.0f) continue; @@ -114,50 +112,49 @@ struct DirectLightShadingPolicy contrib += thisLightContrib * attenuation; } - } - // Take AO in account - contrib *= aoFactor; - - // Then proceed with single bounce ray for indirect lighting - SurfaceHit bounceHit = hit; - NextRay nextRay = materialNextRay(shadingState, ray, ss.rs); - if (glm::any(glm::greaterThan( - nextRay.contributionWeight, glm::vec3(MIN_CONTRIBUTION_EPSILON)))) { - Ray bounceRay = { - bounceHit.hitpoint - + bounceHit.Ng - * std::copysignf( - bounceHit.epsilon, dot(bounceHit.Ns, nextRay.direction)), - nextRay.direction, - }; - - // Only check for intersecting surfaces and background as secondary light - // interactions - bounceHit.foundHit = false; - intersectSurface(ss, bounceRay, RayType::PRIMARY, &bounceHit); - - if (bounceHit.foundHit) { - // We hit something. Gather its contribution, cosine weighted diffuse - // only, we want this to be lightweight. - MaterialShadingState bounceShadingState; - materialInitShading( - &bounceShadingState, frameData, *bounceHit.material, bounceHit); - - auto sampleDir = randomDir(ss.rs, bounceHit.Ns); - auto cosineT = dot(bounceHit.Ns, sampleDir); - auto color = materialEvaluateTint(bounceShadingState) * cosineT; - contrib += color * nextRay.contributionWeight; - } else { - // No hit, get background contribution directly (no surface to weight - // against) - const auto color = getBackground(frameData, ss.screen, bounceRay.dir); - contrib += vec3(color) * nextRay.contributionWeight; + // Take AO in account + contrib *= aoFactor; + + // Then proceed with single bounce ray for indirect lighting + SurfaceHit bounceHit = hit; + NextRay nextRay = materialNextRay(shadingState, ray, ss.rs); + if (glm::any(glm::greaterThan( + nextRay.contributionWeight, glm::vec3(MIN_CONTRIBUTION_EPSILON)))) { + Ray bounceRay = { + bounceHit.hitpoint + + bounceHit.Ng + * std::copysignf( + bounceHit.epsilon, dot(bounceHit.Ns, nextRay.direction)), + normalize(nextRay.direction), + }; + + // Only check for intersecting surfaces and background as secondary light + // interactions + bounceHit.foundHit = false; + intersectSurface(ss, bounceRay, RayType::PRIMARY, &bounceHit); + + if (bounceHit.foundHit) { + // We hit something. Gather its contribution, cosine weighted diffuse + // only, we want this to be lightweight. + MaterialShadingState bounceShadingState; + materialInitShading( + &bounceShadingState, frameData, *bounceHit.material, bounceHit); + + auto sampleDir = randomDir(ss.rs, bounceHit.Ns); + auto cosineT = dot(bounceHit.Ns, sampleDir); + auto color = materialEvaluateTint(bounceShadingState) * cosineT; + contrib += color * nextRay.contributionWeight; + } else { + // No hit, get background contribution directly (no surface to weight + // against) + const auto color = getBackground(frameData, ss.screen, bounceRay.dir); + contrib += vec3(color) * nextRay.contributionWeight; + } } - } - float opacity = evaluateOpacity(shadingState); - return vec4(contrib, opacity); + float opacity = evaluateOpacity(shadingState); + return vec4(contrib, opacity); } }; diff --git a/devices/rtx/device/visrtx_device.json b/devices/rtx/device/visrtx_device.json index 1847661a4..fdbf7d687 100644 --- a/devices/rtx/device/visrtx_device.json +++ b/devices/rtx/device/visrtx_device.json @@ -63,7 +63,9 @@ "parameters": [ { "name": "sampleLimit", - "types": ["ANARI_INT32"], + "types": [ + "ANARI_INT32" + ], "tags": [], "default": 128, "minimum": 0, @@ -71,50 +73,68 @@ }, { "name": "denoise", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "enable the OptiX denoiser" }, { "name": "denoiseMode", - "types": ["ANARI_STRING"], + "types": [ + "ANARI_STRING" + ], "tags": [], "default": "color", - "values": ["color", "colorAlbedo", "colorAlbedoNormal"], + "values": [ + "color", + "colorAlbedo", + "colorAlbedoNormal" + ], "description": "mode controlling buffers given to the denoiser" }, { "name": "tonemap", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": true, "description": "enable internal tonemapping during sample accumulation" }, { "name": "premultiplyBackground", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "pre-multiply alpha channel with background color" }, { "name": "cullTriangleBackfaces", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "enable triangle back face culling" }, { "name": "checkerboarding", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "use checkerboarding to lower frame latency" }, { "name": "pixelSamples", - "types": ["ANARI_INT32"], + "types": [ + "ANARI_INT32" + ], "tags": [], "default": 1, "minimum": 1, @@ -122,7 +142,9 @@ }, { "name": "maxRayDepth", - "types": ["ANARI_INT32"], + "types": [ + "ANARI_INT32" + ], "tags": [], "default": 5, "minimum": 1, @@ -130,7 +152,9 @@ }, { "name": "ambientSamples", - "types": ["ANARI_INT32"], + "types": [ + "ANARI_INT32" + ], "tags": [], "default": 1, "minimum": 0, @@ -138,7 +162,9 @@ }, { "name": "ambientOcclusionDistance", - "types": ["ANARI_FLOAT32"], + "types": [ + "ANARI_FLOAT32" + ], "tags": [], "default": 1e20, "minimum": 0, @@ -146,7 +172,9 @@ }, { "name": "lightFalloff", - "types": ["ANARI_FLOAT32"], + "types": [ + "ANARI_FLOAT32" + ], "tags": [], "default": 1.0, "minimum": 0.0, @@ -155,7 +183,9 @@ }, { "name": "volumeSamplingRate", - "types": ["ANARI_FLOAT32"], + "types": [ + "ANARI_FLOAT32" + ], "tags": [], "default": 0.125, "minimum": 0.001, @@ -164,7 +194,9 @@ }, { "name": "volumeSamplingRateShadows", - "types": ["ANARI_FLOAT32"], + "types": [ + "ANARI_FLOAT32" + ], "tags": [], "default": 0.0125, "minimum": 0.0001, @@ -179,7 +211,9 @@ "parameters": [ { "name": "sampleLimit", - "types": ["ANARI_INT32"], + "types": [ + "ANARI_INT32" + ], "tags": [], "default": 128, "minimum": 0, @@ -187,56 +221,68 @@ }, { "name": "denoise", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "enable the OptiX denoiser" }, { - "name": "denoiseAlbedo", - "types": ["ANARI_BOOL"], - "tags": [], - "default": false, - "description": "enable albedo use by the OptiX denoiser" - }, - { - "name": "denoiseNormal", - "types": ["ANARI_BOOL"], + "name": "denoiseMode", + "types": [ + "ANARI_STRING" + ], "tags": [], - "default": false, - "description": "enable normal use by the OptiX denoiser" + "default": "color", + "values": [ + "color", + "colorAlbedo", + "colorAlbedoNormal" + ], + "description": "mode controlling buffers given to the denoiser" }, { "name": "tonemap", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": true, "description": "enable internal tonemapping during sample accumulation" }, { "name": "premultiplyBackground", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "pre-multiply alpha channel with background color" }, { "name": "cullTriangleBackfaces", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "enable triangle back face culling" }, { "name": "checkerboarding", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "use checkerboarding to lower frame latency" }, { "name": "pixelSamples", - "types": ["ANARI_INT32"], + "types": [ + "ANARI_INT32" + ], "tags": [], "default": 1, "minimum": 1, @@ -244,7 +290,9 @@ }, { "name": "ambientSamples", - "types": ["ANARI_INT32"], + "types": [ + "ANARI_INT32" + ], "tags": [], "default": 1, "minimum": 0, @@ -252,7 +300,9 @@ }, { "name": "ambientOcclusionDistance", - "types": ["ANARI_FLOAT32"], + "types": [ + "ANARI_FLOAT32" + ], "tags": [], "default": 1e20, "minimum": 0, @@ -260,7 +310,9 @@ }, { "name": "volumeSamplingRate", - "types": ["ANARI_FLOAT32"], + "types": [ + "ANARI_FLOAT32" + ], "tags": [], "default": 0.125, "minimum": 0.001, @@ -275,7 +327,9 @@ "parameters": [ { "name": "sampleLimit", - "types": ["ANARI_INT32"], + "types": [ + "ANARI_INT32" + ], "tags": [], "default": 128, "minimum": 0, @@ -283,53 +337,73 @@ }, { "name": "denoise", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "enable the OptiX denoiser" }, { - "name": "denoiseAlbedo", - "types": ["ANARI_BOOL"], - "tags": [], - "default": false, - "description": "enable albedo use by the OptiX denoiser" - }, - { - "name": "denoiseNormal", - "types": ["ANARI_BOOL"], + "name": "denoiseMode", + "types": [ + "ANARI_STRING" + ], "tags": [], - "default": false, - "description": "enable normal use by the OptiX denoiser" + "default": "color", + "values": [ + "color", + "colorAlbedo", + "colorAlbedoNormal" + ], + "description": "mode controlling buffers given to the denoiser" }, { "name": "tonemap", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": true, "description": "enable internal tonemapping during sample accumulation" }, { "name": "cullTriangleBackfaces", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "enable triangle back face culling" }, { "name": "checkerboarding", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "use checkerboarding to lower frame latency" }, { "name": "pixelSamples", - "types": ["ANARI_INT32"], + "types": [ + "ANARI_INT32" + ], "tags": [], "default": 1, "minimum": 1, "description": "samples per-pixel" + }, + { + "name": "maxRayDepth", + "types": [ + "ANARI_INT32" + ], + "tags": [], + "default": 3, + "minimum": 1, + "description": "Maximum number of ray bounces" } ] }, @@ -339,28 +413,36 @@ "parameters": [ { "name": "cullTriangleBackfaces", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "enable triangle back face culling" }, { "name": "tonemap", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": true, "description": "enable internal tonemapping during sample accumulation" }, { "name": "premultiplyBackground", - "types": ["ANARI_BOOL"], + "types": [ + "ANARI_BOOL" + ], "tags": [], "default": false, "description": "pre-multiply alpha channel with background color" }, { "name": "volumeSamplingRate", - "types": ["ANARI_FLOAT32"], + "types": [ + "ANARI_FLOAT32" + ], "tags": [], "default": 0.125, "minimum": 0.001, @@ -375,7 +457,9 @@ "parameters": [ { "name": "method", - "types": ["ANARI_STRING"], + "types": [ + "ANARI_STRING" + ], "tags": [], "default": "primIndex", "values": [ diff --git a/devices/rtx/device/world/Group.cpp b/devices/rtx/device/world/Group.cpp index 0f56e27b6..ed2a54526 100644 --- a/devices/rtx/device/world/Group.cpp +++ b/devices/rtx/device/world/Group.cpp @@ -186,6 +186,11 @@ DeviceObjectIndex Group::firstHDRI() const return m_firstHDRI; } +const std::vector &Group::lights() const +{ + return m_lights; +} + void Group::rebuildSurfaceBVHs() { const auto &state = *deviceState(); diff --git a/devices/rtx/device/world/Group.h b/devices/rtx/device/world/Group.h index 8ce2f42d7..5be8474cd 100644 --- a/devices/rtx/device/world/Group.h +++ b/devices/rtx/device/world/Group.h @@ -72,6 +72,7 @@ struct Group : public Object Span lightGPUIndices() const; DeviceObjectIndex firstHDRI() const; + const std::vector &lights() const; void rebuildSurfaceBVHs(); void rebuildVolumeBVH(); diff --git a/devices/rtx/device/world/World.cpp b/devices/rtx/device/world/World.cpp index 7ca45d42e..90c70ef89 100644 --- a/devices/rtx/device/world/World.cpp +++ b/devices/rtx/device/world/World.cpp @@ -193,7 +193,8 @@ WorldGPUData World::gpuData() const retval.lightInstances = m_instanceLightGPUData.dataDevice(); retval.numLightInstances = m_instanceLightGPUData.size(); - retval.hdri = m_hdri; + retval.hdriLightInstances = m_instanceHdriLightGPUData.dataDevice(); + retval.numHdriLightInstances = m_instanceHdriLightGPUData.size(); return retval; } @@ -456,28 +457,63 @@ void World::buildInstanceVolumeGPUData() void World::buildInstanceLightGPUData() { - m_instanceLightGPUData.resize(m_numLightInstances); + // Calculate total lights + size_t totalLights = 0; + size_t totalHdriLights = 0; - m_hdri = -1; + std::for_each(m_instances.begin(), m_instances.end(), [&](auto *inst) { + auto *group = inst->group(); + if (!group->containsLights()) + return; + + group->rebuildLights(); + const auto &lights = group->lights(); + const size_t numTransforms = inst->numTransforms(); + const DeviceObjectIndex hdriIdx = group->firstHDRI(); + + totalLights += lights.size() * numTransforms; + + // Count HDRI lights separately + for (auto *light : lights) { + if (light->isHDRI()) + totalHdriLights += numTransforms; + } + }); + + // Allocate both arrays + m_instanceLightGPUData.resize(totalLights); + m_instanceHdriLightGPUData.resize(totalHdriLights); + + size_t lightIndex = 0; + size_t hdriIndex = 0; - int instID = 0; std::for_each(m_instances.begin(), m_instances.end(), [&](auto *inst) { auto *group = inst->group(); - auto *li = m_instanceLightGPUData.dataHost(); if (!group->containsLights()) return; group->rebuildLights(); - const auto lgi = group->lightGPUIndices(); - if (m_hdri == -1) - m_hdri = group->firstHDRI(); + auto *lights = m_instanceLightGPUData.dataHost(); + auto *hdris = m_instanceHdriLightGPUData.dataHost(); + + for (size_t t = 0; t < inst->numTransforms(); t++) { + const mat4 xfm = mat4(inst->xfm(t)); + + for (auto *light : group->lights()) { + const auto lightIdx = light->index(); + + lights[lightIndex++] = {lightIdx, xfm}; - for (size_t t = 0; t < inst->numTransforms(); t++) - li[instID++] = {lgi.data(), lgi.size(), mat4(inst->xfm(t))}; + // HDRI lights also go into hdriLights + if (light->isHDRI()) + hdris[hdriIndex++] = {lightIdx, xfm}; + } + } }); m_instanceLightGPUData.upload(); + m_instanceHdriLightGPUData.upload(); } } // namespace visrtx diff --git a/devices/rtx/device/world/World.h b/devices/rtx/device/world/World.h index 483a705ab..36e5eda71 100644 --- a/devices/rtx/device/world/World.h +++ b/devices/rtx/device/world/World.h @@ -111,7 +111,7 @@ struct World : public Object // Lights // HostDeviceArray m_instanceLightGPUData; - DeviceObjectIndex m_hdri{-1}; + HostDeviceArray m_instanceHdriLightGPUData; }; } // namespace visrtx diff --git a/devices/rtx/libmdl/Core.cpp b/devices/rtx/libmdl/Core.cpp index c796cd9b1..f8d990a6b 100644 --- a/devices/rtx/libmdl/Core.cpp +++ b/devices/rtx/libmdl/Core.cpp @@ -243,38 +243,40 @@ void Core::addBuiltinModule( nonstd::scope_exit finalizeTransaction( [transaction]() { transaction->commit(); }); - auto result = impexpApi->load_module_from_string( - transaction.get(), - std::string(moduleName).c_str(), - std::string(moduleSource).c_str(), - executionContext.get() - ); + auto result = impexpApi->load_module_from_string(transaction.get(), + std::string(moduleName).c_str(), + std::string(moduleSource).c_str(), + executionContext.get()); switch (result) { - case 0: { - logMessage(mi::base::MESSAGE_SEVERITY_INFO, - "Added builtin module {} from source", moduleName); - break; - } - case 1: { - logMessage(mi::base::MESSAGE_SEVERITY_INFO, - "Builtin module {} already exists", - moduleName); - break; - } - case -1: - logMessage(mi::base::MESSAGE_SEVERITY_ERROR, - "Invalid name {} or module source for builtin", moduleName); - break; - case -2: - logMessage(mi::base::MESSAGE_SEVERITY_WARNING, - "Ignoring builtin {} would shadow a file based definition", moduleName); - break; - default: - logMessage(mi::base::MESSAGE_SEVERITY_ERROR, - "Unknown error while adding builtin module {}", moduleName); - logExecutionContextMessages(executionContext.get()); - break; + case 0: { + logMessage(mi::base::MESSAGE_SEVERITY_INFO, + "Added builtin module {} from source", + moduleName); + break; + } + case 1: { + logMessage(mi::base::MESSAGE_SEVERITY_INFO, + "Builtin module {} already exists", + moduleName); + break; + } + case -1: + logMessage(mi::base::MESSAGE_SEVERITY_ERROR, + "Invalid name {} or module source for builtin", + moduleName); + break; + case -2: + logMessage(mi::base::MESSAGE_SEVERITY_WARNING, + "Ignoring builtin {} would shadow a file based definition", + moduleName); + break; + default: + logMessage(mi::base::MESSAGE_SEVERITY_ERROR, + "Unknown error while adding builtin module {}", + moduleName); + logExecutionContextMessages(executionContext.get()); + break; } } @@ -288,9 +290,10 @@ const mi::neuraylib::IModule *Core::loadModule( // If that fails, try and resolve it as a file name. // First considering the module name from the MDL file name. - if (auto name = make_handle(impexpApi->get_mdl_module_name(moduleName.c_str())); + if (auto name = + make_handle(impexpApi->get_mdl_module_name(moduleName.c_str())); name.is_valid_interface()) { - moduleName = name->get_c_str(); + moduleName = name->get_c_str(); } else { // Check if this is a single MDL name, such as OmniPBR.mdl and // resolve it to its equivalent module name, such as ::OmniPBR. @@ -304,7 +307,6 @@ const mi::neuraylib::IModule *Core::loadModule( } } - if (moduleName.empty()) { logMessage(mi::base::MESSAGE_SEVERITY_ERROR, "Cannot resolve module name from {}", @@ -388,14 +390,14 @@ mi::neuraylib::ICompiled_material *Core::getCompiledMaterial( return compiledMaterial; } -mi::neuraylib::ICompiled_material *Core::getDistilledToTransmissivePBR( +mi::neuraylib::ICompiled_material *Core::getDistilledToDiffuse( const mi::neuraylib::ICompiled_material *compiledMaterial) { auto distiller_api = make_handle( m_neuray->get_api_component()); mi::Sint32 result = 0; auto distilledMaterial = distiller_api->distill_material( - compiledMaterial, "transmissive_pbr", nullptr, &result); + compiledMaterial, "diffuse", nullptr, &result); if (result != 0) { logMessage(mi::base::MESSAGE_SEVERITY_ERROR, "Failed to distill material: %i\n", @@ -417,8 +419,7 @@ const mi::neuraylib::ITarget_code *Core::getPtxTargetCode( auto executionContext = make_handle(m_mdlFactory->clone(m_executionContext.get())); - auto distilledMaterial = - make_handle(getDistilledToTransmissivePBR(compiledMaterial)); + auto distilledMaterial = make_handle(getDistilledToDiffuse(compiledMaterial)); // ANARI attributes 0 to 3 const int numTextureSpaces = 4; @@ -450,66 +451,44 @@ const mi::neuraylib::ITarget_code *Core::getPtxTargetCode( {"surface.emission.emission", "mdlEmission"}, {"surface.emission.intensity", "mdlEmissionIntensity"}, {"surface.emission.mode", "mdlEmissionMode"}, + + {"volume.scattering_coefficient", "mdlTransmission"}, + + {"geometry.cutout_opacity", "mdlOpacity"}, }; - // Special case for tint, transmission and opacity. - // For some renderers, we want to be able to access these directly to - // compute some simplified light propagation. - // run something like: - // mdl_distiller_cli -class -tmm -m transmissive_pbr -o - -p - // /path/to/materials/folder ::My::Material - // to get a description of a transmissive pbr material. - static mi::neuraylib::Target_function_description - distilledTransmissivePBRMaterialFunctions[][3] = { - // Generic version for transmissive_pbr - { - {"surface.scattering.base.layer.tint", "mdlTint"}, - {"volume.scattering_coefficient", "mdlTransmission"}, - {"geometry.cutout_opacity", "mdlOpacity"}, - }, - - // Simplified version where tint is rooted directly under scattering. - { - {"surface.scattering.layer.tint", "mdlTint"}, - {"volume.scattering_coefficient", "mdlTransmission"}, - {"geometry.cutout_opacity", "mdlOpacity"}, - }, - // Simplified version where tint is rooted directly under scattering. - { - {"surface.scattering.tint", "mdlTint"}, - {"volume.scattering_coefficient", "mdlTransmission"}, - {"geometry.cutout_opacity", "mdlOpacity"}, - } - - }; + static mi::neuraylib::Target_function_description distilledFunctions[] = { + {"surface.scattering.tint", "mdlTint"}, + }; // Generate target code for the compiled material - for (auto &distilledMaterialFunctions : - distilledTransmissivePBRMaterialFunctions) { - auto linkUnit = make_handle( - ptxBackend->create_link_unit(transaction, executionContext.get())); - linkUnit->add_material(compiledMaterial, - std::data(materialFunctions), - std::size(materialFunctions), - executionContext.get()); - - linkUnit->add_material(distilledMaterial.get(), - std::data(distilledMaterialFunctions), - std::size(distilledMaterialFunctions), - executionContext.get()); - - if (!logExecutionContextMessages(executionContext.get())) - continue; - - auto targetCode = - ptxBackend->translate_link_unit(linkUnit.get(), executionContext.get()); - if (!logExecutionContextMessages(executionContext.get())) - continue; - - return targetCode; - } + auto linkUnit = make_handle( + ptxBackend->create_link_unit(transaction, executionContext.get())); + + // Add main material functions (BSDF, emission, and auxiliary + // albedo/normal/roughness) + linkUnit->add_material(compiledMaterial, + std::data(materialFunctions), + std::size(materialFunctions), + executionContext.get()); - return {}; + if (!logExecutionContextMessages(executionContext.get())) + return {}; + + linkUnit->add_material(distilledMaterial.get(), + std::data(distilledFunctions), + std::size(distilledFunctions), + executionContext.get()); + + if (!logExecutionContextMessages(executionContext.get())) + return {}; + + auto targetCode = + ptxBackend->translate_link_unit(linkUnit.get(), executionContext.get()); + if (!logExecutionContextMessages(executionContext.get())) + return {}; + + return targetCode; } bool Core::logExecutionContextMessages( @@ -616,7 +595,8 @@ auto Core::resolveModule(std::string_view moduleId) -> std::string return resolvedModule->get_module_name(); } else { logMessage(mi::base::MESSAGE_SEVERITY_WARNING, - "Failed to resolve module `{}` using entityResolver\n", moduleId); + "Failed to resolve module `{}` using entityResolver\n", + moduleId); } return {}; diff --git a/devices/rtx/libmdl/Core.h b/devices/rtx/libmdl/Core.h index 8318dfda4..d15f1ca4f 100644 --- a/devices/rtx/libmdl/Core.h +++ b/devices/rtx/libmdl/Core.h @@ -110,7 +110,7 @@ class Core mi::neuraylib::ICompiled_material *getCompiledMaterial( const mi::neuraylib::IFunction_definition *, bool classCompilation = true); - mi::neuraylib::ICompiled_material *getDistilledToTransmissivePBR( + mi::neuraylib::ICompiled_material *getDistilledToDiffuse( const mi::neuraylib::ICompiled_material *compiledMaterial); const mi::neuraylib::ITarget_code *getPtxTargetCode( diff --git a/devices/rtx/shaders/visrtx/physically_based.mdl b/devices/rtx/shaders/visrtx/physically_based.mdl index a67b6b471..97a943bf4 100644 --- a/devices/rtx/shaders/visrtx/physically_based.mdl +++ b/devices/rtx/shaders/visrtx/physically_based.mdl @@ -457,11 +457,16 @@ export material physically_based_material( ); // Sheen - bsdf dielectricSheenBsdf = ::df::sheen_bsdf( - tint: resolvedSheenColor, - roughness: resolvedSheenRoughness * resolvedSheenRoughness, - multiscatter_tint: color(1.0), - multiscatter: dielectricIridescenceBsdf, + float sheenWeight = ::math::max_value(resolvedSheenColor); + bsdf dielectricSheenBsdf = ::df::weighted_layer( + weight: sheenWeight, + base: dielectricIridescenceBsdf, + layer: ::df::sheen_bsdf( + tint: resolvedSheenColor, + roughness: resolvedSheenRoughness * resolvedSheenRoughness, + multiscatter_tint: color(1.0), + multiscatter: dielectricIridescenceBsdf, + ), ); // Onto the metallic layer @@ -510,6 +515,7 @@ export material physically_based_material( volume: material_volume( absorption_coefficient: resolvedThickness == 0.0f ? color(0.0f) : -math::log(resolvedAttenuationColor) / resolvedAttenuationDistance, + scattering_coefficient: resolvedBaseColor * resolvedTransmission, ), ior: color(ior), geometry: material_geometry( diff --git a/tsd/src/tsd/rendering/pipeline/passes/VisualizeAOVPass.cpp b/tsd/src/tsd/rendering/pipeline/passes/VisualizeAOVPass.cpp index 0bc62cb9b..b62aec317 100644 --- a/tsd/src/tsd/rendering/pipeline/passes/VisualizeAOVPass.cpp +++ b/tsd/src/tsd/rendering/pipeline/passes/VisualizeAOVPass.cpp @@ -76,7 +76,7 @@ void computeAlbedoImage(RenderBuffers &b, tsd::math::uint2 size) detail::parallel_for( b.stream, 0u, uint32_t(size.x * size.y), [=] DEVICE_FCN(uint32_t i) { const auto albedo = b.albedo ? b.albedo[i] : tsd::math::float3(0.f); - b.color[i] = helium::cvt_color_to_uint32({albedo, 1.f}); + b.color[i] = helium::cvt_color_to_uint32_srgb({albedo, 1.f}); }); }