From b7bb585f86585815839250bf1e4b6b6dcea07807 Mon Sep 17 00:00:00 2001 From: Christoph Neuhauser Date: Wed, 29 Nov 2023 14:45:26 +0100 Subject: [PATCH] Added initial support for isosurfaces. --- Data/Shaders/VPT/Clouds.glsl | 6 + Data/Shaders/VPT/DecompositionTracking.glsl | 5 - Data/Shaders/VPT/DeltaTracking.glsl | 151 +++++++++++--- Data/Shaders/VPT/NextEventTracking.glsl | 92 ++++---- Data/Shaders/VPT/RatioTracking.glsl | 8 - Data/Shaders/VPT/RayTracingUtilities.glsl | 28 +++ Data/Shaders/VPT/ResidualRatioTracking.glsl | 14 -- Data/Shaders/VPT/VptHeader.glsl | 8 + Data/Shaders/VPT/VptUtils.glsl | 197 ++++++++++++++---- LICENSE | 2 +- src/Main.cpp | 1 + src/PathTracer/VolumetricPathTracingPass.cpp | 103 ++++++++- src/PathTracer/VolumetricPathTracingPass.hpp | 33 +++ src/PyTorch/Module.cpp | 111 +++++++++- src/PyTorch/Module.hpp | 16 ++ .../VolumetricPathTracingModuleRenderer.cpp | 24 +++ .../VolumetricPathTracingModuleRenderer.hpp | 8 + 17 files changed, 662 insertions(+), 145 deletions(-) create mode 100644 Data/Shaders/VPT/RayTracingUtilities.glsl diff --git a/Data/Shaders/VPT/Clouds.glsl b/Data/Shaders/VPT/Clouds.glsl index 565072f..4e2b51a 100644 --- a/Data/Shaders/VPT/Clouds.glsl +++ b/Data/Shaders/VPT/Clouds.glsl @@ -26,6 +26,8 @@ #version 450 +//#extension GL_EXT_debug_printf : enable + #include "VptHeader.glsl" #ifdef USE_NANOVDB @@ -59,6 +61,10 @@ void pathTraceSample(int i, bool onlyFirstEvent, out ScatterEvent firstEvent){ vec3 x, w; createCameraRay(screenCoord, x, w); +#ifdef USE_NANOVDB + accessor = createAccessor(); +#endif + // Perform a single path and get radiance #ifdef COMPUTE_SCATTER_RAY_ABSORPTION_MOMENTS float scatterRayAbsorptionMoments[NUM_SCATTER_RAY_ABSORPTION_MOMENTS + 1]; diff --git a/Data/Shaders/VPT/DecompositionTracking.glsl b/Data/Shaders/VPT/DecompositionTracking.glsl index 177cfee..d88b1d4 100644 --- a/Data/Shaders/VPT/DecompositionTracking.glsl +++ b/Data/Shaders/VPT/DecompositionTracking.glsl @@ -35,10 +35,6 @@ vec3 analogDecompositionTracking(vec3 x, vec3 w, out ScatterEvent firstEvent) { firstEvent = ScatterEvent(false, x, 0.0, w, 0.0, 0.0, 0.0); -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor = createAccessor(); -#endif - const vec3 EPSILON_VEC = vec3(1e-6); float tMinVal, tMaxVal; if (rayBoxIntersect(parameters.boxMin + EPSILON_VEC, parameters.boxMax - EPSILON_VEC, x, w, tMinVal, tMaxVal)) { @@ -136,7 +132,6 @@ vec3 analogDecompositionTracking(vec3 x, vec3 w, out ScatterEvent firstEvent) { vec3 analogDecompositionTracking(vec3 x, vec3 w, out ScatterEvent firstEvent) { firstEvent = ScatterEvent(false, x, 0.0, w, 0.0, 0.0, 0.0); - pnanovdb_readaccessor_t accessor = createAccessor(); pnanovdb_buf_t buf = pnanovdb_buf_t(0); pnanovdb_grid_handle_t gridHandle = pnanovdb_grid_handle_t(pnanovdb_address_null()); diff --git a/Data/Shaders/VPT/DeltaTracking.glsl b/Data/Shaders/VPT/DeltaTracking.glsl index 62917f9..4ef0052 100644 --- a/Data/Shaders/VPT/DeltaTracking.glsl +++ b/Data/Shaders/VPT/DeltaTracking.glsl @@ -31,15 +31,15 @@ * ACM Trans. Graph., 36(4), Jul. 2017. */ vec3 deltaTrackingSpectral(vec3 x, vec3 w, out ScatterEvent firstEvent) { -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor = createAccessor(); -#endif - firstEvent = ScatterEvent(false, x, 0.0, w, 0.0, 0.0, 0.0); float majorant = maxComponent(parameters.extinction); vec3 weights = vec3(1, 1, 1); +#ifdef USE_ISOSURFACES + float lastScalarSign, currentScalarSign; + bool isFirstPoint = true; +#endif vec3 absorptionAlbedo = vec3(1, 1, 1) - parameters.scatteringAlbedo; vec3 scatteringAlbedo = parameters.scatteringAlbedo; @@ -57,23 +57,45 @@ vec3 deltaTrackingSpectral(vec3 x, vec3 w, out ScatterEvent firstEvent) { break; } - x += w * t; + vec3 xNew = x + w * t; #ifdef USE_TRANSFER_FUNCTION -#ifdef USE_NANOVDB - vec4 densityEmission = sampleCloudDensityEmission(accessor, x); -#else - vec4 densityEmission = sampleCloudDensityEmission(x); -#endif + vec4 densityEmission = sampleCloudDensityEmission(xNew); float density = densityEmission.a; #else -#ifdef USE_NANOVDB - float density = sampleCloud(accessor, x); + float density = sampleCloud(xNew); +#endif + +#ifdef USE_ISOSURFACES +#if defined(ISOSURFACE_TYPE_DENSITY) && !defined(USE_TRANSFER_FUNCTION) + float scalarValue = density; #else - float density = sampleCloud(x); + float scalarValue = sampleCloudDirect(xNew); #endif + currentScalarSign = sign(scalarValue - parameters.isoValue); + if (isFirstPoint) { + isFirstPoint = false; + lastScalarSign = currentScalarSign; + } + + if (lastScalarSign != currentScalarSign) { + vec3 isosurfaceHitPoint = xNew; + refineIsoSurfaceHit(isosurfaceHitPoint, x, currentScalarSign); + vec3 color = getIsoSurfaceHit(isosurfaceHitPoint, w); + weights *= color; + x = isosurfaceHitPoint; + x += w * 1e-4; + isFirstPoint = true; + if (rayBoxIntersect(parameters.boxMin, parameters.boxMax, x, w, tMin, tMax)) { + x += w * tMin; + d = tMax - tMin; + } + continue; + } #endif + x = xNew; + vec3 sigma_a = absorptionAlbedo * parameters.extinction * density; vec3 sigma_s = scatteringAlbedo * parameters.extinction * density; vec3 sigma_n = vec3(majorant) - parameters.extinction * density; @@ -167,16 +189,19 @@ vec3 deltaTracking( firstEvent = ScatterEvent(false, x, 0.0, w, 0.0, 0.0, 0.0); -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor = createAccessor(); -#endif - float majorant = parameters.extinction.x; float absorptionAlbedo = 1.0 - parameters.scatteringAlbedo.x; float scatteringAlbedo = parameters.scatteringAlbedo.x; float PA = absorptionAlbedo * parameters.extinction.x; float PS = scatteringAlbedo * parameters.extinction.x; +#ifdef USE_ISOSURFACES + vec3 weights = vec3(1, 1, 1); + float lastScalarSign, currentScalarSign; + bool isFirstPoint = true; +#endif + + int i = 0; float tMin, tMax; if (rayBoxIntersect(parameters.boxMin, parameters.boxMax, x, w, tMin, tMax)) { x += w * tMin; @@ -189,6 +214,11 @@ vec3 deltaTracking( float transmittance = 1.0; while (true) { + i++; + if (i == 1000) { + //debugPrintfEXT("HERE"); + return vec3(0.0, 1.0, 0.0); + } #ifdef COMPUTE_SCATTER_RAY_ABSORPTION_MOMENTS float absorbance = -log(transmittance); if (absorbance > ABSORBANCE_MAX_VALUE) { @@ -213,31 +243,84 @@ vec3 deltaTracking( #endif transmittance = 1.0; #endif - float t = -log(max(0.0000000001, 1 - random()))/majorant; + float t = -log(max(0.0000000001, 1 - random())) / majorant; if (t > d) { break; } - x += w * t; + vec3 xNew = x + w * t; #ifdef COMPUTE_SCATTER_RAY_ABSORPTION_MOMENTS depth += t; #endif #ifdef USE_TRANSFER_FUNCTION -#ifdef USE_NANOVDB - vec4 densityEmission = sampleCloudDensityEmission(accessor, x); -#else - vec4 densityEmission = sampleCloudDensityEmission(x); -#endif + vec4 densityEmission = sampleCloudDensityEmission(xNew); float density = densityEmission.a; #else -#ifdef USE_NANOVDB - float density = sampleCloud(accessor, x); -#else - float density = sampleCloud(x); + float density = sampleCloud(xNew); #endif + +#ifdef USE_ISOSURFACES +//#if defined(ISOSURFACE_TYPE_DENSITY) && !defined(USE_TRANSFER_FUNCTION) +// float scalarValue = density; +//#else +// float scalarValue = sampleCloudDirect(xNew); +//#endif + const int isoSubdivs = 2; + bool foundHit = false; + for (int subdiv = 0; subdiv < isoSubdivs; subdiv++) { + vec3 x0 = mix(x, xNew, float(subdiv) / float(isoSubdivs)); + vec3 x1 = mix(x, xNew, float(subdiv + 1) / float(isoSubdivs)); + float scalarValue = sampleCloudDirect(x1); + + currentScalarSign = sign(scalarValue - parameters.isoValue); + if (isFirstPoint) { + isFirstPoint = false; + lastScalarSign = currentScalarSign; + } + + if (lastScalarSign != currentScalarSign) { + refineIsoSurfaceHit(x1, x0, currentScalarSign); + x = x1; + vec3 color = getIsoSurfaceHit(x, w); + weights *= color; + x += w * 1e-4; + isFirstPoint = true; + if (rayBoxIntersect(parameters.boxMin, parameters.boxMax, x, w, tMin, tMax)) { + x += w * tMin; + d = tMax - tMin; + } + foundHit = true; + break; + } + } + if (foundHit) { + continue; + } + /*currentScalarSign = sign(scalarValue - parameters.isoValue); + if (isFirstPoint) { + isFirstPoint = false; + lastScalarSign = currentScalarSign; + } + + if (lastScalarSign != currentScalarSign) { + vec3 isosurfaceHitPoint = xNew; + refineIsoSurfaceHit(isosurfaceHitPoint, x, currentScalarSign); + vec3 color = getIsoSurfaceHit(isosurfaceHitPoint, w); + weights *= color; + x = isosurfaceHitPoint; + x += w * 1e-4; + isFirstPoint = true; + if (rayBoxIntersect(parameters.boxMin, parameters.boxMax, x, w, tMin, tMax)) { + x += w * tMin; + d = tMax - tMin; + } + continue; + }*/ #endif + + x = xNew; transmittance *= 1.0 - density; float sigma_a = PA * density; @@ -265,14 +348,22 @@ vec3 deltaTracking( #endif #ifdef USE_EMISSION L_e += sampleEmission(x); +#ifdef USE_ISOSURFACES + return weights * emission; +#else return emission; #endif +#endif #ifdef USE_TRANSFER_FUNCTION L_e += parameters.emissionStrength * densityEmission.rgb; //return weights * sigma_a / (majorant * Pa) * L_e; #endif #if defined(USE_EMISSION) || defined(USE_TRANSFER_FUNCTION) +#ifdef USE_ISOSURFACES + return weights * L_e; +#else return L_e; +#endif #else return vec3(0); // weights * sigma_a / (majorant * Pa) * L_e; // 0 - No emission #endif @@ -309,6 +400,10 @@ vec3 deltaTracking( } } +#ifdef USE_ISOSURFACES + return weights * (sampleSkybox(w) + sampleLight(w)); +#else return sampleSkybox(w) + sampleLight(w); +#endif } #endif diff --git a/Data/Shaders/VPT/NextEventTracking.glsl b/Data/Shaders/VPT/NextEventTracking.glsl index 2b2ca01..1a1b6b1 100644 --- a/Data/Shaders/VPT/NextEventTracking.glsl +++ b/Data/Shaders/VPT/NextEventTracking.glsl @@ -24,11 +24,7 @@ // Pathtracing with Delta tracking and Spectral tracking. #if defined(USE_NEXT_EVENT_TRACKING) || defined(USE_NEXT_EVENT_TRACKING_SPECTRAL) -float calculateTransmittance(vec3 x, vec3 w -#ifdef USE_NANOVDB - , pnanovdb_readaccessor_t accessor -#endif -) { +float calculateTransmittance(vec3 x, vec3 w) { float majorant = parameters.extinction.x; float absorptionAlbedo = 1.0 - parameters.scatteringAlbedo.x; @@ -66,18 +62,10 @@ float calculateTransmittance(vec3 x, vec3 w x += w * t; #ifdef USE_TRANSFER_FUNCTION -#ifdef USE_NANOVDB - vec4 densityEmission = sampleCloudDensityEmission(accessor, x); -#else vec4 densityEmission = sampleCloudDensityEmission(x); -#endif float density = densityEmission.a; -#else -#ifdef USE_NANOVDB - float density = sampleCloud(accessor, x); #else float density = sampleCloud(x); -#endif #endif float sigma_a = PA * density; @@ -108,10 +96,6 @@ float calculateTransmittance(vec3 x, vec3 w */ #ifdef USE_NEXT_EVENT_TRACKING_SPECTRAL vec3 nextEventTrackingSpectral(vec3 x, vec3 w, out ScatterEvent firstEvent, bool onlyFirstEvent) { -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor = createAccessor(); -#endif - firstEvent = ScatterEvent(false, x, 0.0, w, 0.0, 0.0, 0.0); float majorant = maxComponent(parameters.extinction); @@ -146,12 +130,8 @@ vec3 nextEventTrackingSpectral(vec3 x, vec3 w, out ScatterEvent firstEvent, bool absorptionAlbedo = vec3(1) - scatteringAlbedo; float PA = maxComponent(absorptionAlbedo * parameters.extinction); float PS = maxComponent(scatteringAlbedo * parameters.extinction); -#else -#ifdef USE_NANOVDB - float density = sampleCloud(accessor, x); #else float density = sampleCloud(x); -#endif #endif vec3 sigma_a = absorptionAlbedo * parameters.extinction * density; @@ -234,11 +214,7 @@ vec3 nextEventTrackingSpectral(vec3 x, vec3 w, out ScatterEvent firstEvent, bool weights *= sigma_s / (majorant * Ps); color += bw_nee * min(weights, vec3(100000, 100000, 100000)) * -#ifdef USE_NANOVDB - calculateTransmittance(x,nee_w, accessor) * -#else calculateTransmittance(x,nee_w) * -#endif (sampleSkybox(nee_w) + sampleLight(nee_w)) * pdf_nee_phase / pdf_nee; if (rayBoxIntersect(parameters.boxMin, parameters.boxMax, x, w, tMin, tMax)) { @@ -263,10 +239,6 @@ vec3 nextEventTrackingSpectral(vec3 x, vec3 w, out ScatterEvent firstEvent, bool vec3 nextEventTracking(vec3 x, vec3 w, out ScatterEvent firstEvent, bool onlyFirstEvent) { firstEvent = ScatterEvent(false, x, 0.0, w, 0.0, 0.0, 0.0); -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor = createAccessor(); -#endif - float majorant = parameters.extinction.x; float absorptionAlbedo = 1.0 - parameters.scatteringAlbedo.x; float scatteringAlbedo = parameters.scatteringAlbedo.x; @@ -275,6 +247,12 @@ vec3 nextEventTracking(vec3 x, vec3 w, out ScatterEvent firstEvent, bool onlyFir float transmittance = 1.0; +#ifdef USE_ISOSURFACES + vec3 weights = vec3(1, 1, 1); + float lastScalarSign, currentScalarSign; + bool isFirstPoint = true; +#endif + float bw_phase = 1.; vec3 color = vec3(0.); @@ -291,23 +269,45 @@ vec3 nextEventTracking(vec3 x, vec3 w, out ScatterEvent firstEvent, bool onlyFir break; } - x += w * t; + vec3 xNew = x + w * t; #ifdef USE_TRANSFER_FUNCTION -#ifdef USE_NANOVDB - vec4 densityEmission = sampleCloudDensityEmission(accessor, x); -#else vec4 densityEmission = sampleCloudDensityEmission(x); -#endif float density = densityEmission.a; #else -#ifdef USE_NANOVDB - float density = sampleCloud(accessor, x); + float density = sampleCloud(xNew); +#endif + +#ifdef USE_ISOSURFACES +#if defined(ISOSURFACE_TYPE_DENSITY) && !defined(USE_TRANSFER_FUNCTION) + float scalarValue = density; #else - float density = sampleCloud(x); + float scalarValue = sampleCloudDirect(xNew); #endif + currentScalarSign = sign(scalarValue - parameters.isoValue); + if (isFirstPoint) { + isFirstPoint = false; + lastScalarSign = currentScalarSign; + } + + if (lastScalarSign != currentScalarSign) { + vec3 isosurfaceHitPoint = xNew; + refineIsoSurfaceHit(isosurfaceHitPoint, x, currentScalarSign); + vec3 color = getIsoSurfaceHit(isosurfaceHitPoint, w); + weights *= color; + x = isosurfaceHitPoint; + x += w * 1e-4; + isFirstPoint = true; + if (rayBoxIntersect(parameters.boxMin, parameters.boxMax, x, w, tMin, tMax)) { + x += w * tMin; + d = tMax - tMin; + } + continue; + } #endif + x = xNew; + float sigma_a = PA * density; float sigma_s = PS * density; float sigma_n = majorant - parameters.extinction.x * density; @@ -333,10 +333,18 @@ vec3 nextEventTracking(vec3 x, vec3 w, out ScatterEvent firstEvent, bool onlyFir } #ifdef USE_EMISSION vec3 emission = sampleEmission(x); +#ifdef USE_ISOSURFACES + return color + weights * emission; +#else return color + emission; +#endif #else #ifdef USE_TRANSFER_FUNCTION +#ifdef USE_ISOSURFACES + return weights * parameters.emissionStrength * densityEmission.rgb; +#else return parameters.emissionStrength * densityEmission.rgb; +#endif #endif return color; // weights * sigma_a / (majorant * Pa) * L_e; // 0 - No emission #endif @@ -374,13 +382,13 @@ vec3 nextEventTracking(vec3 x, vec3 w, out ScatterEvent firstEvent, bool onlyFir bw_phase = pdf_w * pdf_w / (pdf_w * pdf_w + pdf_phase_nee * pdf_phase_nee); float bw_nee = pdf_nee * pdf_nee / (pdf_nee * pdf_nee + pdf_nee_phase * pdf_nee_phase); - color += bw_nee * transmittance * -#ifdef USE_NANOVDB - calculateTransmittance(x,nee_w, accessor) * -#else + vec3 colorNew = bw_nee * transmittance * calculateTransmittance(x,nee_w) * -#endif (sampleSkybox(nee_w) + sampleLight(nee_w)) * pdf_nee_phase / pdf_nee; +#ifdef USE_ISOSURFACES + colorNew *= weights; +#endif + color += colorNew; //color += bw_phase * transmittance * calculateTransmittance(x,next_w) * (sampleSkybox(next_w) + sampleLight(next_w)); //return color; diff --git a/Data/Shaders/VPT/RatioTracking.glsl b/Data/Shaders/VPT/RatioTracking.glsl index aefa91c..5a80aca 100644 --- a/Data/Shaders/VPT/RatioTracking.glsl +++ b/Data/Shaders/VPT/RatioTracking.glsl @@ -26,10 +26,6 @@ vec3 ratioTracking(vec3 x, vec3 w, out ScatterEvent firstEvent) { firstEvent = ScatterEvent(false, x, 0.0, w, 0.0, 0.0, 0.0); -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor = createAccessor(); -#endif - float majorant = parameters.extinction.x; float absorptionAlbedo = 1.0 - parameters.scatteringAlbedo.x; float scatteringAlbedo = parameters.scatteringAlbedo.x; @@ -53,11 +49,7 @@ vec3 ratioTracking(vec3 x, vec3 w, out ScatterEvent firstEvent) { x += w * t; -#ifdef USE_NANOVDB - float density = sampleCloud(accessor, x); -#else float density = sampleCloud(x); -#endif float sigma_a = PA * density; float sigma_s = PS * density; diff --git a/Data/Shaders/VPT/RayTracingUtilities.glsl b/Data/Shaders/VPT/RayTracingUtilities.glsl new file mode 100644 index 0000000..815569b --- /dev/null +++ b/Data/Shaders/VPT/RayTracingUtilities.glsl @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION + * SPDX-License-Identifier: Apache-2.0 + */ + +void ComputeDefaultBasis(const vec3 normal, out vec3 x, out vec3 y) +{ + // ZAP's default coordinate system for compatibility + vec3 z = normal; + const float yz = -z.y * z.z; + y = normalize(((abs(z.z) > 0.99999f) ? vec3(-z.x * z.y, 1.0f - z.y * z.y, yz) : vec3(-z.x * z.z, yz, 1.0f - z.z * z.z))); + + x = cross(y, z); +} diff --git a/Data/Shaders/VPT/ResidualRatioTracking.glsl b/Data/Shaders/VPT/ResidualRatioTracking.glsl index 977caf4..59b055d 100644 --- a/Data/Shaders/VPT/ResidualRatioTracking.glsl +++ b/Data/Shaders/VPT/ResidualRatioTracking.glsl @@ -32,9 +32,6 @@ #ifdef USE_RESIDUAL_RATIO_TRACKING float residualRatioTrackingEstimator( -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor, -#endif vec3 x, vec3 w, float dStart, float dEnd, float T, inout float reservoirWeightSum, out float reservoirT, out float reservoirDist, float absorptionAlbedo, float mu_c, float mu_r_bar) { @@ -55,11 +52,7 @@ float residualRatioTrackingEstimator( break; } -#ifdef USE_NANOVDB - float density = sampleCloud(accessor, x); -#else float density = sampleCloud(x); -#endif float mu = parameters.extinction.x * density; //T_r *= (1.0 - absorptionAlbedo * (mu - mu_c) / mu_r_bar); //T_r *= (1.0 - density) * (mu - mu_c) / mu_r_bar; @@ -85,10 +78,6 @@ float residualRatioTrackingEstimator( vec3 residualRatioTracking(vec3 x, vec3 w, out ScatterEvent firstEvent) { firstEvent = ScatterEvent(false, x, 0.0, w, 0.0, 0.0, 0.0); -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor = createAccessor(); -#endif - float absorptionAlbedo = 1.0 - parameters.scatteringAlbedo.x; float scatteringAlbedo = parameters.scatteringAlbedo.x; @@ -183,9 +172,6 @@ vec3 residualRatioTracking(vec3 x, vec3 w, out ScatterEvent firstEvent) { x = oldX + w * tMinVoxel; T *= residualRatioTrackingEstimator( -#ifdef USE_NANOVDB - accessor, -#endif x, w, tMinVoxel, tMaxVoxel, T, reservoirWeightSum, reservoirT, reservoirDist, absorptionAlbedo, mu_c, mu_r_bar); diff --git a/Data/Shaders/VPT/VptHeader.glsl b/Data/Shaders/VPT/VptHeader.glsl index b755575..9254125 100644 --- a/Data/Shaders/VPT/VptHeader.glsl +++ b/Data/Shaders/VPT/VptHeader.glsl @@ -76,6 +76,10 @@ layout (binding = 3) uniform Parameters { ivec3 superVoxelGridSize; //ivec3 gridResolution; + + // Isosurfaces. + vec3 isoSurfaceColor; + float isoValue; } parameters; layout (binding = 4) uniform FrameInfo { @@ -138,3 +142,7 @@ layout(binding = 21) uniform sampler1D transferFunctionTexture; vec2 Multiply(vec2 LHS, vec2 RHS) { return vec2(LHS.x * RHS.x - LHS.y * RHS.y, LHS.x * RHS.y + LHS.y * RHS.x); } + +#ifdef USE_NANOVDB +pnanovdb_readaccessor_t accessor; +#endif diff --git a/Data/Shaders/VPT/VptUtils.glsl b/Data/Shaders/VPT/VptUtils.glsl index 291c874..100aa0b 100644 --- a/Data/Shaders/VPT/VptUtils.glsl +++ b/Data/Shaders/VPT/VptUtils.glsl @@ -475,66 +475,47 @@ vec3 sampleEmission(in vec3 pos){ #endif #ifdef USE_TRANSFER_FUNCTION -vec4 sampleCloudColorAndDensity( -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor, -#endif - in vec3 pos) { +vec4 sampleCloudColorAndDensity(in vec3 pos) { // Idea: Returns (color.rgb, density). vec3 coord = (pos - parameters.boxMin) / (parameters.boxMax - parameters.boxMin); #if defined(FLIP_YZ) coord = coord.xzy; #endif coord = coord * (parameters.gridMax - parameters.gridMin) + parameters.gridMin; - float densityRaw = sampleCloudRaw( -#ifdef USE_NANOVDB - accessor, -#endif - coord); + float densityRaw = sampleCloudRaw(coord); //return densityRaw; return texture(transferFunctionTexture, densityRaw); } #endif #ifdef USE_TRANSFER_FUNCTION -float sampleCloud( -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor, -#endif - in vec3 pos) { - // Idea: Returns (color.rgb, density). +float sampleCloud(in vec3 pos) { + // Idea: Returns density. vec3 coord = (pos - parameters.boxMin) / (parameters.boxMax - parameters.boxMin); #if defined(FLIP_YZ) coord = coord.xzy; #endif coord = coord * (parameters.gridMax - parameters.gridMin) + parameters.gridMin; - float densityRaw = sampleCloudRaw( -#ifdef USE_NANOVDB - accessor, -#endif - pos); + float densityRaw = sampleCloudRaw(coord); return texture(transferFunctionTexture, densityRaw).a; } -vec4 sampleCloudDensityEmission( -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor, -#endif - in vec3 pos) { +vec4 sampleCloudDensityEmission(in vec3 pos) { // Idea: Returns (color.rgb, density). vec3 coord = (pos - parameters.boxMin) / (parameters.boxMax - parameters.boxMin); - float densityRaw = sampleCloudRaw( -#ifdef USE_NANOVDB - accessor, -#endif - coord); + float densityRaw = sampleCloudRaw(coord); return texture(transferFunctionTexture, densityRaw); } -#else -float sampleCloud( -#ifdef USE_NANOVDB - pnanovdb_readaccessor_t accessor, +float sampleCloudDirect(in vec3 pos) { + vec3 coord = (pos - parameters.boxMin) / (parameters.boxMax - parameters.boxMin); +#if defined(FLIP_YZ) + coord = coord.xzy; #endif - in vec3 pos) { + coord = coord * (parameters.gridMax - parameters.gridMin) + parameters.gridMin; + float densityRaw = sampleCloudRaw(coord); + return densityRaw; +} +#else +float sampleCloud(in vec3 pos) { // Transform world position to density grid position. vec3 coord = (pos - parameters.boxMin) / (parameters.boxMax - parameters.boxMin); #if defined(FLIP_YZ) @@ -542,12 +523,9 @@ float sampleCloud( #endif coord = coord * (parameters.gridMax - parameters.gridMin) + parameters.gridMin; - return sampleCloudRaw( -#ifdef USE_NANOVDB - accessor, -#endif - coord);// + parameters.extinction.g / parameters.extinction.r * .01; + return sampleCloudRaw(coord);// + parameters.extinction.g / parameters.extinction.r * .01; } +#define sampleCloudDirect sampleCloud #endif @@ -607,3 +585,140 @@ float maxComponent(vec3 v) { float avgComponent(vec3 v) { return (v.x + v.y + v.z) / 3.0; } + + +#ifdef USE_ISOSURFACES +#include "RayTracingUtilities.glsl" + +#define M_PI 3.14159265358979323846 +vec3 computeGradient(vec3 texCoords) { +#ifdef DIFFERENCES_NEIGHBOR + const float dx = 1.0; + const float dy = 1.0; + const float dz = 1.0; + float gradX = + (textureOffset(gridImage, texCoords, ivec3(-1, 0, 0)).r + - textureOffset(gridImage, texCoords, ivec3(1, 0, 0)).r) * 0.5 / dx; + float gradY = + (textureOffset(gridImage, texCoords, ivec3(0, -1, 0)).r + - textureOffset(gridImage, texCoords, ivec3(0, 1, 0)).r) * 0.5 / dy; + float gradZ = + (textureOffset(gridImage, texCoords, ivec3(0, 0, -1)).r + - textureOffset(gridImage, texCoords, ivec3(0, 0, 1)).r) * 0.5 / dz; +#else + const float dx = 1e-6; + const float dy = 1e-6; + const float dz = 1e-6; + float gradX = + (texture(gridImage, texCoords - vec3(dx, 0.0, 0.0)).r + - texture(gridImage, texCoords + vec3(dx, 0.0, 0.0)).r) * 0.5 / dx; + float gradY = + (texture(gridImage, texCoords - vec3(0.0, dy, 0.0)).r + - texture(gridImage, texCoords + vec3(0.0, dy, 0.0)).r) * 0.5 / dy; + float gradZ = + (texture(gridImage, texCoords - vec3(0.0, 0.0, dz)).r + - texture(gridImage, texCoords + vec3(0.0, 0.0, dz)).r) * 0.5 / dz; +#endif + + vec3 grad = vec3(gradX, gradY, gradZ); + float gradLength = length(grad); + if (gradLength < 1e-3) { + return vec3(0.0, 0.0, 1.0); + } + return grad / gradLength; +} + +const int MAX_NUM_REFINEMENT_STEPS = 8; + +void refineIsoSurfaceHit(inout vec3 currentPoint, vec3 lastPoint, float stepSign) { + for (int i = 0; i < MAX_NUM_REFINEMENT_STEPS; i++) { + vec3 midPoint = (currentPoint + lastPoint) * 0.5; + //vec3 texCoordsMidPoint = (midPoint - parameters.boxMin) / (parameters.boxMax - parameters.boxMin); + //float scalarValueMidPoint = texture(scalarField, texCoordsMidPoint).r; + float scalarValueMidPoint = sampleCloudDirect(midPoint); + if ((scalarValueMidPoint - parameters.isoValue) * stepSign >= 0.0) { + currentPoint = midPoint; + } else { + lastPoint = midPoint; + } + } +} + + +/** + * Uniformly samples a direction on the upper hemisphere for the surface normal vector n = (0, 0, 1)^T. + * For more details see: + * https://www.pbr-book.org/3ed-2018/Monte_Carlo_Integration/2D_Sampling_with_Multidimensional_Transformations + * @param xi Two random numbers uniformly sampled in the range [0, 1). + */ +vec3 sampleHemisphere(vec2 xi) { + // Uniform Hemisphere PDF: 1 / (2 * pi) + //float theta = acos(xi.x); + float phi = 2.0 * M_PI * xi.y; + float r = sqrt(1.0 - xi.x * xi.x); + return vec3(cos(phi) * r, sin(phi) * r, xi.x); +} +vec2 concentricSampleDisk(vec2 xi) { + vec2 xiOffset = 2.0 * xi - vec2(1.0); + if (xiOffset.x == 0 && xiOffset.y == 0) { + return vec2(0.0); + } + float theta, r; + if (abs(xiOffset.x) > abs(xiOffset.y)) { + r = xiOffset.x; + theta = M_PI / 4.0 * (xiOffset.y / xiOffset.x); + } else { + r = xiOffset.y; + theta = M_PI / 2.0 - M_PI / 4.0 * (xiOffset.x / xiOffset.y); + } + return r * vec2(cos(theta), sin(theta)); +} +vec3 sampleHemisphereCosineWeighted(vec2 xi) { + // Cosine Hemisphere PDF: cos(theta) / pi + vec2 d = concentricSampleDisk(xi); + float z = sqrt(1.0 - d.x * d.x - d.y * d.y); + return vec3(d.x, d.y, z); +} + +//#define UNIFORM_SAMPLING + +vec3 getIsoSurfaceHit(vec3 currentPoint, inout vec3 w) { + vec3 texCoords = (currentPoint - parameters.boxMin) / (parameters.boxMax - parameters.boxMin); + texCoords = texCoords * (parameters.gridMax - parameters.gridMin) + parameters.gridMin; + vec3 surfaceNormal = computeGradient(texCoords); + + vec3 surfaceTangent; + vec3 surfaceBitangent; + ComputeDefaultBasis(surfaceNormal, surfaceTangent, surfaceBitangent); + mat3 frame = mat3(surfaceTangent, surfaceBitangent, surfaceNormal); + //mat3 frame = mat3(vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0)); + +#ifdef SURFACE_BRDF_LAMBERTIAN + // Lambertian BRDF is: R / pi +#ifdef UNIFORM_SAMPLING + // Sampling PDF: 1/(2pi) + vec3 dirOut = frame * sampleHemisphere(vec2(random(), random())); + vec3 color = parameters.isoSurfaceColor * dot(surfaceNormal, dirOut); +#else + // Sampling PDF: cos(theta) / pi + vec3 dirOut = frame * sampleHemisphereCosineWeighted(vec2(random(), random())); + vec3 color = parameters.isoSurfaceColor * 0.5; +#endif +#endif + +#ifdef SURFACE_BRDF_BLINN_PHONG + // http://www.thetenthplanet.de/archives/255 + const float n = 10.0; + vec3 dirOut = frame * sampleHemisphere(vec2(random(), random())); + vec3 halfwayVector = normalize(-w + dirOut); + float rdf = pow(max(dot(surfaceNormal, halfwayVector), 0.0), n); + float norm = clamp( + (n + 2.0) / (4.0 * M_PI * (exp2(-0.5 * n))), + (n + 2.0) / (8.0 * M_PI), (n + 4.0) / (8.0 * M_PI)); + vec3 color = parameters.isoSurfaceColor * (rdf / norm); +#endif + + w = dirOut; + return color; +} +#endif diff --git a/LICENSE b/LICENSE index 5607ac0..3f04ef5 100644 --- a/LICENSE +++ b/LICENSE @@ -276,7 +276,7 @@ DroidSans.ttf ---------------------------------------------------------------------------- -The following license applies to Data/Shaders/RayTracingUtilities.glsl. +The following license applies to Data/Shaders/VPT/RayTracingUtilities.glsl. Apache License Version 2.0, January 2004 diff --git a/src/Main.cpp b/src/Main.cpp index 6e71887..fcabee5 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -58,6 +58,7 @@ int main(int argc, char *argv[]) { #else sgl::AppSettings::get()->getSettings().addKeyValue("window-debugContext", true); #endif + //sgl::AppSettings::get()->setVulkanDebugPrintfEnabled(); ImVector fontRanges; ImFontGlyphRangesBuilder builder; diff --git a/src/PathTracer/VolumetricPathTracingPass.cpp b/src/PathTracer/VolumetricPathTracingPass.cpp index e42540a..e133278 100644 --- a/src/PathTracer/VolumetricPathTracingPass.cpp +++ b/src/PathTracer/VolumetricPathTracingPass.cpp @@ -332,6 +332,10 @@ void VolumetricPathTracingPass::updateGridSampler() { densityFieldTexture->getImageView(), samplerSettings); } +const CloudDataPtr& VolumetricPathTracingPass::getCloudData() { + return cloudData; +} + void VolumetricPathTracingPass::setCloudData(const CloudDataPtr& data) { cloudData = data; frameInfo.frameCount = 0; @@ -402,6 +406,55 @@ void VolumetricPathTracingPass::flipYZ(bool flip) { this->flipYZCoordinates = flip; } +void VolumetricPathTracingPass::setUseIsosurfaces(bool _useIsosurfaces) { + if (useIsosurfaces != _useIsosurfaces) { + useIsosurfaces = _useIsosurfaces; + if (gridInterpolationType != GridInterpolationType::TRILINEAR) { + gridInterpolationType = GridInterpolationType::TRILINEAR; + updateGridSampler(); + } + setShaderDirty(); + reRender = true; + frameInfo.frameCount = 0; + } + +} + +void VolumetricPathTracingPass::setIsoValue(float _isoValue) { + if (isoValue != _isoValue) { + isoValue = _isoValue; + setShaderDirty(); + reRender = true; + frameInfo.frameCount = 0; + } +} + +void VolumetricPathTracingPass::setIsoSurfaceColor(const glm::vec3& _isoSurfaceColor) { + if (isoSurfaceColor != _isoSurfaceColor) { + isoSurfaceColor = _isoSurfaceColor; + reRender = true; + frameInfo.frameCount = 0; + } +} + +void VolumetricPathTracingPass::setIsosurfaceType(IsosurfaceType _isosurfaceType) { + if (isosurfaceType != _isosurfaceType) { + isosurfaceType = _isosurfaceType; + setShaderDirty(); + reRender = true; + frameInfo.frameCount = 0; + } +} + +void VolumetricPathTracingPass::setSurfaceBrdf(SurfaceBrdf _surfaceBrdf) { + if (surfaceBrdf != _surfaceBrdf) { + surfaceBrdf = _surfaceBrdf; + setShaderDirty(); + reRender = true; + frameInfo.frameCount = 0; + } +} + void VolumetricPathTracingPass::setFileDialogInstance(ImGuiFileDialog* _fileDialogInstance) { this->fileDialogInstance = _fileDialogInstance; } @@ -675,6 +728,20 @@ void VolumetricPathTracingPass::loadShader() { frameInfo.frameCount = 0; } + if (useIsosurfaces) { + customPreprocessorDefines.insert({ "USE_ISOSURFACES", "" }); + if (surfaceBrdf == SurfaceBrdf::LAMBERTIAN) { + customPreprocessorDefines.insert({ "SURFACE_BRDF_LAMBERTIAN", "" }); + } else if (surfaceBrdf == SurfaceBrdf::BLINN_PHONG) { + customPreprocessorDefines.insert({ "SURFACE_BRDF_BLINN_PHONG", "" }); + } + if (isosurfaceType == IsosurfaceType::DENSITY) { + customPreprocessorDefines.insert({ "ISOSURFACE_TYPE_DENSITY", "" }); + } else if (isosurfaceType == IsosurfaceType::GRADIENT) { + customPreprocessorDefines.insert({ "ISOSURFACE_TYPE_GRADIENT", "" }); + } + } + shaderStages = sgl::vk::ShaderManager->getShaderStages({"Clouds.Compute"}, customPreprocessorDefines); } @@ -842,6 +909,8 @@ void VolumetricPathTracingPass::_render() { uniformData.superVoxelSize = superVoxelGridDecompositionTracking->getSuperVoxelSize(); uniformData.superVoxelGridSize = superVoxelGridDecompositionTracking->getSuperVoxelGridSize(); } + uniformData.isoSurfaceColor = isoSurfaceColor; + uniformData.isoValue = isoValue; uniformBuffer->updateData( sizeof(UniformData), &uniformData, renderer->getVkCommandBuffer()); @@ -1120,7 +1189,7 @@ bool VolumetricPathTracingPass::renderGuiPropertyEditorNodes(sgl::PropertyEditor setDataDirty(); } - if (propertyEditor.addCombo( + if (!useIsosurfaces && propertyEditor.addCombo( "Grid Interpolation", (int*)&gridInterpolationType, GRID_INTERPOLATION_TYPE_NAMES, IM_ARRAYSIZE(GRID_INTERPOLATION_TYPE_NAMES))) { optionChanged = true; @@ -1238,6 +1307,38 @@ bool VolumetricPathTracingPass::renderGuiPropertyEditorNodes(sgl::PropertyEditor setShaderDirty(); } + if (propertyEditor.addCheckbox("Use Isosurfaces", &useIsosurfaces)) { + if (gridInterpolationType != GridInterpolationType::TRILINEAR) { + gridInterpolationType = GridInterpolationType::TRILINEAR; + updateGridSampler(); + } + setShaderDirty(); + reRender = true; + frameInfo.frameCount = 0; + } + if (useIsosurfaces && propertyEditor.addSliderFloat("Iso Value", &isoValue, 0.0f, 1.0f)) { + setShaderDirty(); + reRender = true; + frameInfo.frameCount = 0; + } + if (useIsosurfaces && propertyEditor.addColorEdit3("Isosurface Color", &isoSurfaceColor.x)) { + reRender = true; + frameInfo.frameCount = 0; + } + if (useIsosurfaces && propertyEditor.addCombo( + "Isosurface Field", (int*)&isosurfaceType, + ISOSURFACE_TYPE_NAMES, IM_ARRAYSIZE(ISOSURFACE_TYPE_NAMES))) { + setShaderDirty(); + reRender = true; + frameInfo.frameCount = 0; + } + if (useIsosurfaces && propertyEditor.addCombo( + "Surface BRDF", (int*)&surfaceBrdf, SURFACE_BRDF_NAMES, IM_ARRAYSIZE(SURFACE_BRDF_NAMES))) { + setShaderDirty(); + reRender = true; + frameInfo.frameCount = 0; + } + propertyEditor.endNode(); } diff --git a/src/PathTracer/VolumetricPathTracingPass.hpp b/src/PathTracer/VolumetricPathTracingPass.hpp index 9ee66bd..f7d27e5 100644 --- a/src/PathTracer/VolumetricPathTracingPass.hpp +++ b/src/PathTracer/VolumetricPathTracingPass.hpp @@ -89,6 +89,20 @@ const char* const SPECTRAL_DELTA_TRACKING_COLLISION_PROBABILITY_NAMES[] = { "Max-based", "Avg-based", "Path History Avg-based" }; +enum class IsosurfaceType { + DENSITY, GRADIENT +}; +const char* const ISOSURFACE_TYPE_NAMES[] = { + "Density", "Gradient" +}; + +enum class SurfaceBrdf { + LAMBERTIAN, BLINN_PHONG +}; +const char* const SURFACE_BRDF_NAMES[] = { + "Lambertian", "Blinn Phong" +}; + class VolumetricPathTracingPass : public sgl::vk::ComputePass { public: explicit VolumetricPathTracingPass(sgl::vk::Renderer* renderer, sgl::CameraPtr* camera); @@ -97,6 +111,7 @@ class VolumetricPathTracingPass : public sgl::vk::ComputePass { // Public interface. void setOutputImage(sgl::vk::ImageViewPtr& colorImage); void recreateSwapchain(uint32_t width, uint32_t height) override; + const CloudDataPtr& getCloudData(); void setCloudData(const CloudDataPtr& data); void setEmissionData(const CloudDataPtr& data); void setVptMode(VptMode vptMode); @@ -122,6 +137,13 @@ class VolumetricPathTracingPass : public sgl::vk::ComputePass { void setEmissionCap(float emissionCap); void flipYZ(bool flip); + // Isosurfaces. + void setUseIsosurfaces(bool _useIsosurfaces); + void setIsoValue(float _isoValue); + void setIsoSurfaceColor(const glm::vec3& _isoSurfaceColor); + void setIsosurfaceType(IsosurfaceType _isosurfaceType); + void setSurfaceBrdf(SurfaceBrdf _surfaceBrdf); + // Called when the camera has moved. void onHasMoved(); /// Returns if the data needs to be re-rendered, but the visualization mapping is valid. @@ -235,6 +257,13 @@ class VolumetricPathTracingPass : public sgl::vk::ComputePass { std::shared_ptr denoiser; std::vector featureMapUsedArray; + // Isosurface data. + bool useIsosurfaces = false; + float isoValue = 0.5f; + glm::vec3 isoSurfaceColor = glm::vec3(0.8f, 0.8f, 0.8f); + IsosurfaceType isosurfaceType = IsosurfaceType::DENSITY; + SurfaceBrdf surfaceBrdf = SurfaceBrdf::LAMBERTIAN; + glm::mat4 previousViewProjMatrix; // Uniform buffer object storing the camera settings. @@ -267,6 +296,10 @@ class VolumetricPathTracingPass : public sgl::vk::ComputePass { // For decomposition and residual ratio tracking. glm::ivec3 superVoxelSize; int pad8; glm::ivec3 superVoxelGridSize; int pad9; + + // Isosurfaces. + glm::vec3 isoSurfaceColor; + float isoValue = 0.5f; }; UniformData uniformData{}; sgl::vk::BufferPtr uniformBuffer; diff --git a/src/PyTorch/Module.cpp b/src/PyTorch/Module.cpp index 5e4fd66..28ffe5b 100644 --- a/src/PyTorch/Module.cpp +++ b/src/PyTorch/Module.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "nanovdb/NanoVDB.h" #include "nanovdb/util/Primitives.h" @@ -46,6 +47,7 @@ TORCH_LIBRARY(vpt, m) { m.def("vpt::cleanup", cleanup); m.def("vpt::render_frame", renderFrame); m.def("vpt::load_cloud_file", loadCloudFile); + m.def("vpt::load_volume_file", loadCloudFile); m.def("vpt::load_emission_file", loadEmissionFile); m.def("vpt::load_environment_map", loadEnvironmentMap); m.def("vpt::set_environment_map_intensity", setEnvironmentMapIntensityFactor); @@ -53,10 +55,22 @@ TORCH_LIBRARY(vpt, m) { m.def("vpt::set_extinction_base", setExtinctionBase); m.def("vpt::set_extinction_scale", setExtinctionScale); m.def("vpt::set_vpt_mode", setVPTMode); + m.def("vpt::set_vpt_mode_from_name", setVPTModeFromName); + m.def("vpt::set_use_transfer_function", setUseTransferFunction); + m.def("vpt::load_transfer_function_file", loadTransferFunctionFile); + m.def("vpt::get_camera_position", getCameraPosition); + m.def("vpt::get_camera_view_matrix", getCameraViewMatrix); + m.def("vpt::get_camera_fovy", getCameraFOVy); m.def("vpt::set_camera_position", setCameraPosition); m.def("vpt::set_camera_target", setCameraTarget); + m.def("vpt::overwrite_camera_view_matrix", overwriteCameraViewMatrix); m.def("vpt::set_camera_FOVy", setCameraFOVy); m.def("vpt::set_feature_map_type", setFeatureMapType); + m.def("vpt::set_use_isosurfaces", setUseIsosurfaces); + m.def("vpt::set_iso_value", setIsoValue); + m.def("vpt::set_iso_surface_color", setIsoSurfaceColor); + m.def("vpt::set_isosurface_type", setIsosurfaceType); + m.def("vpt::set_surface_brdf", setSurfaceBrdf); m.def("vpt::set_seed_offset", setSeedOffset); m.def("vpt::get_feature_map", getFeatureMap); m.def("vpt::set_phase_g", setPhaseG); @@ -64,10 +78,10 @@ TORCH_LIBRARY(vpt, m) { m.def("vpt::set_use_emission", setUseEmission); m.def("vpt::set_emission_strength", setEmissionStrength); m.def("vpt::set_emission_cap", setEmissionCap); + m.def("vpt::get_render_bounding_box", getRenderBoundingBox); m.def("vpt::remember_next_bounds", rememberNextBounds); m.def("vpt::forget_current_bounds", forgetCurrentBounds); m.def("vpt::flip_yz_coordinates", flipYZ); - } static sgl::vk::Renderer* renderer = nullptr; @@ -325,7 +339,7 @@ void initialize() { vptRenderer = new VolumetricPathTracingModuleRenderer(renderer); // TODO: Make this configurable. - CloudDataPtr cloudData = std::make_shared(); + CloudDataPtr cloudData = std::make_shared(vptRenderer->getTransferFunctionWindow()); cloudData->setNanoVdbGridHandle(nanovdb::createFogVolumeSphere( 0.25f, nanovdb::Vec3(0), 0.01f)); vptRenderer->setCloudData(cloudData); @@ -349,14 +363,14 @@ void cleanup() { void loadCloudFile(const std::string& filename) { //std::cout << "loading cloud from " << filename << std::endl; - CloudDataPtr cloudData = std::make_shared(); + CloudDataPtr cloudData = std::make_shared(vptRenderer->getTransferFunctionWindow()); cloudData->loadFromFile(filename); vptRenderer->setCloudData(cloudData); } void loadEmissionFile(const std::string& filename) { //std::cout << "loading emission from " << filename << std::endl; - CloudDataPtr emissionData = std::make_shared(); + CloudDataPtr emissionData = std::make_shared(vptRenderer->getTransferFunctionWindow()); emissionData->loadFromFile(filename); vptRenderer->setEmissionData(emissionData); } @@ -405,17 +419,90 @@ void setExtinctionBase(std::vector extinctionBase) { } } -void setVPTMode(int64_t mode){ +void setVPTMode(int64_t mode) { std::cout << "setVPTMode to " << VPT_MODE_NAMES[mode] << std::endl; vptRenderer->setVptMode(VptMode(mode)); } +void setVPTModeFromName(const std::string& modeName) { + for (int mode = 0; mode < IM_ARRAYSIZE(VPT_MODE_NAMES); mode++) { + if (modeName == VPT_MODE_NAMES[mode]) { + std::cout << "setVPTMode to " << VPT_MODE_NAMES[mode] << std::endl; + vptRenderer->setVptMode(VptMode(mode)); + break; + } + } +} + void setFeatureMapType(int64_t type) { //std::cout << "setFeatureMapType to " << type << std::endl; vptRenderer->setFeatureMapType(FeatureMapTypeVpt(type)); } +void setUseIsosurfaces(bool _useIsosurfaces) { + vptRenderer->getVptPass()->setUseIsosurfaces(_useIsosurfaces); +} + +void setIsoValue(double _isoValue) { + vptRenderer->getVptPass()->setIsoValue(float(_isoValue)); +} + +void setIsoSurfaceColor(std::vector _isoSurfaceColor) { + glm::vec3 color = glm::vec3(0,0,0); + if (parseVector3(_isoSurfaceColor, color)) { + vptRenderer->getVptPass()->setIsoSurfaceColor(color); + } +} + +void setIsosurfaceType(const std::string& _isosurfaceType) { + for (int i = 0; i < IM_ARRAYSIZE(ISOSURFACE_TYPE_NAMES); i++) { + if (_isosurfaceType == ISOSURFACE_TYPE_NAMES[i]) { + vptRenderer->getVptPass()->setIsosurfaceType(IsosurfaceType(i)); + break; + } + } +} + +void setSurfaceBrdf(const std::string& _surfaceBrdf) { + for (int i = 0; i < IM_ARRAYSIZE(SURFACE_BRDF_NAMES); i++) { + if (_surfaceBrdf == SURFACE_BRDF_NAMES[i]) { + vptRenderer->getVptPass()->setSurfaceBrdf(SurfaceBrdf(i)); + break; + } + } +} + + +void setUseTransferFunction(bool _useTf) { + sgl::TransferFunctionWindow* tfWindow = vptRenderer->getTransferFunctionWindow(); + tfWindow->setShowWindow(_useTf); +} + +void loadTransferFunctionFile(const std::string& tfFilePath) { + sgl::TransferFunctionWindow* tfWindow = vptRenderer->getTransferFunctionWindow(); + tfWindow->loadFunctionFromFile(tfFilePath); +} + + +std::vector getCameraPosition() { + auto pos = vptRenderer->getCameraPosition(); + return { pos.x, pos.y, pos.z }; +} + +std::vector getCameraViewMatrix() { + std::vector viewMatrixData(16); + auto viewMatrix = vptRenderer->getCamera()->getViewMatrix(); + for (int i = 0; i < 16; i++) { + viewMatrixData[i] = viewMatrix[i / 4][i % 4]; + } + return viewMatrixData; +} + +double getCameraFOVy() { + return vptRenderer->getCamera()->getFOVy(); +} + void setCameraPosition(std::vector cameraPosition) { glm::vec3 vec = glm::vec3(0,0,0); if (parseVector3(cameraPosition, vec)) { @@ -432,6 +519,14 @@ void setCameraTarget(std::vector cameraTarget) { } } +void overwriteCameraViewMatrix(std::vector viewMatrixData) { + glm::mat4 viewMatrix; + for (int i = 0; i < 16; i++) { + viewMatrix[i / 4][i % 4] = viewMatrixData[i]; + } + vptRenderer->getCamera()->overwriteViewMatrix(viewMatrix); +} + void setCameraFOVy(double FOVy){ //std::cout << "setCameraFOVy to " << FOVy << std::endl; vptRenderer->setCameraFOVy(FOVy * sgl::PI / 180); @@ -463,6 +558,12 @@ void flipYZ(bool flip){ vptRenderer->flipYZ(flip); } + +std::vector getRenderBoundingBox() { + const auto& aabb = vptRenderer->getCloudData()->getWorldSpaceBoundingBox(); + return { aabb.min.x, aabb.max.x, aabb.min.y, aabb.max.y, aabb.min.z, aabb.max.z }; +} + void rememberNextBounds(){ vptRenderer->rememberNextBounds(); } diff --git a/src/PyTorch/Module.hpp b/src/PyTorch/Module.hpp index 122e46d..fb55955 100644 --- a/src/PyTorch/Module.hpp +++ b/src/PyTorch/Module.hpp @@ -46,13 +46,28 @@ MODULE_OP_API void setExtinctionScale(double extinctionScale); MODULE_OP_API void setExtinctionBase(std::vector extinctionBase); MODULE_OP_API void setPhaseG(double phaseG); +MODULE_OP_API void setUseTransferFunction(bool _useTf); +MODULE_OP_API void loadTransferFunctionFile(const std::string& tfFilePath); + +MODULE_OP_API std::vector getCameraPosition(); +MODULE_OP_API std::vector getCameraViewMatrix(); +MODULE_OP_API double getCameraFOVy(); + MODULE_OP_API void setCameraPosition(std::vector cameraPosition); MODULE_OP_API void setCameraTarget(std::vector cameraTarget); +MODULE_OP_API void overwriteCameraViewMatrix(std::vector viewMatrixData); MODULE_OP_API void setCameraFOVy(double FOVy); MODULE_OP_API void setVPTMode(int64_t mode); +MODULE_OP_API void setVPTModeFromName(const std::string& modeName); MODULE_OP_API void setFeatureMapType(int64_t type); +MODULE_OP_API void setUseIsosurfaces(bool _useIsosurfaces); +MODULE_OP_API void setIsoValue(double _isoValue); +MODULE_OP_API void setIsoSurfaceColor(std::vector _isoSurfaceColor); +MODULE_OP_API void setIsosurfaceType(const std::string& _isosurfaceType); +MODULE_OP_API void setSurfaceBrdf(const std::string& _surfaceBrdf); + MODULE_OP_API void setSeedOffset(int64_t offset); MODULE_OP_API void setViewProjectionMatrixAsPrevious(); @@ -62,6 +77,7 @@ MODULE_OP_API void setEmissionStrength(double emissionStrength); MODULE_OP_API void setUseEmission(bool useEmission); MODULE_OP_API void flipYZ(bool flip); +MODULE_OP_API std::vector getRenderBoundingBox(); MODULE_OP_API void rememberNextBounds(); MODULE_OP_API void forgetCurrentBounds(); diff --git a/src/PyTorch/VolumetricPathTracingModuleRenderer.cpp b/src/PyTorch/VolumetricPathTracingModuleRenderer.cpp index 31c3f61..853d21c 100644 --- a/src/PyTorch/VolumetricPathTracingModuleRenderer.cpp +++ b/src/PyTorch/VolumetricPathTracingModuleRenderer.cpp @@ -29,6 +29,8 @@ #include #include #include +#include + #include "CloudData.hpp" #include "PathTracer/VolumetricPathTracingPass.hpp" @@ -59,6 +61,9 @@ VolumetricPathTracingModuleRenderer::VolumetricPathTracingModuleRenderer(sgl::vk camera->setFOVy(std::atan(1.0f / 2.0f) * 2.0f); camera->resetLookAtLocation(); + transferFunctionWindow = new sgl::TransferFunctionWindow; + transferFunctionWindow->setShowWindow(false); + sgl::vk::Device* device = sgl::AppSettings::get()->getPrimaryDevice(); vptPass = std::make_shared(renderer, &camera); renderFinishedFence = std::make_shared(device); @@ -74,6 +79,17 @@ VolumetricPathTracingModuleRenderer::~VolumetricPathTracingModuleRenderer() { cudaStreamSynchronize(stream); } renderer->getDevice()->waitIdle(); + + delete transferFunctionWindow; + renderer->getDevice()->waitIdle(); +} + +VolumetricPathTracingPass* VolumetricPathTracingModuleRenderer::getVptPass() { + return vptPass.get(); +} + +const CloudDataPtr& VolumetricPathTracingModuleRenderer::getCloudData() { + return vptPass->getCloudData(); } void VolumetricPathTracingModuleRenderer::setCloudData(const CloudDataPtr& cloudData) { @@ -146,6 +162,14 @@ void VolumetricPathTracingModuleRenderer::flipYZ(bool flip) { vptPass->flipYZ(flip); } +const glm::vec3& VolumetricPathTracingModuleRenderer::getCameraPosition() { + return camera->getPosition(); +} + +const sgl::CameraPtr& VolumetricPathTracingModuleRenderer::getCamera() { + return camera; +} + void VolumetricPathTracingModuleRenderer::setCameraPosition(const glm::vec3& cameraPosition) { this->cameraPosition = cameraPosition; camera->setPosition(cameraPosition); diff --git a/src/PyTorch/VolumetricPathTracingModuleRenderer.hpp b/src/PyTorch/VolumetricPathTracingModuleRenderer.hpp index 2f2a3e0..092dcc8 100644 --- a/src/PyTorch/VolumetricPathTracingModuleRenderer.hpp +++ b/src/PyTorch/VolumetricPathTracingModuleRenderer.hpp @@ -53,7 +53,11 @@ class VolumetricPathTracingModuleRenderer { explicit VolumetricPathTracingModuleRenderer(sgl::vk::Renderer* renderer); ~VolumetricPathTracingModuleRenderer(); + inline sgl::TransferFunctionWindow* getTransferFunctionWindow() { return transferFunctionWindow; } + /// Sets the cloud data that is rendered when calling @see renderFrameCpu. + VolumetricPathTracingPass* getVptPass(); + const CloudDataPtr& getCloudData(); void setCloudData(const CloudDataPtr& cloudData); void setEmissionData(const CloudDataPtr& cloudData); @@ -71,6 +75,9 @@ class VolumetricPathTracingModuleRenderer { void setUseEmission(bool useEmission); void flipYZ(bool flip); + const glm::vec3& getCameraPosition(); + const sgl::CameraPtr& getCamera(); + void setCameraPosition(const glm::vec3& cameraPosition); void setCameraTarget(const glm::vec3& cameraTarget); void setCameraFOVy(double FOVy); @@ -125,6 +132,7 @@ class VolumetricPathTracingModuleRenderer { #endif private: + sgl::TransferFunctionWindow* transferFunctionWindow; sgl::CameraPtr camera; glm::vec3 cameraPosition = glm::vec3(0,0,0); glm::vec3 cameraTarget = glm::vec3(0,0,0);