diff --git a/com.unity.render-pipelines.high-definition/CHANGELOG.md b/com.unity.render-pipelines.high-definition/CHANGELOG.md index 432bf86a352..a68fd624b56 100644 --- a/com.unity.render-pipelines.high-definition/CHANGELOG.md +++ b/com.unity.render-pipelines.high-definition/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Added new panels to Rendering Debugger Display Stats panel, displaying improved CPU/GPU frame timings and bottlenecks. - Added API to edit diffusion profiles and set IES on lights. - Added public API to reset path tracing accumulation, and check its status. +- Added support for SensorSDK's Lidar and camera models in path tracing. ### Fixed - Fixed decal position when created from context menu. (case 1368987) diff --git a/com.unity.render-pipelines.high-definition/Editor/Material/BaseShaderPreprocessor.cs b/com.unity.render-pipelines.high-definition/Editor/Material/BaseShaderPreprocessor.cs index e320561bd3b..2c89fe8e0e9 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Material/BaseShaderPreprocessor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Material/BaseShaderPreprocessor.cs @@ -62,6 +62,11 @@ abstract class BaseShaderPreprocessor protected ShadowKeywords m_ShadowKeywords; +#if !ENABLE_SENSOR_SDK + protected ShaderKeyword m_SensorEnableLidar; + protected ShaderKeyword m_SensorOverrideReflectance; +#endif + protected Dictionary m_ShadowVariants; public virtual int Priority => 0; @@ -94,6 +99,11 @@ public BaseShaderPreprocessor() m_DecalSurfaceGradient = new ShaderKeyword("DECAL_SURFACE_GRADIENT"); m_EditorVisualization = new ShaderKeyword("EDITOR_VISUALIZATION"); m_ShadowKeywords = new ShadowKeywords(); + +#if !ENABLE_SENSOR_SDK + m_SensorEnableLidar = new ShaderKeyword("SENSORSDK_ENABLE_LIDAR"); + m_SensorOverrideReflectance = new ShaderKeyword("SENSORSDK_OVERRIDE_REFLECTANCE"); +#endif } public bool ShadersStripper(HDRenderPipelineAsset hdrpAsset, Shader shader, ShaderSnippetData snippet, diff --git a/com.unity.render-pipelines.high-definition/Editor/Material/Lit/LitShaderPreprocessor.cs b/com.unity.render-pipelines.high-definition/Editor/Material/Lit/LitShaderPreprocessor.cs index 719009abed3..87515a2c236 100644 --- a/com.unity.render-pipelines.high-definition/Editor/Material/Lit/LitShaderPreprocessor.cs +++ b/com.unity.render-pipelines.high-definition/Editor/Material/Lit/LitShaderPreprocessor.cs @@ -72,7 +72,7 @@ protected override bool DoShadersStripper(HDRenderPipelineAsset hdrpAsset, Shade } - // Apply following set of rules only to lit shader (remember that LitPreprocessor is call for any shader) + // Apply following set of rules only to lit shader (remember that LitPreprocessor is called for any shader) if (isBuiltInLit) { // Forward material don't use keyword for WriteNormalBuffer but #define so we can't test for the keyword outside of isBuiltInLit @@ -116,6 +116,12 @@ protected override bool DoShadersStripper(HDRenderPipelineAsset hdrpAsset, Shade } } +#if !ENABLE_SENSOR_SDK + // If the SensorSDK package is not present, make sure that all code related to it is stripped away + if (inputData.shaderKeywordSet.IsEnabled(m_SensorEnableLidar) || inputData.shaderKeywordSet.IsEnabled(m_SensorOverrideReflectance)) + return true; +#endif + // TODO: Tests for later // We need to find a way to strip useless shader features for passes/shader stages that don't need them (example, vertex shaders won't ever need SSS Feature flag) // This causes several problems: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader b/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader index 1b70118c6e7..d250bac5166 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader @@ -1197,6 +1197,11 @@ Shader "HDRP/Lit" #pragma raytracing surface_shader #pragma multi_compile _ DEBUG_DISPLAY + #pragma multi_compile _ SENSORSDK_OVERRIDE_REFLECTANCE + + #ifdef SENSORSDK_OVERRIDE_REFLECTANCE + #define SENSORSDK_ENABLE_LIDAR + #endif #define SHADERPASS SHADERPASS_PATH_TRACING diff --git a/com.unity.render-pipelines.high-definition/Runtime/PackageInfo.cs b/com.unity.render-pipelines.high-definition/Runtime/PackageInfo.cs index 1031875d4ef..0607761357c 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/PackageInfo.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/PackageInfo.cs @@ -5,3 +5,5 @@ [assembly: InternalsVisibleTo("Unity.GraphicTests.Performance.HDRP.Runtime")] [assembly: InternalsVisibleTo("Unity.GraphicTests.Performance.HDRP.Editor")] [assembly: InternalsVisibleTo("TestRuntime")] +[assembly: InternalsVisibleTo("Unity.SensorSDK.Runtime")] +[assembly: InternalsVisibleTo("Unity.SensorSDK.Editor")] diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs index d8239a9d87a..81f038c5860 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Camera/HDCamera.cs @@ -257,6 +257,11 @@ internal struct VolumetricCloudsAnimationData public float verticalErosionOffset; } +#if ENABLE_SENSOR_SDK + internal RayTracingShader pathTracingShaderOverride = null; + internal Action prepareDispatchRays = null; +#endif + internal Vector4[] frustumPlaneEquations; internal int taaFrameIndex; internal float taaSharpenStrength; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs index 7291a3f49e6..3a9ae0fd90c 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.PostProcess.cs @@ -127,7 +127,7 @@ public PostProcessTextureAllocator() Vignette m_Vignette; Tonemapping m_Tonemapping; WhiteBalance m_WhiteBalance; - ColorAdjustments m_ColorAdjustments; + internal ColorAdjustments m_ColorAdjustments; ChannelMixer m_ChannelMixer; SplitToning m_SplitToning; LiftGammaGain m_LiftGammaGain; @@ -3951,7 +3951,7 @@ void DispatchWithGuardBands(CommandBuffer cmd, ComputeShader shader, int kernelI #endregion #region Color Grading - class ColorGradingPassData + internal class ColorGradingPassData { public ComputeShader builderCS; public int builderKernel; @@ -3990,7 +3990,7 @@ class ColorGradingPassData public TextureHandle logLut; } - void PrepareColorGradingParameters(ColorGradingPassData passData) + internal void PrepareColorGradingParameters(ColorGradingPassData passData) { passData.tonemappingMode = m_TonemappingFS ? m_Tonemapping.mode.value : TonemappingMode.None; bool tonemappingIsActive = m_Tonemapping.IsActive() && m_TonemappingFS; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/PathTracing.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/PathTracing.cs index 5ba14611f88..040006ac12f 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/PathTracing.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/PathTracing.cs @@ -280,13 +280,22 @@ class RenderPathTracingData public TextureHandle output; public TextureHandle sky; + +#if ENABLE_SENSOR_SDK + public Action prepareDispatchRays; +#endif } TextureHandle RenderPathTracing(RenderGraph renderGraph, HDCamera hdCamera, in CameraData cameraData, TextureHandle pathTracingBuffer, TextureHandle skyBuffer) { using (var builder = renderGraph.AddRenderPass("Render PathTracing", out var passData)) { +#if ENABLE_SENSOR_SDK + passData.pathTracingShader = hdCamera.pathTracingShaderOverride ? hdCamera.pathTracingShaderOverride : m_GlobalSettings.renderPipelineRayTracingResources.pathTracing; + passData.prepareDispatchRays = hdCamera.prepareDispatchRays; +#else passData.pathTracingShader = m_GlobalSettings.renderPipelineRayTracingResources.pathTracing; +#endif passData.cameraData = cameraData; passData.ditheredTextureSet = GetBlueNoiseManager().DitheredTextureSet256SPP(); passData.backgroundColor = hdCamera.backgroundColorHDR; @@ -344,6 +353,10 @@ TextureHandle RenderPathTracing(RenderGraph renderGraph, HDCamera hdCamera, in C ctx.cmd.SetRayTracingVectorParam(data.pathTracingShader, HDShaderIDs._PathTracingDoFParameters, data.dofParameters); ctx.cmd.SetRayTracingVectorParam(data.pathTracingShader, HDShaderIDs._PathTracingTilingParameters, data.tilingParameters); +#if ENABLE_SENSOR_SDK + // SensorSDK can do its own camera rays generation + data.prepareDispatchRays?.Invoke(ctx.cmd); +#endif // Run the computation ctx.cmd.DispatchRays(data.pathTracingShader, "RayGen", (uint)data.width, (uint)data.height, 1); }); diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/SensorIntersection.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/SensorIntersection.hlsl new file mode 100644 index 00000000000..9d343bc0479 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/SensorIntersection.hlsl @@ -0,0 +1,37 @@ +#ifndef UNITY_SENSOR_INTERSECTION_INCLUDED +#define UNITY_SENSOR_INTERSECTION_INCLUDED + +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingIntersection.hlsl" + +// As we must keep the PathIntersection structure untouched (and at the very least of the same size), +// we alias some of its unused fields to store the sensors data. + +float3 GetBeamOrigin(PathIntersection payload) +{ + return payload.value; +} + +void SetBeamOrigin(inout PathIntersection payload, float3 beamOrigin) +{ + payload.value = beamOrigin; +} + +float3 GetBeamDirection(PathIntersection payload) +{ + return float3(payload.alpha, payload.cone.width, payload.cone.spreadAngle); +} + +void SetBeamDirection(inout PathIntersection payload, float3 beamDirection) +{ + payload.alpha = beamDirection.x; + payload.cone.width = beamDirection.y; + payload.cone.spreadAngle = beamDirection.z; +} + +void clearBeamData(inout PathIntersection payload) +{ + SetBeamOrigin(payload, 0.0); + SetBeamDirection(payload, 0.0); +} + +#endif // UNITY_SENSOR_INTERSECTION_INCLUDED diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/SensorIntersection.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/SensorIntersection.hlsl.meta new file mode 100644 index 00000000000..02f97ddf1c9 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/SensorIntersection.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: ca82d2604e3b1ea4d9680194e7b8ac00 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassPathTracing.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassPathTracing.hlsl index aff95f947a1..93ad0378343 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassPathTracing.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassPathTracing.hlsl @@ -1,3 +1,8 @@ +// SensorSDK support: in Lidar mode, an alternate computation is used, implemented in a separate file +#ifdef SENSORSDK_ENABLE_LIDAR +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassSensorLidar.hlsl" +#else + // Ray tracing includes #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingFragInputs.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Common/AtmosphericScatteringRayTracing.hlsl" @@ -384,3 +389,5 @@ void AnyHit(inout PathIntersection pathIntersection : SV_RayPayload, AttributeDa #endif } } + +#endif // SENSORSDK_ENABLE_LIDAR diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassSensorLidar.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassSensorLidar.hlsl new file mode 100644 index 00000000000..c40acbbcf50 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassSensorLidar.hlsl @@ -0,0 +1,176 @@ +// Ray tracing includes +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/RaytracingFragInputs.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/Shaders/Common/AtmosphericScatteringRayTracing.hlsl" + +// Path tracing includes +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/SensorIntersection.hlsl" +#ifdef HAS_LIGHTLOOP +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/PathTracing/Shaders/PathTracingLight.hlsl" +#endif + +int _SensorLightCount; + +#ifdef SENSORSDK_OVERRIDE_REFLECTANCE + +TEXTURE2D(_SensorCustomReflectance); +float Wavelength; + +float3 OverrideReflectance() +{ + const float minWaveLengthValue = 0.35; // 350 nm + const float maxWaveLengthValue = 2.5; // 2500 nm + + float wlIdx = clamp(Wavelength * 0.001, minWaveLengthValue, maxWaveLengthValue); + float wavelengthSpan = maxWaveLengthValue - minWaveLengthValue + 1.0; + float2 coordCurve = float2(wlIdx / wavelengthSpan, 0.0); + + return SAMPLE_TEXTURE2D(_SensorCustomReflectance, s_linear_clamp_sampler, coordCurve); +} + +#endif // SENSORSDK_OVERRIDE_REFLECTANCE + +bool SampleBeam(LightData lightData, + float3 lightPosition, + float3 lightDirection, + float3 position, + float3 normal, + out float3 outgoingDir, + out float3 value) +{ + const float MM_TO_M = 1e-3; + const float M_TO_MM = 1e3; + + outgoingDir = position - lightPosition; + float dist = length(outgoingDir); + outgoingDir /= dist; + + float apertureRadius = lightData.size.x; + float w0 = lightData.size.y; + float zr = lightData.size.z; + float distToWaist = lightData.size.w; + + // get the hit point in the coordinate frame of the laser as a depth(z) and + // radial measure(r) + float ctheta = dot(lightDirection, outgoingDir); + float zFromAperture = ctheta * dist; + float rSq = Sq(dist) - Sq(zFromAperture); + float3 radialDirection = dist * outgoingDir - zFromAperture*lightDirection; + + float zFromWaist = abs(zFromAperture * M_TO_MM - distToWaist); + if (dot(normal, -outgoingDir) < 0.001) + return false; + + // Total beam power, note: different from the output here which is irradiance. + float P = lightData.color.x; + + const float zRatio = Sq(zFromWaist / zr); + const float wz = w0 * sqrt(1 + zRatio) * MM_TO_M; + const float Eoz = 2 * P; + const float wzSq = wz*wz; + + float gaussianFactor = exp(-2 * rSq / wzSq) / (PI * wzSq); // 1/m^2 + value.x = gaussianFactor * Eoz; // W/m^2 + value.y = wz; // beamRadius + value.z = zFromAperture; // beamDepth + + // sampling a point in the "virtual" aperture + // Find the actual point in the beam aperture that corresponds to this point + float rRatio = apertureRadius / wz; + float3 pAperture = lightPosition + rRatio * radialDirection; // location of the point in the aperture + + outgoingDir = pAperture - position; // corrected outgoing vector using the assumption below + dist = length(outgoingDir); + outgoingDir /= dist; + + return value.x > 0.0; +} + +[shader("closesthit")] +void ClosestHit(inout PathIntersection pathIntersection : SV_RayPayload, AttributeData attributeData : SV_IntersectionAttributes) +{ + // Always set the new t value + pathIntersection.t = RayTCurrent(); + + // Then grab the intersection vertex + IntersectionVertex currentVertex; + GetCurrentIntersectionVertex(attributeData, currentVertex); + + // Build the Frag inputs from the intersection vertex + FragInputs fragInput; + BuildFragInputsFromIntersection(currentVertex, fragInput); + + // Such an invalid remainingDepth value means we are called from a subsurface computation + if (pathIntersection.remainingDepth > _RaytracingMaxRecursion) + { + pathIntersection.value = fragInput.tangentToWorld[2]; // Returns normal + return; + } + + // Fetch, then clear the beam data aliased in our payload + const float3 beamOrigin = GetBeamOrigin(pathIntersection); + const float3 beamDirection = GetBeamDirection(pathIntersection); + clearBeamData(pathIntersection); + + PositionInputs posInput; + posInput.positionWS = fragInput.positionRWS; + posInput.positionSS = pathIntersection.pixelCoord; + + // For path tracing, we want the front-facing test to be performed on the actual geometric normal + float3 geomNormal; + GetCurrentIntersectionGeometricNormal(attributeData, geomNormal); + fragInput.isFrontFace = dot(WorldRayDirection(), geomNormal) < 0.0; + + // Build the surfacedata and builtindata + SurfaceData surfaceData; + BuiltinData builtinData; + bool isVisible; + GetSurfaceAndBuiltinData(fragInput, -WorldRayDirection(), posInput, surfaceData, builtinData, currentVertex, pathIntersection.cone, isVisible); + + // Compute the bsdf data + BSDFData bsdfData = ConvertSurfaceDataToBSDFData(posInput.positionSS, surfaceData); + + #ifdef SENSORSDK_OVERRIDE_REFLECTANCE + // Override the diffuce color when using builtin lit shader (but not with shader graph) + bsdfData.diffuseColor = OverrideReflectance(); + #endif + + // Override the geometric normal (otherwise, it is merely the non-mapped smooth normal) + // Also make sure that it is in the same hemisphere as the shading normal (which may have been flipped) + bsdfData.geomNormalWS = dot(bsdfData.normalWS, geomNormal) > 0.0 ? geomNormal : -geomNormal; + + // Compute the world space position (the non-camera relative one if camera relative rendering is enabled) + float3 shadingPosition = fragInput.positionRWS; + + // Initialize our material data (this will alter the bsdfData to suit path tracing, and choose between BSDF or SSS evaluation) + MaterialData mtlData; + if (CreateMaterialData(pathIntersection, builtinData, bsdfData, shadingPosition, + GetSample(pathIntersection.pixelCoord, _RaytracingSampleIndex, 0), mtlData)) + { + #ifdef _SURFACE_TYPE_TRANSPARENT + float3 lightNormal = 0.0; + #else + float3 lightNormal = GetLightNormal(mtlData); + #endif + + float3 value, direction; + MaterialResult mtlResult; + + for (uint i = 0; i < _SensorLightCount; i++) + { + if (SampleBeam(_LightDatasRT[i], beamOrigin, beamDirection, shadingPosition, bsdfData.normalWS, direction, value)) + { + EvaluateMaterial(mtlData, direction, mtlResult); + + // value is in radian (w/sr) not in lumen (cd/sr), only on the red channel + value.x *= mtlResult.diffValue.x + mtlResult.specValue.x; + + pathIntersection.value.x += value.x; + } + } + + ApplyFogAttenuation(WorldRayOrigin(), WorldRayDirection(), pathIntersection.t, pathIntersection.value); + + // Copy the last beam radius and depth to the payload + pathIntersection.value.yz = value.yz; + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassSensorLidar.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassSensorLidar.hlsl.meta new file mode 100644 index 00000000000..7b6b258128a --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassSensorLidar.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4b6742cd49a19474897e03ea861b7208 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Unity.RenderPipelines.HighDefinition.Runtime.asmdef b/com.unity.render-pipelines.high-definition/Runtime/Unity.RenderPipelines.HighDefinition.Runtime.asmdef index a935c06773b..1a646a4edf3 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Unity.RenderPipelines.HighDefinition.Runtime.asmdef +++ b/com.unity.render-pipelines.high-definition/Runtime/Unity.RenderPipelines.HighDefinition.Runtime.asmdef @@ -50,6 +50,11 @@ "name": "com.unity.burst", "expression": "1.5.0", "define": "ENABLE_BURST_1_5_0_OR_NEWER" + }, + { + "name": "com.unity.sensorsdk", + "expression": "1.0.0", + "define": "ENABLE_SENSOR_SDK" } ], "noEngineReferences": false