diff --git a/src/Graphic3d/Graphic3d_RenderingParams.hxx b/src/Graphic3d/Graphic3d_RenderingParams.hxx index a437d3a6ef..fa18c5b73b 100644 --- a/src/Graphic3d/Graphic3d_RenderingParams.hxx +++ b/src/Graphic3d/Graphic3d_RenderingParams.hxx @@ -115,6 +115,7 @@ public: IsAntialiasingEnabled (Standard_False), IsTransparentShadowEnabled (Standard_False), UseEnvironmentMapBackground (Standard_False), + ToIgnoreNormalMapInRayTracing (Standard_False), CoherentPathTracingMode (Standard_False), AdaptiveScreenSampling (Standard_False), AdaptiveScreenSamplingAtomic(Standard_False), @@ -202,6 +203,7 @@ public: Standard_Boolean IsAntialiasingEnabled; //!< enables/disables adaptive anti-aliasing, False by default Standard_Boolean IsTransparentShadowEnabled; //!< enables/disables light propagation through transparent media, False by default Standard_Boolean UseEnvironmentMapBackground; //!< enables/disables environment map background + Standard_Boolean ToIgnoreNormalMapInRayTracing; //!< enables/disables normal map ignoring during path tracing; FALSE by default Standard_Boolean CoherentPathTracingMode; //!< enables/disables 'coherent' tracing mode (single RNG seed within 16x16 image blocks) Standard_Boolean AdaptiveScreenSampling; //!< enables/disables adaptive screen sampling mode for path tracing, FALSE by default Standard_Boolean AdaptiveScreenSamplingAtomic;//!< enables/disables usage of atomic float operations within adaptive screen sampling, FALSE by default diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx index e5c143a53b..4fda63fe14 100644 --- a/src/OpenGl/OpenGl_ShaderManager.cxx +++ b/src/OpenGl/OpenGl_ShaderManager.cxx @@ -35,6 +35,7 @@ #include "../Shaders/Shaders_PBREnvBaking_fs.pxx" #include "../Shaders/Shaders_PBREnvBaking_vs.pxx" #include "../Shaders/Shaders_PointLightAttenuation_glsl.pxx" +#include "../Shaders/Shaders_TangentSpaceNormal_glsl.pxx" IMPLEMENT_STANDARD_RTTIEXT(OpenGl_ShaderManager,Standard_Transient) @@ -2719,6 +2720,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha && (theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureNormal && myContext->hasFlatShading != OpenGl_FeatureNotAvailable) { + aSrcFrag += Shaders_TangentSpaceNormal_glsl; // apply normal map texture aSrcFragExtraMain += EOL"#if defined(THE_HAS_TEXTURE_NORMAL)" @@ -2726,15 +2728,9 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha EOL" vec4 aMapNormalValue = occTextureNormal(aTexCoord);" EOL" if (aMapNormalValue.w > 0.5)" EOL" {" - EOL" aMapNormalValue.xyz = normalize (aMapNormalValue.xyz * 2.0 - vec3(1.0));" EOL" mat2 aDeltaUVMatrix = mat2 (dFdx(aTexCoord), dFdy(aTexCoord));" - EOL" aDeltaUVMatrix = mat2 (aDeltaUVMatrix[1][1], -aDeltaUVMatrix[0][1], -aDeltaUVMatrix[1][0], aDeltaUVMatrix[0][0]);" EOL" mat2x3 aDeltaVectorMatrix = mat2x3 (dFdx (PositionWorld.xyz), dFdy (PositionWorld.xyz));" - EOL" aDeltaVectorMatrix = aDeltaVectorMatrix * aDeltaUVMatrix;" - EOL" aDeltaVectorMatrix[0] = normalize(aDeltaVectorMatrix[0] - dot(Normal, aDeltaVectorMatrix[0]) * Normal);" - EOL" aDeltaVectorMatrix[1] = normalize(aDeltaVectorMatrix[1] - dot(Normal, aDeltaVectorMatrix[1]) * Normal);" - EOL" float aDirection = gl_FrontFacing ? 1.0 : -1.0;" - EOL" Normal = mat3 (aDirection * aDeltaVectorMatrix[0], aDirection * aDeltaVectorMatrix[1], Normal) * aMapNormalValue.xyz;" + EOL" Normal = TangentSpaceNormal (aDeltaUVMatrix, aDeltaVectorMatrix, aMapNormalValue.xyz, Normal, !gl_FrontFacing);" EOL" }" EOL"#endif"; } @@ -2777,7 +2773,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcFragGetVertColor.IsEmpty(), theIsPBR, (theBits & OpenGl_PO_TextureRGB) == 0 || (theBits & OpenGl_PO_IsPoint) != 0); - aSrcFrag = TCollection_AsciiString() + aSrcFrag += TCollection_AsciiString() + EOL + aSrcFragGetVertColor + EOL"vec3 Normal;" diff --git a/src/OpenGl/OpenGl_View.hxx b/src/OpenGl/OpenGl_View.hxx index 8f39d03f22..346c753a67 100644 --- a/src/OpenGl/OpenGl_View.hxx +++ b/src/OpenGl/OpenGl_View.hxx @@ -756,6 +756,9 @@ protected: //! @name data types related to ray-tracing //! Enables/disables environment map for background. Standard_Boolean UseEnvMapForBackground; + //! Enables/disables normal map ignoring during path tracing. + Standard_Boolean ToIgnoreNormalMap; + //! Maximum radiance value used for clamping radiance estimation. Standard_ShortReal RadianceClampingValue; @@ -779,6 +782,7 @@ protected: //! @name data types related to ray-tracing AdaptiveScreenSampling (Standard_False), AdaptiveScreenSamplingAtomic (Standard_False), UseEnvMapForBackground (Standard_False), + ToIgnoreNormalMap (Standard_False), RadianceClampingValue (30.0), DepthOfField (Standard_False), CubemapForBack (Standard_False), diff --git a/src/OpenGl/OpenGl_View_Raytrace.cxx b/src/OpenGl/OpenGl_View_Raytrace.cxx index 90377c68fb..d39623baa7 100644 --- a/src/OpenGl/OpenGl_View_Raytrace.cxx +++ b/src/OpenGl/OpenGl_View_Raytrace.cxx @@ -28,6 +28,7 @@ #include "../Shaders/Shaders_RaytraceRender_fs.pxx" #include "../Shaders/Shaders_RaytraceSmooth_fs.pxx" #include "../Shaders/Shaders_Display_fs.pxx" +#include "../Shaders/Shaders_TangentSpaceNormal_glsl.pxx" //! Use this macro to output ray-tracing debug info // #define RAY_TRACE_PRINT_INFO @@ -411,6 +412,7 @@ OpenGl_RaytraceMaterial OpenGl_View::convertMaterial (const OpenGl_Aspects* theA aResMat.BSDF.FresnelCoat = aBSDF.FresnelCoat.Serialize (); aResMat.BSDF.FresnelBase = aBSDF.FresnelBase.Serialize (); + aResMat.BSDF.FresnelBase.w() = -1.0; // no normal map texture // Handle material textures if (!theAspect->Aspect()->ToMapTexture()) @@ -447,6 +449,11 @@ OpenGl_RaytraceMaterial OpenGl_View::convertMaterial (const OpenGl_Aspects* theA buildTextureTransform (aTexture->Sampler()->Parameters(), aResMat.TextureTransform); aResMat.BSDF.Le.w() = static_cast (myRaytraceGeometry.AddTexture (aTexture)); } + else if (aTexIter.Unit() == Graphic3d_TextureUnit_Normal) + { + buildTextureTransform (aTexture->Sampler()->Parameters(), aResMat.TextureTransform); + aResMat.BSDF.FresnelBase.w() = static_cast (myRaytraceGeometry.AddTexture (aTexture)); + } } } else if (!myIsRaytraceWarnTextures) @@ -1160,6 +1167,11 @@ TCollection_AsciiString OpenGl_View::generateShaderPrefix (const Handle(OpenGl_C } } + if (myRaytraceParameters.ToIgnoreNormalMap) + { + aPrefixString += TCollection_AsciiString("\n#define IGNORE_NORMAL_MAP"); + } + if (myRaytraceParameters.CubemapForBack) { aPrefixString += TCollection_AsciiString("\n#define BACKGROUND_CUBEMAP"); @@ -1335,13 +1347,15 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Standard_Integer theS || myRenderParams.IsTransparentShadowEnabled != myRaytraceParameters.TransparentShadows || myRenderParams.IsGlobalIlluminationEnabled != myRaytraceParameters.GlobalIllumination || myRenderParams.TwoSidedBsdfModels != myRaytraceParameters.TwoSidedBsdfModels - || myRaytraceGeometry.HasTextures() != myRaytraceParameters.UseBindlessTextures) + || myRaytraceGeometry.HasTextures() != myRaytraceParameters.UseBindlessTextures + || myRenderParams.ToIgnoreNormalMapInRayTracing != myRaytraceParameters.ToIgnoreNormalMap) { myRaytraceParameters.NbBounces = myRenderParams.RaytracingDepth; myRaytraceParameters.TransparentShadows = myRenderParams.IsTransparentShadowEnabled; myRaytraceParameters.GlobalIllumination = myRenderParams.IsGlobalIlluminationEnabled; myRaytraceParameters.TwoSidedBsdfModels = myRenderParams.TwoSidedBsdfModels; myRaytraceParameters.UseBindlessTextures = myRaytraceGeometry.HasTextures(); + myRaytraceParameters.ToIgnoreNormalMap = myRenderParams.ToIgnoreNormalMapInRayTracing; aToRebuildShaders = Standard_True; } @@ -1484,6 +1498,7 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Standard_Integer theS if (!aShaderFolder.IsEmpty()) { const TCollection_AsciiString aFiles[] = { aShaderFolder + "/RaytraceBase.fs", + aShaderFolder + "/TangentSpaceNormal.glsl", aShaderFolder + "/PathtraceBase.fs", aShaderFolder + "/RaytraceRender.fs", "" }; @@ -1495,6 +1510,7 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Standard_Integer theS else { const TCollection_AsciiString aSrcShaders[] = { Shaders_RaytraceBase_fs, + Shaders_TangentSpaceNormal_glsl, Shaders_PathtraceBase_fs, Shaders_RaytraceRender_fs, "" }; diff --git a/src/Shaders/FILES b/src/Shaders/FILES index 06d166ba2e..7c7ada0344 100644 --- a/src/Shaders/FILES +++ b/src/Shaders/FILES @@ -16,6 +16,7 @@ srcinc:::RaytraceRender.fs srcinc:::PathtraceBase.fs srcinc:::RaytraceBase.vs srcinc:::RaytraceSmooth.fs +srcinc:::TangentSpaceNormal.glsl Shaders_Declarations_glsl.pxx Shaders_DeclarationsImpl_glsl.pxx Shaders_Display_fs.pxx @@ -32,3 +33,4 @@ Shaders_RaytraceRender_fs.pxx Shaders_PathtraceBase_fs.pxx Shaders_RaytraceBase_vs.pxx Shaders_RaytraceSmooth_fs.pxx +Shaders_TangentSpaceNormal_glsl.pxx diff --git a/src/Shaders/PathtraceBase.fs b/src/Shaders/PathtraceBase.fs index 0d8c908558..e7a324ff15 100644 --- a/src/Shaders/PathtraceBase.fs +++ b/src/Shaders/PathtraceBase.fs @@ -46,8 +46,8 @@ struct SBSDF //! Fresnel coefficients of coat layer. vec3 FresnelCoat; - //! Fresnel coefficients of base layer. - vec3 FresnelBase; + //! Fresnel coefficients of base layer + normal map texture index in W. + vec4 FresnelBase; }; /////////////////////////////////////////////////////////////////////////////////////// @@ -322,7 +322,7 @@ vec3 EvalBsdfLayered (in SBSDF theBSDF, in vec3 theWi, in vec3 theWo) if (theBSDF.Ks.w > FLT_EPSILON) { - aBxDF += theBSDF.Ks.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.FresnelBase, theBSDF.Ks.w); + aBxDF += theBSDF.Ks.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.FresnelBase.rgb, theBSDF.Ks.w); } aBxDF *= UNIT - fresnelMedia (theWo.z, theBSDF.FresnelCoat); @@ -546,7 +546,7 @@ float SampleBsdfLayered (in SBSDF theBSDF, in vec3 theWo, out vec3 theWi, inout if (theBSDF.Ks.w < FLT_EPSILON) { - theWeight *= fresnelMedia (theWo.z, theBSDF.FresnelBase); + theWeight *= fresnelMedia (theWo.z, theBSDF.FresnelBase.rgb); theWi = vec3 (-theWo.x, -theWo.y, @@ -554,7 +554,7 @@ float SampleBsdfLayered (in SBSDF theBSDF, in vec3 theWo, out vec3 theWi, inout } else { - theWeight *= SampleGlossyBlinnReflection (theWo, theWi, theBSDF.FresnelBase, theBSDF.Ks.w, aPDF); + theWeight *= SampleGlossyBlinnReflection (theWo, theWi, theBSDF.FresnelBase.rgb, theBSDF.Ks.w, aPDF); } aPDF = mix (aPDF, MAXFLOAT, theBSDF.Ks.w < FLT_EPSILON); @@ -759,6 +759,23 @@ bool IsNotZero (in SBSDF theBSDF, in vec3 theThroughput) return convolve (theBSDF.Kd.rgb + aGlossy, theThroughput) > FLT_EPSILON; } +//======================================================================= +// function : NormalAdaptation +// purpose : Adapt smooth normal (which may be different from geometry normal) in order to avoid black areas in render +//======================================================================= +bool NormalAdaptation (in vec3 theView, in vec3 theGeometryNormal, inout vec3 theSmoothNormal) +{ + float aMinCos = dot(theView, theGeometryNormal); + aMinCos = 0.5 * (sqrt(1.0 - aMinCos) + sqrt(1.0 + aMinCos)); + float aCos = dot(theGeometryNormal, theSmoothNormal); + if (aCos < aMinCos) + { + theSmoothNormal = aMinCos * theGeometryNormal + normalize(theSmoothNormal - aCos * theGeometryNormal) * sqrt(1.0 - aMinCos * aMinCos); + return true; + } + return false; +} + //======================================================================= // function : PathTrace // purpose : Calculates radiance along the given ray @@ -780,12 +797,12 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples) { SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO); - ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTransfID); + STriangle aTriangle = SceneNearestHit (theRay, theInverse, aHit, aTransfID); // check implicit path vec3 aLe = IntersectLight (theRay, aDepth, aHit.Time, aExpPDF); - if (any (greaterThan (aLe, ZERO)) || aTriIndex.x == -1) + if (any (greaterThan (aLe, ZERO)) || aTriangle.TriIndex.x == -1) { float aMIS = (aDepth == 0 || aImpPDF == MAXFLOAT) ? 1.f : aImpPDF * aImpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF); @@ -816,31 +833,30 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples) SBSDF aBSDF; // fetch BxDF weights - aBSDF.Kc = texelFetch (uRaytraceMaterialTexture, MATERIAL_KC (aTriIndex.w)); - aBSDF.Kd = texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriIndex.w)); - aBSDF.Ks = texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriIndex.w)); - aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriIndex.w)); + aBSDF.Kc = texelFetch (uRaytraceMaterialTexture, MATERIAL_KC (aTriangle.TriIndex.w)); + aBSDF.Kd = texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriangle.TriIndex.w)); + aBSDF.Ks = texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriangle.TriIndex.w)); + aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriangle.TriIndex.w)); // fetch Fresnel reflectance for both layers - aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriIndex.w)).xyz; - aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriIndex.w)).xyz; + aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriangle.TriIndex.w)).xyz; + aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriangle.TriIndex.w)); - vec4 anLE = texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w)); + vec4 anLE = texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriangle.TriIndex.w)); // compute smooth normal (in parallel with fetch) - vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex); + vec3 aNormal = SmoothNormal (aHit.UV, aTriangle.TriIndex); aNormal = normalize (vec3 (dot (aInvTransf0, aNormal), dot (aInvTransf1, aNormal), dot (aInvTransf2, aNormal))); - SLocalSpace aSpace = buildLocalSpace (aNormal); - #ifdef USE_TEXTURES - if (aBSDF.Kd.w >= 0.0 || aBSDF.Kt.w >= 0.0 || anLE.w >= 0.0) + if (aBSDF.Kd.w >= 0.0 || aBSDF.Kt.w >= 0.0 || aBSDF.FresnelBase.w >=0.0 || anLE.w >= 0.0) { - vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f); - vec4 aTrsfRow1 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w)); - vec4 aTrsfRow2 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w)); + vec2 aUVs[3]; + vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriangle.TriIndex, aUVs), 0.f, 1.f); + vec4 aTrsfRow1 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriangle.TriIndex.w)); + vec4 aTrsfRow2 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriangle.TriIndex.w)); aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord), dot (aTrsfRow2, aTexCoord)); @@ -855,15 +871,15 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples) float aPbrRough2 = aTexMetRough.y * aTexMetRough.y; aBSDF.Ks.a *= aPbrRough2; // when using metal-roughness texture, global metalness of material (encoded in FresnelBase) is expected to be 1.0 so that Kd will be 0.0 - aBSDF.Kd.rgb = aBSDF.FresnelBase * (1.0 - aPbrMetal); - aBSDF.FresnelBase *= aPbrMetal; + aBSDF.Kd.rgb = aBSDF.FresnelBase.rgb * (1.0 - aPbrMetal); + aBSDF.FresnelBase.rgb *= aPbrMetal; } if (aBSDF.Kd.w >= 0.0) { vec4 aTexColor = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kd.w)]), aTexCoord.st, 0.0); vec3 aDiff = aTexColor.rgb * aTexColor.a; aBSDF.Kd.rgb *= aDiff; - aBSDF.FresnelBase *= aDiff; + aBSDF.FresnelBase.rgb *= aDiff; if (aTexColor.a != 1.0) { // mix transparency BTDF with texture alpha-channel @@ -871,8 +887,25 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples) aBSDF.Kt.rgb = (UNIT - aTexColor.aaa) + aTexColor.a * aBSDF.Kt.rgb; } } + #ifndef IGNORE_NORMAL_MAP + if (aBSDF.FresnelBase.w >= 0.0) + { + for (int i = 0 ; i < 3; ++i) + { + aUVs[i] = vec2 (dot (aTrsfRow1, vec4(aUVs[i], 0.0, 1.0)), + dot (aTrsfRow2, vec4(aUVs[i], 0.0, 1.0))); + } + vec3 aMapNormalValue = textureLod (sampler2D (uTextureSamplers[int (aBSDF.FresnelBase.w)]), aTexCoord.st, 0.0).xyz; + mat2 aDeltaUVMatrix = mat2 (aUVs[1] - aUVs[0], aUVs[1] - aUVs[2]); + mat2x3 aDeltaVectorMatrix = mat2x3 (aTriangle.Points[1] - aTriangle.Points[0], aTriangle.Points[1] - aTriangle.Points[2]); + aNormal = TangentSpaceNormal (aDeltaUVMatrix, aDeltaVectorMatrix, aMapNormalValue, aNormal, true); + } + #endif } #endif + NormalAdaptation (-theRay.Direct, aHit.Normal, aNormal); + aHit.Normal = aNormal; + SLocalSpace aSpace = buildLocalSpace (aNormal); if (uLightCount > 0 && IsNotZero (aBSDF, aThroughput)) { @@ -921,7 +954,7 @@ vec4 PathTrace (in SRay theRay, in vec3 theInverse, in int theNbSamples) if (aInMedium) // handle attenuation { - vec4 aScattering = texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT_BASE (aTriIndex.w)); + vec4 aScattering = texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT_BASE (aTriangle.TriIndex.w)); aThroughput *= exp (-aHit.Time * aScattering.w * (UNIT - aScattering.rgb)); } diff --git a/src/Shaders/PointLightAttenuation.glsl b/src/Shaders/PointLightAttenuation.glsl index cb840393a5..3334e956fb 100644 --- a/src/Shaders/PointLightAttenuation.glsl +++ b/src/Shaders/PointLightAttenuation.glsl @@ -32,4 +32,4 @@ float occPointLightAttenuation (in float theDistance, in float theRange, in floa return 1.0 / (theConstAttenuation + theLinearAttenuation * theDistance); } return occRangedPointLightAttenuation (theDistance, theRange); -} \ No newline at end of file +} diff --git a/src/Shaders/RaytraceBase.fs b/src/Shaders/RaytraceBase.fs index 5c73a6773a..0c7ead83ca 100644 --- a/src/Shaders/RaytraceBase.fs +++ b/src/Shaders/RaytraceBase.fs @@ -170,6 +170,14 @@ struct SIntersect vec3 Normal; }; +//! Stores triangle's vertex indexes and vertexes itself +struct STriangle +{ + ivec4 TriIndex; + + vec3 Points[3]; +}; + ///////////////////////////////////////////////////////////////////////////////////////// // Some useful constants @@ -462,7 +470,7 @@ struct SSubTree #define TRG_OFFSET(treelet) treelet.SubData.w //! Identifies the absence of intersection. -#define INALID_HIT ivec4 (-1) +#define INVALID_HIT ivec4 (-1) //! Global stack shared between traversal functions. int Stack[STACK_SIZE]; @@ -498,9 +506,9 @@ int pop (inout int theHead) // function : SceneNearestHit // purpose : Finds intersection with nearest scene triangle // ======================================================================= -ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId) +STriangle SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId) { - ivec4 aTriIndex = INALID_HIT; + STriangle aTriangle = STriangle (INVALID_HIT, vec3[](vec3(0.0), vec3(0.0), vec3(0.0))); int aNode = 0; // node to traverse int aHead = -1; // pointer of stack @@ -607,17 +615,22 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx) { - ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree)); + ivec4 aTriIndex = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree)); + vec3 aPoints[3]; - vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz; - vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz; - vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz; + aPoints[0] = texelFetch (uGeometryVertexTexture, aTriIndex.x += VRT_OFFSET (aSubTree)).xyz; + aPoints[1] = texelFetch (uGeometryVertexTexture, aTriIndex.y += VRT_OFFSET (aSubTree)).xyz; + aPoints[2] = texelFetch (uGeometryVertexTexture, aTriIndex.z += VRT_OFFSET (aSubTree)).xyz; - IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal); + IntersectTriangle (aSubTree.TrsfRay, aPoints[0], aPoints[1], aPoints[2], aTimeUV, aNormal); if (aTimeUV.x < theHit.Time) { - aTriIndex = aTriangle; + aTriangle.TriIndex = aTriIndex; + for (int i = 0; i < 3; ++i) + { + aTriangle.Points[i] = aPoints[i]; + } theTrsfId = TRS_OFFSET (aSubTree); @@ -664,7 +677,7 @@ ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theH } } - return aTriIndex; + return aTriangle; } // ======================================================================= @@ -914,15 +927,21 @@ float PolygonOffset (in vec3 theNormal, in vec3 thePoint) // purpose : Interpolates UV coordinates across the triangle // ======================================================================= #ifdef USE_TEXTURES +vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle, out vec2[3] theUVs) +{ + theUVs[0] = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st; + theUVs[1] = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st; + theUVs[2] = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st; + + return theUVs[1] * theUV.x + + theUVs[2] * theUV.y + + theUVs[0] * (1.0f - theUV.x - theUV.y); +} + vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle) { - vec2 aTexCrd0 = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st; - vec2 aTexCrd1 = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st; - vec2 aTexCrd2 = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st; - - return aTexCrd1 * theUV.x + - aTexCrd2 * theUV.y + - aTexCrd0 * (1.0f - theUV.x - theUV.y); + vec2 aUVs[3]; + return SmoothUV (theUV, theTriangle, aUVs); } #endif @@ -1009,7 +1028,7 @@ vec4 Radiance (in SRay theRay, in vec3 theInverse) { SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO); - ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId); + ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId).TriIndex; if (aTriIndex.x == -1) { diff --git a/src/Shaders/Shaders_PathtraceBase_fs.pxx b/src/Shaders/Shaders_PathtraceBase_fs.pxx index 3db4426aeb..fb32f24022 100644 --- a/src/Shaders/Shaders_PathtraceBase_fs.pxx +++ b/src/Shaders/Shaders_PathtraceBase_fs.pxx @@ -49,8 +49,8 @@ static const char Shaders_PathtraceBase_fs[] = " //! Fresnel coefficients of coat layer.\n" " vec3 FresnelCoat;\n" "\n" - " //! Fresnel coefficients of base layer.\n" - " vec3 FresnelBase;\n" + " //! Fresnel coefficients of base layer + normal map texture index in W.\n" + " vec4 FresnelBase;\n" "};\n" "\n" "///////////////////////////////////////////////////////////////////////////////////////\n" @@ -325,7 +325,7 @@ static const char Shaders_PathtraceBase_fs[] = "\n" " if (theBSDF.Ks.w > FLT_EPSILON)\n" " {\n" - " aBxDF += theBSDF.Ks.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.FresnelBase, theBSDF.Ks.w);\n" + " aBxDF += theBSDF.Ks.rgb * EvalBlinnReflection (theWi, theWo, theBSDF.FresnelBase.rgb, theBSDF.Ks.w);\n" " }\n" "\n" " aBxDF *= UNIT - fresnelMedia (theWo.z, theBSDF.FresnelCoat);\n" @@ -549,7 +549,7 @@ static const char Shaders_PathtraceBase_fs[] = "\n" " if (theBSDF.Ks.w < FLT_EPSILON)\n" " {\n" - " theWeight *= fresnelMedia (theWo.z, theBSDF.FresnelBase);\n" + " theWeight *= fresnelMedia (theWo.z, theBSDF.FresnelBase.rgb);\n" "\n" " theWi = vec3 (-theWo.x,\n" " -theWo.y,\n" @@ -557,7 +557,7 @@ static const char Shaders_PathtraceBase_fs[] = " }\n" " else\n" " {\n" - " theWeight *= SampleGlossyBlinnReflection (theWo, theWi, theBSDF.FresnelBase, theBSDF.Ks.w, aPDF);\n" + " theWeight *= SampleGlossyBlinnReflection (theWo, theWi, theBSDF.FresnelBase.rgb, theBSDF.Ks.w, aPDF);\n" " }\n" "\n" " aPDF = mix (aPDF, MAXFLOAT, theBSDF.Ks.w < FLT_EPSILON);\n" @@ -763,6 +763,23 @@ static const char Shaders_PathtraceBase_fs[] = "}\n" "\n" "//=======================================================================\n" + "// function : NormalAdaptation\n" + "// purpose : Adapt smooth normal (which may be different from geometry normal) in order to avoid black areas in render\n" + "//=======================================================================\n" + "bool NormalAdaptation (in vec3 theView, in vec3 theGeometryNormal, inout vec3 theSmoothNormal)\n" + "{\n" + " float aMinCos = dot(theView, theGeometryNormal);\n" + " aMinCos = 0.5 * (sqrt(1.0 - aMinCos) + sqrt(1.0 + aMinCos));\n" + " float aCos = dot(theGeometryNormal, theSmoothNormal);\n" + " if (aCos < aMinCos)\n" + " {\n" + " theSmoothNormal = aMinCos * theGeometryNormal + normalize(theSmoothNormal - aCos * theGeometryNormal) * sqrt(1.0 - aMinCos * aMinCos);\n" + " return true;\n" + " }\n" + " return false;\n" + "}\n" + "\n" + "//=======================================================================\n" "// function : PathTrace\n" "// purpose : Calculates radiance along the given ray\n" "//=======================================================================\n" @@ -783,12 +800,12 @@ static const char Shaders_PathtraceBase_fs[] = " {\n" " SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);\n" "\n" - " ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTransfID);\n" + " STriangle aTriangle = SceneNearestHit (theRay, theInverse, aHit, aTransfID);\n" "\n" " // check implicit path\n" " vec3 aLe = IntersectLight (theRay, aDepth, aHit.Time, aExpPDF);\n" "\n" - " if (any (greaterThan (aLe, ZERO)) || aTriIndex.x == -1)\n" + " if (any (greaterThan (aLe, ZERO)) || aTriangle.TriIndex.x == -1)\n" " {\n" " float aMIS = (aDepth == 0 || aImpPDF == MAXFLOAT) ? 1.f :\n" " aImpPDF * aImpPDF / (aExpPDF * aExpPDF + aImpPDF * aImpPDF);\n" @@ -819,31 +836,30 @@ static const char Shaders_PathtraceBase_fs[] = " SBSDF aBSDF;\n" "\n" " // fetch BxDF weights\n" - " aBSDF.Kc = texelFetch (uRaytraceMaterialTexture, MATERIAL_KC (aTriIndex.w));\n" - " aBSDF.Kd = texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriIndex.w));\n" - " aBSDF.Ks = texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriIndex.w));\n" - " aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriIndex.w));\n" + " aBSDF.Kc = texelFetch (uRaytraceMaterialTexture, MATERIAL_KC (aTriangle.TriIndex.w));\n" + " aBSDF.Kd = texelFetch (uRaytraceMaterialTexture, MATERIAL_KD (aTriangle.TriIndex.w));\n" + " aBSDF.Ks = texelFetch (uRaytraceMaterialTexture, MATERIAL_KS (aTriangle.TriIndex.w));\n" + " aBSDF.Kt = texelFetch (uRaytraceMaterialTexture, MATERIAL_KT (aTriangle.TriIndex.w));\n" "\n" " // fetch Fresnel reflectance for both layers\n" - " aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriIndex.w)).xyz;\n" - " aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriIndex.w)).xyz;\n" + " aBSDF.FresnelCoat = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_COAT (aTriangle.TriIndex.w)).xyz;\n" + " aBSDF.FresnelBase = texelFetch (uRaytraceMaterialTexture, MATERIAL_FRESNEL_BASE (aTriangle.TriIndex.w));\n" "\n" - " vec4 anLE = texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriIndex.w));\n" + " vec4 anLE = texelFetch (uRaytraceMaterialTexture, MATERIAL_LE (aTriangle.TriIndex.w));\n" "\n" " // compute smooth normal (in parallel with fetch)\n" - " vec3 aNormal = SmoothNormal (aHit.UV, aTriIndex);\n" + " vec3 aNormal = SmoothNormal (aHit.UV, aTriangle.TriIndex);\n" " aNormal = normalize (vec3 (dot (aInvTransf0, aNormal),\n" " dot (aInvTransf1, aNormal),\n" " dot (aInvTransf2, aNormal)));\n" "\n" - " SLocalSpace aSpace = buildLocalSpace (aNormal);\n" - "\n" "#ifdef USE_TEXTURES\n" - " if (aBSDF.Kd.w >= 0.0 || aBSDF.Kt.w >= 0.0 || anLE.w >= 0.0)\n" + " if (aBSDF.Kd.w >= 0.0 || aBSDF.Kt.w >= 0.0 || aBSDF.FresnelBase.w >=0.0 || anLE.w >= 0.0)\n" " {\n" - " vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriIndex), 0.f, 1.f);\n" - " vec4 aTrsfRow1 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriIndex.w));\n" - " vec4 aTrsfRow2 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriIndex.w));\n" + " vec2 aUVs[3];\n" + " vec4 aTexCoord = vec4 (SmoothUV (aHit.UV, aTriangle.TriIndex, aUVs), 0.f, 1.f);\n" + " vec4 aTrsfRow1 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS1 (aTriangle.TriIndex.w));\n" + " vec4 aTrsfRow2 = texelFetch (uRaytraceMaterialTexture, MATERIAL_TRS2 (aTriangle.TriIndex.w));\n" " aTexCoord.st = vec2 (dot (aTrsfRow1, aTexCoord),\n" " dot (aTrsfRow2, aTexCoord));\n" "\n" @@ -858,15 +874,15 @@ static const char Shaders_PathtraceBase_fs[] = " float aPbrRough2 = aTexMetRough.y * aTexMetRough.y;\n" " aBSDF.Ks.a *= aPbrRough2;\n" " // when using metal-roughness texture, global metalness of material (encoded in FresnelBase) is expected to be 1.0 so that Kd will be 0.0\n" - " aBSDF.Kd.rgb = aBSDF.FresnelBase * (1.0 - aPbrMetal);\n" - " aBSDF.FresnelBase *= aPbrMetal;\n" + " aBSDF.Kd.rgb = aBSDF.FresnelBase.rgb * (1.0 - aPbrMetal);\n" + " aBSDF.FresnelBase.rgb *= aPbrMetal;\n" " }\n" " if (aBSDF.Kd.w >= 0.0)\n" " {\n" " vec4 aTexColor = textureLod (sampler2D (uTextureSamplers[int (aBSDF.Kd.w)]), aTexCoord.st, 0.0);\n" " vec3 aDiff = aTexColor.rgb * aTexColor.a;\n" " aBSDF.Kd.rgb *= aDiff;\n" - " aBSDF.FresnelBase *= aDiff;\n" + " aBSDF.FresnelBase.rgb *= aDiff;\n" " if (aTexColor.a != 1.0)\n" " {\n" " // mix transparency BTDF with texture alpha-channel\n" @@ -874,8 +890,25 @@ static const char Shaders_PathtraceBase_fs[] = " aBSDF.Kt.rgb = (UNIT - aTexColor.aaa) + aTexColor.a * aBSDF.Kt.rgb;\n" " }\n" " }\n" + " #ifndef IGNORE_NORMAL_MAP\n" + " if (aBSDF.FresnelBase.w >= 0.0)\n" + " {\n" + " for (int i = 0 ; i < 3; ++i)\n" + " {\n" + " aUVs[i] = vec2 (dot (aTrsfRow1, vec4(aUVs[i], 0.0, 1.0)),\n" + " dot (aTrsfRow2, vec4(aUVs[i], 0.0, 1.0)));\n" + " }\n" + " vec3 aMapNormalValue = textureLod (sampler2D (uTextureSamplers[int (aBSDF.FresnelBase.w)]), aTexCoord.st, 0.0).xyz;\n" + " mat2 aDeltaUVMatrix = mat2 (aUVs[1] - aUVs[0], aUVs[1] - aUVs[2]);\n" + " mat2x3 aDeltaVectorMatrix = mat2x3 (aTriangle.Points[1] - aTriangle.Points[0], aTriangle.Points[1] - aTriangle.Points[2]);\n" + " aNormal = TangentSpaceNormal (aDeltaUVMatrix, aDeltaVectorMatrix, aMapNormalValue, aNormal, true);\n" + " }\n" + " #endif\n" " }\n" "#endif\n" + " NormalAdaptation (-theRay.Direct, aHit.Normal, aNormal);\n" + " aHit.Normal = aNormal;\n" + " SLocalSpace aSpace = buildLocalSpace (aNormal);\n" "\n" " if (uLightCount > 0 && IsNotZero (aBSDF, aThroughput))\n" " {\n" @@ -924,7 +957,7 @@ static const char Shaders_PathtraceBase_fs[] = "\n" " if (aInMedium) // handle attenuation\n" " {\n" - " vec4 aScattering = texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT_BASE (aTriIndex.w));\n" + " vec4 aScattering = texelFetch (uRaytraceMaterialTexture, MATERIAL_ABSORPT_BASE (aTriangle.TriIndex.w));\n" "\n" " aThroughput *= exp (-aHit.Time * aScattering.w * (UNIT - aScattering.rgb));\n" " }\n" diff --git a/src/Shaders/Shaders_RaytraceBase_fs.pxx b/src/Shaders/Shaders_RaytraceBase_fs.pxx index 6b852d4a4b..63f44e1a69 100644 --- a/src/Shaders/Shaders_RaytraceBase_fs.pxx +++ b/src/Shaders/Shaders_RaytraceBase_fs.pxx @@ -173,6 +173,14 @@ static const char Shaders_RaytraceBase_fs[] = " vec3 Normal;\n" "};\n" "\n" + "//! Stores triangle's vertex indexes and vertexes itself\n" + "struct STriangle\n" + "{\n" + " ivec4 TriIndex;\n" + "\n" + " vec3 Points[3];\n" + "};\n" + "\n" "/////////////////////////////////////////////////////////////////////////////////////////\n" "// Some useful constants\n" "\n" @@ -465,7 +473,7 @@ static const char Shaders_RaytraceBase_fs[] = "#define TRG_OFFSET(treelet) treelet.SubData.w\n" "\n" "//! Identifies the absence of intersection.\n" - "#define INALID_HIT ivec4 (-1)\n" + "#define INVALID_HIT ivec4 (-1)\n" "\n" "//! Global stack shared between traversal functions.\n" "int Stack[STACK_SIZE];\n" @@ -501,9 +509,9 @@ static const char Shaders_RaytraceBase_fs[] = "// function : SceneNearestHit\n" "// purpose : Finds intersection with nearest scene triangle\n" "// =======================================================================\n" - "ivec4 SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)\n" + "STriangle SceneNearestHit (in SRay theRay, in vec3 theInverse, inout SIntersect theHit, out int theTrsfId)\n" "{\n" - " ivec4 aTriIndex = INALID_HIT;\n" + " STriangle aTriangle = STriangle (INVALID_HIT, vec3[](vec3(0.0), vec3(0.0), vec3(0.0)));\n" "\n" " int aNode = 0; // node to traverse\n" " int aHead = -1; // pointer of stack\n" @@ -610,17 +618,22 @@ static const char Shaders_RaytraceBase_fs[] = "\n" " for (int anIdx = aData.y; anIdx <= aData.z; ++anIdx)\n" " {\n" - " ivec4 aTriangle = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));\n" + " ivec4 aTriIndex = texelFetch (uGeometryTriangTexture, anIdx + TRG_OFFSET (aSubTree));\n" + " vec3 aPoints[3];\n" "\n" - " vec3 aPoint0 = texelFetch (uGeometryVertexTexture, aTriangle.x += VRT_OFFSET (aSubTree)).xyz;\n" - " vec3 aPoint1 = texelFetch (uGeometryVertexTexture, aTriangle.y += VRT_OFFSET (aSubTree)).xyz;\n" - " vec3 aPoint2 = texelFetch (uGeometryVertexTexture, aTriangle.z += VRT_OFFSET (aSubTree)).xyz;\n" + " aPoints[0] = texelFetch (uGeometryVertexTexture, aTriIndex.x += VRT_OFFSET (aSubTree)).xyz;\n" + " aPoints[1] = texelFetch (uGeometryVertexTexture, aTriIndex.y += VRT_OFFSET (aSubTree)).xyz;\n" + " aPoints[2] = texelFetch (uGeometryVertexTexture, aTriIndex.z += VRT_OFFSET (aSubTree)).xyz;\n" "\n" - " IntersectTriangle (aSubTree.TrsfRay, aPoint0, aPoint1, aPoint2, aTimeUV, aNormal);\n" + " IntersectTriangle (aSubTree.TrsfRay, aPoints[0], aPoints[1], aPoints[2], aTimeUV, aNormal);\n" "\n" " if (aTimeUV.x < theHit.Time)\n" " {\n" - " aTriIndex = aTriangle;\n" + " aTriangle.TriIndex = aTriIndex;\n" + " for (int i = 0; i < 3; ++i)\n" + " {\n" + " aTriangle.Points[i] = aPoints[i];\n" + " }\n" "\n" " theTrsfId = TRS_OFFSET (aSubTree);\n" "\n" @@ -667,7 +680,7 @@ static const char Shaders_RaytraceBase_fs[] = " }\n" " }\n" "\n" - " return aTriIndex;\n" + " return aTriangle;\n" "}\n" "\n" "// =======================================================================\n" @@ -917,15 +930,21 @@ static const char Shaders_RaytraceBase_fs[] = "// purpose : Interpolates UV coordinates across the triangle\n" "// =======================================================================\n" "#ifdef USE_TEXTURES\n" + "vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle, out vec2[3] theUVs)\n" + "{\n" + " theUVs[0] = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st;\n" + " theUVs[1] = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st;\n" + " theUVs[2] = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st;\n" + "\n" + " return theUVs[1] * theUV.x +\n" + " theUVs[2] * theUV.y +\n" + " theUVs[0] * (1.0f - theUV.x - theUV.y);\n" + "}\n" + "\n" "vec2 SmoothUV (in vec2 theUV, in ivec4 theTriangle)\n" "{\n" - " vec2 aTexCrd0 = texelFetch (uGeometryTexCrdTexture, theTriangle.x).st;\n" - " vec2 aTexCrd1 = texelFetch (uGeometryTexCrdTexture, theTriangle.y).st;\n" - " vec2 aTexCrd2 = texelFetch (uGeometryTexCrdTexture, theTriangle.z).st;\n" - "\n" - " return aTexCrd1 * theUV.x +\n" - " aTexCrd2 * theUV.y +\n" - " aTexCrd0 * (1.0f - theUV.x - theUV.y);\n" + " vec2 aUVs[3];\n" + " return SmoothUV (theUV, theTriangle, aUVs);\n" "}\n" "#endif\n" "\n" @@ -1012,7 +1031,7 @@ static const char Shaders_RaytraceBase_fs[] = " {\n" " SIntersect aHit = SIntersect (MAXFLOAT, vec2 (ZERO), ZERO);\n" "\n" - " ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId);\n" + " ivec4 aTriIndex = SceneNearestHit (theRay, theInverse, aHit, aTrsfId).TriIndex;\n" "\n" " if (aTriIndex.x == -1)\n" " {\n" diff --git a/src/Shaders/Shaders_TangentSpaceNormal_glsl.pxx b/src/Shaders/Shaders_TangentSpaceNormal_glsl.pxx new file mode 100644 index 0000000000..0878cd55f3 --- /dev/null +++ b/src/Shaders/Shaders_TangentSpaceNormal_glsl.pxx @@ -0,0 +1,20 @@ +// This file has been automatically generated from resource file src/Shaders/TangentSpaceNormal.glsl + +static const char Shaders_TangentSpaceNormal_glsl[] = + "//! Calculates transformation from tangent space and apply it to value from normal map to get normal in object space\n" + "vec3 TangentSpaceNormal (in mat2 theDeltaUVMatrix,\n" + " in mat2x3 theDeltaVectorMatrix,\n" + " in vec3 theNormalMapValue,\n" + " in vec3 theNormal,\n" + " in bool theIsInverse)\n" + "{\n" + " theNormalMapValue = normalize(theNormalMapValue * 2.0 - vec3(1.0));\n" + " // Inverse matrix\n" + " theDeltaUVMatrix = mat2 (theDeltaUVMatrix[1][1], -theDeltaUVMatrix[0][1], -theDeltaUVMatrix[1][0], theDeltaUVMatrix[0][0]);\n" + " theDeltaVectorMatrix = theDeltaVectorMatrix * theDeltaUVMatrix;\n" + " // Gram-Schmidt orthogonalization\n" + " theDeltaVectorMatrix[1] = normalize(theDeltaVectorMatrix[1] - dot(theNormal, theDeltaVectorMatrix[1]) * theNormal);\n" + " theDeltaVectorMatrix[0] = cross(theDeltaVectorMatrix[1], theNormal);\n" + " float aDirection = theIsInverse ? -1.0 : 1.0;\n" + " return mat3 (aDirection * theDeltaVectorMatrix[0], aDirection * theDeltaVectorMatrix[1], theNormal) * theNormalMapValue;\n" + "}\n"; diff --git a/src/Shaders/TangentSpaceNormal.glsl b/src/Shaders/TangentSpaceNormal.glsl new file mode 100644 index 0000000000..539759fe44 --- /dev/null +++ b/src/Shaders/TangentSpaceNormal.glsl @@ -0,0 +1,17 @@ +//! Calculates transformation from tangent space and apply it to value from normal map to get normal in object space +vec3 TangentSpaceNormal (in mat2 theDeltaUVMatrix, + in mat2x3 theDeltaVectorMatrix, + in vec3 theNormalMapValue, + in vec3 theNormal, + in bool theIsInverse) +{ + theNormalMapValue = normalize(theNormalMapValue * 2.0 - vec3(1.0)); + // Inverse matrix + theDeltaUVMatrix = mat2 (theDeltaUVMatrix[1][1], -theDeltaUVMatrix[0][1], -theDeltaUVMatrix[1][0], theDeltaUVMatrix[0][0]); + theDeltaVectorMatrix = theDeltaVectorMatrix * theDeltaUVMatrix; + // Gram-Schmidt orthogonalization + theDeltaVectorMatrix[1] = normalize(theDeltaVectorMatrix[1] - dot(theNormal, theDeltaVectorMatrix[1]) * theNormal); + theDeltaVectorMatrix[0] = cross(theDeltaVectorMatrix[1], theNormal); + float aDirection = theIsInverse ? -1.0 : 1.0; + return mat3 (aDirection * theDeltaVectorMatrix[0], aDirection * theDeltaVectorMatrix[1], theNormal) * theNormalMapValue; +} diff --git a/src/ViewerTest/ViewerTest_ViewerCommands.cxx b/src/ViewerTest/ViewerTest_ViewerCommands.cxx index 65a1834d49..d1aa802c10 100644 --- a/src/ViewerTest/ViewerTest_ViewerCommands.cxx +++ b/src/ViewerTest/ViewerTest_ViewerCommands.cxx @@ -12022,6 +12022,22 @@ static Standard_Integer VRenderParams (Draw_Interpretor& theDI, } aParams.UseEnvironmentMapBackground = toEnable; } + else if (aFlag == "-ignorenormalmap") + { + if (toPrint) + { + theDI << (aParams.ToIgnoreNormalMapInRayTracing ? "on" : "off") << " "; + continue; + } + + Standard_Boolean toEnable = Standard_True; + if (++anArgIter < theArgNb + && !ViewerTest::ParseOnOff (theArgVec[anArgIter], toEnable)) + { + --anArgIter; + } + aParams.ToIgnoreNormalMapInRayTracing = toEnable; + } else if (aFlag == "-twoside") { if (toPrint) @@ -14433,6 +14449,7 @@ void ViewerTest::ViewerCommands(Draw_Interpretor& theCommands) "\n '-gi on|off' Enables/disables global illumination effects" "\n '-brng on|off' Enables/disables blocked RNG (fast coherent PT)" "\n '-env on|off' Enables/disables environment map background" + "\n '-ignoreNormalMap on|off' Enables/disables normal map ignoring during path tracing" "\n '-twoside on|off' Enables/disables two-sided BSDF models (PT mode)" "\n '-iss on|off' Enables/disables adaptive screen sampling (PT mode)" "\n '-issd on|off' Shows screen sampling distribution in ISS mode" diff --git a/tests/v3d/raytrace/normal_map b/tests/v3d/raytrace/normal_map new file mode 100644 index 0000000000..f2b6ff8075 --- /dev/null +++ b/tests/v3d/raytrace/normal_map @@ -0,0 +1,34 @@ +puts "========" +puts "0031275: Visualization, TKOpenGl - handle normal-map texture with Path-Tracing" +puts "========" + +pload XDE OCAF MODELING VISUALIZATION +catch { Close D } +ReadGltf D [locate_data_file bug31275_SphereWithNormalMap.glb] + +vclear +vinit v -w 1024 -h 1024 +vbackground -cubemap [locate_data_file Circus_CubeMap_V.png] +vcamera -persp +vlight -clear +vlight -add ambient +XDisplay -dispmode 1 D +vback +vfit + +vrenderparams -ignoreNormalMap on +vrenderparams -ray -gi -rayDepth 10 +vfps 200 +vdump ${imagedir}/${casename}_without_normal_map.png + +vrenderparams -ignoreNormalMap off +vfps 200 +vdump ${imagedir}/${casename}_with_normal_map_back.png + +vfront +vfps 200 +vdump ${imagedir}/${casename}_with_normal_map_front.png + +vlight -add positional -pos 0 0 0 -head 1 -intensity 10 +vfps 200 +vdump ${imagedir}/${casename}_point_light.png