diff --git a/src/foundation/definitions/ShaderSemantics.ts b/src/foundation/definitions/ShaderSemantics.ts index 811041e55..6686a1df6 100644 --- a/src/foundation/definitions/ShaderSemantics.ts +++ b/src/foundation/definitions/ShaderSemantics.ts @@ -410,6 +410,16 @@ const IridescenceThicknessTexture = new ShaderSemanticsClass({ const GaussianKernelSize = new ShaderSemanticsClass({ str: 'gaussianKernelSize', }); +const AnisotropyStrength = new ShaderSemanticsClass({ + str: 'anisotropyStrength', +}); +const AnisotropyRotation = new ShaderSemanticsClass({ + str: 'anisotropyRotation', +}); +const AnisotropyTexture = new ShaderSemanticsClass({ + str: 'anisotropyTexture', +}); + const GaussianRatio = new ShaderSemanticsClass({ str: 'gaussianRatio' }); const IsHorizontal = new ShaderSemanticsClass({ str: 'isHorizontal' }); @@ -538,6 +548,9 @@ const typeList = [ GaussianKernelSize, GaussianRatio, IsHorizontal, + AnisotropyStrength, + AnisotropyRotation, + AnisotropyTexture, ]; function from(index: ShaderSemanticsIndex): ShaderSemanticsEnum { @@ -795,4 +808,7 @@ export const ShaderSemantics = Object.freeze({ GaussianKernelSize, GaussianRatio, IsHorizontal, + AnisotropyStrength, + AnisotropyRotation, + AnisotropyTexture, }); diff --git a/src/foundation/helpers/MaterialHelper.ts b/src/foundation/helpers/MaterialHelper.ts index d1e4b7bb0..7bd88be57 100644 --- a/src/foundation/helpers/MaterialHelper.ts +++ b/src/foundation/helpers/MaterialHelper.ts @@ -49,6 +49,7 @@ import { MaterialRepository } from '../materials/core/MaterialRepository'; import { Vrm0xMaterialProperty } from '../../types'; import { Sampler } from '../textures/Sampler'; import { + dummyAnisotropyTexture, dummyBlackTexture, dummyBlueTexture, dummyWhiteTexture, @@ -117,6 +118,7 @@ function createPbrUberMaterial({ isSheen = false, isSpecular = false, isIridescence = false, + isAnisotropy = false, isShadow = false, useTangentAttribute = false, useNormalTexture = true, @@ -134,6 +136,7 @@ function createPbrUberMaterial({ (isSheen ? '+sheen' : '') + (isSpecular ? '+specular' : '') + (isIridescence ? '+iridescence' : '') + + (isAnisotropy ? '+anisotropy' : '') + (useTangentAttribute ? '+tangentAttribute' : '') + (useNormalTexture ? '' : '-normalTexture'); @@ -336,6 +339,21 @@ function createPbrUberMaterial({ max: Number.MAX_VALUE, }); } + if (isAnisotropy) { + additionalShaderSemanticInfo.push({ + semantic: ShaderSemantics.AnisotropyTexture, + componentType: ComponentType.Int, + compositionType: CompositionType.Texture2D, + stage: ShaderType.PixelShader, + isCustomSetting: true, + soloDatum: false, + updateInterval: ShaderVariableUpdateInterval.EveryTime, + initialValue: [textureSlotIdx++, dummyAnisotropyTexture], + min: 0, + max: Number.MAX_VALUE, + needUniformInDataTextureMode: true, + }); + } if (isShadow) { additionalShaderSemanticInfo.push({ @@ -363,6 +381,7 @@ function createPbrUberMaterial({ isSheen, isSpecular, isIridescence, + isAnisotropy, isShadow, useTangentAttribute, useNormalTexture, diff --git a/src/foundation/importer/Gltf2Importer.ts b/src/foundation/importer/Gltf2Importer.ts index 47e49bd36..75835237c 100644 --- a/src/foundation/importer/Gltf2Importer.ts +++ b/src/foundation/importer/Gltf2Importer.ts @@ -493,6 +493,12 @@ export class Gltf2Importer { gltfJson.textures[iridescenceThicknessTexture.index]; } } + if (Is.exist(extensions.KHR_materials_anisotropy)) { + const anisotropyTexture = extensions.KHR_materials_anisotropy.anisotropyTexture; + if (anisotropyTexture !== void 0) { + anisotropyTexture.texture = gltfJson.textures[anisotropyTexture.index]; + } + } } } } diff --git a/src/foundation/importer/ModelConverter.ts b/src/foundation/importer/ModelConverter.ts index 2c72c96d5..019f12a02 100644 --- a/src/foundation/importer/ModelConverter.ts +++ b/src/foundation/importer/ModelConverter.ts @@ -1085,6 +1085,7 @@ export class ModelConverter { isSheen: Is.exist(materialJson?.extensions?.KHR_materials_sheen), isSpecular: Is.exist(materialJson?.extensions?.KHR_materials_specular), isIridescence: Is.exist(materialJson?.extensions?.KHR_materials_iridescence), + isAnisotropy: Is.exist(materialJson?.extensions?.KHR_materials_anisotropy), isShadow: rnLoaderOptions.shadow ? true : false, useTangentAttribute, useNormalTexture, @@ -2294,6 +2295,8 @@ function setupPbrMetallicRoughness( setup_KHR_materials_iridescence(materialJson, material, gltfModel); + setup_KHR_materials_anisotropy(materialJson, material, gltfModel); + // BaseColor TexCoord Transform setup_KHR_texture_transform(baseColorTexture, material, metallicRoughnessTexture); } @@ -2634,3 +2637,38 @@ function setup_KHR_materials_iridescence( } } } + +function setup_KHR_materials_anisotropy( + materialJson: RnM2Material, + material: Material, + gltfModel: RnM2 +) { + const KHR_materials_anisotropy = materialJson?.extensions?.KHR_materials_anisotropy; + if (Is.exist(KHR_materials_anisotropy)) { + const anisotropyStrength = Is.exist(KHR_materials_anisotropy.anisotropyStrength) + ? KHR_materials_anisotropy.anisotropyStrength + : 0.0; + material.setParameter(ShaderSemantics.AnisotropyStrength, anisotropyStrength); + const anisotropyRotation = Is.exist(KHR_materials_anisotropy.anisotropyRotation) + ? KHR_materials_anisotropy.anisotropyRotation + : 0.0; + material.setParameter( + ShaderSemantics.AnisotropyRotation, + Vector2.fromCopy2(Math.cos(anisotropyRotation), Math.sin(anisotropyRotation)) + ); + + const anisotropyTexture = KHR_materials_anisotropy.anisotropyTexture; + if (anisotropyTexture != null) { + const rnAnisotropyTexture = ModelConverter._createTexture( + anisotropyTexture.texture!, + gltfModel + ); + const rnSampler = ModelConverter._createSampler(anisotropyTexture.texture!); + material.setTextureParameter( + ShaderSemantics.AnisotropyTexture, + rnAnisotropyTexture, + rnSampler + ); + } + } +} diff --git a/src/foundation/materials/contents/CustomMaterialContent.ts b/src/foundation/materials/contents/CustomMaterialContent.ts index 6357b93e4..caf42ccf9 100644 --- a/src/foundation/materials/contents/CustomMaterialContent.ts +++ b/src/foundation/materials/contents/CustomMaterialContent.ts @@ -26,6 +26,7 @@ export class CustomMaterialContent extends AbstractMaterialContent { isSheen, isSpecular, isIridescence, + isAnisotropy, isShadow, useTangentAttribute, useNormalTexture, @@ -44,6 +45,7 @@ export class CustomMaterialContent extends AbstractMaterialContent { isSheen?: boolean; isSpecular?: boolean; isIridescence?: boolean; + isAnisotropy?: boolean; isShadow?: boolean; useTangentAttribute: boolean; useNormalTexture: boolean; @@ -64,6 +66,7 @@ export class CustomMaterialContent extends AbstractMaterialContent { (isSpecular ? '+specular' : '') + (isSheen ? '+sheen' : '') + (isIridescence ? '+iridescence' : '') + + (isAnisotropy ? '+anisotropy' : '') + (useTangentAttribute ? '+tangentAttribute' : ''), { isMorphing, isSkinning, isLighting } ); @@ -135,6 +138,9 @@ export class CustomMaterialContent extends AbstractMaterialContent { if (isIridescence) { this.__definitions += '#define RN_USE_IRIDESCENCE\n'; } + if (isAnisotropy) { + this.__definitions += '#define RN_USE_ANISOTROPY\n'; + } if (isShadow) { this.__definitions += '#define RN_USE_SHADOW_MAPPING\n'; } diff --git a/src/foundation/materials/core/DummyTextures.ts b/src/foundation/materials/core/DummyTextures.ts index fecb50b1c..c0ba8fe20 100644 --- a/src/foundation/materials/core/DummyTextures.ts +++ b/src/foundation/materials/core/DummyTextures.ts @@ -7,6 +7,7 @@ export const dummyBlackTexture = new Texture(); export const dummyBlackCubeTexture = new CubeTexture(); export const sheenLutTexture = new Texture(); export const dummySRGBGrayTexture = new Texture(); +export const dummyAnisotropyTexture = new Texture(); export async function initDefaultTextures() { if (dummyWhiteTexture.isTextureReady) { @@ -18,6 +19,7 @@ export async function initDefaultTextures() { dummyBlackCubeTexture.tryToSetUniqueName('dummyBlackCubeTexture', true); sheenLutTexture.tryToSetUniqueName('sheenLutTexture', true); dummySRGBGrayTexture.tryToSetUniqueName('dummySRGBGrayTexture', true); + dummyAnisotropyTexture.tryToSetUniqueName('dummyAnisotropyTexture', true); dummyWhiteTexture.generate1x1TextureFrom(); dummyBlueTexture.generate1x1TextureFrom('rgba(127.5, 127.5, 255, 1)'); @@ -25,6 +27,7 @@ export async function initDefaultTextures() { dummyBlackCubeTexture.load1x1Texture('rgba(0, 0, 0, 1)'); await sheenLutTexture.generateSheenLutTextureFromDataUri(); dummySRGBGrayTexture.generate1x1TextureFrom('rgba(186, 186, 186, 1)'); + dummyAnisotropyTexture.generate1x1TextureFrom('rgba(255, 127.5, 255, 1)'); } export const DefaultTextures = { @@ -34,4 +37,5 @@ export const DefaultTextures = { dummyBlackCubeTexture, sheenLutTexture, dummySRGBGrayTexture, + dummyAnisotropyTexture, }; diff --git a/src/webgl/shaderity_shaders/MToonSingleShader/MToonSingleShader.frag b/src/webgl/shaderity_shaders/MToonSingleShader/MToonSingleShader.frag index b89f6ec46..1865315f1 100644 --- a/src/webgl/shaderity_shaders/MToonSingleShader/MToonSingleShader.frag +++ b/src/webgl/shaderity_shaders/MToonSingleShader/MToonSingleShader.frag @@ -100,7 +100,8 @@ void main (){ vec3 normal_inWorld = normalize(v_normal_inWorld); #ifdef RN_MTOON_HAS_BUMPMAP vec3 normal = texture(u_normalTexture, v_texcoord_0).xyz * 2.0 - 1.0; - normal_inWorld = perturb_normal(normal_inWorld, viewVector, v_texcoord_0, normal); + mat3 TBN = getTBN(normal_inWorld, viewVector, v_texcoord_0); + normal_inWorld = normalize(TBN * normal); #endif #ifdef RN_MTOON_IS_OUTLINE diff --git a/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag b/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag index 31e3def98..c87bc0266 100644 --- a/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag +++ b/src/webgl/shaderity_shaders/PbrSingleShader/PbrSingleShader.frag @@ -103,6 +103,11 @@ uniform float u_ior; // initialValue=1.5 uniform float u_iridescenceThicknessMaximum; // initialValue=400 #endif +#ifdef RN_USE_ANISOTROPY + uniform float u_anisotropyStrength; // initialValue=0 + uniform vec2 u_anisotropyRotation; // initialValue=(1,0) +#endif + uniform float u_alphaCutoff; // initialValue=(0.01) #pragma shaderity: require(../common/rt0.glsl) @@ -379,8 +384,19 @@ vec3 getNormalForEnv(mat3 rotEnvMatrix, vec3 normal_inWorld, float materialSID) return normal_forEnv; } -vec3 getReflection(mat3 rotEnvMatrix, vec3 viewDirection, vec3 normal_inWorld, float materialSID) { +vec3 getReflection(mat3 rotEnvMatrix, vec3 viewDirection, vec3 normal_inWorld, float materialSID, float perceptualRoughness, float anisotropy, vec3 anisotropyDirection) { +#ifdef RN_USE_ANISOTROPY + + float tangentRoughness = mix(perceptualRoughness, 1.0, anisotropy * anisotropy); + vec3 anisotropicTangent = cross(anisotropyDirection, viewDirection); + vec3 anisotropicNormal = cross(anisotropicTangent, anisotropyDirection); + float bendFactor = 1.0 - anisotropy * (1.0 - perceptualRoughness); + float bendFactorPow4 = bendFactor * bendFactor * bendFactor * bendFactor; + vec3 bentNormal = normalize(mix(anisotropicNormal, normal_inWorld, bendFactorPow4)); + vec3 reflection = rotEnvMatrix * reflect(-viewDirection, bentNormal); +#else vec3 reflection = rotEnvMatrix * reflect(-viewDirection, normal_inWorld); +#endif if (get_inverseEnvironment(materialSID, 0)) { reflection.x *= -1.0; } @@ -391,7 +407,7 @@ vec3 IBLContribution(float materialSID, vec3 normal_inWorld, float NdotV, vec3 v vec3 albedo, vec3 F0, float perceptualRoughness, float clearcoatRoughness, vec3 clearcoatNormal_inWorld, float clearcoat, float VdotNc, vec3 geomNormal_inWorld, float cameraSID, float transmission, vec3 v_position_inWorld, float thickness, vec3 sheenColor, float sheenRoughness, float albedoSheenScalingNdotV, float ior, - vec3 iridescenceFresnel, vec3 iridescenceF0, float iridescence) + vec3 iridescenceFresnel, vec3 iridescenceF0, float iridescence, float anisotropy, vec3 anisotropyDirection) { vec4 iblParameter = get_iblParameter(materialSID, 0); float rot = iblParameter.w + 3.1415; @@ -399,7 +415,7 @@ vec3 IBLContribution(float materialSID, vec3 normal_inWorld, float NdotV, vec3 v ivec2 hdriFormat = get_hdriFormat(materialSID, 0); vec3 normal_forEnv = getNormalForEnv(rotEnvMatrix, normal_inWorld, materialSID); - vec3 reflection = getReflection(rotEnvMatrix, viewDirection, normal_inWorld, materialSID); + vec3 reflection = getReflection(rotEnvMatrix, viewDirection, normal_inWorld, materialSID, perceptualRoughness, anisotropy, anisotropyDirection); // IBL #ifdef RN_USE_IRIDESCENCE @@ -446,9 +462,8 @@ vec3 IBLContribution(float materialSID, vec3 normal_inWorld, float NdotV, vec3 v #ifdef RN_USE_CLEARCOAT float VdotNg = dot(geomNormal_inWorld, viewDirection); vec3 clearcoatNormal_forEnv = getNormalForEnv(rotEnvMatrix, normal_inWorld, materialSID); - vec3 clearcoatReflection = getReflection(rotEnvMatrix, viewDirection, normal_inWorld, materialSID); IblResult coatResult = getIBLRadianceGGX(materialSID, VdotNc, viewDirection, vec3(0.0), F0, - clearcoatRoughness, iblParameter, hdriFormat, rotEnvMatrix, clearcoatNormal_forEnv, clearcoatReflection); + clearcoatRoughness, iblParameter, hdriFormat, rotEnvMatrix, clearcoatNormal_forEnv, reflection); vec3 coatLayer = coatResult.specular; float clearcoatFresnel = 0.04 + (1.0 - 0.04) * pow(1.0 - abs(VdotNc), 5.0); @@ -500,6 +515,7 @@ void main () int normalTexcoordIndex = get_normalTexcoordIndex(materialSID, 0); vec2 normalTexcoord = getTexcoord(normalTexcoordIndex); vec2 normalTexUv = uvTransform(normalTextureTransform.xy, normalTextureTransform.zw, normalTextureRotation, normalTexcoord); + mat3 TBN = getTBN(normal_inWorld, viewVector, normalTexUv); #ifdef RN_USE_NORMAL_TEXTURE vec3 normalTexValue = texture(u_normalTexture, normalTexUv).xyz; if(normalTexValue.b >= 128.0 / 255.0) { @@ -507,7 +523,7 @@ void main () vec3 normalTex = normalTexValue * 2.0 - 1.0; float normalScale = get_normalScale(materialSID, 0); vec3 scaledNormal = normalize(normalTex * vec3(normalScale, normalScale, 1.0)); - normal_inWorld = perturb_normal(normal_inWorld, viewVector, normalTexUv, scaledNormal); + normal_inWorld = normalize(TBN * scaledNormal); } #endif @@ -543,6 +559,23 @@ void main () vec3 viewDirection = normalize(viewVector); float NdotV = saturateEpsilonToOne(dot(normal_inWorld, viewDirection)); +#ifdef RN_USE_ANISOTROPY + float anisotropy = get_anisotropyStrength(materialSID, 0); + vec2 anisotropyRotation = get_anisotropyRotation(materialSID, 0); + vec2 direction = anisotropyRotation; + vec3 anisotropyTex = texture(u_anisotropyTexture, baseColorTexUv).rgb; + direction = anisotropyTex.rg * 2.0 - vec2(1.0); + direction = mat2(anisotropyRotation.x, anisotropyRotation.y, -anisotropyRotation.y, anisotropyRotation.x) * normalize(direction); + anisotropy *= anisotropyTex.b; + vec3 anisotropicT = normalize(TBN * vec3(direction, 0.0)); + vec3 anisotropicB = normalize(cross(geomNormal_inWorld, anisotropicT)); + float BdotV = dot(anisotropicB, viewDirection); + float TdotV = dot(anisotropicT, viewDirection); +#else + float anisotropy = 0.0; + vec3 anisotropicB = vec3(0.0, 0.0, 0.0); +#endif + // Clearcoat #ifdef RN_USE_CLEARCOAT float clearcoatFactor = get_clearCoatFactor(materialSID, 0); @@ -656,7 +689,7 @@ void main () float clearcoatNormalTextureRotation = get_clearCoatNormalTextureRotation(materialSID, 0); vec2 clearcoatNormalTexUv = uvTransform(clearcoatNormalTextureTransform.xy, clearcoatNormalTextureTransform.zw, clearcoatNormalTextureRotation, clearCoatNormalTexcoord); vec3 textureNormal_tangent = texture(u_clearCoatNormalTexture, clearcoatNormalTexUv).xyz * vec3(2.0) - vec3(1.0); - vec3 clearcoatNormal_inWorld = perturb_normal(geomNormal_inWorld, viewVector, normalTexUv, textureNormal_tangent); + vec3 clearcoatNormal_inWorld = normalize(TBN * textureNormal_tangent); float VdotNc = saturateEpsilonToOne(dot(viewDirection, clearcoatNormal_inWorld)); #else float clearcoatRoughness = 0.0; @@ -739,8 +772,15 @@ void main () // Specular float NdotH = saturateEpsilonToOne(dot(normal_inWorld, halfVector)); +#ifdef RN_USE_ANISOTROPY + float TdotL = dot(anisotropicT, light.direction); + float BdotL = dot(anisotropicB, light.direction); + float TdotH = dot(anisotropicT, halfVector); + float BdotH = dot(anisotropicB, halfVector); + vec3 specularContrib = BRDF_specularAnisotropicGGX(F, alphaRoughness, VdotH, NdotL, NdotV, NdotH, BdotV, TdotV, TdotL, BdotL, TdotH, BdotH, anisotropy) * vec3(NdotL) * light.attenuatedIntensity; +#else vec3 specularContrib = cook_torrance_specular_brdf(NdotH, NdotL, NdotV, F, alphaRoughness) * vec3(NdotL) * light.attenuatedIntensity; - +#endif // RN_USE_ANISOTROPY // Base Layer vec3 baseLayer = diffuseContrib + specularContrib; @@ -782,7 +822,7 @@ void main () vec3 ibl = IBLContribution(materialSID, normal_inWorld, NdotV, viewDirection, albedo, F0, perceptualRoughness, clearcoatRoughness, clearcoatNormal_inWorld, clearcoat, VdotNc, geomNormal_inWorld, cameraSID, transmission, v_position_inWorld.xyz, thickness, - sheenColor, sheenRoughness, albedoSheenScalingNdotV, ior, iridescenceFresnel, iridescenceF0, iridescence); + sheenColor, sheenRoughness, albedoSheenScalingNdotV, ior, iridescenceFresnel, iridescenceF0, iridescence, anisotropy, anisotropicB); int occlusionTexcoordIndex = get_occlusionTexcoordIndex(materialSID, 0); vec2 occlusionTexcoord = getTexcoord(occlusionTexcoordIndex); diff --git a/src/webgl/shaderity_shaders/common/pbrDefinition.glsl b/src/webgl/shaderity_shaders/common/pbrDefinition.glsl index 93dc81171..26a4522d4 100644 --- a/src/webgl/shaderity_shaders/common/pbrDefinition.glsl +++ b/src/webgl/shaderity_shaders/common/pbrDefinition.glsl @@ -288,3 +288,34 @@ float IsotropicNDFFiltering(vec3 normal, float roughness2) { float filteredRoughness2 = saturate(roughness2 + clampedKernelRoughness2); return filteredRoughness2; } + +// https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_anisotropy +float D_GGX_anisotropic(float NdotH, float TdotH, float BdotH, float at, float ab) +{ + float a2 = at * ab; + vec3 f = vec3(ab * TdotH, at * BdotH, a2 * NdotH); + float w2 = a2 / dot(f, f); + return a2 * w2 * w2 / M_PI; +} + +float V_GGX_anisotropic(float NdotL, float NdotV, float BdotV, float TdotV, float TdotL, float BdotL, + float at, float ab) +{ + float GGXV = NdotL * length(vec3(at * TdotV, ab * BdotV, NdotV)); + float GGXL = NdotV * length(vec3(at * TdotL, ab * BdotL, NdotL)); + float v = 0.5 / (GGXV + GGXL); + return clamp(v, 0.0, 1.0); +} + +vec3 BRDF_specularAnisotropicGGX(vec3 F, float alphaRoughness, + float VdotH, float NdotL, float NdotV, float NdotH, float BdotV, float TdotV, + float TdotL, float BdotL, float TdotH, float BdotH, float anisotropy) +{ + float at = mix(alphaRoughness, 1.0, anisotropy * anisotropy); + float ab = alphaRoughness; + + float V = V_GGX_anisotropic(NdotL, NdotV, BdotV, TdotV, TdotL, BdotL, at, ab); + float D = D_GGX_anisotropic(NdotH, TdotH, BdotH, at, ab); + + return F * V * D; +} diff --git a/src/webgl/shaderity_shaders/common/perturbedNormal.glsl b/src/webgl/shaderity_shaders/common/perturbedNormal.glsl index 856ac9ecb..87b10e9dc 100644 --- a/src/webgl/shaderity_shaders/common/perturbedNormal.glsl +++ b/src/webgl/shaderity_shaders/common/perturbedNormal.glsl @@ -1,13 +1,12 @@ #ifdef RN_USE_TANGENT_ATTRIBUTE - vec3 perturb_normal(vec3 normal_inWorld, vec3 viewVector, vec2 texcoord, vec3 normalTex) { + mat3 getTBN(vec3 normal_inWorld, vec3 viewVector, vec2 texcoord) { vec3 tangent_inWorld = normalize(v_tangent_inWorld); vec3 binormal_inWorld = normalize(v_binormal_inWorld); mat3 tbnMat_tangent_to_world = mat3(tangent_inWorld, binormal_inWorld, normal_inWorld); - return normalize(tbnMat_tangent_to_world * normalTex); + return tbnMat_tangent_to_world; } #else - #ifdef RN_IS_SUPPORTING_STANDARD_DERIVATIVES // This is based on http://www.thetenthplanet.de/archives/1180 mat3 cotangent_frame(vec3 normal_inWorld, vec3 position, vec2 uv) { uv = gl_FrontFacing ? uv : -uv; @@ -30,17 +29,9 @@ return mat3(tangent * invMat, bitangent * invMat, normal_inWorld); } - vec3 perturb_normal(vec3 normal_inWorld, vec3 viewVector, vec2 texcoord, vec3 normalTex) { + mat3 getTBN(vec3 normal_inWorld, vec3 viewVector, vec2 texcoord) { mat3 tbnMat_tangent_to_world = cotangent_frame(normal_inWorld, -viewVector, texcoord); - if (texcoord.x > 0.0 || texcoord.y > 0.0) { - return normalize(tbnMat_tangent_to_world * normalTex); - } else { - return normal_inWorld; - } - } - #else - vec3 perturb_normal(vec3 normal_inWorld, vec3 viewVector, vec2 texcoord, vec3 normalTex) { - return normal_inWorld; + + return tbnMat_tangent_to_world; } - #endif #endif