From 1804bb99a682a8653a8228408b476a811553b54e Mon Sep 17 00:00:00 2001 From: dbp Date: Thu, 2 Apr 2015 14:27:16 +0300 Subject: [PATCH] 0025833: Visualization, ray tracing - Problems with the backside of triangles Backside triangles are handled correctly by implementing two-sided lighting model. Ray-tracing shader was optimized (up to 25% performance increase). Test case for CR25833 --- src/Shaders/RaytraceBase.fs | 149 ++++++++++++++++-------------------- tests/v3d/raytrace/bug25833 | 47 ++++++++++++ 2 files changed, 113 insertions(+), 83 deletions(-) create mode 100755 tests/v3d/raytrace/bug25833 diff --git a/src/Shaders/RaytraceBase.fs b/src/Shaders/RaytraceBase.fs index a300273749..2cc2df938b 100644 --- a/src/Shaders/RaytraceBase.fs +++ b/src/Shaders/RaytraceBase.fs @@ -125,20 +125,6 @@ struct SIntersect #define AXIS_Y vec3 (0.0f, 1.0f, 0.0f) #define AXIS_Z vec3 (0.0f, 0.0f, 1.0f) -// ======================================================================= -// function : MatrixRowMultiplyDir -// purpose : Multiplies a vector by matrix -// ======================================================================= -vec3 MatrixRowMultiplyDir (in vec3 v, - in vec4 m0, - in vec4 m1, - in vec4 m2) -{ - return vec3 (dot (m0.xyz, v), - dot (m1.xyz, v), - dot (m2.xyz, v)); -} - //! 32-bit state of random number generator. uint RandState; @@ -897,6 +883,8 @@ vec3 Refract (in vec3 theInput, #define THRESHOLD vec3 (0.1f) +#define INVALID_BOUNCES 1000 + #define LIGHT_POS(index) (2 * index + 1) #define LIGHT_PWR(index) (2 * index + 0) @@ -921,12 +909,12 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse) if (aTriIndex.x == -1) { - vec4 aColor = vec4 (0.0f, 0.0f, 0.0f, 1.0f); + vec4 aColor = vec4 (0.0f); if (aWeight.w != 0.0f) { - if (anOpenGlDepth != MAXFLOAT) - aColor = ComputeOpenGlColor (theRay); + aColor = anOpenGlDepth != MAXFLOAT ? + ComputeOpenGlColor (theRay) : vec4 (0.0f, 0.0f, 0.0f, 1.0f); } else if (bool(uEnvironmentEnable)) { @@ -940,23 +928,33 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse) } aHit.Normal = normalize (aHit.Normal); - + // For polygons that are parallel to the screen plane, the depth slope // is equal to 1, resulting in small polygon offset. For polygons that // that are at a large angle to the screen, the depth slope tends to 1, // resulting in a larger polygon offset - float aPolygonOffset = uSceneEpsilon * min ( - EPS_SCALE / abs (dot (theRay.Direct, aHit.Normal)), EPS_SCALE / MIN_SLOPE); + float aPolygonOffset = uSceneEpsilon * EPS_SCALE / + max (abs (dot (theRay.Direct, aHit.Normal)), MIN_SLOPE); - if (anOpenGlDepth - aPolygonOffset < aHit.Time) + if (anOpenGlDepth < aHit.Time + aPolygonOffset) { - vec4 aColor = ComputeOpenGlColor (theRay); + vec4 aGlColor = ComputeOpenGlColor (theRay); - aResult += aWeight.xyz * aColor.xyz; - aWeight *= aColor.w; + aResult += aWeight.xyz * aGlColor.xyz; + aWeight *= aGlColor.w; } - vec3 aPoint = theRay.Direct * aHit.Time + theRay.Origin; + theRay.Origin += theRay.Direct * aHit.Time; // intersection point + + vec3 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0).xyz; + vec3 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1).xyz; + vec3 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2).xyz; + + vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex); + + aNormal = normalize (vec3 (dot (aInvTransf0, aNormal), + dot (aInvTransf1, aNormal), + dot (aInvTransf2, aNormal))); vec3 aAmbient = texelFetch ( uRaytraceMaterialTexture, MATERIAL_AMBN (aTriIndex.w)).rgb; @@ -966,8 +964,6 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse) uRaytraceMaterialTexture, MATERIAL_SPEC (aTriIndex.w)); vec4 aOpacity = texelFetch ( uRaytraceMaterialTexture, MATERIAL_TRAN (aTriIndex.w)); - vec3 aEmission = texelFetch ( - uRaytraceMaterialTexture, MATERIAL_EMIS (aTriIndex.w)).rgb; #ifdef USE_TEXTURES if (aDiffuse.w >= 0.f) @@ -990,14 +986,15 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse) } #endif - vec4 aInvTransf0 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 0); - vec4 aInvTransf1 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 1); - vec4 aInvTransf2 = texelFetch (uSceneTransformTexture, anObjectId * 4 + 2); + vec3 aEmission = texelFetch ( + uRaytraceMaterialTexture, MATERIAL_EMIS (aTriIndex.w)).rgb; - vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex); + float aGeomFactor = dot (aNormal, theRay.Direct); + + aResult.xyz += aWeight.xyz * aOpacity.x * ( + uGlobalAmbient.xyz * aAmbient * max (abs (aGeomFactor), 0.5f) + aEmission); - aNormal = normalize (MatrixRowMultiplyDir ( - aNormal, aInvTransf0, aInvTransf1, aInvTransf2)); + vec3 aSidedNormal = mix (aNormal, -aNormal, step (0.0f, aGeomFactor)); for (int aLightIdx = 0; aLightIdx < uLightCount; ++aLightIdx) { @@ -1008,49 +1005,43 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse) if (aLight.w != 0.0f) // point light source { - aDistance = length (aLight.xyz -= aPoint); + aDistance = length (aLight.xyz -= theRay.Origin); aLight.xyz *= 1.0f / aDistance; } - SRay aShadow = SRay (aPoint + aLight.xyz * uSceneEpsilon, aLight.xyz); - - aShadow.Origin += aHit.Normal * uSceneEpsilon * - (dot (aHit.Normal, aLight.xyz) >= 0.0f ? 1.0f : -1.0f); - - float aVisibility = 1.0f; + float aLdotN = dot (aLight.xyz, aSidedNormal); - if (bool(uShadowsEnable)) + if (aLdotN > 0.0f) // first check if light source is important { - vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL); + float aVisibility = 1.0f; - aVisibility = SceneAnyHit ( - aShadow, mix (-aInverse, aInverse, step (ZERO, aLight.xyz)), aDistance); - } + if (bool(uShadowsEnable)) + { + SRay aShadow = SRay (theRay.Origin, aLight.xyz); - if (aVisibility > 0.0f) - { - vec3 aIntensity = vec3 (texelFetch ( - uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx))); + aShadow.Origin += uSceneEpsilon * (aLight.xyz + + mix (-aHit.Normal, aHit.Normal, step (0.0f, dot (aHit.Normal, aLight.xyz)))); - float aLdotN = dot (aShadow.Direct, aNormal); + vec3 aInverse = 1.0f / max (abs (aLight.xyz), SMALL); - if (aOpacity.y > 0.0f) // force two-sided lighting - aLdotN = abs (aLdotN); // for transparent surfaces + aVisibility = SceneAnyHit ( + aShadow, mix (-aInverse, aInverse, step (ZERO, aLight.xyz)), aDistance); + } - if (aLdotN > 0.0f) + if (aVisibility > 0.0f) { - float aRdotV = dot (reflect (aShadow.Direct, aNormal), theRay.Direct); + vec3 aIntensity = vec3 (texelFetch ( + uRaytraceLightSrcTexture, LIGHT_PWR (aLightIdx))); + + float aRdotV = dot (reflect (aLight.xyz, aSidedNormal), theRay.Direct); aResult.xyz += aWeight.xyz * (aOpacity.x * aVisibility) * aIntensity * - (aDiffuse.rgb * aLdotN + aSpecular.xyz * pow (max (0.0f, aRdotV), aSpecular.w)); + (aDiffuse.xyz * aLdotN + aSpecular.xyz * pow (max (0.f, aRdotV), aSpecular.w)); } } } - aResult.xyz += aWeight.xyz * aOpacity.x * (uGlobalAmbient.xyz * - aAmbient * max (abs (dot (aNormal, theRay.Direct)), 0.5f) + aEmission); - if (aOpacity.x != 1.0f) { aWeight *= aOpacity.y; @@ -1058,15 +1049,6 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse) if (aOpacity.z != 1.0f) { theRay.Direct = Refract (theRay.Direct, aNormal, aOpacity.z, aOpacity.w); - - theInverse = 1.0f / max (abs (theRay.Direct), SMALL); - - theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct)); - - aPoint += aHit.Normal * (dot (aHit.Normal, theRay.Direct) >= 0.0f ? uSceneEpsilon : -uSceneEpsilon); - - // Disable combining image with OpenGL output - anOpenGlDepth = MAXFLOAT; } else { @@ -1078,32 +1060,33 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse) aWeight *= bool(uReflectionsEnable) ? texelFetch (uRaytraceMaterialTexture, MATERIAL_REFL (aTriIndex.w)) : vec4 (0.0f); - theRay.Direct = reflect (theRay.Direct, aNormal); + vec3 aReflect = reflect (theRay.Direct, aNormal); - if (dot (theRay.Direct, aHit.Normal) < 0.0f) + if (dot (aReflect, aHit.Normal) * dot (theRay.Direct, aHit.Normal) > 0.0f) { - theRay.Direct = reflect (theRay.Direct, aHit.Normal); + aReflect = reflect (theRay.Direct, aHit.Normal); } - theInverse = 1.0f / max (abs (theRay.Direct), SMALL); - - theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct)); - - aPoint += aHit.Normal * (dot (aHit.Normal, theRay.Direct) >= 0.0f ? uSceneEpsilon : -uSceneEpsilon); - - // Disable combining image with OpenGL output - anOpenGlDepth = MAXFLOAT; + theRay.Direct = aReflect; } if (all (lessThanEqual (aWeight.xyz, THRESHOLD))) { - return vec4 (aResult.x, - aResult.y, - aResult.z, - aWeight.w); + aDepth = INVALID_BOUNCES; + } + else if (aOpacity.x == 1.0f || aOpacity.z != 1.0f) // if no simple transparency + { + theRay.Origin += aHit.Normal * mix ( + -uSceneEpsilon, uSceneEpsilon, step (0.0f, dot (aHit.Normal, theRay.Direct))); + + theInverse = 1.0f / max (abs (theRay.Direct), SMALL); + + theInverse = mix (-theInverse, theInverse, step (ZERO, theRay.Direct)); + + anOpenGlDepth = MAXFLOAT; // disable combining image with OpenGL output } - theRay.Origin = theRay.Direct * uSceneEpsilon + aPoint; + theRay.Origin += theRay.Direct * uSceneEpsilon; } return vec4 (aResult.x, diff --git a/tests/v3d/raytrace/bug25833 b/tests/v3d/raytrace/bug25833 new file mode 100755 index 0000000000..46eafc85be --- /dev/null +++ b/tests/v3d/raytrace/bug25833 @@ -0,0 +1,47 @@ +puts "========" +puts "OCC25833" +puts "========" +puts "" +########################################## +## Visualization, Ray Tracing - fix problems with the backside of triangles +########################################## + +box b1 100 100 100 +explode b1 Fa +box b2 10 10 -20 10 10 10 + +vsetdispmode 1 +vdisplay b1_5 b1_6 b2 +vsetmaterial b1_5 steel +vsetmaterial b1_6 steel +vfit + +# Problem 1: b1_5 (grey) becomes semi-transparent after the next line, +# compare it with b1_6 visible from the frontside +vrenderparams -rayTrace +vdump ${imagedir}/${test_image}_1.png +checkcolor 100 300 0.37647059559822083 0.3803921639919281 0.40392157435417175 +if { ${stat} != 1 } { + puts "Error : bad color (case 1)" +} + +# Problem 2: The small box shows through b1_5 +vrenderparams -reflections +vdump ${imagedir}/${test_image}_2.png +checkcolor 190 250 0.37647059559822083 0.3803921639919281 0.40392157435417175 +if { ${stat} != 1 } { + puts "Error : bad color (case 2)" +} + +ttranslate b2 30 30 30 +# Problem 3: The small box is not reflected from the backface of b1_5 +vdisplay b2 +vdump ${imagedir}/${test_image}_3.png +checkcolor 190 260 0.79607844352722168 0.60784316062927246 0.21960784494876862 +if { ${stat} != 1 } { + puts "Error : bad color (case 3)" +} +checkcolor 190 310 0.61960786581039429 0.56078433990478516 0.43529412150382996 +if { ${stat} != 1 } { + puts "Error : bad color (case 4)" +} -- 2.20.1