├── LICENSE ├── README.md ├── SelfIntersectionAvoidance.glsl └── SelfIntersectionAvoidance.hlsl /LICENSE: -------------------------------------------------------------------------------- 1 | # 2 | # SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | # SPDX-License-Identifier: BSD-3-Clause 4 | # 5 | # Redistribution and use in source and binary forms, with or without 6 | # modification, are permitted provided that the following conditions are met: 7 | # 8 | # 1. Redistributions of source code must retain the above copyright notice, this 9 | # list of conditions and the following disclaimer. 10 | # 11 | # 2. Redistributions in binary form must reproduce the above copyright notice, 12 | # this list of conditions and the following disclaimer in the documentation 13 | # and/or other materials provided with the distribution. 14 | # 15 | # 3. Neither the name of the copyright holder nor the names of its 16 | # contributors may be used to endorse or promote products derived from 17 | # this software without specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | # -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SelfIntersectionAvoidance 2 | Repository with HLSL and GLSL sample code for self-intersection avoidance in DXR and Vulkan 3 | -------------------------------------------------------------------------------- /SelfIntersectionAvoidance.glsl: -------------------------------------------------------------------------------- 1 | // 2 | // SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, 12 | // this list of conditions and the following disclaimer in the documentation 13 | // and/or other materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | 31 | // Compute the object and world space position and normal corresponding to a triangle hit point. 32 | // Compute a safe spawn point offset along the normal in world space to prevent self intersection of secondary rays. 33 | void safeSpawnOffset( 34 | out vec3 outObjPosition, // position in object space 35 | out vec3 outWldPosition, // position in world space 36 | out vec3 outObjNormal, // unit length surface normal in object space 37 | out vec3 outWldNormal, // unit length surface normal in world space 38 | out float outWldOffset, // safe offset for spawn position in world space 39 | in const vec3 v0, // spawn triangle vertex 0 in object space 40 | in const vec3 v1, // spawn triangle vertex 1 in object space 41 | in const vec3 v2, // spawn triangle vertex 2 in object space 42 | in const vec2 bary, // spawn barycentrics 43 | in const mat4x3 o2w, // spawn instance object-to-world transformation 44 | in const mat4x3 w2o ) // spawn instance world-to-object transformation 45 | { 46 | precise vec3 edge1 = v1 - v0; 47 | precise vec3 edge2 = v2 - v0; 48 | 49 | // interpolate triangle using barycentrics. 50 | // add in base vertex last to reduce object space error. 51 | precise vec3 objPosition = v0 + fma( vec3( bary.x ), edge1, ( vec3( bary.y ) * edge2 ) ); 52 | vec3 objNormal = cross( edge1, edge2 ); 53 | 54 | // transform object space position. 55 | // add in translation last to reduce world space error. 56 | precise vec3 wldPosition; 57 | wldPosition.x = o2w[3][0] + 58 | fma( o2w[0][0], objPosition.x, 59 | fma( o2w[1][0], objPosition.y, 60 | ( o2w[2][0] * objPosition.z ) ) ); 61 | wldPosition.y = o2w[3][1] + 62 | fma( o2w[0][1], objPosition.x, 63 | fma( o2w[1][1], objPosition.y, 64 | ( o2w[2][1] * objPosition.z ) ) ); 65 | wldPosition.z = o2w[3][2] + 66 | fma( o2w[0][2], objPosition.x, 67 | fma( o2w[1][2], objPosition.y, 68 | ( o2w[2][2] * objPosition.z ) ) ); 69 | 70 | // transform normal to world - space using 71 | // inverse transpose matrix 72 | vec3 wldNormal = transpose( mat3( w2o ) ) * objNormal; 73 | 74 | // normalize world space normal 75 | const float wldScale = inversesqrt( dot( wldNormal, wldNormal ) ); 76 | wldNormal = wldScale * wldNormal; 77 | 78 | const float c0 = 5.9604644775390625E-8f; 79 | const float c1 = 1.788139769587360206060111522674560546875E-7f; 80 | 81 | const vec3 extent3 = abs( edge1 ) + abs( edge2 ) + abs( edge1 - edge2 ); 82 | const float extent = max( max( extent3.x, extent3.y ), extent3.z ); 83 | 84 | // bound object space error due to reconstruction and intersection 85 | vec3 objErr = fma( vec3( c0 ), abs( v0 ), vec3( c1 * extent ) ); 86 | 87 | // bound world space error due to object to world transform 88 | const float c2 = 1.19209317972490680404007434844970703125E-7f; 89 | mat4x3 abs_o2w = mat4x3( abs( o2w[0] ), abs( o2w[1] ), abs( o2w[2] ), abs( o2w[3] ) ); 90 | vec3 wldErr = fma( vec3( c1 ), mat3( abs_o2w ) * abs( objPosition ), ( c2 * abs( o2w[3] ) ) ); 91 | 92 | // bound object space error due to world to object transform 93 | mat4x3 abs_w2o = mat4x3( abs( w2o[0] ), abs( w2o[1] ), abs( w2o[2] ), abs( w2o[3] ) ); 94 | objErr = fma( vec3( c2 ), ( abs_w2o * vec4( abs( wldPosition ), 1 ) ), objErr ); 95 | 96 | // compute world space self intersection avoidance offset 97 | float wldOffset = dot( wldErr, abs( wldNormal ) ); 98 | float objOffset = dot( objErr, abs( objNormal ) ); 99 | 100 | wldOffset = fma( wldScale, objOffset, wldOffset ); 101 | 102 | // output safe front and back spawn points 103 | outObjPosition = objPosition; 104 | outWldPosition = wldPosition; 105 | outObjNormal = normalize( objNormal ); 106 | outWldNormal = wldNormal; 107 | outWldOffset = wldOffset; 108 | } 109 | 110 | // Offset the world-space position along the world-space normal by the safe offset to obtain the safe spawn point. 111 | vec3 safeSpawnPoint( 112 | in const vec3 position, 113 | in const vec3 normal, 114 | in const float offset ) 115 | { 116 | precise vec3 p = fma( vec3( offset ), normal, position ); 117 | return p; 118 | } 119 | -------------------------------------------------------------------------------- /SelfIntersectionAvoidance.hlsl: -------------------------------------------------------------------------------- 1 | // 2 | // SPDX-FileCopyrightText: Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 3 | // SPDX-License-Identifier: BSD-3-Clause 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are met: 7 | // 8 | // 1. Redistributions of source code must retain the above copyright notice, this 9 | // list of conditions and the following disclaimer. 10 | // 11 | // 2. Redistributions in binary form must reproduce the above copyright notice, 12 | // this list of conditions and the following disclaimer in the documentation 13 | // and/or other materials provided with the distribution. 14 | // 15 | // 3. Neither the name of the copyright holder nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 | // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 | // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 | // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 | // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | // 30 | 31 | // Compute the object and world space position and normal corresponding to a triangle hit point. 32 | // Compute a safe spawn point offset along the normal in world space to prevent self intersection of secondary rays. 33 | void safeSpawnPoint( 34 | out float3 outObjPosition, // position in object space 35 | out float3 outWldPosition, // position in world space 36 | out float3 outObjNormal, // unit length surface normal in object space 37 | out float3 outWldNormal, // unit length surface normal in world space 38 | out float outWldOffset, // safe offset for spawn position in world space 39 | const float3 v0, // spawn triangle vertex 0 in object space 40 | const float3 v1, // spawn triangle vertex 1 in object space 41 | const float3 v2, // spawn triangle vertex 2 in object space 42 | const float2 bary, // spawn barycentrics 43 | const float3x4 o2w, // spawn instance object-to-world transformation 44 | const float3x4 w2o ) // spawn instance world-to-object transformation 45 | { 46 | precise float3 edge1 = v1 - v0; 47 | precise float3 edge2 = v2 - v0; 48 | 49 | // interpolate triangle using barycentrics. 50 | // add in base vertex last to reduce object space error. 51 | precise float3 objPosition = v0 + mad( bary.x, edge1, mul( bary.y, edge2 ) ); 52 | float3 objNormal = cross( edge1, edge2 ); 53 | 54 | // transform object space position. 55 | // add in translation last to reduce world space error. 56 | precise float3 wldPosition; 57 | wldPosition.x = o2w._m03 + 58 | mad( o2w._m00, objPosition.x, 59 | mad( o2w._m01, objPosition.y, 60 | mul( o2w._m02, objPosition.z ) ) ); 61 | wldPosition.y = o2w._m13 + 62 | mad( o2w._m10, objPosition.x, 63 | mad( o2w._m11, objPosition.y, 64 | mul( o2w._m12, objPosition.z ) ) ); 65 | wldPosition.z = o2w._m23 + 66 | mad( o2w._m20, objPosition.x, 67 | mad( o2w._m21, objPosition.y, 68 | mul( o2w._m22, objPosition.z ) ) ); 69 | 70 | // transform normal to world - space using 71 | // inverse transpose matrix 72 | float3 wldNormal = mul( transpose( ( float3x3 )w2o ), objNormal ); 73 | 74 | // normalize world space normal 75 | const float wldScale = rsqrt( dot( wldNormal, wldNormal ) ); 76 | wldNormal = mul( wldScale, wldNormal ); 77 | 78 | const float c0 = 5.9604644775390625E-8f; 79 | const float c1 = 1.788139769587360206060111522674560546875E-7f; 80 | 81 | const float3 extent3 = abs( edge1 ) + abs( edge2 ) + abs( edge1 - edge2 ); 82 | const float extent = max( max( extent3.x, extent3.y ), extent3.z ); 83 | 84 | // bound object space error due to reconstruction and intersection 85 | float3 objErr = mad( c0, abs( v0 ), mul( c1, extent ) ); 86 | 87 | // bound world space error due to object to world transform 88 | const float c2 = 1.19209317972490680404007434844970703125E-7f; 89 | float3 wldErr = mad( c1, mul( abs( ( float3x3 )o2w ), abs( objPosition ) ), mul( c2, abs( transpose( o2w )[3] ) ) ); 90 | 91 | // bound object space error due to world to object transform 92 | objErr = mad( c2, mul( abs( w2o ), float4( abs( wldPosition ), 1 ) ), objErr ); 93 | 94 | // compute world space self intersection avoidance offset 95 | float wldOffset = dot( wldErr, abs( wldNormal ) ); 96 | float objOffset = dot( objErr, abs( objNormal ) ); 97 | 98 | wldOffset = mad( wldScale, objOffset, wldOffset ); 99 | 100 | // output safe front and back spawn points 101 | outObjPosition = objPosition; 102 | outWldPosition = wldPosition; 103 | outObjNormal = normalize( objNormal ); 104 | outWldNormal = wldNormal; 105 | outWldOffset = wldOffset; 106 | } 107 | 108 | // Offset the world-space position along the world-space normal by the safe offset to obtain the safe spawn point. 109 | float3 safeSpawnPoint( 110 | const float3 position, 111 | const float3 normal, 112 | const float offset ) 113 | { 114 | precise float3 p = mad( offset, normal, position ); 115 | return p; 116 | } 117 | --------------------------------------------------------------------------------