├── assets ├── deon2023student.pdf └── deon2023studentsupp.pdf ├── test ├── NDFs │ ├── test_dirac_NDF_sigma.cpp │ ├── test_ggx_vNDF.cpp │ ├── test_beckmann_vNDF.cpp │ ├── test_ST_sigma.cpp │ ├── test_ST_vNDF.cpp │ ├── test_ST_vNDF_null.cpp │ ├── test_vMF_sigma.cpp │ ├── test_null_ST_sigma.cpp │ ├── test_dirac_NDF_sigma.nb │ └── test_ST_sigma.nb ├── lambert │ └── test_lambert_eval_sample.cpp ├── rough_mirror │ ├── test_rough_mirror_vmf_eval_sample.cpp │ └── test_biscale_rough_mirror_beckmann_eval_sample.cpp ├── rough_diffuse │ ├── test_rough_diffuse_ggx_eval_sample.cpp │ ├── test_rough_diffuse_beckmann_eval_sample.cpp │ └── test_rough_diffuse_ST_eval_sample.cpp ├── rough_conductor │ ├── test_rough_conductor_vMF_eval_sample.cpp │ ├── test_rough_conductor_ggx_eval_sample.cpp │ ├── test_rough_conductor_beckmann_eval_sample.cpp │ └── test_rough_conductor_null_ST_eval_sample.cpp └── rough_dielectric │ ├── test_rough_dielectric_beckmann_eval_sample.cpp │ ├── test_rough_dielectric_ST_eval_sample.cpp │ └── test_rough_dielectric_null_ST_eval_sample.cpp ├── include ├── bsdfs │ ├── NDFs │ │ ├── NullvMF.h │ │ ├── NullStudentT.h │ │ ├── BlendedNDF.h │ │ ├── GGX.h │ │ ├── ShapeInvariantNDF.h │ │ ├── beckmann.h │ │ ├── NullNDF.h │ │ └── studentT.h │ ├── mirror.h │ ├── lambert.h │ ├── conductor.h │ ├── dielectric.h │ ├── blend_BSDF.h │ ├── NDF.h │ └── microsurface.h ├── bsdf.h ├── random.h ├── math_functions.h ├── fresnel.h ├── testing │ └── compare_eval_sample.h ├── vector.h └── util.h ├── CONTRIBUTING.md ├── README.md └── LICENSE /assets/deon2023student.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVlabs/facet-forge/HEAD/assets/deon2023student.pdf -------------------------------------------------------------------------------- /assets/deon2023studentsupp.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NVlabs/facet-forge/HEAD/assets/deon2023studentsupp.pdf -------------------------------------------------------------------------------- /test/NDFs/test_dirac_NDF_sigma.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // test sigma_t for Dirac NDF 18 | 19 | #include 20 | 21 | int main(int argc, char **argv) 22 | { 23 | srand48(time(NULL)); 24 | 25 | if (argc != 3) 26 | { 27 | std::cout << "usage: test du un \n"; 28 | exit(-1); 29 | } 30 | 31 | const double du = StringToNumber(std::string(argv[1])); 32 | const double un = StringToNumber(std::string(argv[2])); 33 | 34 | for (double u = -1.0; u < 1.0; u += du) 35 | { 36 | std::cout << diracSigma(u, un) << " "; 37 | } 38 | 39 | return 0; 40 | } -------------------------------------------------------------------------------- /include/bsdfs/NDFs/NullvMF.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | // null-collision von-Mises Fischer (spherical Gaussian/vMF) NDF 22 | 23 | class NullvMFNDF : public NullNDF 24 | { 25 | public: 26 | NullvMFNDF(BSDF *bsdf, double roughness) 27 | : NullNDF(bsdf, 1), m_roughness(roughness){}; 28 | 29 | double m_roughness; 30 | 31 | virtual double D(const Vector3 &wm) const 32 | { 33 | // vMF matched to Beckmann roughness, normalized to 1.0 at normal incidence 34 | const double u = wm.z; 35 | return exp((2.0 * (-1.0 + u)) / pow(m_roughness, 2)); 36 | }; 37 | }; 38 | -------------------------------------------------------------------------------- /include/bsdfs/mirror.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | // smooth mirror 22 | class MirrorBRDF : public BSDF 23 | { 24 | public: 25 | MirrorBRDF(){}; 26 | 27 | virtual Vector3 sample(const double ior_i, const double ior_t, const Vector3 &wi, double &weight) const 28 | { 29 | return reflect(wi, Vector3(0, 0, 1)); 30 | } 31 | 32 | virtual double eval(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 33 | { 34 | return 0.0; 35 | } 36 | 37 | virtual double evalSingular(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 38 | { 39 | return 1.0; 40 | } 41 | }; -------------------------------------------------------------------------------- /test/lambert/test_lambert_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | 20 | int main(int argc, char **argv) 21 | { 22 | srand48(time(NULL)); 23 | 24 | if (argc != 5) 25 | { 26 | std::cout << "usage: testlambert kd theta_i numsamplesSample numsamplesEval \n"; 27 | exit(-1); 28 | } 29 | 30 | const double kd = StringToNumber(std::string(argv[1])); 31 | const float theta_i = StringToNumber(std::string(argv[2])); 32 | size_t numsamplesSample = StringToNumber(std::string(argv[3])); 33 | size_t numsamplesEval = StringToNumber(std::string(argv[4])); 34 | 35 | LambertBRDF brdf(kd); 36 | 37 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, 1.0); 38 | 39 | return 1; 40 | } -------------------------------------------------------------------------------- /include/bsdfs/NDFs/NullStudentT.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | // null-collision student-T NDF 22 | 23 | class NullStudentTNDF : public NullNDF 24 | { 25 | public: 26 | NullStudentTNDF(BSDF *bsdf, double roughness, double gamma, double majorant) 27 | : NullNDF(bsdf, majorant), m_roughness(roughness), m_gamma(gamma){}; 28 | 29 | double m_gamma, m_roughness; 30 | 31 | virtual double D(const Vector3 &wm) const 32 | { 33 | const double u = wm.z; 34 | if (u > 0.0 && u <= 1.0) 35 | { 36 | return 1 / (Pi * Power(u, 4) * Power(m_roughness, 2) * Power(1 + (1 - Power(u, 2)) / (Power(u, 2) * Power(m_roughness, 2) * (-1 + m_gamma)), m_gamma)); 37 | } 38 | elseß 39 | { 40 | return 0.0; 41 | } 42 | }; 43 | }; -------------------------------------------------------------------------------- /include/bsdfs/lambert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | class LambertBRDF : public BSDF 23 | { 24 | public: 25 | double m_kd; // diffuse color 26 | 27 | LambertBRDF(const double kd) : m_kd(kd){}; 28 | 29 | virtual Vector3 sample(const double ior_i, const double ior_t, const Vector3 &wi, double &weight) const 30 | { 31 | weight *= m_kd; 32 | return lambertDir(); 33 | } 34 | 35 | virtual double eval(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 36 | { 37 | return (wi.z > 0.0 && wo.z > 0.0) ? (wo.z * m_kd / Pi) : 0.0; 38 | } 39 | 40 | virtual double evalSingular(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 41 | { 42 | return 0.0; 43 | } 44 | }; -------------------------------------------------------------------------------- /test/rough_mirror/test_rough_mirror_vmf_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 5) 27 | { 28 | std::cout << "usage: testmirror roughness theta_i numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const float roughness = StringToNumber(std::string(argv[1])); 33 | const float theta_i = StringToNumber(std::string(argv[2])); 34 | size_t numsamplesSample = StringToNumber(std::string(argv[3])); 35 | size_t numsamplesEval = StringToNumber(std::string(argv[4])); 36 | 37 | MirrorBRDF micro_brdf; 38 | NullvMFNDF ndf(µ_brdf, roughness); 39 | Microsurface brdf(&ndf); 40 | 41 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, 1.0); 42 | 43 | return 1; 44 | } -------------------------------------------------------------------------------- /test/NDFs/test_ggx_vNDF.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // test vNDF sampling for Beckmann 18 | 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 7) 27 | { 28 | std::cout << "usage: test roughx roughy theta_i phi numsamplesEval numsamplesSample \n"; 29 | exit(-1); 30 | } 31 | 32 | const double rough_x = StringToNumber(std::string(argv[1])); 33 | const double rough_y = StringToNumber(std::string(argv[2])); 34 | const double theta_i = StringToNumber(std::string(argv[3])); 35 | const double phi = StringToNumber(std::string(argv[4])); 36 | const size_t numsamplesEval = StringToNumber(std::string(argv[5])); 37 | const size_t numsamplesSample = StringToNumber(std::string(argv[6])); 38 | 39 | GGXNDF ndf(0, rough_x, rough_y); 40 | 41 | testVNDF(ndf, theta_i, phi, numsamplesEval, numsamplesSample); 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /test/NDFs/test_beckmann_vNDF.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // test vNDF sampling for Beckmann 18 | 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 7) 27 | { 28 | std::cout << "usage: test roughx roughy theta_i phi numsamplesEval numsamplesSample \n"; 29 | exit(-1); 30 | } 31 | 32 | const double rough_x = StringToNumber(std::string(argv[1])); 33 | const double rough_y = StringToNumber(std::string(argv[2])); 34 | const double theta_i = StringToNumber(std::string(argv[3])); 35 | const double phi = StringToNumber(std::string(argv[4])); 36 | const size_t numsamplesEval = StringToNumber(std::string(argv[5])); 37 | const size_t numsamplesSample = StringToNumber(std::string(argv[6])); 38 | 39 | BeckmannNDF ndf(0, rough_x, rough_y); 40 | 41 | testVNDF(ndf, theta_i, phi, numsamplesEval, numsamplesSample); 42 | 43 | return 0; 44 | } -------------------------------------------------------------------------------- /test/NDFs/test_ST_sigma.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // test student-T NDF sigma (projected area or cross-section) 18 | 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 6) 27 | { 28 | std::cout << "usage: test roughx roughy gamma du phi\n"; 29 | exit(-1); 30 | } 31 | 32 | const double rough_x = StringToNumber(std::string(argv[1])); 33 | const double rough_y = StringToNumber(std::string(argv[2])); 34 | const double gamma = StringToNumber(std::string(argv[3])); 35 | const double du = StringToNumber(std::string(argv[4])); 36 | const double phi = StringToNumber(std::string(argv[5])); 37 | 38 | StudentTNDF ndf(0, rough_x, rough_y, gamma); 39 | 40 | for (double u = -1.0; u < 1.0; u += du) 41 | { 42 | Vector3 wi(sqrt(1 - u * u), 0.0, u); 43 | std::cout << ndf.sigma(wi) << " "; 44 | } 45 | std::cout << std::endl; 46 | 47 | return 0; 48 | } -------------------------------------------------------------------------------- /include/bsdfs/conductor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | // smooth conductor 23 | class ConductorBRDF : public BSDF 24 | { 25 | public: 26 | double m_eta; // real part of ior 27 | double m_k; // imaginary part of ior 28 | 29 | ConductorBRDF(const double eta, const double k) : m_eta(eta), m_k(k){}; 30 | 31 | virtual Vector3 sample(const double ior_i, const double ior_t, const Vector3 &wi, double &weight) const 32 | { 33 | // NB: ior_t is ignored, since this comes from the conductor properties directly on creation 34 | const double FR = ConductorR(wi.z, ior_i, m_eta, m_k); 35 | weight *= FR; 36 | return reflect(wi, Vector3(0, 0, 1)); 37 | } 38 | 39 | virtual double eval(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 40 | { 41 | return 0.0; 42 | } 43 | 44 | virtual double evalSingular(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 45 | { 46 | return ConductorR(wi.z, ior_i, m_eta, m_k); 47 | } 48 | }; -------------------------------------------------------------------------------- /test/NDFs/test_ST_vNDF.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // test vNDF sampling for student-T NDF 18 | 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 8) 27 | { 28 | std::cout << "usage: test roughx roughy gamma theta_i phi numsamplesEval numsamplesSample \n"; 29 | exit(-1); 30 | } 31 | 32 | const double rough_x = StringToNumber(std::string(argv[1])); 33 | const double rough_y = StringToNumber(std::string(argv[2])); 34 | const double gamma = StringToNumber(std::string(argv[3])); 35 | const double theta_i = StringToNumber(std::string(argv[4])); 36 | const double phi = StringToNumber(std::string(argv[5])); 37 | const size_t numsamplesEval = StringToNumber(std::string(argv[6])); 38 | const size_t numsamplesSample = StringToNumber(std::string(argv[7])); 39 | 40 | StudentTNDF ndf(0, rough_x, rough_y, gamma); 41 | 42 | testVNDF(ndf, theta_i, phi, numsamplesEval, numsamplesSample); 43 | 44 | return 0; 45 | } -------------------------------------------------------------------------------- /test/rough_diffuse/test_rough_diffuse_ggx_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 7) 27 | { 28 | std::cout << "usage: test roughx roughy kd theta_i numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const double roughx = StringToNumber(std::string(argv[1])); 33 | const double roughy = StringToNumber(std::string(argv[2])); 34 | const double kd = StringToNumber(std::string(argv[3])); 35 | const float theta_i = StringToNumber(std::string(argv[4])); 36 | size_t numsamplesSample = StringToNumber(std::string(argv[5])); 37 | size_t numsamplesEval = StringToNumber(std::string(argv[6])); 38 | 39 | LambertBRDF micro_brdf(kd); 40 | GGXNDF ndf(µ_brdf, roughx, roughy); 41 | Microsurface brdf(&ndf); 42 | 43 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, 1.0); 44 | 45 | return 1; 46 | } -------------------------------------------------------------------------------- /test/NDFs/test_ST_vNDF_null.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // test vNDF sampling for student-T NDF 18 | 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 8) 27 | { 28 | std::cout << "usage: test roughness majorant gamma theta_i phi numsamplesEval numsamplesSample \n"; 29 | exit(-1); 30 | } 31 | 32 | const double roughness = StringToNumber(std::string(argv[1])); 33 | const double majorant = StringToNumber(std::string(argv[2])); 34 | const double gamma = StringToNumber(std::string(argv[3])); 35 | const double theta_i = StringToNumber(std::string(argv[4])); 36 | const double phi = StringToNumber(std::string(argv[5])); 37 | const size_t numsamplesEval = StringToNumber(std::string(argv[6])); 38 | const size_t numsamplesSample = StringToNumber(std::string(argv[7])); 39 | 40 | NullStudentTNDF ndf(0, roughness, gamma, majorant); 41 | 42 | testVNDF(ndf, theta_i, phi, numsamplesEval, numsamplesSample); 43 | 44 | return 0; 45 | } -------------------------------------------------------------------------------- /test/rough_diffuse/test_rough_diffuse_beckmann_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 7) 27 | { 28 | std::cout << "usage: test roughx roughy kd theta_i numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const double roughx = StringToNumber(std::string(argv[1])); 33 | const double roughy = StringToNumber(std::string(argv[2])); 34 | const double kd = StringToNumber(std::string(argv[3])); 35 | const float theta_i = StringToNumber(std::string(argv[4])); 36 | size_t numsamplesSample = StringToNumber(std::string(argv[5])); 37 | size_t numsamplesEval = StringToNumber(std::string(argv[6])); 38 | 39 | LambertBRDF micro_brdf(kd); 40 | BeckmannNDF ndf(µ_brdf, roughx, roughy); 41 | Microsurface brdf(&ndf); 42 | 43 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, 1.0); 44 | 45 | return 1; 46 | } -------------------------------------------------------------------------------- /test/rough_conductor/test_rough_conductor_vMF_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 7) 27 | { 28 | std::cout << "usage: testcond roughness theta_i eta k numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const double roughness = StringToNumber(std::string(argv[1])); 33 | const double theta_i = StringToNumber(std::string(argv[2])); 34 | const double eta = StringToNumber(std::string(argv[3])); 35 | const double k = StringToNumber(std::string(argv[4])); 36 | size_t numsamplesSample = StringToNumber(std::string(argv[5])); 37 | size_t numsamplesEval = StringToNumber(std::string(argv[6])); 38 | 39 | ConductorBRDF micro_brdf(eta, k); 40 | NullvMFNDF ndf(µ_brdf, roughness); 41 | Microsurface brdf(&ndf); 42 | 43 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, 1.0); 44 | 45 | return 1; 46 | } -------------------------------------------------------------------------------- /test/rough_dielectric/test_rough_dielectric_beckmann_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 7) 27 | { 28 | std::cout << "usage: testdiel roughx roughy theta_i ior numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const float rough_x = StringToNumber(std::string(argv[1])); 33 | const float rough_y = StringToNumber(std::string(argv[2])); 34 | const float theta_i = StringToNumber(std::string(argv[3])); 35 | const float ior = StringToNumber(std::string(argv[4])); 36 | size_t numsamplesSample = StringToNumber(std::string(argv[5])); 37 | size_t numsamplesEval = StringToNumber(std::string(argv[6])); 38 | 39 | DielectricBSDF micro_brdf; 40 | BeckmannNDF ndf(µ_brdf, rough_x, rough_y); 41 | Microsurface brdf(&ndf); 42 | 43 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, ior); 44 | 45 | return 1; 46 | } -------------------------------------------------------------------------------- /test/rough_mirror/test_biscale_rough_mirror_beckmann_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 6) 27 | { 28 | std::cout << "usage: testmirror roughx roughy theta_i numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const float rough_x = StringToNumber(std::string(argv[1])); 33 | const float rough_y = StringToNumber(std::string(argv[2])); 34 | const float theta_i = StringToNumber(std::string(argv[3])); 35 | size_t numsamplesSample = StringToNumber(std::string(argv[4])); 36 | size_t numsamplesEval = StringToNumber(std::string(argv[5])); 37 | 38 | MirrorBRDF micro_brdf; 39 | BeckmannNDF ndf(µ_brdf, rough_x, rough_y); 40 | Microsurface brdf(&ndf); 41 | BeckmannNDF ndf2(&brdf, rough_x, rough_y); 42 | Microsurface brdf2(&ndf2); 43 | 44 | compareEvalSample(brdf2, theta_i, numsamplesSample, numsamplesEval, 1.0, 1.0); 45 | 46 | return 1; 47 | } -------------------------------------------------------------------------------- /test/rough_conductor/test_rough_conductor_ggx_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 8) 27 | { 28 | std::cout << "usage: testmirror roughx roughy theta_i eta k numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const float rough_x = StringToNumber(std::string(argv[1])); 33 | const float rough_y = StringToNumber(std::string(argv[2])); 34 | const float theta_i = StringToNumber(std::string(argv[3])); 35 | const float eta = StringToNumber(std::string(argv[4])); 36 | const float k = StringToNumber(std::string(argv[5])); 37 | size_t numsamplesSample = StringToNumber(std::string(argv[6])); 38 | size_t numsamplesEval = StringToNumber(std::string(argv[7])); 39 | 40 | ConductorBRDF micro_brdf(eta, k); 41 | GGXNDF ndf(µ_brdf, rough_x, rough_y); 42 | Microsurface brdf(&ndf); 43 | 44 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, 1.0); 45 | 46 | return 1; 47 | } -------------------------------------------------------------------------------- /include/bsdfs/dielectric.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | // smooth dielectric 24 | class DielectricBSDF : public BSDF 25 | { 26 | public: 27 | DielectricBSDF(){}; 28 | 29 | virtual Vector3 sample(const double ior_i, const double ior_t, const Vector3 &wi, double &weight) const 30 | { 31 | const double FR = DielectricR(wi.z, ior_t / ior_i); 32 | if (RandomReal() <= FR) 33 | { 34 | return reflect(wi, Vector3(0, 0, 1)); 35 | } 36 | else 37 | { 38 | return refract(-wi, Vector3(0, 0, 1), ior_i, ior_t); 39 | } 40 | } 41 | 42 | virtual double eval(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 43 | { 44 | return 0.0; 45 | } 46 | 47 | virtual double evalSingular(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 48 | { 49 | double eta = ior_t / ior_i; 50 | if (wo.z >= 0.0) 51 | { 52 | return DielectricR(wi.z, eta); 53 | } 54 | else 55 | { 56 | return (1.0 - DielectricR(wi.z, eta)) * eta * eta; 57 | } 58 | } 59 | }; -------------------------------------------------------------------------------- /test/rough_diffuse/test_rough_diffuse_ST_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 8) 27 | { 28 | std::cout << "usage: testmirror roughx roughy gamma kd theta_i numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const float rough_x = StringToNumber(std::string(argv[1])); 33 | const float rough_y = StringToNumber(std::string(argv[2])); 34 | const float gamma = StringToNumber(std::string(argv[3])); 35 | const double kd = StringToNumber(std::string(argv[4])); 36 | const float theta_i = StringToNumber(std::string(argv[5])); 37 | size_t numsamplesSample = StringToNumber(std::string(argv[6])); 38 | size_t numsamplesEval = StringToNumber(std::string(argv[7])); 39 | 40 | LambertBRDF micro_brdf(kd); 41 | StudentTNDF ndf(µ_brdf, rough_x, rough_y, gamma); 42 | Microsurface brdf(&ndf); 43 | 44 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, 1.0); 45 | 46 | return 1; 47 | } -------------------------------------------------------------------------------- /test/rough_conductor/test_rough_conductor_beckmann_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 8) 27 | { 28 | std::cout << "usage: testmirror roughx roughy theta_i eta k numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const float rough_x = StringToNumber(std::string(argv[1])); 33 | const float rough_y = StringToNumber(std::string(argv[2])); 34 | const float theta_i = StringToNumber(std::string(argv[3])); 35 | const float eta = StringToNumber(std::string(argv[4])); 36 | const float k = StringToNumber(std::string(argv[5])); 37 | size_t numsamplesSample = StringToNumber(std::string(argv[6])); 38 | size_t numsamplesEval = StringToNumber(std::string(argv[7])); 39 | 40 | ConductorBRDF micro_brdf(eta, k); 41 | BeckmannNDF ndf(µ_brdf, rough_x, rough_y); 42 | Microsurface brdf(&ndf); 43 | 44 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, 1.0); 45 | 46 | return 1; 47 | } -------------------------------------------------------------------------------- /test/rough_dielectric/test_rough_dielectric_ST_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 8) 27 | { 28 | std::cout << "usage: testdiel roughx roughy gamma theta_i ior numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const double rough_x = StringToNumber(std::string(argv[1])); 33 | const double rough_y = StringToNumber(std::string(argv[2])); 34 | const double gamma = StringToNumber(std::string(argv[3])); 35 | const double theta_i = StringToNumber(std::string(argv[4])); 36 | const double ior = StringToNumber(std::string(argv[5])); 37 | size_t numsamplesSample = StringToNumber(std::string(argv[6])); 38 | size_t numsamplesEval = StringToNumber(std::string(argv[7])); 39 | 40 | DielectricBSDF micro_brdf; 41 | StudentTNDF ndf(µ_brdf, rough_x, rough_y, gamma); 42 | Microsurface brdf(&ndf); 43 | 44 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, ior); 45 | 46 | return 1; 47 | } -------------------------------------------------------------------------------- /test/rough_dielectric/test_rough_dielectric_null_ST_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 8) 27 | { 28 | std::cout << "usage: testdiel roughness majorant gamma theta_i ior numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const double roughness = StringToNumber(std::string(argv[1])); 33 | const double majorant = StringToNumber(std::string(argv[2])); 34 | const double gamma = StringToNumber(std::string(argv[3])); 35 | const double theta_i = StringToNumber(std::string(argv[4])); 36 | const double ior = StringToNumber(std::string(argv[5])); 37 | size_t numsamplesSample = StringToNumber(std::string(argv[6])); 38 | size_t numsamplesEval = StringToNumber(std::string(argv[7])); 39 | 40 | DielectricBSDF micro_brdf; 41 | NullStudentTNDF ndf(µ_brdf, roughness, gamma, majorant); 42 | Microsurface brdf(&ndf); 43 | 44 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, ior); 45 | 46 | return 1; 47 | } -------------------------------------------------------------------------------- /include/bsdfs/blend_BSDF.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | // smooth mirror 23 | class BlendBSDF : public BSDF 24 | { 25 | public: 26 | const BSDF *m_bsdfA; 27 | const BSDF *m_bsdfB; 28 | const double m_mix_A; 29 | 30 | BlendBSDF(const BSDF *bsdfA, const BSDF *bsdfB, double mix_A) : m_bsdfA(bsdfA), m_bsdfB(bsdfB), m_mix_A(mix_A){}; 31 | 32 | virtual Vector3 sample(const double ior_i, const double ior_t, const Vector3 &wi, double &weight) const 33 | { 34 | if (RandomReal() < m_mix_A) 35 | { 36 | return m_bsdfA->sample(ior_i, ior_t, wi, weight); 37 | } 38 | else 39 | { 40 | return m_bsdfB->sample(ior_i, ior_t, wi, weight); 41 | } 42 | } 43 | 44 | virtual double eval(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 45 | { 46 | return m_mix_A * m_bsdfA->eval(ior_i, ior_t, wi, wo) + (1.0 - m_mix_A) * m_bsdfB->eval(ior_i, ior_t, wi, wo); 47 | } 48 | 49 | virtual double evalSingular(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 50 | { 51 | return m_mix_A * m_bsdfA->evalSingular(ior_i, ior_t, wi, wo) + (1.0 - m_mix_A) * m_bsdfB->evalSingular(ior_i, ior_t, wi, wo); 52 | } 53 | }; -------------------------------------------------------------------------------- /test/rough_conductor/test_rough_conductor_null_ST_eval_sample.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 9) 27 | { 28 | std::cout << "usage: testcond roughness majorant gamma theta_i eta k numsamplesSample numsamplesEval \n"; 29 | exit(-1); 30 | } 31 | 32 | const double roughness = StringToNumber(std::string(argv[1])); 33 | const double majorant = StringToNumber(std::string(argv[2])); 34 | const double gamma = StringToNumber(std::string(argv[3])); 35 | const double theta_i = StringToNumber(std::string(argv[4])); 36 | const double eta = StringToNumber(std::string(argv[5])); 37 | const double k = StringToNumber(std::string(argv[6])); 38 | size_t numsamplesSample = StringToNumber(std::string(argv[7])); 39 | size_t numsamplesEval = StringToNumber(std::string(argv[8])); 40 | 41 | ConductorBRDF micro_brdf(eta, k); 42 | NullStudentTNDF ndf(µ_brdf, roughness, gamma, majorant); 43 | Microsurface brdf(&ndf); 44 | 45 | compareEvalSample(brdf, theta_i, numsamplesSample, numsamplesEval, 1.0, 1.0); 46 | 47 | return 1; 48 | } -------------------------------------------------------------------------------- /include/bsdf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | class BSDF 22 | { 23 | public: 24 | // NB: this function takes an input weight and MODIFIES it 25 | virtual Vector3 sample(const double ior_i, const double ior_t, const Vector3 &wi, double &io_weight) const = 0; 26 | 27 | // sample in a space oriented to normal wm 28 | Vector3 sample(const double ior_i, const double ior_t, const Vector3 &wi, double &io_weight, const Vector3 &wm) const 29 | { 30 | Vector3 w1(0, 0, 0); 31 | Vector3 w2(0, 0, 0); 32 | buildOrthonormalBasis(w1, w2, wm); 33 | 34 | Vector3 wi_local(dot(wi, w1), dot(wi, w2), dot(wi, wm)); 35 | Vector3 wo_local = sample(ior_i, ior_t, wi_local, io_weight); 36 | 37 | return wo_local.x * w1 + wo_local.y * w2 + wo_local.z * wm; 38 | } 39 | 40 | // BRDF * cos(theta_o) evaluation 41 | virtual double eval(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const = 0; 42 | double eval(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo, const Vector3 &wm) const 43 | { 44 | Vector3 w1(0, 0, 0); 45 | Vector3 w2(0, 0, 0); 46 | buildOrthonormalBasis(w1, w2, wm); 47 | 48 | Vector3 wi_local(dot(wi, w1), dot(wi, w2), dot(wi, wm)); 49 | Vector3 wo_local(dot(wo, w1), dot(wo, w2), dot(wo, wm)); 50 | 51 | return eval(ior_i, ior_t, wi_local, wo_local); 52 | } 53 | 54 | virtual double evalSingular(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const = 0; 55 | // sample in a space oriented to normal wm 56 | double evalSingular(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo, const Vector3 &wm) const 57 | { 58 | Vector3 w1(0, 0, 0); 59 | Vector3 w2(0, 0, 0); 60 | buildOrthonormalBasis(w1, w2, wm); 61 | 62 | Vector3 wi_local(dot(wi, w1), dot(wi, w2), dot(wi, wm)); 63 | Vector3 wo_local(dot(wo, w1), dot(wo, w2), dot(wo, wm)); 64 | 65 | return evalSingular(ior_i, ior_t, wi_local, wo_local); 66 | } 67 | }; -------------------------------------------------------------------------------- /include/random.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | ////////////////////////////////////////////////////////////////////////////////// 23 | // Random numbers 24 | ////////////////////////////////////////////////////////////////////////////////// 25 | 26 | double RandomReal() 27 | { 28 | return drand48(); 29 | } 30 | 31 | double RandomReal(double a, double b) 32 | { 33 | double r = drand48(); 34 | return r * b + (1.0 - r) * a; 35 | } 36 | 37 | double RandomGauss() 38 | { 39 | return sqrt(2.0) * cos(2 * M_PI * RandomReal()) * sqrt(-log(RandomReal())); 40 | } 41 | 42 | std::mt19937 g_mt; 43 | typedef std::gamma_distribution<> D_gamma; 44 | 45 | // random Gamma variate for general shape parameter a > 0.0 46 | double RandomGamma(const double a) 47 | { 48 | 49 | D_gamma r(a, 1.0); 50 | return r(g_mt); 51 | } 52 | 53 | ////////////////////////////////////////////////////////////////////////////////// 54 | // Random Directions 55 | ////////////////////////////////////////////////////////////////////////////////// 56 | 57 | Vector2 diskSample2D(const double radius) 58 | { 59 | const double phi = RandomReal(0.0, 2 * M_PI); 60 | return radius * sqrt(RandomReal()) * Vector2(cos(phi), sin(phi)); 61 | } 62 | 63 | Vector3 diskSample(const double radius) 64 | { 65 | const double phi = RandomReal(0.0, 2 * M_PI); 66 | return radius * sqrt(RandomReal()) * Vector3(cos(phi), sin(phi), 0.0); 67 | } 68 | 69 | Vector3 isotropicDir() 70 | { 71 | const double w = RandomReal(-1.0, 1.0); 72 | const double p = RandomReal(0.0, 2.0 * M_PI); 73 | const double s = sqrt(1.0 - w * w); 74 | return Vector3(w, s * cos(p), s * sin(p)); 75 | } 76 | 77 | Vector3 lambertDir() 78 | { 79 | const double w = sqrt(RandomReal()); 80 | const double p = RandomReal(0.0, 2.0 * M_PI); 81 | const double s = sqrt(1.0 - w * w); 82 | return Vector3(s * cos(p), s * sin(p), w); // z axis is the normal 83 | } 84 | 85 | // sample a Lambertian direction about normal n: 86 | Vector3 lambertDir(const Vector3 &n) 87 | { 88 | const Vector3 local(lambertDir()); 89 | Vector3 x, y; 90 | buildOrthonormalBasis(x, y, n); 91 | return x * local.x + y * local.y + n * local.z; 92 | } 93 | -------------------------------------------------------------------------------- /test/NDFs/test_vMF_sigma.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // test vMF NDF sigma (projected area or cross-section) 18 | 19 | #include 20 | #include 21 | 22 | int main(int argc, char **argv) 23 | { 24 | srand48(time(NULL)); 25 | 26 | if (argc != 3) 27 | { 28 | std::cout << "usage: test roughness du\n"; 29 | exit(-1); 30 | } 31 | 32 | const double roughness = StringToNumber(std::string(argv[1])); 33 | const double du = StringToNumber(std::string(argv[2])); 34 | 35 | NullvMFNDF ndf(0, roughness); 36 | 37 | for (double u = -1.0; u < 1.0; u += du) 38 | { 39 | Vector3 wi(sqrt(1 - u * u), 0.0, u); 40 | std::cout << ndf.sigma(wi) << " "; 41 | } 42 | std::cout << std::endl; 43 | 44 | const size_t NUMSAMPLES = 100000; 45 | 46 | for (double u = -1.0; u < 1.0; u += du) 47 | { 48 | double sigma = 0.0; 49 | for (size_t j = 0; j < NUMSAMPLES; j++) 50 | { 51 | Vector2 diskOffset = diskSample2D(0.999999); 52 | 53 | // microfacet normal / sphere position - pre rotation 54 | Vector3 mPR(diskOffset.x, diskOffset.y, sqrt(1.0 - diskOffset.x * diskOffset.x - diskOffset.y * diskOffset.y)); 55 | // rotate to the same cos(theta) 56 | Vector3 mPR2(mPR.x * u + sqrt(1.0 - u * u) * mPR.z, mPR.y, u * mPR.z - mPR.x * sqrt(1.0 - u * u)); 57 | // rotate to match azimuth 58 | const double phi = atan2(sqrt(1 - u * u), 0.0); 59 | const double cosphi = cos(phi); 60 | const double sinphi = sin(phi); 61 | // this is where we strike the unit sphere of the microsurface NDFs - this is then the microfacet normal 62 | Vector3 microspherePos(-cosphi * mPR2.y + sinphi * mPR2.x, sinphi * mPR2.y + cosphi * mPR2.x, mPR2.z); 63 | 64 | // null scattering unless there is enough density for this microfacet normal - cosine factor is already accounted 65 | // for in the disk sampling above 66 | if (RandomReal() < ndf.D(microspherePos)) 67 | { 68 | sigma += 1.0; 69 | } 70 | } 71 | std::cout << sigma / double(NUMSAMPLES) << " "; 72 | } 73 | std::cout << std::endl; 74 | 75 | return 0; 76 | } -------------------------------------------------------------------------------- /include/math_functions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | const double sign(const double a) 22 | { 23 | if (a > 0.0) 24 | { 25 | return 1.0; 26 | } 27 | else 28 | { 29 | return -1.0; 30 | } 31 | } 32 | 33 | bool IsFiniteNumber(float x) 34 | { 35 | return (x <= FLT_MAX && x >= -FLT_MAX); 36 | } 37 | 38 | bool IsFiniteNumber(double x) 39 | { 40 | return (x <= DBL_MAX && x >= -DBL_MAX); 41 | } 42 | 43 | double erfinv(double x) 44 | { 45 | double w, p; 46 | w = -log((1.0 - x) * (1.0 + x)); 47 | if (w < 5.0) 48 | { 49 | w = w - 2.500000; 50 | p = 2.81022636e-08; 51 | p = 3.43273939e-07 + p * w; 52 | p = -3.5233877e-06 + p * w; 53 | p = -4.39150654e-06 + p * w; 54 | p = 0.00021858087 + p * w; 55 | p = -0.00125372503 + p * w; 56 | p = -0.00417768164 + p * w; 57 | p = 0.246640727 + p * w; 58 | p = 1.50140941 + p * w; 59 | } 60 | else 61 | { 62 | w = sqrt(w) - 3.000000; 63 | p = -0.000200214257; 64 | p = 0.000100950558 + p * w; 65 | p = 0.00134934322 + p * w; 66 | p = -0.00367342844 + p * w; 67 | p = 0.00573950773 + p * w; 68 | p = -0.0076224613 + p * w; 69 | p = 0.00943887047 + p * w; 70 | p = 1.00167406 + p * w; 71 | p = 2.83297682 + p * w; 72 | } 73 | return p * x; 74 | } 75 | 76 | static double abgam(double x) 77 | { 78 | double gam[10], 79 | temp; 80 | 81 | gam[0] = 1. / 12.; 82 | gam[1] = 1. / 30.; 83 | gam[2] = 53. / 210.; 84 | gam[3] = 195. / 371.; 85 | gam[4] = 22999. / 22737.; 86 | gam[5] = 29944523. / 19733142.; 87 | gam[6] = 109535241009. / 48264275462.; 88 | temp = 0.5 * log(2 * M_PI) - x + (x - 0.5) * log(x) + gam[0] / (x + gam[1] / (x + gam[2] / (x + gam[3] / (x + gam[4] / (x + gam[5] / (x + gam[6] / x)))))); 89 | 90 | return temp; 91 | } 92 | 93 | static double mygamma(double x) 94 | { 95 | double result; 96 | result = exp(abgam(x + 5)) / (x * (x + 1) * (x + 2) * (x + 3) * (x + 4)); 97 | return result; 98 | } 99 | 100 | static double beta(double m, double n) 101 | { 102 | return (mygamma(m) * mygamma(n) / mygamma(m + n)); 103 | } -------------------------------------------------------------------------------- /include/bsdfs/NDFs/BlendedNDF.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | ////////////////////////////////////////////////////////////////////////////////// 26 | // BlendedNDF 27 | ////////////////////////////////////////////////////////////////////////////////// 28 | 29 | class BlendedNDF : public NDF 30 | { 31 | public: 32 | BlendedNDF(const NDF *ndf1, const NDF *ndf2, const double w1) // mix between NDFs ndf1 and ndf2 where ndf1 has a weight of w1 in the mixture 33 | : NDF(ndf1->m_bsdf), m_w1(w1), m_ndf1(ndf1), m_ndf2(ndf2){}; 34 | double m_w1; 35 | const NDF *m_ndf1; 36 | const NDF *m_ndf2; 37 | 38 | public: 39 | // distribution of normals (NDF) 40 | virtual double D(const Vector3 &wm) const; 41 | // sample the VNDF - for debugging purposes 42 | virtual Vector3 sampleD_wi(const Vector3 &wi) const; 43 | 44 | public: 45 | // cross section 46 | virtual double sigma(const Vector3 &wi) const; 47 | 48 | // sample a free-path length along direction wr from starting height hr 49 | // if a collision occurs before escape, return the normal (out_wm) and BSDF (out_bsdf) of the sampled facet 50 | virtual double sampleHeight(const Vector3 &wr, const double hr, const bool outside, 51 | Vector3 &out_wm, const BSDF *&out_bsdf) const; 52 | }; 53 | 54 | double BlendedNDF::D(const Vector3 &wm) const 55 | { 56 | return m_w1 * m_ndf1->D(wm) + (1.0 - m_w1) * m_ndf2->D(wm); 57 | } 58 | 59 | double BlendedNDF::sigma(const Vector3 &wi) const 60 | { 61 | return m_w1 * m_ndf1->sigma(wi) + (1.0 - m_w1) * m_ndf2->sigma(wi); 62 | } 63 | 64 | double BlendedNDF::sampleHeight(const Vector3 &wr, const double hr, const bool outside, 65 | Vector3 &out_wm, const BSDF *&out_bsdf) const 66 | { 67 | const double sigma_t = sigma(-wr); 68 | 69 | if (sigma_t < 0.00001) 70 | return (wr.z < 0.0) ? hr : 0.0; 71 | 72 | const double dh = -log(RandomReal()) * wr.z / sigma_t; 73 | 74 | const double h = std::min(0.0, hr) + dh; 75 | 76 | if (h < 0.0) 77 | { 78 | out_wm = sampleD_wi(-wr); 79 | out_bsdf = m_bsdf; // uniform microsurface 80 | } 81 | 82 | return h; 83 | } 84 | 85 | Vector3 BlendedNDF::sampleD_wi(const Vector3 &wi) const 86 | { 87 | double sigma1 = m_ndf1->sigma(wi); 88 | double sigma2 = m_ndf2->sigma(wi); 89 | double p1 = m_w1 * sigma1 / (m_w1 * sigma1 + (1.0 - m_w1) * sigma2); 90 | if (RandomReal() < p1) 91 | { 92 | return m_ndf1->sampleD_wi(wi); 93 | } 94 | else 95 | { 96 | return m_ndf2->sampleD_wi(wi); 97 | } 98 | } -------------------------------------------------------------------------------- /test/NDFs/test_null_ST_sigma.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | int main(int argc, char **argv) 22 | { 23 | srand48(time(NULL)); 24 | 25 | if (argc != 5) 26 | { 27 | std::cout << "usage: testsigma roughness majorant gamma du \n"; 28 | exit(-1); 29 | } 30 | 31 | const double roughness = StringToNumber(std::string(argv[1])); 32 | const double majorant = StringToNumber(std::string(argv[2])); 33 | const double gamma = StringToNumber(std::string(argv[3])); 34 | const double du = StringToNumber(std::string(argv[4])); 35 | 36 | std::cout << "roughness: " << roughness << std::endl; 37 | std::cout << "majorant: " << majorant << std::endl; 38 | std::cout << "gamma: " << gamma << std::endl; 39 | std::cout << "du: " << du << std::endl; 40 | 41 | DielectricBSDF micro_brdf; 42 | NullStudentTNDF ndf(µ_brdf, roughness, gamma, majorant); 43 | Microsurface brdf(&ndf); 44 | 45 | for (double u = -0.999; u <= 0.98; u += du) 46 | { 47 | Vector3 w(sqrt(1.0 - u * u), 0.0, u); 48 | std::cout << ndf.sigma(w) << " "; 49 | } 50 | 51 | std::cout << std::endl; 52 | 53 | const size_t NUMSAMPLES = 100000; 54 | 55 | for (double u = -1.0; u < 1.0; u += du) 56 | { 57 | double sigma = 0.0; 58 | for (size_t j = 0; j < NUMSAMPLES; j++) 59 | { 60 | Vector2 diskOffset = diskSample2D(0.999999); 61 | 62 | // microfacet normal / sphere position - pre rotation 63 | Vector3 mPR(diskOffset.x, diskOffset.y, sqrt(1.0 - diskOffset.x * diskOffset.x - diskOffset.y * diskOffset.y)); 64 | // rotate to the same cos(theta) 65 | Vector3 mPR2(mPR.x * u + sqrt(1.0 - u * u) * mPR.z, mPR.y, u * mPR.z - mPR.x * sqrt(1.0 - u * u)); 66 | // rotate to match azimuth 67 | const double phi = atan2(sqrt(1 - u * u), 0.0); 68 | const double cosphi = cos(phi); 69 | const double sinphi = sin(phi); 70 | // this is where we strike the unit sphere of the microsurface NDFs - this is then the microfacet normal 71 | Vector3 microspherePos(-cosphi * mPR2.y + sinphi * mPR2.x, sinphi * mPR2.y + cosphi * mPR2.x, mPR2.z); 72 | 73 | // null scattering unless there is enough density for this microfacet normal - cosine factor is already accounted 74 | // for in the disk sampling above 75 | if (RandomReal() < ndf.D(microspherePos) / majorant) 76 | { 77 | sigma += 1.0; 78 | } 79 | } 80 | std::cout << sigma / double(NUMSAMPLES) << " "; 81 | } 82 | std::cout << std::endl; 83 | 84 | return 1; 85 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | ## FacetForce Contribution Rules 3 | 4 | #### Pull Requests 5 | Developer workflow for code contributions is as follows: 6 | 7 | 1. Developers must first [fork](https://help.github.com/en/articles/fork-a-repo) the [upstream](https://github.com/nvlabs/facet-forge) FacetForge repository. 8 | 9 | 2. Git clone the forked repository and push changes to the personal fork. 10 | 11 | ```bash 12 | git clone https://github.com/YOUR_USERNAME/YOUR_FORK.git FacetForge 13 | # Checkout the targeted branch and commit changes 14 | # Push the commits to a branch on the fork (remote). 15 | git push -u origin : 16 | ``` 17 | 18 | 3. Once the code changes are staged on the fork and ready for review, a [Pull Request](https://help.github.com/en/articles/about-pull-requests) (PR) can be [requested](https://help.github.com/en/articles/creating-a-pull-request) to merge the changes from a branch of the fork into a selected branch of upstream. 19 | * While under review, mark your PRs as work-in-progress by prefixing the PR title with [WIP]. 20 | 21 | 4. Since there is no CI/CD process in place yet, the PR will be accepted and the corresponding issue closed only after adequate testing has been completed, manually, by the developer and/or FacetForce engineer reviewing the code. 22 | 23 | 24 | #### Signing Your Work 25 | 26 | * We require that all contributors "sign-off" on their commits. This certifies that the contribution is your original work, or you have rights to submit it under the same license, or a compatible license. 27 | 28 | * Any contribution which contains commits that are not Signed-Off will not be accepted. 29 | 30 | * To sign off on a commit you simply use the `--signoff` (or `-s`) option when committing your changes: 31 | ```bash 32 | $ git commit -s -m "Add cool feature." 33 | ``` 34 | This will append the following to your commit message: 35 | ``` 36 | Signed-off-by: Your Name 37 | ``` 38 | 39 | * Full text of the DCO: 40 | 41 | ``` 42 | Developer Certificate of Origin 43 | Version 1.1 44 | 45 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 46 | 1 Letterman Drive 47 | Suite D4700 48 | San Francisco, CA, 94129 49 | 50 | Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. 51 | ``` 52 | 53 | ``` 54 | Developer's Certificate of Origin 1.1 55 | 56 | By making a contribution to this project, I certify that: 57 | 58 | (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or 59 | 60 | (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or 61 | 62 | (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. 63 | 64 | (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. 65 | ``` 66 | -------------------------------------------------------------------------------- /include/bsdfs/NDFs/GGX.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | ////////////////////////////////////////////////////////////////////////////////// 22 | // GGXNDF 23 | ////////////////////////////////////////////////////////////////////////////////// 24 | 25 | class GGXNDF : public ShapeInvariantNDF 26 | { 27 | public: 28 | GGXNDF(const BSDF *bsdf, const double roughness_x, const double roughness_y) 29 | : ShapeInvariantNDF(bsdf, roughness_x, roughness_y) 30 | { 31 | } 32 | 33 | // distribution of slopes 34 | virtual double P22(const double slope_x, const double slope_y) const; 35 | // cross section 36 | virtual double sigma(const Vector3 &wi) const; 37 | // sample the distribution of visible slopes with roughness=1.0 38 | virtual Vector2 sampleP22_11(const double theta_i) const; 39 | }; 40 | 41 | double GGXNDF::P22(const double slope_x, const double slope_y) const 42 | { 43 | const double tmp = 1.0 + slope_x * slope_x / (m_roughness_x * m_roughness_x) + slope_y * slope_y / (m_roughness_y * m_roughness_y); 44 | return 1.0 / (M_PI * m_roughness_x * m_roughness_y) / (tmp * tmp); 45 | } 46 | 47 | Vector2 GGXNDF::sampleP22_11(const double theta_i) const 48 | { 49 | Vector2 slope; 50 | 51 | const double U = RandomReal(); 52 | const double U_2 = RandomReal(); 53 | 54 | if (theta_i < 0.0001) 55 | { 56 | const double r = sqrt(U / (1 - U)); 57 | const double phi = 2 * Pi * U_2; 58 | slope.x = r * cos(phi); 59 | slope.y = r * sin(phi); 60 | return slope; 61 | } 62 | 63 | // constant 64 | const double sin_theta_i = sin(theta_i); 65 | const double cos_theta_i = cos(theta_i); 66 | const double tan_theta_i = sin_theta_i / cos_theta_i; 67 | 68 | // slope associated to theta_i 69 | const double slope_i = cos_theta_i / sin_theta_i; 70 | 71 | // projected area 72 | const double sigma = 0.5 * (cos_theta_i + 1); 73 | if (sigma < 0.0001f || sigma != sigma) 74 | return Vector2(0, 0); 75 | 76 | // normalization coefficient 77 | const double c = 1.0 / sigma; 78 | 79 | const double A = 2 * U / cos_theta_i / c - 1; 80 | const double B = tan_theta_i; 81 | const double tmp = 1 / (A * A - 1); 82 | 83 | const double D = sqrt(std::max(0.0, B * B * tmp * tmp - (A * A - B * B) * tmp)); 84 | const double slope_x_1 = B * tmp - D; 85 | const double slope_x_2 = B * tmp + D; 86 | slope.x = (A < 0.0 || slope_x_2 > 1.0 / tan_theta_i) ? slope_x_1 : slope_x_2; 87 | slope.y = sqrt(-1 - slope.x * slope.x + (1 + slope.x * slope.x) / pow(1 - U_2, 2.0 / 3.0)) * sin(2 * Pi * RandomReal()); 88 | 89 | return slope; 90 | } 91 | 92 | double GGXNDF::sigma(const Vector3 &wi) const 93 | { 94 | if (wi.z > 0.9999) 95 | return 1.0; 96 | if (wi.z < -0.9999) 97 | return 0.0; 98 | 99 | const double theta_i = acos(wi.z); 100 | const double sin_theta_i = sin(theta_i); 101 | const double roughnessi = roughness_i(wi); 102 | 103 | return 0.5 * (wi.z + sqrt(wi.z * wi.z + sin_theta_i * sin_theta_i * roughnessi * roughnessi)); 104 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FacetForge 2 | 3 | FacetForge is a reference C++ codebase that provides benchmark implementations of microfacet BSDFs with unbiased multiple scattering. Unique capabilities: 4 | - Quickly add new NDFs (including full-sphere NDFs) by implementing one simple function (the NDF itself) 5 | - Visible-distribution-of-normals sampling for Student-T NDFs 6 | - Support for biscale roughness: put any BSDF onto the microsurface, including other microsurface BSDFs 7 | 8 | The initial release of this codebase was part of: 9 | > __Student-T and Beyond: Practical Tools for Multiple-Scattering BSDFs with General NDFs__ 10 | > [Eugene d'Eon](http://eugenedeon.com) 11 | > _ACM (__SIGGRAPH__) Talks, August 2023_ 12 | > __[Paper](assets/deon2023student.pdf) / [Supplemental](assets/deon2023studentsupp.pdf)__ 13 | 14 | We will update the codebase over time. Pull requests are encouraged. For guidelines, see [CONTRIBUTING](CONTRIBUTING.md). 15 | 16 | ## Usage 17 | 18 | ### Microsurface 19 | 20 | Different from other approaches, in FacetForge a Microsurface is an operator that takes as input a BSDF and an NDF and outputs a new BSDF. Therefore, there are no RoughDielectric or RoughConductor BSDFs. To create a rough conductor, for example, you first create a smooth ConductorBRDF, plug it into your chosen NDF, and plug that into the Microsurface class to create a new BRDF: 21 | ``` 22 | ConductorBRDF micro_brdf(eta, k); // take a smooth conductor BRDF 23 | GGXNDF ndf(µ_brdf, rough_x, rough_y); // and assign it to microfacets with a GGX distribution 24 | Microsurface macro_brdf(&ndf); // and feed this to a Microsurface operator to create a rough conductor BRDF 25 | ``` 26 | More examples of rough BSDFs are included in the `test` folder. 27 | 28 | ### NDFs 29 | 30 | NDFs can be added to FacetForge in two ways: 31 | - heightfield NDFs can derive from the `ShapeInvariantNDF` and must implement the `P22` slope distribution (which defines the NDF), sampling of the visible distribution of slopes when both roughnesses are equal to unity, and the cross section as a function of direction over the full sphere 32 | - general full-sphere NDFs can derive from the `NullNDF` and implement the NDF `D` together with a majorant 33 | 34 | ## Limitations 35 | 36 | The primary purpose of the codebase is to implement flexible microfacet BSDFs with general NDFs. Achieving this goal comes with some limitations (some of which are straightforward to remove, some not), including: 37 | - `pdf()` is not implemented 38 | - NullNDFs will suffer crippling inefficiency for very low roughness (analogous to null scattering through a mostly empty inhomogeneous medium with a very large majorant) 39 | - Analytic `eval` for single-scattering and specular facets is not currently implemented 40 | - Polarization is not currently supported 41 | - There is no notion of spectrum or color - radiance is monochromatic `double` 42 | 43 | ## Assumptions 44 | 45 | The code has three parts: 46 | - C++ implementation (generally portable) in the `include` folder 47 | - assumes `drand48()` 48 | - tested on Mac OS Arm M1 with `clang++` 49 | - assumes `std::mt19937` for gamma random variates (for Student-T NDF sampling) 50 | - Mathematica tests (described below) in the `test` folder 51 | 52 | ## Running the Tests 53 | 54 | The `test` folder contains Mathematica notebooks that compare `eval` and `sample` for various BSDFs. To use the tests: 55 | - In Mathematica `SetDirectory[]` to the `facet-forge` root dir where you cloned to 56 | - (optional): edit the arguments of the test to vary roughness parameters, iors, incidence angle, numbers of samples 57 | - run the full notebook, which will: 58 | - compile the required C++ test using `clang++` 59 | - execute the test, dumping the output to a `.txt` file 60 | - load the output and compare 2D histograms and 1D curves that compare `eval` and `sample` 61 | 62 | ## Thanks 63 | 64 | This codebase is an extension of Eric Heitz's original implementation from the 2016 SIGGRAPH paper that introduced multiple scattering to microfacet theory: 65 | https://eheitzresearch.wordpress.com/240-2/ 66 | 67 | ## License and Citation 68 | 69 | ```bibtex 70 | @incollection{deon2023, 71 | author = {Eugene d'Eon}, 72 | title = {Student-T and Beyond: Practical Tools for Multiple-Scattering BSDFs with General NDFs}, 73 | booktitle={ACM SIGGRAPH 2023 Talks}, 74 | pages={1--2}, 75 | year={2023}, 76 | url={https://doi.org/10.1145/3587421.3595417} 77 | } 78 | ``` 79 | 80 | Copyright © 2023, NVIDIA Corporation. All rights reserved. 81 | 82 | This code is made available under the Apache-2.0 license. 83 | -------------------------------------------------------------------------------- /include/bsdfs/NDF.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | ////////////////////////////////////////////////////////////////////////////////// 24 | // NDF 25 | ////////////////////////////////////////////////////////////////////////////////// 26 | 27 | class NDF 28 | { 29 | public: 30 | NDF(const BSDF *bsdf) 31 | : m_bsdf(bsdf) 32 | { 33 | } 34 | 35 | public: 36 | // BSDF on the microfacets: 37 | const BSDF *m_bsdf; 38 | 39 | public: 40 | // distribution of normals (NDF) 41 | virtual double D(const Vector3 &wm) const = 0; 42 | // distribution of visible normals (vNDF) 43 | virtual double D_wi(const Vector3 &wi, const Vector3 &wm) const; 44 | 45 | // only used for ShapeInvariant NDF - and included in NullNDF for debugging purposes 46 | virtual Vector3 sampleD_wi(const Vector3 &wi) const = 0; 47 | 48 | public: 49 | // cross section (projected area) sigma_t when moving in direction wi 50 | virtual double sigma(const Vector3 &wi) const = 0; 51 | 52 | // sample a free-path length along direction wr from starting height hr 53 | // if a collision occurs before escape, return the normal (out_wm) and BSDF (out_bsdf) of the sampled facet 54 | virtual double sampleHeight(const Vector3 &wr, const double hr, const bool outside, 55 | Vector3 &out_wm, const BSDF *&out_bsdf) const = 0; 56 | 57 | virtual double evalPhaseFunctionSingular(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo, const bool wi_outside, const bool wo_outside) const; 58 | // transmittance from a depth h0 in the half space along a ray with direction wi 59 | virtual double G_1(const Vector3 &wi, const double h0) const; 60 | }; 61 | 62 | double NDF::G_1(const Vector3 &wi, const double h0) const 63 | { 64 | if (wi.z <= 0.0) 65 | return 0.0; 66 | 67 | if (h0 >= 0.0) 68 | return 1.0; 69 | 70 | const double a = sigma(-wi); 71 | return exp(h0 / wi.z * a); // exponential transmittance 72 | } 73 | 74 | double NDF::D_wi(const Vector3 &wi, const Vector3 &wm) const 75 | { 76 | // normalization coefficient 77 | const double l_sigma = sigma(wi); 78 | if (l_sigma == 0) 79 | return 0; 80 | const double c = 1.0 / l_sigma; 81 | 82 | return c * std::max(0.0, dot(wi, wm)) * D(wm); 83 | } 84 | 85 | double NDF::evalPhaseFunctionSingular(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo, const bool wi_outside, const bool wo_outside) const 86 | { 87 | const double etaRatio = ior_t / ior_i; 88 | double eta = wi_outside ? etaRatio : 1.0 / etaRatio; 89 | 90 | if (wi_outside == wo_outside) // reflection 91 | { 92 | // half vector 93 | const Vector3 wh = normalize(wi + wo); 94 | // value 95 | const double value = (wi_outside) ? (0.25 * D_wi(wi, wh) / dot(wi, wh) * m_bsdf->evalSingular(1.0, eta, wi, wo, wh)) : (0.25 * D_wi(-wi, -wh) / dot(-wi, -wh) * m_bsdf->evalSingular(1.0, eta, -wi, -wo, -wh)); 96 | return value; 97 | } 98 | else // transmission 99 | { 100 | Vector3 wh = -normalize(wi + wo * eta); 101 | wh *= (wi_outside) ? (sign(wh.z)) : (-sign(wh.z)); 102 | 103 | if (dot(wh, wi) < 0) 104 | return 0; 105 | 106 | float value; 107 | if (wi_outside) 108 | { 109 | value = m_bsdf->evalSingular(1.0, eta, wi, wo, wh) * 110 | D_wi(wi, wh) * std::max(0.0, -dot(wo, wh)) * 111 | 1.0 / pow(dot(wi, wh) + eta * dot(wo, wh), 2.0); 112 | } 113 | else 114 | { 115 | value = m_bsdf->evalSingular(wi_outside ? eta : 1.0, wi_outside ? 1.0 : eta, -wi, -wo, -wh) * 116 | D_wi(-wi, -wh) * std::max(0.0, -dot(-wo, -wh)) * 117 | 1.0 / pow(dot(-wi, -wh) + eta * dot(-wo, -wh), 2.0); 118 | } 119 | 120 | return value; 121 | } 122 | } -------------------------------------------------------------------------------- /include/bsdfs/NDFs/ShapeInvariantNDF.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | ////////////////////////////////////////////////////////////////////////////////// 26 | // Shape Invariant NDF 27 | ////////////////////////////////////////////////////////////////////////////////// 28 | 29 | class ShapeInvariantNDF : public NDF 30 | { 31 | public: 32 | ShapeInvariantNDF(const BSDF *bsdf, const double roughness_x, const double roughness_y) 33 | : NDF(bsdf), m_roughness_x(roughness_x), m_roughness_y(roughness_y) 34 | { 35 | } 36 | 37 | public: 38 | // roughness 39 | double m_roughness_x, m_roughness_y; 40 | // projected roughness in wi 41 | double roughness_i(const Vector3 &wi) const; 42 | 43 | public: 44 | // distribution of normals (NDF) 45 | virtual double D(const Vector3 &wm) const; 46 | // sample the VNDF 47 | virtual Vector3 sampleD_wi(const Vector3 &wi) const; 48 | 49 | public: 50 | // distribution of slopes 51 | virtual double P22(const double slope_x, const double slope_y) const = 0; 52 | // cross section 53 | virtual double sigma(const Vector3 &wi) const = 0; 54 | // sample the distribution of visible slopes with roughness=1.0 55 | virtual Vector2 sampleP22_11(const double theta_i) const = 0; 56 | 57 | // sample a free-path length along direction wr from starting height hr 58 | // if a collision occurs before escape, return the normal (out_wm) and BSDF (out_bsdf) of the sampled facet 59 | virtual double sampleHeight(const Vector3 &wr, const double hr, const bool outside, 60 | Vector3 &out_wm, const BSDF *&out_bsdf) const; 61 | }; 62 | 63 | double ShapeInvariantNDF::sampleHeight(const Vector3 &wr, const double hr, const bool outside, 64 | Vector3 &out_wm, const BSDF *&out_bsdf) const 65 | { 66 | const double sigma_t = sigma(-wr); 67 | 68 | if (sigma_t < 0.00001) 69 | return (wr.z < 0.0) ? hr : 0.0; 70 | 71 | const double dh = -log(RandomReal()) * wr.z / sigma_t; 72 | 73 | const double h = std::min(0.0, hr) + dh; 74 | 75 | if (h < 0.0) 76 | { 77 | out_wm = sampleD_wi(-wr); 78 | out_bsdf = m_bsdf; // uniform microsurface 79 | } 80 | 81 | return h; 82 | } 83 | 84 | double ShapeInvariantNDF::D(const Vector3 &wm) const 85 | { 86 | if (wm.z <= 0.0) 87 | return 0.0; 88 | 89 | // slope of wm 90 | const double slope_x = -wm.x / wm.z; 91 | const double slope_y = -wm.y / wm.z; 92 | 93 | return P22(slope_x, slope_y) / (wm.z * wm.z * wm.z * wm.z); 94 | } 95 | 96 | Vector3 ShapeInvariantNDF::sampleD_wi(const Vector3 &wi) const 97 | { 98 | 99 | // stretch to match configuration with roughness=1.0 100 | const Vector3 wi_11 = normalize(Vector3(m_roughness_x * wi.x, m_roughness_y * wi.y, wi.z)); 101 | 102 | // sample visible slope with roughness=1.0 103 | Vector2 slope_11 = sampleP22_11(acos(wi_11.z)); 104 | 105 | // align with view direction 106 | const double phi = atan2(wi_11.y, wi_11.x); 107 | Vector2 slope(cos(phi) * slope_11.x - sin(phi) * slope_11.y, sin(phi) * slope_11.x + cos(phi) * slope_11.y); 108 | 109 | // stretch back 110 | slope.x *= m_roughness_x; 111 | slope.y *= m_roughness_y; 112 | 113 | // if numerical instability 114 | if ((slope.x != slope.x) || !IsFiniteNumber(slope.x)) 115 | { 116 | if (wi.z > 0) 117 | return Vector3(0, 0, 1); 118 | else 119 | return normalize(Vector3(wi.x, wi.y, 0)); 120 | } 121 | 122 | // compute normal 123 | return normalize(Vector3(-slope.x, -slope.y, 1.0)); 124 | } 125 | 126 | double ShapeInvariantNDF::roughness_i(const Vector3 &wi) const 127 | { 128 | const double invSinTheta2 = 1.0 / (1.0 - wi.z * wi.z); 129 | const double cosPhi2 = wi.x * wi.x * invSinTheta2; 130 | const double sinPhi2 = wi.y * wi.y * invSinTheta2; 131 | return sqrt(cosPhi2 * m_roughness_x * m_roughness_x + sinPhi2 * m_roughness_y * m_roughness_y); 132 | } -------------------------------------------------------------------------------- /include/fresnel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | 22 | ////////////////////////////////////////////////////////////////////////////////// 23 | // Fresnel 24 | ////////////////////////////////////////////////////////////////////////////////// 25 | 26 | double evalF(const double g, const double c) 27 | { 28 | return (pow(-c + g, 2) * (1 + pow(-1 + c * (c + g), 2) / pow(1 + c * (-c + g), 2))) / 29 | (2. * pow(c + g, 2)); 30 | } 31 | 32 | // costheta = 1 is normal incidence 33 | // eta is ratio of new medium / current medium 34 | double DielectricR(const double costheta, const double eta) 35 | { 36 | const double sqrtinput = eta * eta - 1.0 + costheta * costheta; 37 | if (sqrtinput <= 0.0) 38 | { 39 | return 1.0; 40 | } 41 | else 42 | { 43 | return evalF(sqrt(std::max(0.0, sqrtinput)), costheta); 44 | } 45 | } 46 | 47 | // careful: "in" here is the direction light is MOVING before striking the surface 48 | // (pointing away from the camera/light) 49 | Vector3 refract(const Vector3 in, const Vector3 normal, const double etai, const double etat) 50 | { 51 | return (etai * (in - normal * dot(in, normal))) / etat - 52 | normal * Sqrt(1 - (pow(etai, 2) * (1 - pow(dot(in, normal), 2))) / pow(etat, 2)); 53 | } 54 | 55 | double refractCosine(const double ui, const double etai, const double etao) 56 | { 57 | return sqrt(1.0 - etai * etai * (1.0 - ui * ui) / (etao * etao)); 58 | } 59 | 60 | double ConductorR(const double costheta, const double etai, const double eta, const double k) 61 | { 62 | return ((Power(etai, 2) - 2 * Power(costheta, 2) * Power(etai, 2) + Power(costheta, 4) * Power(etai, 2) + 63 | Power(costheta, 2) * Sqrt(4 * Power(eta, 2) * Power(k, 2) + 64 | Power(Power(eta, 2) + (-1 + Power(costheta, 2)) * Power(etai, 2) - Power(k, 2), 2))) * 65 | (Power(costheta, 2) * Power(etai, 2) + Sqrt(4 * Power(eta, 2) * Power(k, 2) + Power(Power(eta, 2) + (-1 + Power(costheta, 2)) * Power(etai, 2) - Power(k, 2), 2)) - 66 | Sqrt(2) * costheta * etai * Sqrt(Power(eta, 2) - Power(etai, 2) + Power(costheta, 2) * Power(etai, 2) - Power(k, 2) + Sqrt(4 * Power(eta, 2) * Power(k, 2) + Power(Power(eta, 2) + (-1 + Power(costheta, 2)) * Power(etai, 2) - Power(k, 2), 2))))) / 67 | ((Power(costheta, 2) * Power(etai, 2) + Sqrt(4 * Power(eta, 2) * Power(k, 2) + Power(Power(eta, 2) + (-1 + Power(costheta, 2)) * Power(etai, 2) - Power(k, 2), 2)) + 68 | Sqrt(2) * costheta * etai * Sqrt(Power(eta, 2) - Power(etai, 2) + Power(costheta, 2) * Power(etai, 2) - Power(k, 2) + Sqrt(4 * Power(eta, 2) * Power(k, 2) + Power(Power(eta, 2) + (-1 + Power(costheta, 2)) * Power(etai, 2) - Power(k, 2), 2)))) * 69 | (Power(-1 + Power(costheta, 2), 2) * Power(etai, 2) + 70 | Power(costheta, 2) * Sqrt(Power(eta, 4) + 71 | Power(-((-1 + Power(costheta, 2)) * Power(etai, 2)) + Power(k, 2), 2) + 72 | 2 * Power(eta, 2) * ((-1 + Power(costheta, 2)) * Power(etai, 2) + Power(k, 2))) - 73 | Sqrt(2) * costheta * (-1 + Power(costheta, 2)) * etai * 74 | Sqrt(Power(eta, 2) - Power(etai, 2) + Power(costheta, 2) * Power(etai, 2) - Power(k, 2) + 75 | Sqrt(Power(eta, 4) + Power(-((-1 + Power(costheta, 2)) * Power(etai, 2)) + Power(k, 2), 2) + 76 | 2 * Power(eta, 2) * ((-1 + Power(costheta, 2)) * Power(etai, 2) + Power(k, 2)))))); 77 | } 78 | 79 | // exact [Dunkle 1963] 80 | // n = ior_ratio 81 | double SmoothDielectricHemisphericalAlbedo(const double n) 82 | { 83 | if (n <= 0.0) 84 | { 85 | return 0.0; 86 | } 87 | if (n < 1.0) 88 | { 89 | return 1.0 - n * n * (1.0 - SmoothDielectricHemisphericalAlbedo(1.0 / n)); 90 | } 91 | if (n < 1.00000000001) 92 | { 93 | return 0.0; 94 | } 95 | if (n < 1.001) 96 | { 97 | return (-1 + n) / 3. - (79 * Power(-1 + n, 3)) / 60. + 98 | (Power(-1 + n, 4) * (37 + 100 * Log(2) - 100 * Log(-1 + n))) / 160. + 99 | (Power(-1 + n, 2) * (19 - 12 * Log(2) + 12 * Log(-1 + n))) / 24.; 100 | } 101 | return 0.5 + ((-1 + n) * (1 + 3 * n)) / (6. * Power(1 + n, 2)) - 102 | (2 * Power(n, 3) * (-1 + 2 * n + Power(n, 2))) / ((1 + Power(n, 2)) * (-1 + Power(n, 4))) + 103 | (8 * Power(n, 4) * (1 + Power(n, 4)) * Log(n)) / ((1 + Power(n, 2)) * Power(-1 + Power(n, 4), 2)) + 104 | (Power(n, 2) * Power(-1 + Power(n, 2), 2) * Log((-1 + n) / (1 + n))) / Power(1 + Power(n, 2), 3); 105 | } -------------------------------------------------------------------------------- /include/bsdfs/microsurface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | #define MAX_WALK_LENGTH 10 24 | 25 | class Microsurface : public BSDF 26 | { 27 | public: 28 | const NDF *m_ndf; 29 | 30 | Microsurface(NDF *ndf) : m_ndf(ndf) 31 | { 32 | } 33 | 34 | virtual Vector3 sample(const double ior_i, const double ior_t, const Vector3 &wi, double &io_weight) const; 35 | virtual double eval(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const; 36 | virtual double evalSingular(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 37 | { 38 | return 0.0; // TODO - special case this when both roughnesses are 0 39 | } 40 | }; 41 | 42 | Vector3 Microsurface::sample(const double ior_i, const double ior_t, const Vector3 &wi, double &io_weight) const 43 | { 44 | if (wi.z < 0) 45 | { 46 | io_weight = 0; 47 | return Vector3(0, 0, 1); 48 | } 49 | 50 | Vector3 wr = -wi; 51 | double hr = 0.0; 52 | bool outside = true; 53 | 54 | // random walk 55 | size_t collision_count = 0; 56 | while (collision_count < MAX_WALK_LENGTH + 1) 57 | { 58 | // next height 59 | Vector3 wm; // microfacet normal 60 | const BSDF *microfacet_bsdf = 0; 61 | hr = m_ndf->sampleHeight(wr, hr, outside, wm, microfacet_bsdf); 62 | 63 | // leave the microsurface? 64 | if (hr >= 0.0) 65 | break; 66 | 67 | assert(0 != microfacet_bsdf); 68 | 69 | // next direction 70 | collision_count++; 71 | wr = microfacet_bsdf->sample(outside ? ior_i : ior_t, outside ? ior_t : ior_i, -wr, io_weight, wm); 72 | if (dot(wr, wm) < 0.0) 73 | { 74 | outside = !outside; 75 | wr = -wr; 76 | hr = log(1.0 - exp(hr)); 77 | } 78 | 79 | // if NaN (should not happen, just in case) 80 | if ((hr != hr) || (wr.z != wr.z)) 81 | { 82 | io_weight = 0.0; 83 | return Vector3(0, 0, 1); 84 | } 85 | } 86 | 87 | if (hr < 0.0) 88 | { 89 | io_weight = 0.0; 90 | } 91 | 92 | return outside ? wr : -wr; 93 | } 94 | 95 | double Microsurface::eval(const double ior_i, const double ior_t, const Vector3 &wi, const Vector3 &wo) const 96 | { 97 | if (wi.z < 0) 98 | return 0; 99 | 100 | Vector3 wr = -wi; // direction of the ray 101 | double hr = 0.0; // height of the ray 102 | bool outside = true; 103 | double sum = 0; 104 | double weight = 1.0; 105 | 106 | // random walk 107 | size_t collision_count = 0; 108 | while (collision_count < MAX_WALK_LENGTH) 109 | { 110 | // next height 111 | Vector3 wm; // microfacet normal 112 | const BSDF *microfacet_bsdf = 0; 113 | hr = m_ndf->sampleHeight(wr, hr, outside, wm, microfacet_bsdf); 114 | 115 | // leave the microsurface? 116 | if (hr >= 0.0) 117 | break; 118 | 119 | assert(0 != microfacet_bsdf); 120 | 121 | // next event estimation 122 | const double phaseFunctionSingular = m_ndf->evalPhaseFunctionSingular(ior_i, ior_t, outside ? -wr : wr, wo, outside, (wo.z > 0)); 123 | const double phaseFunction = microfacet_bsdf->eval(outside ? ior_i : ior_t, outside ? ior_t : ior_i, -wr, wo, wm); 124 | const double hr_inside = outside ? log(1.0 - exp(hr)) : hr; 125 | const double hr_outside = outside ? hr : log(1.0 - exp(hr)); 126 | const double shadowingSingular = (wo.z > 0) ? m_ndf->G_1(wo, hr_outside) : m_ndf->G_1(-wo, hr_inside); 127 | 128 | // apply the shadowing that aligns with what side we started on and whether the facet reflected or not 129 | bool facet_reflected = dot(wo, wm) >= 0.0; 130 | assert(dot(-wr, wm) >= 0.0); // assuming the facet always faces the ray 131 | const double shadowing = (facet_reflected == outside) ? m_ndf->G_1(wo, hr_outside) : m_ndf->G_1(-wo, hr_inside); 132 | const double I = weight * (phaseFunctionSingular * shadowingSingular + phaseFunction * shadowing); 133 | 134 | if (IsFiniteNumber(I)) 135 | sum += I; 136 | 137 | // next direction 138 | collision_count++; 139 | wr = microfacet_bsdf->sample(outside ? ior_i : ior_t, outside ? ior_t : ior_i, -wr, weight, wm); 140 | if (dot(wr, wm) < 0.0) 141 | { 142 | outside = !outside; 143 | wr = -wr; 144 | hr = log(1.0 - exp(hr)); 145 | } 146 | 147 | // if NaN (should not happen, just in case) 148 | if ((hr != hr) || (wr.z != wr.z)) 149 | { 150 | return 0.0; 151 | } 152 | } 153 | 154 | return sum; 155 | } 156 | -------------------------------------------------------------------------------- /include/bsdfs/NDFs/beckmann.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | ////////////////////////////////////////////////////////////////////////////////// 22 | // BeckmannNDF 23 | ////////////////////////////////////////////////////////////////////////////////// 24 | 25 | class BeckmannNDF : public ShapeInvariantNDF 26 | { 27 | public: 28 | BeckmannNDF(const BSDF *bsdf, const double roughness_x, const double roughness_y) 29 | : ShapeInvariantNDF(bsdf, roughness_x, roughness_y) 30 | { 31 | } 32 | 33 | // distribution of slopes 34 | virtual double P22(const double slope_x, const double slope_y) const; 35 | // cross section 36 | virtual double sigma(const Vector3 &wi) const; 37 | // sample the distribution of visible slopes with roughness=1.0 38 | virtual Vector2 sampleP22_11(const double theta_i) const; 39 | }; 40 | 41 | double BeckmannNDF::P22(const double slope_x, const double slope_y) const 42 | { 43 | return 1.0 / (M_PI * m_roughness_x * m_roughness_y) * exp(-slope_x * slope_x / (m_roughness_x * m_roughness_x) - slope_y * slope_y / (m_roughness_y * m_roughness_y)); 44 | } 45 | 46 | double BeckmannNDF::sigma(const Vector3 &wi) const 47 | { 48 | if (wi.z > 0.9999) 49 | return 1.0; 50 | if (wi.z < -0.9999) 51 | return 0.0; 52 | 53 | const double roughnessi = roughness_i(wi); 54 | const double theta_i = acos(wi.z); 55 | const double sin_theta_i = sin(theta_i); 56 | const double a = 1.0 / tan(theta_i) / roughnessi; 57 | 58 | return 0.5 * (erf(a) + 1.0) * wi.z + INV_2_SQRT_M_PI * roughnessi * sin(theta_i) * exp(-a * a); 59 | } 60 | 61 | Vector2 BeckmannNDF::sampleP22_11(const double theta_i) const 62 | { 63 | Vector2 slope; 64 | 65 | const double U = RandomReal(); 66 | const double U_2 = RandomReal(); 67 | 68 | if (theta_i < 0.00001) 69 | { 70 | const double r = sqrt(-log(U)); 71 | const double phi = 2 * Pi * U_2; 72 | slope.x = r * cos(phi); 73 | slope.y = r * sin(phi); 74 | return slope; 75 | } 76 | 77 | // constant 78 | const double sin_theta_i = sin(theta_i); 79 | const double cos_theta_i = cos(theta_i); 80 | 81 | // slope associated to theta_i 82 | const double slope_i = cos_theta_i / sin_theta_i; 83 | 84 | // projected area 85 | const double a = cos_theta_i / sin_theta_i; 86 | const double sigma = 0.5 * (erf(a) + 1.0) * cos_theta_i + INV_2_SQRT_M_PI * sin_theta_i * exp(-a * a); 87 | 88 | // VNDF normalization factor 89 | const double c = 1.0 / sigma; 90 | 91 | // search 92 | double erf_min = -0.9999; 93 | double erf_max = std::max(erf_min, erf(slope_i)); 94 | double erf_current = 0.5 * (erf_min + erf_max); 95 | 96 | while (erf_max - erf_min > 0.000001) 97 | { 98 | if (!(erf_current >= erf_min && erf_current <= erf_max)) 99 | erf_current = 0.5 * (erf_min + erf_max); 100 | 101 | // evaluate slope 102 | const double slope = erfinv(erf_current); 103 | 104 | // CDF 105 | const double CDF = (slope >= slope_i) ? 1.0 : c * (INV_2_SQRT_M_PI * sin_theta_i * exp(-slope * slope) + cos_theta_i * (0.5 + 0.5 * erf(slope))); 106 | const double diff = CDF - U; 107 | 108 | // test estimate 109 | if (std::abs(diff) < 0.000001) 110 | break; 111 | 112 | // update bounds 113 | if (diff > 0.0) 114 | { 115 | if (erf_max == erf_current) 116 | break; 117 | erf_max = erf_current; 118 | } 119 | else 120 | { 121 | if (erf_min == erf_current) 122 | break; 123 | erf_min = erf_current; 124 | } 125 | 126 | // update estimate 127 | const double derivative = 0.5 * c * cos_theta_i - 0.5 * c * sin_theta_i * slope; 128 | erf_current -= diff / derivative; 129 | } 130 | 131 | slope.x = erfinv(std::min(erf_max, std::max(erf_min, erf_current))); 132 | slope.y = erfinv(2.0 * U_2 - 1.0); 133 | 134 | const double u = cos_theta_i; 135 | 136 | if (u < 0.0) 137 | { 138 | const double m = u / sqrt(1.0 - u * u); 139 | double xx; 140 | if (RandomReal() < powf(-u, 1.3)) 141 | { 142 | xx = RandomReal() * RandomReal(); 143 | } 144 | else 145 | { 146 | xx = 1.0 - erf(sqrt(-log(RandomReal()))); 147 | } 148 | slope.x = erfinv(-1.0 + xx * (1.0 + erf(m))); 149 | } 150 | 151 | if (u < -0.9) 152 | { 153 | const double m = u / sqrt(1.0 - u * u); 154 | const double x = RandomReal() * pow(RandomReal(), -u); 155 | slope.x = -(sqrt(2 * Power(m, 2) + log(8) - 2 * log((x - 2 * pow(m, 2) * x) / pow(m, 3)) - 156 | log(2 * pow(m, 2) + log(8) - 2 * log((x - 2 * pow(m, 2) * x) / pow(m, 3)))) / 157 | sqrt(2)); 158 | } 159 | 160 | return slope; 161 | } -------------------------------------------------------------------------------- /include/testing/compare_eval_sample.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // Compare eval() and sample() in a lat-long histogram 18 | 19 | #pragma once 20 | 21 | #include 22 | #include 23 | 24 | const int numtheta = 100; 25 | const int numphi = 101; 26 | const int numOrdinates = numphi * numtheta; 27 | 28 | int thetaIndex(const Vector3 &o) 29 | { 30 | const double theta_o = asin(o.z); 31 | return int(floor((theta_o + 0.5 * M_PI) * numtheta / M_PI)); 32 | } 33 | 34 | int phiIndex(const Vector3 &o, const double azimuth) 35 | { 36 | if (o.x == double(0) && o.y == double(0)) 37 | return 0; 38 | double phi = atan2(o.x, o.y) - azimuth; 39 | while (phi > M_PI) 40 | { 41 | phi -= 2.0 * M_PI; 42 | } 43 | while (phi < -M_PI) 44 | { 45 | phi += 2.0 * M_PI; 46 | } 47 | return int(floor((phi + M_PI) * numphi / (2.0 * M_PI))); 48 | } 49 | 50 | int oIndex(const Vector3 &o, const float azimuth) 51 | { 52 | const int thetai = std::max(0, std::min(numtheta - 1, thetaIndex(o))); 53 | const int phii = std::max(0, std::min(numphi - 1, phiIndex(o, azimuth))); 54 | return numphi * thetai + phii; 55 | } 56 | 57 | void writeHistogram(double *histogram, const size_t numsamples) 58 | { 59 | int index = 0; 60 | for (int i = 0; i < numtheta; ++i) 61 | { 62 | for (int j = 0; j < numphi; ++j) 63 | { 64 | std::cout << histogram[index] / double(numsamples) << " "; 65 | index++; 66 | } 67 | std::cout << "\n"; 68 | } 69 | std::cout << "\n\n"; 70 | } 71 | 72 | // BSDF buffers 73 | double g_bsdfsampled[numOrdinates]; 74 | 75 | const double evalFactor = 2.0 * M_PI * M_PI / (numtheta * numphi); 76 | 77 | //////////////////////////////////////////////////////////////////////////// 78 | // compareEvalSample: 79 | // 80 | // numsamplesSample: number of samples to test sample() with 81 | // numsamplesEval: number of samples to test eval() with (run for every pixel in the output) 82 | //////////////////////////////////////////////////////////////////////////// 83 | 84 | void compareEvalSample(BSDF &bsdf, const double theta_i, const size_t numsamplesSample, const size_t numsamplesEval, const double ior_i, const double ior_t) 85 | { 86 | for (size_t i = 0; i < numOrdinates; ++i) 87 | { 88 | g_bsdfsampled[i] = 0.0; 89 | } 90 | 91 | const double phi = -M_PI * 0.5; 92 | const Vector3 wi = Vector3(sin(theta_i) * cos(phi), sin(theta_i) * sin(phi), cos(theta_i)); 93 | 94 | for (size_t i = 0; i < numsamplesSample; ++i) 95 | { 96 | double w(1.0); 97 | Vector3 wo = bsdf.sample(ior_i, ior_t, wi, w); 98 | int oi = oIndex(wo, 0.0); 99 | g_bsdfsampled[oi] += w; 100 | } 101 | 102 | std::cout << "BSDF.sample():\n"; 103 | writeHistogram(g_bsdfsampled, numsamplesSample); 104 | 105 | std::cout << "BSDF.eval():\n"; 106 | for (int theta_index = 0; theta_index < numtheta; ++theta_index) 107 | { 108 | for (int phi_i = 0; phi_i < numphi; ++phi_i) 109 | { 110 | double meanEval(0.f); 111 | for (size_t i = 0; i < numsamplesEval; ++i) 112 | { 113 | const double theta = -0.5 * M_PI + double(theta_index + RandomReal()) * M_PI / double(numtheta); 114 | const double phi = -M_PI + double(phi_i + RandomReal()) * 2.0 * M_PI / double(numphi); 115 | Vector3 wo = Vector3(cosf(theta) * sinf(phi), cosf(theta) * cosf(phi), sinf(theta)); 116 | meanEval += bsdf.eval(ior_i, ior_t, wi, wo) * cosf(theta); 117 | } 118 | std::cout << evalFactor * meanEval / double(numsamplesEval) << " "; 119 | } 120 | std::cout << std::endl; 121 | } 122 | } 123 | 124 | //////////////////////////////////////////////////////////////////////////// 125 | // testVNDF() - samples VNDF and compares to an explicit evaluation 126 | // 127 | // numsamplesSample: number of samples to test sample() with 128 | // numsamplesEval: number of samples to test eval() with (run for every pixel in the output) 129 | //////////////////////////////////////////////////////////////////////////// 130 | 131 | void testVNDF(NDF &ndf, const double theta_i, const double phi, const size_t numsamplesSample, const size_t numsamplesEval) 132 | { 133 | for (size_t i = 0; i < numOrdinates; ++i) 134 | { 135 | g_bsdfsampled[i] = 0.0; 136 | } 137 | 138 | const Vector3 wi = Vector3(sin(theta_i) * cos(phi), sin(theta_i) * sin(phi), cos(theta_i)); 139 | 140 | for (size_t i = 0; i < numsamplesSample; ++i) 141 | { 142 | double w(1.0); 143 | Vector3 wo = ndf.sampleD_wi(wi); 144 | int oi = oIndex(wo, 0.0); 145 | g_bsdfsampled[oi] += w; 146 | } 147 | 148 | std::cout << "vNDF.sample():\n"; 149 | writeHistogram(g_bsdfsampled, numsamplesSample); 150 | 151 | std::cout << "vNDF.eval():\n"; 152 | for (int theta_index = 0; theta_index < numtheta; ++theta_index) 153 | { 154 | for (int phi_i = 0; phi_i < numphi; ++phi_i) 155 | { 156 | double meanEval(0.f); 157 | for (size_t i = 0; i < numsamplesEval; ++i) 158 | { 159 | const double theta = -0.5 * M_PI + double(theta_index + RandomReal()) * M_PI / double(numtheta); 160 | const double phi = -M_PI + double(phi_i + RandomReal()) * 2.0 * M_PI / double(numphi); 161 | Vector3 wo = Vector3(cosf(theta) * sinf(phi), cosf(theta) * cosf(phi), sinf(theta)); 162 | meanEval += ndf.D_wi(wi, wo) * cosf(theta); 163 | // meanEval += bsdf.eval(ior_i, ior_t, wi, wo) * cosf(theta); 164 | } 165 | std::cout << evalFactor * meanEval / double(numsamplesEval) << " "; 166 | } 167 | std::cout << std::endl; 168 | } 169 | } -------------------------------------------------------------------------------- /include/bsdfs/NDFs/NullNDF.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | ////////////////////////////////////////////////////////////////////////////////// 26 | // General NDF implementation using null scattering 27 | ////////////////////////////////////////////////////////////////////////////////// 28 | 29 | class NullNDF : public NDF 30 | { 31 | public: 32 | NullNDF(const BSDF *bsdf, const double majorant) 33 | : NDF(bsdf), m_majorant(majorant){}; 34 | double m_majorant; 35 | 36 | public: 37 | // distribution of normals (NDF) 38 | virtual double D(const Vector3 &wm) const = 0; 39 | virtual double D_wi(const Vector3 &wi, const Vector3 &wm) const; 40 | // sample the VNDF - for debugging purposes 41 | virtual Vector3 sampleD_wi(const Vector3 &wi) const; 42 | 43 | public: 44 | // cross section 45 | virtual double sigma(const Vector3 &wi) const; 46 | 47 | // sample a free-path length along direction wr from starting height hr 48 | // if a collision occurs before escape, return the normal (out_wm) and BSDF (out_bsdf) of the sampled facet 49 | virtual double sampleHeight(const Vector3 &wr, const double hr, const bool outside, 50 | Vector3 &out_wm, const BSDF *&out_bsdf) const; 51 | }; 52 | 53 | // projected Area (or sigma_t) for singular NDF with all microfacets having cosine un 54 | double diracSigma(const double u, const double un) 55 | { 56 | double result = 0.0; 57 | if (u * un > 0.0) 58 | { 59 | result += 2 * Pi * u * un; 60 | } 61 | if (std::abs(u) < sqrt(1.0 - un * un)) 62 | { 63 | result += 2.0 * sqrt(-un * un - u * u + 1); 64 | const double acosarg = -u * un / (sqrt((1 - u * u) * (1 - un * un))); 65 | result += 2 * u * un * acos(acosarg); 66 | if (u * un > 0.0) 67 | { 68 | result -= 2 * Pi * u * un; 69 | } 70 | } 71 | return result; 72 | } 73 | 74 | double NullNDF::sigma(const Vector3 &wi) const 75 | { 76 | // quadrature integration over D(wm) using the Dirac NDF sigma() Green's function: 77 | double result = 0.0; 78 | for (int i = 0; i < 100; ++i) 79 | { 80 | const double u = Gauss100xs[i] * 2 - 1; // rescale abscissas into [-1,1] from [0,1] 81 | Vector3 wm(sqrt(1.0 - u * u), 0, u); 82 | result += Gauss100ws[i] * D(wm) * diracSigma(wi.z, u); 83 | } 84 | 85 | return result * 2 / Pi / m_majorant; // adjust for 2x change of interval length 86 | } 87 | 88 | double NullNDF::D_wi(const Vector3 &wi, const Vector3 &wm) const 89 | { 90 | 91 | // normalization coefficient 92 | const double l_sigma = sigma(wi); 93 | if (l_sigma == 0) 94 | return 0; 95 | const double c = 1.0 / l_sigma; 96 | return c * std::max(0.0, dot(wi, wm)) * D(wm) / Pi / m_majorant; 97 | } 98 | 99 | double NullNDF::sampleHeight(const Vector3 &wr, const double hr, const bool outside, 100 | Vector3 &out_wm, const BSDF *&out_bsdf) const 101 | { 102 | double dh = -log(RandomReal()) * wr.z; 103 | double h = std::min(0.0, hr) + dh; 104 | out_bsdf = 0; 105 | 106 | while (h <= 0.0) 107 | { 108 | const double u = -wr.z; 109 | Vector2 diskOffset = diskSample2D(0.999999); 110 | 111 | // microfacet normal / sphere position - pre rotation 112 | Vector3 mPR(diskOffset.x, diskOffset.y, sqrt(1.0 - diskOffset.x * diskOffset.x - diskOffset.y * diskOffset.y)); 113 | // rotate to the same cos(theta) 114 | Vector3 mPR2(mPR.x * u + sqrt(1.0 - u * u) * mPR.z, mPR.y, u * mPR.z - mPR.x * sqrt(1.0 - u * u)); 115 | // rotate to match azimuth 116 | const double phi = atan2(-wr.x, -wr.y); 117 | const double cosphi = cos(phi); 118 | const double sinphi = sin(phi); 119 | // this is where we strike the unit sphere of the microsurface NDFs - this is then the microfacet normal 120 | Vector3 microspherePos(-cosphi * mPR2.y + sinphi * mPR2.x, sinphi * mPR2.y + cosphi * mPR2.x, mPR2.z); 121 | 122 | // null scattering unless there is enough density for this microfacet normal - cosine factor is already accounted 123 | // for in the disk sampling above 124 | if (RandomReal() < D(microspherePos) / m_majorant) 125 | { 126 | out_wm = microspherePos; 127 | assert(dot(wr, out_wm) <= 0.0); 128 | out_bsdf = m_bsdf; 129 | return h; 130 | } 131 | h += -log(RandomReal()) * wr.z; 132 | } 133 | 134 | return h; 135 | } 136 | 137 | Vector3 NullNDF::sampleD_wi(const Vector3 &wi) const 138 | { 139 | while (true) 140 | { 141 | const double u = wi.z; 142 | Vector2 diskOffset = diskSample2D(0.999999); 143 | 144 | // microfacet normal / sphere position - pre rotation 145 | Vector3 mPR(diskOffset.x, diskOffset.y, sqrt(1.0 - diskOffset.x * diskOffset.x - diskOffset.y * diskOffset.y)); 146 | // rotate to the same cos(theta) 147 | Vector3 mPR2(mPR.x * u + sqrt(1.0 - u * u) * mPR.z, mPR.y, u * mPR.z - mPR.x * sqrt(1.0 - u * u)); 148 | // rotate to match azimuth 149 | const double phi = atan2(wi.x, wi.y); 150 | const double cosphi = cos(phi); 151 | const double sinphi = sin(phi); 152 | // this is where we strike the unit sphere of the microsurface NDFs - this is then the microfacet normal 153 | Vector3 microspherePos(-cosphi * mPR2.y + sinphi * mPR2.x, sinphi * mPR2.y + cosphi * mPR2.x, mPR2.z); 154 | 155 | // null scattering unless there is enough density for this microfacet normal - cosine factor is already accounted 156 | // for in the disk sampling above 157 | if (RandomReal() < D(microspherePos) / m_majorant) 158 | { 159 | return microspherePos; 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /include/vector.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | ////////////////////////////////////////////////////////////////////////////////// 22 | // Vector2 23 | ////////////////////////////////////////////////////////////////////////////////// 24 | 25 | struct Vector2 26 | { 27 | Vector2(const double in_x, const double in_y) 28 | : x(in_x), y(in_y){}; 29 | 30 | Vector2() 31 | : x(0.0), y(0.0){}; 32 | 33 | double x, y; 34 | 35 | Vector2 operator*(const double c) const 36 | { 37 | return Vector2(c * this->x, c * this->y); 38 | }; 39 | 40 | Vector2 operator/(const double c) const 41 | { 42 | return Vector2(this->x / c, this->y / c); 43 | }; 44 | 45 | Vector2 operator+(Vector2 b) const 46 | { 47 | return Vector2(b.x + this->x, b.y + this->y); 48 | }; 49 | 50 | Vector2 operator-() const 51 | { 52 | return Vector2(-this->x, -this->y); 53 | }; 54 | 55 | Vector2 operator+=(Vector2 b) 56 | { 57 | this->x += b.x; 58 | this->y += b.y; 59 | return *this; 60 | }; 61 | 62 | Vector2 operator-=(Vector2 b) 63 | { 64 | this->x -= b.x; 65 | this->y -= b.y; 66 | return *this; 67 | }; 68 | }; 69 | 70 | Vector2 operator*(const double c, const Vector2 &v) 71 | { 72 | return Vector2(c * v.x, c * v.y); 73 | } 74 | 75 | Vector2 operator-(const Vector2 &a, const Vector2 &b) 76 | { 77 | return Vector2(a.x - b.x, a.y - b.y); 78 | } 79 | 80 | bool operator==(const Vector2 &a, const Vector2 &b) 81 | { 82 | return a.x == b.x && a.y == b.y; 83 | } 84 | 85 | bool operator!=(const Vector2 &a, const Vector2 &b) 86 | { 87 | return a.x != b.x || a.y != b.y; 88 | } 89 | 90 | double dot(const Vector2 &a, const Vector2 &b) 91 | { 92 | return a.x * b.x + a.y * b.y; 93 | } 94 | 95 | double Norm(const Vector2 &v) 96 | { 97 | return sqrt(v.x * v.x + v.y * v.y); 98 | } 99 | 100 | Vector2 normalize(const Vector2 &v) 101 | { 102 | return v * (1.0 / Norm(v)); 103 | } 104 | 105 | ////////////////////////////////////////////////////////////////////////////////// 106 | // Vector3 107 | ////////////////////////////////////////////////////////////////////////////////// 108 | 109 | struct Vector3 110 | { 111 | Vector3(const double in_x, const double in_y, const double in_z) 112 | : x(in_x), y(in_y), z(in_z){}; 113 | 114 | Vector3() 115 | : x(0.0), y(0.0), z(0.0){}; 116 | double x, y, z; 117 | 118 | Vector3(const double *ptr) 119 | { 120 | x = ptr[0]; 121 | y = ptr[1]; 122 | z = ptr[2]; 123 | } 124 | 125 | Vector3 operator*(const Vector3 &c) const 126 | { 127 | return Vector3(c.x * this->x, c.y * this->y, c.z * this->z); 128 | }; 129 | 130 | double min() const 131 | { 132 | return std::min(x, std::min(y, z)); 133 | } 134 | 135 | double max() const 136 | { 137 | return std::max(x, std::max(y, z)); 138 | } 139 | 140 | double sum() const 141 | { 142 | return x + y + z; 143 | } 144 | 145 | Vector3 operator*(const double c) const 146 | { 147 | return Vector3(c * this->x, c * this->y, c * this->z); 148 | }; 149 | 150 | Vector3 operator/(const double c) const 151 | { 152 | return Vector3(this->x / c, this->y / c, this->z / c); 153 | }; 154 | 155 | Vector3 operator+(Vector3 b) const 156 | { 157 | return Vector3(b.x + this->x, b.y + this->y, b.z + this->z); 158 | }; 159 | 160 | Vector3 operator-() const 161 | { 162 | return Vector3(-this->x, -this->y, -this->z); 163 | }; 164 | 165 | Vector3 operator+=(Vector3 b) 166 | { 167 | this->x += b.x; 168 | this->y += b.y; 169 | this->z += b.z; 170 | 171 | return *this; 172 | }; 173 | 174 | Vector3 operator*=(Vector3 b) 175 | { 176 | this->x *= b.x; 177 | this->y *= b.y; 178 | this->z *= b.z; 179 | 180 | return *this; 181 | }; 182 | 183 | Vector3 operator*=(double b) 184 | { 185 | this->x *= b; 186 | this->y *= b; 187 | this->z *= b; 188 | 189 | return *this; 190 | }; 191 | 192 | Vector3 operator-=(Vector3 b) 193 | { 194 | this->x -= b.x; 195 | this->y -= b.y; 196 | this->z -= b.z; 197 | 198 | return *this; 199 | }; 200 | }; 201 | 202 | Vector3 operator*(const double c, const Vector3 &v) 203 | { 204 | return Vector3(c * v.x, c * v.y, c * v.z); 205 | } 206 | 207 | Vector3 operator/(const double c, const Vector3 &v) 208 | { 209 | return Vector3(c / v.x, c / v.y, c / v.z); 210 | } 211 | 212 | Vector3 operator-(const Vector3 &a, const Vector3 &b) 213 | { 214 | return Vector3(a.x - b.x, a.y - b.y, a.z - b.z); 215 | } 216 | 217 | Vector3 operator/(const Vector3 &a, const Vector3 &b) 218 | { 219 | return Vector3(a.x / b.x, a.y / b.y, a.z / b.z); 220 | } 221 | 222 | bool operator==(const Vector3 &a, const Vector3 &b) 223 | { 224 | return a.x == b.x && a.y == b.y && a.z == b.z; 225 | } 226 | 227 | bool operator!=(const Vector3 &a, const Vector3 &b) 228 | { 229 | return a.x != b.x || a.y != b.y || a.z != b.z; 230 | } 231 | 232 | double dot(const Vector3 &a, const Vector3 &b) 233 | { 234 | return a.x * b.x + a.y * b.y + a.z * b.z; 235 | } 236 | 237 | double Norm(const Vector3 &v) 238 | { 239 | return sqrt(v.x * v.x + v.y * v.y + v.z * v.z); 240 | } 241 | 242 | Vector3 normalize(const Vector3 &v) 243 | { 244 | return v * (1.0 / Norm(v)); 245 | } 246 | 247 | Vector3 Clamp(const Vector3 &v, const double min, const double max) 248 | { 249 | return Vector3( 250 | Clamp(v.x, min, max), 251 | Clamp(v.y, min, max), 252 | Clamp(v.z, min, max)); 253 | } 254 | 255 | Vector3 Cross(const Vector3 &a, const Vector3 &b) 256 | { 257 | return Vector3(-b.y * a.z + a.y * b.z, b.x * a.z - a.x * b.z, -b.x * a.y + a.x * b.y); 258 | } 259 | 260 | Vector3 reflect(const Vector3 &in, const Vector3 &n) 261 | { 262 | return -in + 2.0 * dot(in, n) * n; 263 | } 264 | 265 | // build orthonormal basis (Building an Orthonormal Basis from a 3D Unit Vector Without Normalization, [Frisvad2012]) 266 | void buildOrthonormalBasis(Vector3 &omega_1, Vector3 &omega_2, const Vector3 &omega_3) 267 | { 268 | if (omega_3.z < -0.9999999f) 269 | { 270 | omega_1 = Vector3(0.0f, -1.0f, 0.0f); 271 | omega_2 = Vector3(-1.0f, 0.0f, 0.0f); 272 | } 273 | else 274 | { 275 | const float a = 1.0f / (1.0f + omega_3.z); 276 | const float b = -omega_3.x * omega_3.y * a; 277 | omega_1 = Vector3(1.0f - omega_3.x * omega_3.x * a, b, -omega_3.x); 278 | omega_2 = Vector3(b, 1.0f - omega_3.y * omega_3.y * a, -omega_3.y); 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /include/bsdfs/NDFs/studentT.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | ////////////////////////////////////////////////////////////////////////////////// 22 | // StudentTNDF 23 | ////////////////////////////////////////////////////////////////////////////////// 24 | 25 | class StudentTNDF : public ShapeInvariantNDF 26 | { 27 | public: 28 | double m_gamma; // shape parameter 29 | StudentTNDF(const BSDF *bsdf, const double roughness_x, const double roughness_y, const double gamma) 30 | : ShapeInvariantNDF(bsdf, roughness_x, roughness_y), m_gamma(gamma){}; 31 | 32 | // distribution of slopes 33 | virtual double P22(const double slope_x, const double slope_y) const; 34 | // cross section 35 | virtual double sigma(const Vector3 &wi) const; 36 | // sample the distribution of visible slopes with roughness=1.0 37 | virtual Vector2 sampleP22_11(const double theta_i) const; 38 | 39 | virtual Vector3 sampleD_wi(const Vector3 &wi) const; 40 | }; 41 | 42 | ////////////////////////////////////////////////////////////////////////////////// 43 | // helper functions 44 | ////////////////////////////////////////////////////////////////////////////////// 45 | 46 | // probability mass of the first term in the 3-term m' Beckmann superposition 47 | double p_term1(const double u, const double gamma) 48 | { 49 | return (3 * Sqrt(3 - 3 * Power(u, 2))) / 50 | (Power(1 + Power(u, 2) / (3 - 3 * Power(u, 2)), 2.5) * 51 | (8 * u - (81 * Power(-1 + Power(u, 2), 3)) / Power(3 - 2 * Power(u, 2), 2.5) - 52 | (Power(u, 2) * Sqrt(3 - 2 * Power(u, 2)) * Sqrt((-1 + Power(u, 2)) / (-3 + 2 * Power(u, 2))) * 53 | (135 - 210 * Power(u, 2) + 83 * Power(u, 4))) / 54 | (Power(-1 + Power(u, 2), 3) * Power((-3 + 2 * Power(u, 2)) / (-1 + Power(u, 2)), 2.5)))); 55 | } 56 | 57 | // probability mass of the second term in the 3-term m' Beckmann superposition 58 | double p_term2(const double u, const double x) 59 | { 60 | return Power(u, 0.809494 + 0.170783 / (-1.1224 + x)) / 61 | (1 + Power(u, 0.145598 + 0.000805627 * x + atan(1.05504 * (-2.91109 + Power(x, 2))))); 62 | } 63 | 64 | // Beckmann superposition sampling of Student-T: sample angle-dependent Beckmann roughness 65 | double sample_m_prime(const double u, const double gamma) 66 | { 67 | if (u < 0.0) 68 | { 69 | // approximate method using fitted gen gamma distribution 70 | 71 | const double y = gamma; 72 | const double a = -1.49293 + y - (0.0655156 * (0.0442664 + u)) / (1.20697 + cos(0.633638 + y)); 73 | const double c = 1.00448 + (0.0138041 + u) / (-0.850096 - u + 0.516877 * pow(y, 2) - asinh(u)); 74 | 75 | // {2,2}-Pade approximant of full m1 at u = 0 76 | const double m1 = (Sqrt(-1 + y) * (-3 + 2 * y) * (-6 * Power(Pi, 1.5) * u * Power(-1 + y, 3.5) * (-4 + 3 * y) * Power(mygamma(-1 + y), 3) + 4 * (4 * Power(-1 + y, 2) * (-3 + Power(u, 2) + (3 + Power(u, 2)) * y) * Power(mygamma(-0.5 + y), 3) + Power(2, 3 - 2 * y) * Pi * u * Power(-1 + y, 2.5) * (-14 + 13 * y) * mygamma(-0.5 + y) * mygamma(-2 + 2 * y) + (Power(Pi, 1.5) * (-6 * (-1 + y) * (-4 + 3 * y) + Power(u, 2) * (8 - 5 * Power(y, 2))) * mygamma(y) * mygamma(-1 + 2 * y)) / Power(4, y)))) / 77 | (2. * (16 * (Power(u, 2) * (-2 + y) + 3 * (-1 + y)) * Power(-1 + y, 2.5) * 78 | Power(mygamma(-0.5 + y), 3) + 79 | Power(2, 5 - 2 * y) * Pi * u * Power(-1 + y, 3) * (-20 + 13 * y) * 80 | mygamma(-0.5 + y) * mygamma(-2 + 2 * y) + 81 | Power(Pi, 1.5) * mygamma(y) * (-3 * u * (-3 + 2 * y) * (-4 + 3 * y) * Power(mygamma(y), 2) - Power(2, 3 - 2 * y) * Power(-1 + y, 1.5) * (6 * (-1 + y) * (-4 + 3 * y) + Power(u, 2) * (-2 + y) * (-6 + 5 * y)) * mygamma(-2 + 2 * y)))); 82 | 83 | const double b = m1 * mygamma(a) / mygamma(a + 1 / c); 84 | 85 | return pow(RandomGamma(a), 1.0 / c) * b; 86 | } 87 | 88 | assert(gamma > 2.0); 89 | 90 | double xi1 = RandomReal(); 91 | const double p1 = p_term1(u, gamma); 92 | const double p2 = p_term2(u, gamma); 93 | 94 | const double gamma_width = 1 / (1 - Power(u, 2) / ((-1 + gamma) * (-1 + Power(u, 2)))); 95 | 96 | if (xi1 < p1) 97 | { 98 | // term 1 99 | return RandomGamma(-1.5 + gamma) * gamma_width; 100 | } 101 | else 102 | { 103 | if (xi1 < p1 + p2) 104 | { 105 | // term 2 106 | return RandomGamma(gamma - 1.0); 107 | } 108 | else 109 | { 110 | // term 3 111 | double m = RandomGamma(gamma - 1.0); 112 | while (RandomReal() > erf(u * Sqrt(-(m / ((-1 + gamma) * (-1 + Power(u, 2))))))) 113 | { 114 | m = RandomGamma(gamma - 1.0); 115 | } 116 | return m; 117 | } 118 | } 119 | } 120 | 121 | // auxiliary functions for approximating sigma/Lambda: 122 | double auxF(const double u, const double g) 123 | { 124 | return atan(2.00141 - 1.6253863790572571 * g) * sin(0.993127 * 125 | (-1.00658 + u - (0.0209307 * (-2.63062 + g) * u) / (2.19417 + g)) * tan(u)); 126 | } 127 | 128 | double auxF2(const double x, const double g) 129 | { 130 | return 1 + 1 / erf(auxF(x / Sqrt(1 + Power(x, 2)), g) / (1 - x / Sqrt(1 + Power(x, 2)))); 131 | } 132 | 133 | ////////////////////////////////////////////////////////////////////////////////// 134 | // implementation 135 | ////////////////////////////////////////////////////////////////////////////////// 136 | 137 | double StudentTNDF::P22(const double p, const double q) const 138 | { 139 | return pow((-1 + m_gamma) / 140 | (-1 + pow(p, 2) / pow(m_roughness_x, 2) + 141 | pow(q, 2) / pow(m_roughness_y, 2) + m_gamma), 142 | m_gamma) / 143 | (m_roughness_x * m_roughness_y * Pi); 144 | } 145 | 146 | // use an approximation of the cross section to avoid having to use 2F1 147 | double StudentTNDF::sigma(const Vector3 &wi) const 148 | { 149 | if (wi.z > 0.9999) 150 | return 1.0; 151 | if (wi.z < -0.9999) 152 | return 0.0; 153 | 154 | const double roughnessi = roughness_i(wi); 155 | const double theta_i = acos(wi.z); 156 | const double x = 1.0 / tan(theta_i) / roughnessi; 157 | 158 | const double u = wi.z; 159 | 160 | if (u > 0.0) 161 | { 162 | return 0.5 * u * auxF2(x, m_gamma); 163 | } 164 | else 165 | { 166 | return -0.5 * u * auxF2(-x, m_gamma) + u; 167 | } 168 | } 169 | 170 | Vector2 StudentTNDF::sampleP22_11(const double theta_i) const 171 | { 172 | assert(false); // handled by sampleD_wi() 173 | return Vector2(0, 0); 174 | } 175 | 176 | // vNDF sampling using Beckmann superpositions 177 | Vector3 StudentTNDF::sampleD_wi(const Vector3 &wi) const 178 | { 179 | const double m_prime = sample_m_prime(wi.z, m_gamma); 180 | const double beck_rough = 1.0 / sqrt(m_prime / (m_gamma - 1.0)); 181 | BeckmannNDF beck(0, beck_rough * m_roughness_x, beck_rough * m_roughness_y); 182 | return beck.sampleD_wi(wi); 183 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2023 Eugene d'Eon 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /include/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #pragma once 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | // mappings for Mathematica CForm[] output: 28 | #define Sqrt sqrt 29 | #define Power pow 30 | #define Log log 31 | #define Cosh cosh 32 | #define Sinh sinh 33 | 34 | const double Pi(M_PI); 35 | 36 | #define INV_M_PI 0.31830988618379067153f /* 1/pi */ 37 | #define SQRT_M_PI 1.77245385090551602729f /* sqrt(pi) */ 38 | #define SQRT_2 1.41421356237309504880f /* sqrt(2) */ 39 | #define INV_SQRT_M_PI 0.56418958354775628694f /* 1/sqrt(pi) */ 40 | #define INV_2_SQRT_M_PI 0.28209479177387814347f /* 0.5/sqrt(pi) */ 41 | #define INV_SQRT_2_M_PI 0.3989422804014326779f /* 1/sqrt(2*pi) */ 42 | #define INV_SQRT_2 0.7071067811865475244f /* 1/sqrt(2) */ 43 | 44 | ////////////////////////////////////////////////////////////////////////////////// 45 | // utilities 46 | ////////////////////////////////////////////////////////////////////////////////// 47 | 48 | template 49 | T StringToNumber(const std::string &Text) 50 | { 51 | std::stringstream ss(Text); 52 | T result; 53 | return ss >> result ? result : 0; 54 | } 55 | 56 | double sqr(double x) 57 | { 58 | return x * x; 59 | } 60 | 61 | // clamp a value into a specified range 62 | double Clamp(const double x, const double min, const double max) 63 | { 64 | return std::max(std::min(max, x), min); 65 | } 66 | 67 | // map a continuous range [min,max] into dx sized intervals and return the integer index 68 | // of an element x 69 | size_t discreteMap(const double min, const double max, const double dx, const double x) 70 | { 71 | const double clampx = Clamp(x, min, max); 72 | return size_t(floor((clampx - min) / dx)); 73 | } 74 | 75 | ////////////////////////////////////////////////////////////////////////////////// 76 | // Gauss Quadrature points over [0,1] 77 | ////////////////////////////////////////////////////////////////////////////////// 78 | 79 | const double Gauss100xs[100] = {0.0001431366132793599, 0.0007540246802020256, 0.001852432633437484, 80 | 0.003437531481278233, 0.005507802378504123, 0.008061229646971535, 0.01109532075654085, 81 | 0.014607112118146803, 0.01859317287209228, 0.02304960853725413, 0.027972064931871987, 82 | 0.03335573247846024, 0.03919535092733306, 0.04548521450873522, 0.05221917751463656, 83 | 0.05939066030749074, 0.06699265575141766, 0.07501773606020434, 0.08345806005579959, 84 | 0.09230538083041195, 0.10155105380484275, 0.11118604517525221, 0.12120094074014642, 85 | 0.13158595509898963, 0.14233094121347178, 0.15342540032209895, 0.16485849219842952, 86 | 0.1766190457429353, 0.18869556989814606, 0.20107626487641062, 0.21374903368930942, 87 | 0.22670149396745298, 0.2399209900591185, 0.2533946053959045, 0.267109175113321, 88 | 0.2810512989139843, 0.2952073541608492, 0.30956350918768505, 0.3241057368137892, 89 | 0.3388198280497354, 0.353691405980764, 0.36870593981424826, 0.38384875907751304, 90 | 0.39910506795213196, 0.4144599597306984, 0.42989843138194306, 0.4454053982099695, 91 | 0.4609657085932817, 0.4765641587892042, 0.4921855077892284, 0.5078144922107716, 92 | 0.5234358412107958, 0.5390342914067183, 0.5545946017900305, 0.5701015686180569, 93 | 0.5855400402693016, 0.600894932047868, 0.616151240922487, 0.6312940601857517, 94 | 0.646308594019236, 0.6611801719502646, 0.6758942631862108, 0.690436490812315, 95 | 0.7047926458391508, 0.7189487010860157, 0.732890824886679, 0.7466053946040955, 96 | 0.7600790099408815, 0.773298506032547, 0.7862509663106906, 0.7989237351235894, 97 | 0.8113044301018539, 0.8233809542570647, 0.8351415078015705, 0.846574599677901, 98 | 0.8576690587865282, 0.8684140449010104, 0.8787990592598536, 0.8888139548247478, 99 | 0.8984489461951572, 0.907694619169588, 0.9165419399442004, 0.9249822639397957, 100 | 0.9330073442485823, 0.9406093396925093, 0.9477808224853634, 0.9545147854912648, 101 | 0.9608046490726669, 0.9666442675215398, 0.972027935068128, 0.9769503914627459, 102 | 0.9814068271279077, 0.9853928878818532, 0.9889046792434592, 0.9919387703530285, 103 | 0.9944921976214959, 0.9965624685187218, 0.9981475673665625, 0.999245975319798, 104 | 0.9998568633867206}; 105 | const double Gauss100ws[100] = {0.00036731724524932316, 0.0008546963267554215, 0.0013419626857791437, 106 | 0.0018279806006622767, 0.002312225031711083, 0.002794214001933608, 0.0032734742254225493, 107 | 0.0037495366277319757, 0.004221935734834934, 0.004690209826847327, 0.005153901287434295, 108 | 0.005612557011593201, 0.006065728831490082, 0.006512973946486294, 0.006953855351859815, 109 | 0.007387942263720422, 0.007814810538772953, 0.008234043088072605, 0.008645230284161875, 110 | 0.009047970361064483, 0.009441869806687491, 0.009826543747217534, 0.010201616323104836, 111 | 0.010566721056263852, 0.010921501208123853, 0.011265610128168027, 0.011598711592627197, 112 | 0.01192048013298404, 0.01223060135397848, 0.012528772240789849, 0.012814701455104213, 113 | 0.013088109619773088, 0.013348729591785617, 0.01359630672328859, 0.01383059911039636, 114 | 0.01405137782955077, 0.014258427161197655, 0.014451544800562783, 0.014630542055319343, 115 | 0.01479524402995644, 0.014945489796666525, 0.015081132552584713, 0.015202039763227548, 116 | 0.015308093291990342, 0.015399189515576422, 0.015475239425245637, 0.015536168713783409, 117 | 0.015581917848105089, 0.015612442127424813, 0.01562771172693182, 0.01562771172693182, 118 | 0.015612442127424813, 0.015581917848105089, 0.015536168713783409, 0.015475239425245637, 119 | 0.015399189515576422, 0.015308093291990342, 0.015202039763227548, 0.015081132552584713, 120 | 0.014945489796666525, 0.01479524402995644, 0.014630542055319343, 0.014451544800562783, 121 | 0.014258427161197655, 0.01405137782955077, 0.01383059911039636, 0.01359630672328859, 122 | 0.013348729591785617, 0.013088109619773088, 0.012814701455104213, 0.012528772240789849, 123 | 0.01223060135397848, 0.01192048013298404, 0.011598711592627197, 0.011265610128168027, 124 | 0.010921501208123853, 0.010566721056263852, 0.010201616323104836, 0.009826543747217534, 125 | 0.009441869806687491, 0.009047970361064483, 0.008645230284161875, 0.008234043088072605, 126 | 0.007814810538772953, 0.007387942263720422, 0.006953855351859815, 0.006512973946486294, 127 | 0.006065728831490082, 0.005612557011593201, 0.005153901287434295, 0.004690209826847327, 128 | 0.004221935734834934, 0.0037495366277319757, 0.0032734742254225493, 0.002794214001933608, 129 | 0.002312225031711083, 0.0018279806006622767, 0.0013419626857791437, 130 | 0.0008546963267554215, 0.00036731724524932316}; 131 | 132 | ////////////////////////////////////////////////////////////////////////////////// 133 | // Lobatto Quadrature points over [0,1] (which include the interval endpoints) 134 | ////////////////////////////////////////////////////////////////////////////////// 135 | 136 | const double Lobatto100xs[100] = {0, 0.000370711017377538597, 0.001242375481435694907, 0.002611346404772358912, 137 | 0.004476153143535852271, 0.0068349180915945049708, 0.0096852846389917529964, 138 | 0.0130244094961698053349, 0.016848963279590500672, 0.0211551331595129402674, 139 | 0.0259386264188233776701, 0.0311946746322406739235, 0.036918038373885555008, 140 | 0.043103012417379119138, 0.04974343141092531795, 0.056832676016351728468, 141 | 0.0643636795034798662743, 0.0723289347920048358038, 0.080720501933212326136, 142 | 0.0895300160237179806443, 0.0987486955431374767109, 0.1083673511072566450853, 143 | 0.1183763946279038126606, 0.1287658488703484705308, 0.139525357398670443759, 144 | 0.1506441948991670226592, 0.162111277871494969447, 0.173915175676881780936, 145 | 0.18604412193238728922, 0.198486026239853485001, 0.2112284862378480089263, 146 | 0.224258799964585602476, 0.2375639785195023862961, 0.2511307590108605290052, 147 | 0.2649456177764760327272, 0.2789947838643903116662, 0.2932642527600472719697, 148 | 0.3077398003462919891057, 0.3224069970822750790546, 0.3372512223871287108446, 149 | 0.3522576792140761333, 0.3674114088004467956906, 0.3826973055788938222698, 150 | 0.398100132234949931316, 0.413604534895912031852, 0.42919505843591383225, 151 | 0.444856161881929985787, 0.460572233905354694641, 0.47632760838371239727, 152 | 0.4921065800169882588148, 0.5078934199830117411852, 0.5236723916162876027252, 153 | 0.5394277660946453053591, 0.5551438381180700142132, 0.570804941564086167745, 154 | 0.5863954651040879681482, 0.6018998677650500686836, 0.6173026944211061777302, 155 | 0.6325885911995532043093, 0.647742320785923866699, 0.662748777612871289155, 156 | 0.6775930029177249209453, 0.692260199653708010894, 0.7067357472399527280302, 157 | 0.7210052161356096883338, 0.7350543822235239672728, 0.7488692409891394709948, 158 | 0.762436021480497613704, 0.7757412000354143975236, 0.7887715137621519910737, 159 | 0.8015139737601465149983, 0.81395587806761271078, 0.8260848243231182190637, 160 | 0.8378887221285050305528, 0.8493558051008329773408, 0.8604746426013295562404, 161 | 0.8712341511296515294692, 0.8816236053720961873394, 0.8916326488927433549146, 162 | 0.9012513044568625232891, 0.9104699839762820193557, 0.919279498066787673864, 163 | 0.9276710652079951641961, 0.9356363204965201337256, 0.9431673239836482715319, 164 | 0.9502565685890746820448, 0.9568969875826208808618, 0.9630819616261144449912, 165 | 0.9688053253677593260764, 0.9740613735811766223299, 0.9788448668404870597326, 166 | 0.983151036720409499328, 0.9869755905038301946651, 0.9903147153610082470036, 167 | 0.9931650819084054950291, 0.9955238468564641477293, 0.9973886535952276410876, 168 | 0.9987576245185643050931, 0.9996292889826224614031, 1}; 169 | const double Lobatto100ws[100] = {0.0002020202020202020202, 0.0012450766591352942893, 0.00224107975508296304, 170 | 0.0032343259236349601274, 0.00422427633165450744, 0.005209998070585079867, 171 | 0.006190520319146799369, 0.007164869223011786039, 0.008132074847738999054, 172 | 0.009091173626580326381, 0.010041209778500831941, 0.010981236426462550781, 173 | 0.01191031660877146948, 0.012827524243262733436, 0.0137319450650154626976, 174 | 0.014622677545198368306, 0.015498833793784865807, 0.01635954044691377603, 175 | 0.01720393953882560454, 0.018031189357921348572, 0.0188404652863124740298, 176 | 0.019630960622148179418, 0.020401887383970712731, 0.02115247709633855397, 177 | 0.02188198155595957279, 0.022589673577586142378, 0.02327484771893864316, 178 | 0.023936820983941188731, 0.02457493350357283128, 0.0251885491936584163, 179 | 0.02577705638894533387, 0.026339868452835451554, 0.026876424362165378012, 180 | 0.027386189266452805112, 0.0278686550210519396, 0.028323340693686911759, 181 | 0.028749793043858492721, 0.0291475869746464259332, 0.029516325956457147251, 182 | 0.029855642422294598437, 0.030165198134160199712, 0.03044468452021680701, 183 | 0.030693822982380608454, 0.03091236517403438183, 0.031100093247585310487, 184 | 0.031256820071620608072, 0.0313823894174445036, 0.031476676114810655384, 185 | 0.031539586176694766221, 0.031571056892983030979, 0.031571056892983030979, 186 | 0.03153958617669476622, 0.03147667611481065538, 0.031382389417444503601, 187 | 0.031256820071620608072, 0.031100093247585310487, 0.03091236517403438183, 188 | 0.030693822982380608454, 0.03044468452021680701, 0.030165198134160199712, 189 | 0.029855642422294598437, 0.029516325956457147251, 0.029147586974646425933, 190 | 0.02874979304385849272, 0.02832334069368691176, 0.0278686550210519396, 191 | 0.02738618926645280511, 0.02687642436216537801, 0.02633986845283545155, 192 | 0.02577705638894533387, 0.0251885491936584163, 0.02457493350357283128, 193 | 0.023936820983941188731, 0.023274847718938643155, 0.02258967357758614238, 194 | 0.02188198155595957279, 0.021152477096338553971, 0.02040188738397071273, 195 | 0.019630960622148179418, 0.01884046528631247403, 0.01803118935792134857, 196 | 0.017203939538825604536, 0.016359540446913776, 0.01549883379378486581, 197 | 0.01462267754519836831, 0.0137319450650154627, 0.012827524243262733436, 198 | 0.01191031660877146948, 0.010981236426462550781, 0.010041209778500831941, 199 | 0.009091173626580326381, 0.00813207484773899905, 0.007164869223011786039, 200 | 0.006190520319146799369, 0.00520999807058507987, 0.0042242763316545074348, 201 | 0.003234325923634960127, 0.00224107975508296304, 0.001245076659135294289, 202 | 0.0002020202020202020202}; -------------------------------------------------------------------------------- /test/NDFs/test_dirac_NDF_sigma.nb: -------------------------------------------------------------------------------- 1 | (* Content-type: application/vnd.wolfram.mathematica *) 2 | 3 | (*** Wolfram Notebook File ***) 4 | (* http://www.wolfram.com/nb *) 5 | 6 | (* CreatedBy='Mathematica 13.0' *) 7 | 8 | (*CacheID: 234*) 9 | (* Internal cache information: 10 | NotebookFileLineBreakTest 11 | NotebookFileLineBreakTest 12 | NotebookDataPosition[ 158, 7] 13 | NotebookDataLength[ 19106, 420] 14 | NotebookOptionsPosition[ 17749, 387] 15 | NotebookOutlinePosition[ 18145, 403] 16 | CellTagsIndexPosition[ 18102, 400] 17 | WindowFrame->Normal*) 18 | 19 | (* Beginning of Notebook Content *) 20 | Notebook[{ 21 | 22 | Cell[CellGroupData[{ 23 | Cell["Test Dirac NDF C++ implementation", "Title", 24 | CellChangeTimes->{{3.8856095365929823`*^9, 25 | 3.885609547347034*^9}},ExpressionUUID->"46271c2f-5f41-4bb6-868c-\ 26 | 17337ce2922a"], 27 | 28 | Cell[CellGroupData[{ 29 | 30 | Cell["License", "Section", 31 | CellChangeTimes->{{3.893968108307357*^9, 32 | 3.893968109187154*^9}},ExpressionUUID->"e1964352-9710-41d8-83a2-\ 33 | 15f09971a5b9"], 34 | 35 | Cell["\<\ 36 | /* 37 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 38 | * 39 | * Licensed under the Apache License, Version 2.0 (the \ 40 | \[OpenCurlyDoubleQuote]License\[CloseCurlyDoubleQuote]); 41 | * you may not use this file except in compliance with the License. 42 | * You may obtain a copy of the License at 43 | * 44 | * http://www.apache.org/licenses/LICENSE-2.0 45 | * 46 | * Unless required by applicable law or agreed to in writing, software 47 | * distributed under the License is distributed on an \ 48 | \[OpenCurlyDoubleQuote]AS IS\[CloseCurlyDoubleQuote] BASIS, 49 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 50 | * See the License for the specific language governing permissions and 51 | * limitations under the License. 52 | */\ 53 | \>", "Text", 54 | CellChangeTimes->{{3.8939680334818897`*^9, 3.893968079467637*^9}, { 55 | 3.895081298208552*^9, 56 | 3.895081310279977*^9}},ExpressionUUID->"67d4b80a-4cde-4b69-a538-\ 57 | 8c09190818e3"] 58 | }, Closed]], 59 | 60 | Cell[CellGroupData[{ 61 | 62 | Cell["", "Section",ExpressionUUID->"591af34a-2bc8-4028-be01-7856bcd39fde"], 63 | 64 | Cell[CellGroupData[{ 65 | 66 | Cell[BoxData[ 67 | RowBox[{"Run", "[", 68 | "\"\\"", "]"}]], "Input", 70 | CellChangeTimes->{{3.8767825053242607`*^9, 3.876782521757235*^9}}, 71 | CellLabel->"In[77]:=",ExpressionUUID->"6324783e-3886-4299-bbaf-1fc8a8326dc7"], 72 | 73 | Cell[BoxData["0"], "Output", 74 | CellChangeTimes->{{3.8767825147761106`*^9, 3.8767825224936666`*^9}, 75 | 3.876782669994176*^9, {3.876782725980735*^9, 3.876782756908813*^9}, 76 | 3.877050544289469*^9, 3.877118802816209*^9, {3.885609512248098*^9, 77 | 3.885609516601956*^9}, {3.885609552077551*^9, 3.885609561775597*^9}}, 78 | CellLabel->"Out[77]=",ExpressionUUID->"ecf46109-6bb6-48e9-b2e4-3f4b57a417ef"] 79 | }, Open ]], 80 | 81 | Cell[BoxData[ 82 | RowBox[{ 83 | RowBox[{ 84 | RowBox[{"plotpoints", "[", 85 | RowBox[{"data_", ",", "d_", ",", "min_"}], "]"}], ":=", 86 | RowBox[{"Table", "[", 87 | RowBox[{ 88 | RowBox[{"{", 89 | RowBox[{ 90 | RowBox[{"min", "+", 91 | RowBox[{"d", " ", "i"}], " ", "-", " ", 92 | RowBox[{"0.5", " ", "d"}]}], ",", 93 | RowBox[{"data", "[", 94 | RowBox[{"[", "i", "]"}], "]"}]}], "}"}], ",", 95 | RowBox[{"{", 96 | RowBox[{"i", ",", "1", ",", 97 | RowBox[{"Length", "[", "data", "]"}]}], "}"}]}], "]"}]}], 98 | ";"}]], "Input", 99 | CellChangeTimes->{{3.679782606935545*^9, 3.6797826436214*^9}, 100 | 3.734496433004559*^9, 3.76235299969685*^9, 3.8088973085476093`*^9}, 101 | CellLabel->"In[78]:=",ExpressionUUID->"2e909850-687a-4205-95e6-e662fa006aa7"], 102 | 103 | Cell[BoxData[ 104 | RowBox[{ 105 | RowBox[{"Dirac`\[Sigma]", "[", 106 | RowBox[{"u_", ",", "ui_"}], "]"}], ":=", 107 | RowBox[{"Re", "[", 108 | RowBox[{"2", 109 | RowBox[{"(", 110 | RowBox[{ 111 | SqrtBox[ 112 | RowBox[{"1", "-", 113 | SuperscriptBox["u", "2"], "-", 114 | SuperscriptBox["ui", "2"]}]], "+", 115 | RowBox[{"u", " ", "ui", " ", 116 | RowBox[{"ArcCos", "[", 117 | RowBox[{"-", 118 | FractionBox[ 119 | RowBox[{"u", " ", "ui"}], 120 | RowBox[{ 121 | SqrtBox[ 122 | RowBox[{"1", "-", 123 | SuperscriptBox["u", "2"]}]], " ", 124 | SqrtBox[ 125 | RowBox[{"1", "-", 126 | SuperscriptBox["ui", "2"]}]]}]]}], "]"}]}]}], ")"}]}], 127 | "]"}]}]], "Input", 128 | CellChangeTimes->{{3.7991299144968576`*^9, 3.799129916991254*^9}, { 129 | 3.799129956990402*^9, 3.799129977197599*^9}, {3.799136714555601*^9, 130 | 3.7991367428749*^9}, 3.799136873974616*^9, {3.7991375100946817`*^9, 131 | 3.799137512252878*^9}, 3.799137552161944*^9, {3.799137613430187*^9, 132 | 3.799137613543277*^9}}, 133 | CellLabel->"In[79]:=",ExpressionUUID->"5371d1dd-3647-4237-94b5-ca5d17eb8603"], 134 | 135 | Cell[CellGroupData[{ 136 | 137 | Cell[BoxData[{ 138 | RowBox[{ 139 | RowBox[{"un", "=", ".4"}], ";"}], "\[IndentingNewLine]", 140 | RowBox[{ 141 | RowBox[{"Run", "[", 142 | RowBox[{"\"\<./test/NDFs/test_dirac_NDF_sigma 0.01 \>\"", "<>", 143 | RowBox[{"ToString", "[", "un", "]"}], "<>", "\"\< > test.txt\>\""}], 144 | "]"}], ";"}], "\[IndentingNewLine]", 145 | RowBox[{ 146 | RowBox[{"p", "=", 147 | RowBox[{"Import", "[", 148 | RowBox[{"\"\\"", ",", "\"\\""}], "]"}]}], 149 | ";"}], "\[IndentingNewLine]", 150 | RowBox[{"Show", "[", "\[IndentingNewLine]", 151 | RowBox[{ 152 | RowBox[{"ListPlot", "[", 153 | RowBox[{"plotpoints", "[", 154 | RowBox[{ 155 | RowBox[{"p", "[", 156 | RowBox[{"[", "1", "]"}], "]"}], ",", "0.01", ",", 157 | RowBox[{"-", "1"}]}], "]"}], "]"}], ",", "\[IndentingNewLine]", 158 | RowBox[{"Plot", "[", 159 | RowBox[{ 160 | RowBox[{"Dirac`\[Sigma]", "[", 161 | RowBox[{"u", ",", "un"}], "]"}], ",", 162 | RowBox[{"{", 163 | RowBox[{"u", ",", 164 | RowBox[{"-", "1"}], ",", "1"}], "}"}], ",", 165 | RowBox[{"PlotStyle", "\[Rule]", "Black"}]}], "]"}]}], 166 | "\[IndentingNewLine]", "]"}]}], "Input", 167 | CellChangeTimes->{{3.876782536023967*^9, 3.8767826588699512`*^9}, { 168 | 3.8767826897371264`*^9, 3.876782755876789*^9}, {3.885609550992951*^9, 169 | 3.8856095608292522`*^9}}, 170 | CellLabel->"In[80]:=",ExpressionUUID->"5173a0c1-8ca7-4efa-a186-b74386d38f13"], 171 | 172 | Cell[BoxData[ 173 | GraphicsBox[{{{}, 174 | {RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.009166666666666668], 175 | AbsoluteThickness[1.6], PointBox[CompressedData[" 176 | 1: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 226 | Oy9w/nMVxqOO9m+VCvk/trsZpw== 227 | "]]}, {{}, {}}}, {{{}, {}, 228 | TagBox[ 229 | {GrayLevel[0], AbsoluteThickness[1.6], Opacity[1.], 230 | LineBox[CompressedData[" 231 | 1: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 347 | XFSy 348 | "]]}, 349 | Annotation[#, "Charting`Private`Tag$5694#1"]& ]}, {}}}, 350 | AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], 351 | Axes->{True, True}, 352 | AxesLabel->{None, None}, 353 | AxesOrigin->{0, 0}, 354 | DisplayFunction->Identity, 355 | Frame->{{False, False}, {False, False}}, 356 | FrameLabel->{{None, None}, {None, None}}, 357 | FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}}, 358 | GridLines->{None, None}, 359 | GridLinesStyle->Directive[ 360 | GrayLevel[0.5, 0.4]], 361 | Method->{ 362 | "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, 363 | "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ 364 | Identity[ 365 | Part[#, 1]], 366 | Identity[ 367 | Part[#, 2]]}& ), "CopiedValueFunction" -> ({ 368 | Identity[ 369 | Part[#, 1]], 370 | Identity[ 371 | Part[#, 2]]}& )}}, 372 | PlotRange->{{-0.995, 0.995}, {0, 2.48814}}, 373 | PlotRangeClipping->True, 374 | PlotRangePadding->{{ 375 | Scaled[0.02], 376 | Scaled[0.02]}, { 377 | Scaled[0.02], 378 | Scaled[0.05]}}, 379 | Ticks->{Automatic, Automatic}]], "Output", 380 | CellChangeTimes->{{3.876782632815411*^9, 3.87678275706187*^9}, 381 | 3.877050544760765*^9, 3.87711880319042*^9, {3.8856095127510242`*^9, 382 | 3.88560951669007*^9}, {3.885609552165169*^9, 3.885609561864146*^9}}, 383 | CellLabel->"Out[83]=",ExpressionUUID->"5fee35a3-cc28-4dfc-bebc-df3cff7ba9fc"] 384 | }, Open ]] 385 | }, Open ]] 386 | }, Open ]] 387 | }, 388 | WindowSize->{808, 763}, 389 | WindowMargins->{{258, Automatic}, {Automatic, 0}}, 390 | FrontEndVersion->"13.0 for Mac OS X ARM (64-bit) (December 2, 2021)", 391 | StyleDefinitions->"Default.nb", 392 | ExpressionUUID->"03051b70-4935-47b7-8b2d-e0b1f5492957" 393 | ] 394 | (* End of Notebook Content *) 395 | 396 | (* Internal cache information *) 397 | (*CellTagsOutline 398 | CellTagsIndex->{} 399 | *) 400 | (*CellTagsIndex 401 | CellTagsIndex->{} 402 | *) 403 | (*NotebookFileOutline 404 | Notebook[{ 405 | Cell[CellGroupData[{ 406 | Cell[580, 22, 178, 3, 98, "Title",ExpressionUUID->"46271c2f-5f41-4bb6-868c-17337ce2922a"], 407 | Cell[CellGroupData[{ 408 | Cell[783, 29, 152, 3, 67, "Section",ExpressionUUID->"e1964352-9710-41d8-83a2-15f09971a5b9"], 409 | Cell[938, 34, 937, 22, 357, "Text",ExpressionUUID->"67d4b80a-4cde-4b69-a538-8c09190818e3"] 410 | }, Closed]], 411 | Cell[CellGroupData[{ 412 | Cell[1912, 61, 74, 0, 53, "Section",ExpressionUUID->"591af34a-2bc8-4028-be01-7856bcd39fde"], 413 | Cell[CellGroupData[{ 414 | Cell[2011, 65, 306, 5, 73, "Input",ExpressionUUID->"6324783e-3886-4299-bbaf-1fc8a8326dc7"], 415 | Cell[2320, 72, 393, 5, 34, "Output",ExpressionUUID->"ecf46109-6bb6-48e9-b2e4-3f4b57a417ef"] 416 | }, Open ]], 417 | Cell[2728, 80, 756, 20, 30, "Input",ExpressionUUID->"2e909850-687a-4205-95e6-e662fa006aa7"], 418 | Cell[3487, 102, 1097, 30, 62, "Input",ExpressionUUID->"5371d1dd-3647-4237-94b5-ca5d17eb8603"], 419 | Cell[CellGroupData[{ 420 | Cell[4609, 136, 1311, 33, 157, "Input",ExpressionUUID->"5173a0c1-8ca7-4efa-a186-b74386d38f13"], 421 | Cell[5923, 171, 11786, 211, 249, "Output",ExpressionUUID->"5fee35a3-cc28-4dfc-bebc-df3cff7ba9fc"] 422 | }, Open ]] 423 | }, Open ]] 424 | }, Open ]] 425 | } 426 | ] 427 | *) 428 | 429 | -------------------------------------------------------------------------------- /test/NDFs/test_ST_sigma.nb: -------------------------------------------------------------------------------- 1 | (* Content-type: application/vnd.wolfram.mathematica *) 2 | 3 | (*** Wolfram Notebook File ***) 4 | (* http://www.wolfram.com/nb *) 5 | 6 | (* CreatedBy='Mathematica 13.0' *) 7 | 8 | (*CacheID: 234*) 9 | (* Internal cache information: 10 | NotebookFileLineBreakTest 11 | NotebookFileLineBreakTest 12 | NotebookDataPosition[ 158, 7] 13 | NotebookDataLength[ 32267, 665] 14 | NotebookOptionsPosition[ 30166, 621] 15 | NotebookOutlinePosition[ 30562, 637] 16 | CellTagsIndexPosition[ 30519, 634] 17 | WindowFrame->Normal*) 18 | 19 | (* Beginning of Notebook Content *) 20 | Notebook[{ 21 | 22 | Cell[CellGroupData[{ 23 | Cell["Test Student-T sigma", "Title", 24 | CellChangeTimes->{{3.853604869177883*^9, 3.853604877927293*^9}, { 25 | 3.874988896332384*^9, 3.874988909329043*^9}, {3.8750765113830757`*^9, 26 | 3.875076514272233*^9}, {3.8751789191101093`*^9, 3.8751789227053223`*^9}, { 27 | 3.875180676914577*^9, 3.875180677602037*^9}, {3.876072136154594*^9, 28 | 3.87607214032512*^9}, {3.8760755072489853`*^9, 3.876075507563546*^9}, { 29 | 3.876104755579564*^9, 3.876104758142618*^9}, {3.876195505315456*^9, 30 | 3.876195507079241*^9}},ExpressionUUID->"cafadb98-a2c8-47cd-905c-\ 31 | 0b5027ceb082"], 32 | 33 | Cell[CellGroupData[{ 34 | 35 | Cell["License", "Section", 36 | CellChangeTimes->{{3.893968108307357*^9, 37 | 3.893968109187154*^9}},ExpressionUUID->"8d766eea-8eda-4cef-846a-\ 38 | 462ef231d3bb"], 39 | 40 | Cell["\<\ 41 | /* 42 | * Copyright (c) <2023> NVIDIA CORPORATION & AFFILIATES. All rights reserved. 43 | * 44 | * Licensed under the Apache License, Version 2.0 (the \ 45 | \[OpenCurlyDoubleQuote]License\[CloseCurlyDoubleQuote]); 46 | * you may not use this file except in compliance with the License. 47 | * You may obtain a copy of the License at 48 | * 49 | * http://www.apache.org/licenses/LICENSE-2.0 50 | * 51 | * Unless required by applicable law or agreed to in writing, software 52 | * distributed under the License is distributed on an \ 53 | \[OpenCurlyDoubleQuote]AS IS\[CloseCurlyDoubleQuote] BASIS, 54 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 55 | * See the License for the specific language governing permissions and 56 | * limitations under the License. 57 | */\ 58 | \>", "Text", 59 | CellChangeTimes->{{3.8939680334818897`*^9, 3.893968079467637*^9}, { 60 | 3.895081298208552*^9, 61 | 3.895081310279977*^9}},ExpressionUUID->"e1fe63ab-ac92-4729-bfde-\ 62 | 22abf2ab7567"] 63 | }, Closed]], 64 | 65 | Cell[CellGroupData[{ 66 | 67 | Cell["", "Section",ExpressionUUID->"0fa69ea0-81c8-4cec-8193-e8fdd7605d49"], 68 | 69 | Cell[CellGroupData[{ 70 | 71 | Cell[BoxData[ 72 | RowBox[{"Run", "[", 73 | "\"\\"", "]"}]], "Input", 75 | CellChangeTimes->{{3.853652509624414*^9, 3.853652522875248*^9}, { 76 | 3.8544026405483017`*^9, 3.854402644487611*^9}, {3.874988935418335*^9, 77 | 3.8749889708595753`*^9}, {3.8750765199864073`*^9, 3.875076542529344*^9}, { 78 | 3.8751789281186857`*^9, 3.875178934749113*^9}, {3.8751804556963997`*^9, 79 | 3.875180484482751*^9}, {3.87607215084118*^9, 3.876072180802795*^9}, { 80 | 3.8760755119732*^9, 3.8760755152815247`*^9}, {3.87610476162609*^9, 81 | 3.876104764086453*^9}, {3.876106006015765*^9, 3.876106006335411*^9}, { 82 | 3.876195512752673*^9, 3.876195516612089*^9}, 3.8761957407401867`*^9, { 83 | 3.87669387477634*^9, 3.8766938753152742`*^9}}, 84 | CellLabel-> 85 | "In[2048]:=",ExpressionUUID->"d4774696-34be-4f98-82f8-ff055f032631"], 86 | 87 | Cell[BoxData["0"], "Output", 88 | CellChangeTimes->{ 89 | 3.853652523973271*^9, 3.853652562133616*^9, {3.853652668011551*^9, 90 | 3.853652709601359*^9}, 3.853652743224126*^9, 3.853652821097744*^9, { 91 | 3.8536529154676933`*^9, 3.8536529396594067`*^9}, 3.853653007141691*^9, { 92 | 3.853653038155518*^9, 3.853653055688315*^9}, {3.853653688495758*^9, 93 | 3.853653716899053*^9}, 3.8536539427935753`*^9, 3.853693753850423*^9, 94 | 3.853693874930637*^9, 3.853693913692821*^9, 3.853694098948028*^9, 95 | 3.853694146668632*^9, 3.853694182827147*^9, 3.8536942295674686`*^9, { 96 | 3.853694261666278*^9, 3.853694285525242*^9}, 3.853792100605393*^9, 97 | 3.853942077770421*^9, 3.854327369902961*^9, 3.8543275593927794`*^9, { 98 | 3.8543276084245033`*^9, 3.854327626824141*^9}, 3.8543276794481087`*^9, { 99 | 3.85432772098759*^9, 3.854327736957007*^9}, {3.854327789435568*^9, 100 | 3.854327808210045*^9}, 3.854327868450338*^9, {3.854327957819296*^9, 101 | 3.8543279783721437`*^9}, 3.85432803839225*^9, 3.85432815306593*^9, 102 | 3.854328784338279*^9, 3.85432885999581*^9, 3.8543289914238777`*^9, 103 | 3.854402644902904*^9, 3.854402675187337*^9, {3.854403091889188*^9, 104 | 3.854403115738021*^9}, 3.8544032113354797`*^9, 3.874988972620096*^9, 105 | 3.874989249199707*^9, {3.87507558937219*^9, 3.875075599264119*^9}, 106 | 3.875076544173409*^9, {3.8750766468769903`*^9, 3.87507667292799*^9}, 107 | 3.8751346629620447`*^9, {3.875135865847496*^9, 3.875135889662197*^9}, 108 | 3.8751369974017153`*^9, 3.8751750368868647`*^9, 3.875175285671653*^9, 109 | 3.8751753464442863`*^9, 3.8751757551046553`*^9, 3.8751758055099382`*^9, 110 | 3.875175884731575*^9, {3.8751789359737797`*^9, 3.87517894745704*^9}, 111 | 3.875180486701968*^9, 3.875200453292428*^9, 3.875209037610875*^9, { 112 | 3.875219919849084*^9, 3.87521994240879*^9}, 3.875220115204533*^9, 113 | 3.875222681038704*^9, 3.875223510482109*^9, 3.875223591577156*^9, { 114 | 3.875223680328719*^9, 3.875223689171563*^9}, 3.8752239195390472`*^9, 115 | 3.8752260886945*^9, {3.875227690250386*^9, 3.875227711231428*^9}, 116 | 3.875233943548562*^9, 3.8752344668806963`*^9, 3.875234527097649*^9, { 117 | 3.875246386276141*^9, 3.8752464111826982`*^9}, 3.8752790834192753`*^9, 118 | 3.87607218238418*^9, {3.876072334456561*^9, 3.8760723694944353`*^9}, 119 | 3.876074832904368*^9, {3.876074917466744*^9, 3.8760749622048903`*^9}, { 120 | 3.876075024045567*^9, 3.876075045093923*^9}, 3.876075524987368*^9, { 121 | 3.876104764834284*^9, 3.8761047947633467`*^9}, {3.8761048463557*^9, 122 | 3.876104866126589*^9}, {3.876104925875739*^9, 3.876104988132979*^9}, { 123 | 3.876106007715541*^9, 3.87610600944475*^9}, {3.8761061163808947`*^9, 124 | 3.8761061303086557`*^9}, {3.876106303435734*^9, 3.876106320835754*^9}, { 125 | 3.8761064265097103`*^9, 3.8761064875540867`*^9}, {3.8761065450279207`*^9, 126 | 3.8761065578328123`*^9}, {3.8761065885349197`*^9, 3.876106607887334*^9}, { 127 | 3.876106942473052*^9, 3.876106964228303*^9}, {3.8761931137994633`*^9, 128 | 3.8761931328110533`*^9}, 3.876193412287566*^9, {3.876193457225864*^9, 129 | 3.876193490923644*^9}, {3.876193542401517*^9, 3.8761935948048267`*^9}, 130 | 3.876194762070649*^9, 3.876194802662773*^9, 3.876194990959659*^9, { 131 | 3.876195268933544*^9, 3.876195304293785*^9}, {3.876195654484125*^9, 132 | 3.876195686103978*^9}, 3.876195741657359*^9, 3.876195812155143*^9, 133 | 3.876196281383926*^9, 3.876196348451281*^9, 3.87619638514211*^9, { 134 | 3.876196501708316*^9, 3.8761965430420237`*^9}, {3.87627661834746*^9, 135 | 3.876276620225773*^9}, {3.876276667651886*^9, 3.8762766851832113`*^9}, { 136 | 3.876276718978969*^9, 3.876276748147312*^9}, 3.8762813652340107`*^9, { 137 | 3.876611797090736*^9, 3.876611844173483*^9}, {3.876612849484488*^9, 138 | 3.876612852177414*^9}, 3.876693876671816*^9, 3.877118876373248*^9, { 139 | 3.877118940406514*^9, 3.8771189625530243`*^9}, 3.885609665672162*^9, 140 | 3.894728239427272*^9, {3.894729291694722*^9, 3.89472935168812*^9}}, 141 | CellLabel-> 142 | "Out[2048]=",ExpressionUUID->"646e102e-4024-4a89-9b15-51334ddde6c0"] 143 | }, Open ]], 144 | 145 | Cell[BoxData[{ 146 | RowBox[{ 147 | RowBox[{"roughx", "=", "\"\<0.8\>\""}], ";"}], "\[IndentingNewLine]", 148 | RowBox[{ 149 | RowBox[{"roughy", "=", "\"\<0.6\>\""}], ";"}], "\[IndentingNewLine]", 150 | RowBox[{ 151 | RowBox[{"gamma", "=", "\"\<2.1\>\""}], ";"}], "\[IndentingNewLine]", 152 | RowBox[{ 153 | RowBox[{"du", "=", "\"\<0.01\>\""}], ";"}], "\[IndentingNewLine]", 154 | RowBox[{ 155 | RowBox[{"phi", "=", "\"\<2.2\>\""}], ";"}]}], "Input", 156 | CellChangeTimes->{{3.8751751796732063`*^9, 3.875175212843752*^9}, { 157 | 3.8751753375455503`*^9, 3.875175343299201*^9}, 3.875175392137182*^9, { 158 | 3.875175752365299*^9, 3.875175753225226*^9}, {3.8751758033051367`*^9, 159 | 3.8751758037269278`*^9}, 3.875175883081215*^9, 3.875180488848906*^9, { 160 | 3.8752199408894367`*^9, 3.875219941017952*^9}, {3.8752235041200438`*^9, 161 | 3.875223509077883*^9}, {3.87522358927988*^9, 3.875223590090238*^9}, { 162 | 3.875246408224306*^9, 3.875246427716936*^9}, {3.876072332044539*^9, 163 | 3.876072368265914*^9}, 3.876074831206682*^9, 3.876074961055306*^9, { 164 | 3.87607501464277*^9, 3.8760750437660837`*^9}, {3.876104766293109*^9, 165 | 3.876104773351941*^9}, {3.8761048448203783`*^9, 3.876104864987185*^9}, { 166 | 3.876104958655368*^9, 3.8761049856262197`*^9}, {3.876106115006587*^9, 167 | 3.876106129193095*^9}, {3.876106465970325*^9, 3.876106486491523*^9}, { 168 | 3.876106955011815*^9, 3.876106963167938*^9}, {3.87619311151121*^9, 169 | 3.876193131594797*^9}, {3.876193473414679*^9, 3.876193489947809*^9}, { 170 | 3.876193541225902*^9, 3.8761935937068443`*^9}, {3.876195521529647*^9, 171 | 3.8761955257784767`*^9}, 3.876196383072544*^9, {3.876196500504909*^9, 172 | 3.876196542065382*^9}, {3.876276737040634*^9, 3.8762767473275003`*^9}, { 173 | 3.876611806583118*^9, 3.876611843110072*^9}, {3.894729313456134*^9, 174 | 3.894729351005265*^9}}, 175 | CellLabel-> 176 | "In[2049]:=",ExpressionUUID->"6cb796c9-96ba-4e21-a182-e7743e98a6ca"], 177 | 178 | Cell[CellGroupData[{ 179 | 180 | Cell[BoxData[ 181 | RowBox[{"argstr", "=", 182 | RowBox[{ 183 | "roughx", "<>", "\"\< \>\"", "<>", "roughy", "<>", "\"\< \>\"", "<>", 184 | "gamma", "<>", "\"\< \>\"", "<>", "du", "<>", "\"\< \>\"", "<>", "phi", 185 | "<>", "\"\< > test/NDFs/MC.txt\>\""}]}]], "Input", 186 | CellChangeTimes->{{3.875136889195887*^9, 3.875136901297858*^9}, 187 | 3.875175018696622*^9, {3.8751752173496857`*^9, 3.875175271101522*^9}, { 188 | 3.8751804975006733`*^9, 3.875180503259213*^9}, {3.875223678270338*^9, 189 | 3.875223679340989*^9}, {3.8760722133081217`*^9, 3.876072219327136*^9}, { 190 | 3.87607502105656*^9, 3.876075022523555*^9}, {3.87610478389305*^9, 191 | 3.876104785590461*^9}, {3.8761955286899023`*^9, 3.876195529187557*^9}, { 192 | 3.894729286583235*^9, 3.89472928701735*^9}}, 193 | CellLabel-> 194 | "In[2054]:=",ExpressionUUID->"852e0457-7370-4a2e-9a2c-b07ee476dd16"], 195 | 196 | Cell[BoxData["\<\"0.8 0.6 2.1 0.01 2.2 > test/NDFs/MC.txt\"\>"], "Output", 197 | CellChangeTimes->{{3.875175256941235*^9, 3.8751752856878157`*^9}, 198 | 3.8751753464623327`*^9, 3.875175755120822*^9, 3.875175805525391*^9, 199 | 3.875175884748804*^9, 3.875178947472733*^9, 3.87518050459064*^9, 200 | 3.87520903762372*^9, {3.875219919863879*^9, 3.8752199424207*^9}, 201 | 3.8752201152167253`*^9, 3.875222681052072*^9, 3.875223510497527*^9, 202 | 3.875223591589816*^9, {3.875223680341004*^9, 3.8752236891829*^9}, 203 | 3.875223919551713*^9, 3.8752260887073727`*^9, {3.8752276902626553`*^9, 204 | 3.875227711242196*^9}, 3.875233943581912*^9, 3.8752344668920317`*^9, 205 | 3.8752345271098137`*^9, {3.875246386288125*^9, 3.875246411194936*^9}, 206 | 3.87527908343359*^9, {3.876072222414824*^9, 3.876072227162318*^9}, { 207 | 3.876072334473621*^9, 3.876072369508688*^9}, 3.87607483292218*^9, { 208 | 3.876074917480055*^9, 3.876074962220594*^9}, {3.876075024061021*^9, 209 | 3.876075045109836*^9}, 3.876075525003195*^9, {3.876104786128214*^9, 210 | 3.876104794779016*^9}, {3.8761048463707314`*^9, 3.8761048661410427`*^9}, { 211 | 3.876104925889155*^9, 3.8761049881476707`*^9}, 3.876106009458515*^9, { 212 | 3.876106116398117*^9, 3.876106130323333*^9}, {3.876106303449839*^9, 213 | 3.876106320850342*^9}, {3.8761064265236807`*^9, 3.876106487569463*^9}, { 214 | 3.876106545042741*^9, 3.8761065578460073`*^9}, {3.876106588548732*^9, 215 | 3.876106607901906*^9}, {3.876106942489406*^9, 3.876106964242711*^9}, { 216 | 3.876193113825262*^9, 3.876193132830019*^9}, 3.876193412303658*^9, { 217 | 3.8761934572445593`*^9, 3.876193490939761*^9}, {3.876193542418539*^9, 218 | 3.8761935948228893`*^9}, 3.8761948026787577`*^9, 3.876194990975863*^9, 219 | 3.876195268950479*^9, 3.876195304313251*^9, 3.876195532562853*^9, 220 | 3.8761956544986877`*^9, 3.8761956861172028`*^9, 3.876195741671225*^9, 221 | 3.8761958121688347`*^9, 3.876196281397838*^9, 3.876196348464731*^9, 222 | 3.876196385157967*^9, {3.8761965017270937`*^9, 3.8761965430573997`*^9}, 223 | 3.876276618363214*^9, {3.87627666766756*^9, 3.8762766851972437`*^9}, { 224 | 3.87627671899271*^9, 3.876276748163947*^9}, 3.876281365250722*^9, { 225 | 3.8766117971083603`*^9, 3.876611844189086*^9}, 3.8766128521906137`*^9, 226 | 3.876693876683029*^9, 3.877118876384819*^9, {3.877118940418221*^9, 227 | 3.877118962565196*^9}, 3.885609665689972*^9, 3.8947282394628973`*^9, { 228 | 3.8947292917321253`*^9, 3.8947293517071133`*^9}}, 229 | CellLabel-> 230 | "Out[2054]=",ExpressionUUID->"154fef02-a55a-4542-b66d-0dead71c55d8"] 231 | }, Open ]], 232 | 233 | Cell[CellGroupData[{ 234 | 235 | Cell[BoxData[ 236 | RowBox[{"Run", "[", 237 | RowBox[{"\"\<./test/NDFs/test_ST_sigma \>\"", "<>", "argstr"}], 238 | "]"}]], "Input", 239 | CellChangeTimes->{{3.853652526441062*^9, 3.853652560646174*^9}, { 240 | 3.853652664750012*^9, 3.853652708205249*^9}, {3.853652741561326*^9, 241 | 3.853652741949379*^9}, 3.853652938129249*^9, 3.853653003306163*^9, { 242 | 3.853653036780143*^9, 3.85365305440639*^9}, {3.8536939075499573`*^9, 243 | 3.8536939123599358`*^9}, {3.853694144308626*^9, 3.853694181231407*^9}, { 244 | 3.8543274008722763`*^9, 3.85432740105027*^9}, {3.8543275264907837`*^9, 245 | 3.854327558193596*^9}, 3.85432815174284*^9, {3.854328782198861*^9, 246 | 3.85432879562749*^9}, {3.854328986856161*^9, 3.854328989896563*^9}, 247 | 3.854402681779684*^9, {3.874988995898716*^9, 3.874989009508758*^9}, 248 | 3.8750755980980473`*^9, {3.8750766592261972`*^9, 3.8750766691536837`*^9}, { 249 | 3.875135875355103*^9, 3.8751358811361856`*^9}, {3.875136063983959*^9, 250 | 3.8751360647988377`*^9}, {3.875136895508535*^9, 3.875136905167297*^9}, 251 | 3.875178943681772*^9, {3.875180528537393*^9, 3.8751805332496758`*^9}, { 252 | 3.876072236911015*^9, 3.8760722449985456`*^9}, {3.876075521663803*^9, 253 | 3.876075521982987*^9}, {3.876104790095347*^9, 3.876104790965116*^9}, 254 | 3.876195541357691*^9}, 255 | CellLabel-> 256 | "In[2055]:=",ExpressionUUID->"2fc2e019-7298-4725-8615-083447076ba2"], 257 | 258 | Cell[BoxData["0"], "Output", 259 | CellChangeTimes->{ 260 | 3.853652567245309*^9, {3.8536526736151037`*^9, 3.853652723013242*^9}, 261 | 3.853652757135872*^9, 3.853652835307925*^9, {3.853652929735057*^9, 262 | 3.853652952926835*^9}, {3.853653019983626*^9, 3.853653065945003*^9}, { 263 | 3.8536536986724157`*^9, 3.853653727082522*^9}, 3.853653953388418*^9, 264 | 3.853693764605667*^9, 3.8536938858559523`*^9, 3.8536939239764633`*^9, 265 | 3.853694109792078*^9, 3.853694158268716*^9, 3.853694195834531*^9, 266 | 3.853694242050582*^9, {3.8536942747121677`*^9, 3.85369429879499*^9}, 267 | 3.853792113876783*^9, 3.853942091128665*^9, 3.8543274142943583`*^9, 268 | 3.854327569762792*^9, {3.854327618722677*^9, 3.854327636991335*^9}, 269 | 3.854327689652165*^9, 3.8543277474835157`*^9, {3.8543277960535088`*^9, 270 | 3.854327818026061*^9}, 3.854327878980809*^9, {3.854327968350078*^9, 271 | 3.8543279888674297`*^9}, 3.854328048822425*^9, 3.854328165496497*^9, 272 | 3.854328859435875*^9, {3.854328979607871*^9, 3.854329004581148*^9}, 273 | 3.854402690306857*^9, {3.854403109036046*^9, 3.854403129772744*^9}, 274 | 3.8544032257074203`*^9, 3.874989011113585*^9, 3.874989250215481*^9, { 275 | 3.875075590337451*^9, 3.875075599867872*^9}, 3.875076682448441*^9, 276 | 3.875134670372231*^9, {3.875135869654499*^9, 3.875135893129034*^9}, 277 | 3.875136073834897*^9, 3.875136942703494*^9, 3.8751370060421047`*^9, 278 | 3.875175040361989*^9, 3.875175290962119*^9, 3.87517534826737*^9, 279 | 3.8751757624729156`*^9, 3.875175813026826*^9, 3.875175891594831*^9, 280 | 3.8751789546326*^9, 3.875180541598917*^9, 3.875209044857706*^9, { 281 | 3.875219927529859*^9, 3.8752199500180197`*^9}, 3.87522012291671*^9, 282 | 3.875222693233653*^9, 3.875223518892263*^9, 3.875223605885721*^9, { 283 | 3.875223682157885*^9, 3.875223690698599*^9}, 3.875223921435503*^9, 284 | 3.875226090625267*^9, {3.87522769208106*^9, 3.875227712967205*^9}, 285 | 3.87523394500121*^9, 3.875234468674646*^9, 3.875234528805805*^9, { 286 | 3.87524638866142*^9, 3.875246414919972*^9}, 3.875279085790738*^9, 287 | 3.8760722469939423`*^9, {3.8760723350624228`*^9, 3.8760723702962217`*^9}, 288 | 3.8760748344163103`*^9, {3.876074918524067*^9, 3.876074962908188*^9}, { 289 | 3.8760750250336733`*^9, 3.876075045933181*^9}, 3.876075525617915*^9, { 290 | 3.876104792303121*^9, 3.876104795656872*^9}, {3.876104847253017*^9, 291 | 3.876104866954959*^9}, {3.876104926963305*^9, 3.876104988390027*^9}, 292 | 3.8761060098785667`*^9, {3.876106117518309*^9, 3.876106131246728*^9}, { 293 | 3.876106304534272*^9, 3.876106321989991*^9}, {3.876106427594986*^9, 294 | 3.876106488508456*^9}, {3.8761065460464287`*^9, 3.876106558717971*^9}, { 295 | 3.876106589242985*^9, 3.876106608767478*^9}, {3.876106943722818*^9, 296 | 3.876106965121394*^9}, {3.87619311523954*^9, 3.876193133696569*^9}, 297 | 3.8761934130623693`*^9, {3.876193458489044*^9, 3.876193491707306*^9}, { 298 | 3.876193543192151*^9, 3.876193596042185*^9}, 3.876194804285775*^9, 299 | 3.876194992647409*^9, {3.8761952508160963`*^9, 3.876195270496299*^9}, 300 | 3.8761953064640207`*^9, 3.876195654909005*^9, 3.876195686502165*^9, 301 | 3.8761957420780354`*^9, 3.876195812584537*^9, 3.876196281789896*^9, 302 | 3.876196348969672*^9, 3.87619638537457*^9, {3.876196501919766*^9, 303 | 3.8761965431276073`*^9}, 3.8762766184213343`*^9, {3.876276668334487*^9, 304 | 3.876276685582513*^9}, {3.8762767190581913`*^9, 3.876276748240864*^9}, 305 | 3.8762813655524054`*^9, {3.876611797589271*^9, 3.8766118442499943`*^9}, 306 | 3.876612852614873*^9, 3.876693876960437*^9, 3.8771188763959923`*^9, { 307 | 3.877118940423794*^9, 3.877118963029252*^9}, 3.8856096660827427`*^9, 308 | 3.894728239469412*^9, {3.894729292380471*^9, 3.89472935177726*^9}}, 309 | CellLabel-> 310 | "Out[2055]=",ExpressionUUID->"6690a9e3-4e4a-4385-82b0-f22c2f7a3a55"] 311 | }, Open ]], 312 | 313 | Cell[BoxData[ 314 | RowBox[{ 315 | RowBox[{"check", "=", 316 | RowBox[{"Import", "[", 317 | RowBox[{"\"\\"", ",", "\"\\""}], "]"}]}], 318 | ";"}]], "Input", 319 | CellChangeTimes->{{3.853554614501339*^9, 3.853554618167905*^9}, { 320 | 3.8535550377373466`*^9, 3.853555041196226*^9}, 3.874989044014344*^9, 321 | 3.8750766717007227`*^9, {3.875180520609432*^9, 3.875180521436009*^9}, 322 | 3.8760722602157593`*^9}, 323 | CellLabel-> 324 | "In[2056]:=",ExpressionUUID->"516f4ceb-0aa4-4db0-b45e-b04f27f6cbf1"], 325 | 326 | Cell[BoxData[ 327 | RowBox[{ 328 | RowBox[{ 329 | RowBox[{"plotpoints", "[", 330 | RowBox[{"data_", ",", "du_"}], "]"}], ":=", 331 | RowBox[{"Table", "[", 332 | RowBox[{ 333 | RowBox[{"{", 334 | RowBox[{ 335 | RowBox[{ 336 | RowBox[{"du", " ", "i"}], " ", "-", " ", 337 | RowBox[{"0.5", " ", "du"}]}], ",", 338 | RowBox[{"data", "[", 339 | RowBox[{"[", "i", "]"}], "]"}]}], "}"}], ",", 340 | RowBox[{"{", 341 | RowBox[{"i", ",", "1", ",", 342 | RowBox[{"Length", "[", "data", "]"}]}], "}"}]}], "]"}]}], 343 | ";"}]], "Input", 344 | CellChangeTimes->{{3.6783815736105022`*^9, 3.678381617418*^9}, { 345 | 3.6783828408499107`*^9, 3.678382841109769*^9}, 3.734496431691584*^9, 346 | 3.762352999689952*^9, {3.779282587458425*^9, 3.779282588014493*^9}, { 347 | 3.8088972979502974`*^9, 3.808897301578064*^9}}, 348 | CellLabel-> 349 | "In[2057]:=",ExpressionUUID->"8fd102bb-bd1d-4c23-9540-ad3405b67836"], 350 | 351 | Cell[BoxData[ 352 | RowBox[{ 353 | RowBox[{ 354 | RowBox[{"plotpoints", "[", 355 | RowBox[{"data_", ",", "d_", ",", "min_"}], "]"}], ":=", 356 | RowBox[{"Table", "[", 357 | RowBox[{ 358 | RowBox[{"{", 359 | RowBox[{ 360 | RowBox[{"min", "+", 361 | RowBox[{"d", " ", "i"}], " ", "-", " ", 362 | RowBox[{"0.5", " ", "d"}]}], ",", 363 | RowBox[{"data", "[", 364 | RowBox[{"[", "i", "]"}], "]"}]}], "}"}], ",", 365 | RowBox[{"{", 366 | RowBox[{"i", ",", "1", ",", 367 | RowBox[{"Length", "[", "data", "]"}]}], "}"}]}], "]"}]}], 368 | ";"}]], "Input", 369 | CellChangeTimes->{{3.679782606935545*^9, 3.6797826436214*^9}, 370 | 3.734496433004559*^9, 3.76235299969685*^9, 3.8088973085476093`*^9}, 371 | CellLabel-> 372 | "In[2058]:=",ExpressionUUID->"16ef2b34-fe5c-49b5-a721-b6e2d800c2a1"], 373 | 374 | Cell[BoxData[ 375 | RowBox[{ 376 | RowBox[{"ST`\[Sigma]", "[", 377 | RowBox[{"u_", ",", "\[Alpha]_", ",", "\[Gamma]_"}], "]"}], ":=", 378 | RowBox[{ 379 | FractionBox["u", "2"], "+", 380 | FractionBox[ 381 | RowBox[{"\[Alpha]", " ", 382 | SuperscriptBox[ 383 | RowBox[{"(", 384 | RowBox[{"1", "-", 385 | FractionBox[ 386 | SuperscriptBox["u", "2"], 387 | RowBox[{ 388 | RowBox[{"(", 389 | RowBox[{ 390 | RowBox[{"-", "1"}], "+", 391 | SuperscriptBox["u", "2"]}], ")"}], " ", 392 | SuperscriptBox["\[Alpha]", "2"], " ", 393 | RowBox[{"(", 394 | RowBox[{ 395 | RowBox[{"-", "1"}], "+", "\[Gamma]"}], ")"}]}]]}], ")"}], 396 | RowBox[{ 397 | FractionBox["3", "2"], "-", "\[Gamma]"}]], " ", 398 | SqrtBox[ 399 | RowBox[{ 400 | RowBox[{"(", 401 | RowBox[{"1", "-", 402 | SuperscriptBox["u", "2"]}], ")"}], " ", 403 | RowBox[{"(", 404 | RowBox[{ 405 | RowBox[{"-", "1"}], "+", "\[Gamma]"}], ")"}]}]], " ", 406 | RowBox[{"Gamma", "[", 407 | RowBox[{ 408 | RowBox[{"-", 409 | FractionBox["3", "2"]}], "+", "\[Gamma]"}], "]"}]}], 410 | RowBox[{"2", " ", 411 | SqrtBox["\[Pi]"], " ", 412 | RowBox[{"Gamma", "[", 413 | RowBox[{ 414 | RowBox[{"-", "1"}], "+", "\[Gamma]"}], "]"}]}]], "+", 415 | FractionBox[ 416 | RowBox[{ 417 | SuperscriptBox["u", "2"], " ", 418 | RowBox[{"Gamma", "[", 419 | RowBox[{ 420 | RowBox[{"-", 421 | FractionBox["1", "2"]}], "+", "\[Gamma]"}], "]"}], " ", 422 | RowBox[{"Hypergeometric2F1", "[", 423 | RowBox[{ 424 | FractionBox["1", "2"], ",", 425 | RowBox[{ 426 | RowBox[{"-", 427 | FractionBox["1", "2"]}], "+", "\[Gamma]"}], ",", 428 | FractionBox["3", "2"], ",", 429 | FractionBox[ 430 | SuperscriptBox["u", "2"], 431 | RowBox[{ 432 | RowBox[{"(", 433 | RowBox[{ 434 | RowBox[{"-", "1"}], "+", 435 | SuperscriptBox["u", "2"]}], ")"}], " ", 436 | SuperscriptBox["\[Alpha]", "2"], " ", 437 | RowBox[{"(", 438 | RowBox[{ 439 | RowBox[{"-", "1"}], "+", "\[Gamma]"}], ")"}]}]]}], "]"}]}], 440 | RowBox[{ 441 | SqrtBox["\[Pi]"], " ", "\[Alpha]", " ", 442 | SqrtBox[ 443 | RowBox[{ 444 | RowBox[{"(", 445 | RowBox[{"1", "-", 446 | SuperscriptBox["u", "2"]}], ")"}], " ", 447 | RowBox[{"(", 448 | RowBox[{ 449 | RowBox[{"-", "1"}], "+", "\[Gamma]"}], ")"}]}]], " ", 450 | RowBox[{"Gamma", "[", 451 | RowBox[{ 452 | RowBox[{"-", "1"}], "+", "\[Gamma]"}], "]"}]}]]}]}]], "Input", 453 | CellChangeTimes->{{3.7991299144968576`*^9, 3.799129916991254*^9}, { 454 | 3.799129956990402*^9, 3.799129977197599*^9}, {3.799136714555601*^9, 455 | 3.7991367428749*^9}, 3.799136873974616*^9, 3.799200762510812*^9, { 456 | 3.799201218770273*^9, 3.7992012481715803`*^9}}, 457 | CellLabel-> 458 | "In[2059]:=",ExpressionUUID->"d42447d8-2f7f-460d-b2f5-03f01c388467"], 459 | 460 | Cell[CellGroupData[{ 461 | 462 | Cell[BoxData[ 463 | RowBox[{"Show", "[", "\[IndentingNewLine]", 464 | RowBox[{ 465 | RowBox[{"ListPlot", "[", 466 | RowBox[{"plotpoints", "[", 467 | RowBox[{ 468 | RowBox[{"check", "[", 469 | RowBox[{"[", "1", "]"}], "]"}], ",", "0.01", ",", 470 | RowBox[{"-", "1"}]}], "]"}], "]"}], ",", "\[IndentingNewLine]", 471 | RowBox[{"Plot", "[", 472 | RowBox[{ 473 | RowBox[{"ST`\[Sigma]", "[", 474 | RowBox[{"u", ",", 475 | RowBox[{"ToExpression", "[", "roughx", "]"}], ",", 476 | RowBox[{"ToExpression", "[", "gamma", "]"}]}], "]"}], ",", 477 | RowBox[{"{", 478 | RowBox[{"u", ",", 479 | RowBox[{"-", "1"}], ",", "1"}], "}"}], ",", 480 | RowBox[{"PlotStyle", "\[Rule]", "Black"}]}], "]"}]}], 481 | "\[IndentingNewLine]", "]"}]], "Input", 482 | CellChangeTimes->{{3.8761963885767527`*^9, 3.876196459076375*^9}, { 483 | 3.876276672072633*^9, 3.876276672233995*^9}, {3.876276716400063*^9, 484 | 3.876276727325891*^9}}, 485 | CellLabel-> 486 | "In[2060]:=",ExpressionUUID->"7e078971-b4f6-4a20-9db5-fad4ce8f0ba6"], 487 | 488 | Cell[BoxData[ 489 | GraphicsBox[{{{}, 490 | {RGBColor[0.368417, 0.506779, 0.709798], PointSize[0.009166666666666668], 491 | AbsoluteThickness[1.6], PointBox[CompressedData[" 492 | 1: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 530 | vT4ya7RIEfUSMW4bLtmc2uAl6ikGbpD4jP6ojestcs9kvPwhuo3rMcKkMxyc 531 | z7ZxvYZXRflSuayN6zmC0p75ynrruN7jcoAlqZePju8DRJ4Jj46M0PF9gV9u 532 | 4q2B6Tq+TxD6/dYYU6WO7xsUtTXf6ftSx/cRHmqWWcM89Xxf4cTXijGvwvR8 533 | n+GL6GF7VYf1fN9hhMY6q1+5nu9DVJTtnBTbpef7EiV/BOV84NnO9ynk209m 534 | +Kxuh6O4bxHup/p0/7F2hIj7GIu9pt+YUtWOLHFf49cv9ug8HAxwEPc58o8e 535 | HJzgY0CwuO+xTe3+6egoA86LfgAvvJeedfnZgGeiX8Dq7YqAeLmB+wlUZO+Z 536 | 5jXYyP0GJldGHZw3x8j9CAqvBySUbDVyv4J18S4tJ28YuZ9B5LPLEpXVyP0O 537 | sqf/rTrRrYP7IURMsMWlrujgfgkHSla+GpDewf2U2E91Hdxvweu1MWPqQBP3 538 | Y2jela83BZq4X8PT/HcdB+w0cT+Hq8nSgKMFJu730Pji+fy9nSbuB7Fp1G3v 539 | Dh8z94tY2zlOe/VbM/eTOJW+0rcp28x4mGBxvtw3zGZmPMxwTQx8N/B9C+Nh 540 | RnfyHjsjLYxH998VrvVvXrQwHhaMdt+fpjBYGA8LZoS05sjdrIyHBarSrk1d 541 | a6yMhwXKV0eOuJ23Mh5WlJblp/jqrIyHFYc9141xcLVxv46lxcq3/cJs3M/D 542 | +VjbsN2nbNzvI7brilew0sY/D2BZ3o4N0r/b+ecFbIV3aN48O+NhR6+T8zIu 543 | fWdnPOwIHXLoeGyOHf8H71hxFA== 544 | "]]}, {{}, {}}}, {{{}, {}, 545 | TagBox[ 546 | {GrayLevel[0], AbsoluteThickness[1.6], Opacity[1.], 547 | LineBox[CompressedData[" 548 | 1:eJwt1Gs01HkYB3ARDcot2sgkilSyIYTqK5dKUcxWtJJG1ha5rKOMbBfXlWrr 549 | xJxD910q4riUyxL+Rok2rcu4TI3rMOM68yN32dNO5+yL53yfz3me87x89P1C 550 | GT/JysjIuEnrW5pi1cjXr4SStn+dKzLYHTq/Pml+Qeom1ex/wleh4KWZ0eS0 551 | 1Fma7DZVY5gbu/mJRqW+bUKLfW8Da/X4Tw0d3+Y5lrLZB2HfP/F3er7UOr96 552 | T+X6gPHbhxwLX6lHH+sJukMR2Rgf/HOVhOp9prnS2SgGra3KIxymmBo/nt60 553 | 8UwK6NWhmta6Y9Q4h7fbcc9DFAe9kVftGqF4zEcPeksyceqG2fjH2GGKt3Sw 554 | tU0xB3N3opMoDFFzjKO039kFyFDp1k7rE1EnjoVoKSoU4f4Bs3DuNSFl6pe3 555 | dS6uFLHnmKxNLgPU47iH1s96yhEt9zwyXCygnk5EhpY9qgLzauOG9qw+qjh3 556 | UU2BzgG7Uph2P7CX8qjGWXdxDcp7jJfnGnRTc/7BibWf32C9mr3DkYd8qiB2 557 | R1OC4C1ebE4KFPTzqFylS4orld6hp7ZwnZVVO9U7cSxs0fI9hCZsc6qES4U4 558 | WEYFu3yA+uVsK9MlzVTSD+y3ummNMLEiJk8mG6gKC8dqlqgJcU7ipjJWHbVd 559 | wf/LgF4LtI7k3T7+XQ21rdn0mKE3Fy9malXrN5RTuome8rJJrXjCF94cjs+j 560 | uuKuBd5ra4OPh24R/3QqRXMqvK6s2YEypei2mvMpCNtTZFTL4MFSsGRtjFc+ 561 | 3I0XmjpffsT68VfztjVleKQRVWy3lA+XjI8fDnnVIJ25k+3I6oSzm4bcdHEd 562 | anLDbGjiLtzy7bi6rbQB5Ep2z9nDPag7RF/hrtGMm7YXhZeCeiHW17rccpcL 563 | 44xEp0zDPpyP2MK8taodhXc1fPb19KGjU40RUM+DfkuB345cAU5F7Rxc5sqH 564 | cPDH1Jch/Xi9xTr5tXw3/hjjRqs7D8BIsWIoc38vGmmuV5LVhKBXBDnLJ/Wh 565 | vH33rjV8IWQWZLPDBQJwiqarncpFmPWoPFlrOACG+ffjb28Ogr/dd41hvBDz 566 | LYfT4y8MIcxTTd2gU4Swkgt+f54chnbqgNdS+hDoVQ7sCNsR5Hk/fjbJGoa7 567 | /7RdgskoPHdd2V9fOQKzSYZoq8YYCk8GG9gujsJW5Xmy8uwY5pQc5cqOiiHP 568 | 4pasnhKD0WxnRU+TILDgmjJXKIGSnTKn4oEEAb7z2jojEnAyPx08kSHB6usF 569 | DUyJBNtYUcx7eRI49b42mpyRQEWv9IZ2rQTmnZxBOo3g3Tnzfq3P0v2Lmvns 570 | zQT2tE23VVwJVq4bzNoQRjD3y5xOngfBRS+ZroQIgnx+3RM3T4JihcGtQyyC 571 | tfkBr274EbjZhToXxBAsHs0UKUURJFoc2Hs4haA0Q2/XsqcESv7Q4ZYQhKwg 572 | dU9zCCILLQIOviIwiqxi7C0kmN1hU1lLEaQe8DmTUEGwbvmwGqeeIHzibooc 573 | l0BhyM6+4xPBZu/AtRk8gn1RIW3+PQR9b2yyHbqldxYiTs/0E7in8apihgmS 574 | Xe/MbhQT0GSzXPQJwdiyrH/fTRBQQZGt1VMEkorh5IgZggtte31PLRCMlE89 575 | 2PKF4P//hYWEPaPf8j+yyH93 576 | "]]}, 577 | Annotation[#, "Charting`Private`Tag$165192#1"]& ]}, {}}}, 578 | AspectRatio->NCache[GoldenRatio^(-1), 0.6180339887498948], 579 | Axes->{True, True}, 580 | AxesLabel->{None, None}, 581 | AxesOrigin->{0, 0}, 582 | DisplayFunction->Identity, 583 | Frame->{{False, False}, {False, False}}, 584 | FrameLabel->{{None, None}, {None, None}}, 585 | FrameTicks->{{Automatic, Automatic}, {Automatic, Automatic}}, 586 | GridLines->{None, None}, 587 | GridLinesStyle->Directive[ 588 | GrayLevel[0.5, 0.4]], 589 | Method->{ 590 | "OptimizePlotMarkers" -> True, "OptimizePlotMarkers" -> True, 591 | "CoordinatesToolOptions" -> {"DisplayFunction" -> ({ 592 | Identity[ 593 | Part[#, 1]], 594 | Identity[ 595 | Part[#, 2]]}& ), "CopiedValueFunction" -> ({ 596 | Identity[ 597 | Part[#, 1]], 598 | Identity[ 599 | Part[#, 2]]}& )}}, 600 | PlotRange->{{-0.995, 0.995}, {0, 0.990413}}, 601 | PlotRangeClipping->True, 602 | PlotRangePadding->{{ 603 | Scaled[0.02], 604 | Scaled[0.02]}, { 605 | Scaled[0.02], 606 | Scaled[0.05]}}, 607 | Ticks->{Automatic, Automatic}]], "Output", 608 | CellChangeTimes->{{3.87619639381184*^9, 3.876196420448765*^9}, { 609 | 3.876196456106738*^9, 3.876196459380588*^9}, {3.876196501978517*^9, 610 | 3.876196543176957*^9}, 3.876276618553981*^9, {3.8762766684551353`*^9, 611 | 3.8762766856715918`*^9}, {3.876276717027542*^9, 3.876276748325691*^9}, 612 | 3.87628136564802*^9, {3.876611797713787*^9, 3.876611844320187*^9}, 613 | 3.876612852725276*^9, 3.876693877047435*^9, 3.877118876444377*^9, { 614 | 3.877118940477931*^9, 3.877118963125938*^9}, 3.885609666150646*^9, 615 | 3.894728239545587*^9, {3.894729292472103*^9, 3.894729351845182*^9}}, 616 | CellLabel-> 617 | "Out[2060]=",ExpressionUUID->"32cf393d-7d9e-40d6-8e1a-61e6ac4409ff"] 618 | }, Open ]] 619 | }, Open ]] 620 | }, Open ]] 621 | }, 622 | WindowSize->{808, 861}, 623 | WindowMargins->{{109, Automatic}, {Automatic, 0}}, 624 | FrontEndVersion->"13.0 for Mac OS X ARM (64-bit) (December 2, 2021)", 625 | StyleDefinitions->"Default.nb", 626 | ExpressionUUID->"56bc803a-add6-4e4c-b365-96dd742bb56d" 627 | ] 628 | (* End of Notebook Content *) 629 | 630 | (* Internal cache information *) 631 | (*CellTagsOutline 632 | CellTagsIndex->{} 633 | *) 634 | (*CellTagsIndex 635 | CellTagsIndex->{} 636 | *) 637 | (*NotebookFileOutline 638 | Notebook[{ 639 | Cell[CellGroupData[{ 640 | Cell[580, 22, 553, 8, 98, "Title",ExpressionUUID->"cafadb98-a2c8-47cd-905c-0b5027ceb082"], 641 | Cell[CellGroupData[{ 642 | Cell[1158, 34, 152, 3, 67, "Section",ExpressionUUID->"8d766eea-8eda-4cef-846a-462ef231d3bb"], 643 | Cell[1313, 39, 937, 22, 357, "Text",ExpressionUUID->"e1fe63ab-ac92-4729-bfde-22abf2ab7567"] 644 | }, Closed]], 645 | Cell[CellGroupData[{ 646 | Cell[2287, 66, 74, 0, 53, "Section",ExpressionUUID->"0fa69ea0-81c8-4cec-8193-e8fdd7605d49"], 647 | Cell[CellGroupData[{ 648 | Cell[2386, 70, 862, 14, 30, "Input",ExpressionUUID->"d4774696-34be-4f98-82f8-ff055f032631"], 649 | Cell[3251, 86, 3920, 55, 34, "Output",ExpressionUUID->"646e102e-4024-4a89-9b15-51334ddde6c0"] 650 | }, Open ]], 651 | Cell[7186, 144, 1842, 31, 115, "Input",ExpressionUUID->"6cb796c9-96ba-4e21-a182-e7743e98a6ca"], 652 | Cell[CellGroupData[{ 653 | Cell[9053, 179, 821, 14, 52, "Input",ExpressionUUID->"852e0457-7370-4a2e-9a2c-b07ee476dd16"], 654 | Cell[9877, 195, 2466, 34, 34, "Output",ExpressionUUID->"154fef02-a55a-4542-b66d-0dead71c55d8"] 655 | }, Open ]], 656 | Cell[CellGroupData[{ 657 | Cell[12380, 234, 1331, 21, 30, "Input",ExpressionUUID->"2fc2e019-7298-4725-8615-083447076ba2"], 658 | Cell[13714, 257, 3688, 52, 34, "Output",ExpressionUUID->"6690a9e3-4e4a-4385-82b0-f22c2f7a3a55"] 659 | }, Open ]], 660 | Cell[17417, 312, 494, 11, 30, "Input",ExpressionUUID->"516f4ceb-0aa4-4db0-b45e-b04f27f6cbf1"], 661 | Cell[17914, 325, 867, 23, 30, "Input",ExpressionUUID->"8fd102bb-bd1d-4c23-9540-ad3405b67836"], 662 | Cell[18784, 350, 761, 21, 30, "Input",ExpressionUUID->"16ef2b34-fe5c-49b5-a721-b6e2d800c2a1"], 663 | Cell[19548, 373, 2767, 84, 162, "Input",ExpressionUUID->"d42447d8-2f7f-460d-b2f5-03f01c388467"], 664 | Cell[CellGroupData[{ 665 | Cell[22340, 461, 974, 24, 115, "Input",ExpressionUUID->"7e078971-b4f6-4a20-9db5-fad4ce8f0ba6"], 666 | Cell[23317, 487, 6809, 129, 249, "Output",ExpressionUUID->"32cf393d-7d9e-40d6-8e1a-61e6ac4409ff"] 667 | }, Open ]] 668 | }, Open ]] 669 | }, Open ]] 670 | } 671 | ] 672 | *) 673 | 674 | --------------------------------------------------------------------------------