Learn OpenGL. Lesson 5.5 - Normal Mapping
文章推薦指數: 80 %
It is interesting to note the blue tint of this normal map (almost all normal maps have a similar shade). This happens because all the normals are oriented ...
LearnOpenGL.Lesson5.5-NormalMappingOriginalauthor:JoeydeVriesTransferTutorialNormalmapping
Allthescenesweuseconsistofpolygons,inturn,consistingofhundreds,thousandsofabsolutelyflattriangles.Wehavealreadymanagedtoslightlyenhancetherealismofthescenesduetoadditionaldetails,whichareprovidedbyapplyingtwo-dimensionaltexturestotheseflattriangles.Texturinghelpstohidethefactthatallobjectsinthescenearejustacollectionofmanysmalltriangles.Greattechnique,butitspossibilitiesarenotunlimited:whenapproachinganysurface,allonebecomesclearthatitconsistsofflatsurfaces.Mostoftherealobjectsarenotcompletelyflatandshowalotofembosseddetails.ContentPart1.StartOpenglCreatingawindowHellowindowHellotriangleShadersTexturesTransformationsCoordinatesystemsCamera
Part2.BasiclightingColorsLightingBasicsMaterialsTextureCardsSourcesoflightMultiplelightsources
Part3.Loading3DModelsAssimplibraryMeshmeshclass3Dmodelclass
Part4.OpenGLadvancedfeaturesDepthtestStenciltestMixingcolorsFaceclippingFramebufferCubiccardsAdvanceddatahandlingAdvancedGLSLGeometricshaderInstancingСглаживание
Часть5.ПродвинутоеосвещениеПродвинутоеосвещение.МодельБлинна-Фонга.Гамма-коррекцияКартытенейВсенаправленныекартытенейNormalMapping
Forexample,takeabrickwork.Itssurfaceisveryroughand,obviously,isrepresentedfarfromplane:ithascavitieswithcementandmanysmalldetailslikeholesandcracks.Ifthescenewithimitationofbrickworkisanalyzedinthepresenceoflight,thentheillusionofthereliefofthesurfaceisveryeasilydestroyed.Belowisanexampleofsuchascene,containingaplanewithappliedbrickworktextureandonepointlightsource:
Ascanbeseen,thelightingdoesnotatalltakeintoaccountthedetailsofthereliefintendedforthissurface:allsmallcracksareabsent,andthehollowswithcementareindistinguishablefromtherestofthesurface.Itwouldbepossibletouseaspecularglossmapinordertolimittheilluminationofcertainpartsthatarelocatedinthesurfacerecesses.Butthisismorelikeadirtyhackthanaworkingsolution.Whatweneedisawaytoprovidetheequationsofilluminationwithsurfacemicroreliefdata.
Inthecontextofthelightingequationsknowntous,considerthisquestion:underwhatconditionswillthesurfacebelitasideallyflat?Theanswerisrelatedtothesurfacenormal.Fromthepointofviewofthelightingalgorithm,informationontheshapeofthesurfaceistransmittedonlythroughthenormalvector.Sincethenormalvectorisconstanteverywhereontheabovesurface,theilluminationisuniform,correspondingtotheplane.Andwhatifthelightalgorithmisnottransmittedtoasinglenormal,constantforallfragmentsbelongingtoanobject,butauniquenormalforeachfragment?Thus,thenormalvectorwillvaryslightlybasedonthesurfacetopography,whichwillcreateamoreconvincingillusionofsurfacecomplexity:
Duetotheuseoffragmentsofdifferentnormals,theilluminationalgorithmwillconsiderthesurfaceasconsistingofasetofmicroscopicplanesperpendiculartoitsnormalvector.Intheend,thiswillsignificantlyaddtheobjectoftexture.Thetechniqueofapplyingnormalsuniquetoafragment,andnottheentiresurface-thisisNormalMappingorBumpMapping.Appliedtoanalreadyfamiliarscene:
Animpressiveincreaseinvisualcomplexityisseenduetotheverymodestcostofproductivity.Sinceweareallchangesinthelightingmodelareonlyinthepresentationofauniquenormalineachfragment,thennoformulasforthecalculationsdonotchange.Onlytheinputinsteadoftheinterpolatedsurfacenormalentersthenormalforthecurrentfragment.Allthesamelightingequationsdotherestoftheworktocreateanillusionofrelief.Normalmapping
So,itturnsout,weneedtoprovidetheilluminationalgorithmwithnormals,uniqueforeachfragment.Weusethemethodalreadyfamiliarfromthetexturesofdiffuseandspecularreflectionandusetheusual2Dtexturetostoredataaboutthenormalateachpointofthesurface.Don'tbesurprised,texturesaregreatforstoringnormalvectors.Next,wewillonlyhavetosamplethetexture,restorethenormalvectorandcalculatetheillumination.
Atfirstglance,itmaynotbeveryclearhowtostorevectordatainaregulartexture,whichistypicallyusedtostorecolorinformation.Butthinkforasecond:theRGBcolortriadisessentiallyathree-dimensionalvector.Similarly,youcansavethecomponentsoftheXYZnormalvectorinthecorrespondingcolorcomponents.Themagnitudesofthecomponentsofthenormalvectorlieintheinterval[-1,1]andthereforerequireadditionalconversiontotheinterval[0,1]:vec3rgb_normal=normal*0.5+0.5;//переходот[-1,1]к[0,1]
SuchareductionofthenormalvectortothespaceoftheRGBcolorcomponentswillallowustopreservethetextureofthenormalvectorobtainedonthebasisoftherealreliefofthemodeledobjectanduniqueforeachfragment.Anexampleofsuchatexture-normalmaps-forthesamebrickwork:
Itisinterestingtonotethebluetintofthisnormalmap(almostallnormalmapshaveasimilarshade).ThishappensbecauseallthenormalsareorientedapproximatelyalongtheoZaxis,whichisrepresentedbythecoordinatetriple(0,0,1),i.e.intheformofacolortriad-pureblue.SmallchangesinshadeareduetothedeviationofthenormalsfromthepositiveoZsemi-axisinsomeareas,whichcorrespondstotheuneventerrain.So,youcanseethatontheupperedgesofeachbrick,thetextureacquiresagreentint.Andthisislogical:ontheupperedgesofthebrick,thenormalsshouldbeorientedmoretowardstheoYaxis(0,1,0),whichcorrespondstothegreencolor.
Forthetestscene,wetakeaplaneorientedtowardsthepositivesemi-axisoZandusethefollowingforit.diffusemapandnormalmap.Pleasenotethatthenormalmaponthelinkandinthepictureabovearedifferent.Inthearticle,theauthorrathercasuallymentionedthereasonsforthedifferences,limitinghimselfwiththeadvicetotransformnormalmapstosuchaformthatthegreencomponentpoints“down”ratherthan“up”inthesystemlocaltothetextureplane.
Ifyoulookinmoredetail,thentwofactorsinteract:ThedifferenceinhowtexelsareaddressedinclientmemoryandinOpenGLtexturememoryThepresenceoftwonotationsfornormalmaps.Conventionally,twocamps:DirectX-styleandOpenGL-style
Asforthenormalmapnotation,thetwocampsthatarehistoricallyfamiliarare:DirectXandOpenGL.
Asyoucansee,theyarenotcompatible.AndhavingalittlethoughtonecanunderstandthatDirectXconsidersthetangentspacetobeleft-handedandOpenGLtoright-handed.Havingslippedthex-cardofnormalstoourapplicationwithoutchanges,wegetincorrectillumination,anditisnotalwaysimmediatelyobviousthatitisincorrect.ThemostnoticeableisthatthebumpsintheOpenGLformatbecomerecessesforDirectXandviceversa.
Asforaddressing:loadingdatafromatexturefileintomemory,weassumethatthefirsttexelistheleftuppertexeloftheimage.Forthepresentationofthetexturedataintheapplication'smemory,thisisgenerallythecase.ButOpenGLusesadifferenttexturecoordinatesystem:forit,thefirsttexelisthebottomleft.Forcorrecttexturing,imagesareusuallyturnedoveralongtheYaxiseveninthecodeofoneoranotherimagefileloader.FortheStb_imageusedinthelessonsyouneedtoaddacheckboxstbi_set_flip_vertically_on_load(1);
Whatisthemostfunny,twooptionsaredisplayedcorrectlyintermsoflighting:thenormalmapinOpenGLnotationwithYreflectionturnedonorthenormalmapinDirectXnotationwithYreflectionturnedoff.Thelightinginbothcasesworkscorrectly,thedifferencewillremainonlyinthetextureinversionY.Noteper.
So,let'sloadbothtextures,attachthemtotextureunitsandrenderthepreparedplane,takingintoaccountthefollowingmodificationsofthefragmentshadercode:uniformsampler2DnormalMap;
voidmain(){
//выборкавектораизкартынормалейсобластьюзначений[0,1]
normal=texture(normalMap,fs_in.TexCoords).rgb;
//переводвекторанормаливинтервал[-1,1]
normal=normalize(normal*2.0-1.0);
[...]
//вычислениеосвещения...
}
HereweapplytheinversetransformfromtheRGBvaluespacetothefullnormalvectorandthensimplyuseitinthefamiliarBlinna-Phonglightingmodel.
Now,ifyouslowlychangethepositionofthelightsourceinthescene,youcanfeeltheillusionofthesurfacereliefprovidedbythenormalmap:
Butthereremainsoneproblemthatradicallynarrowstherangeofpossibleuseofnormalmaps.Asalreadynoted,thebluetintofthenormalmaphintedthatallthevectorsinthetextureareorientedonaveragealongthepositiveoZaxis.Inourscene,thisdidnotcreateproblems,becausethenormaltothesurfaceoftheplanewasalsoalignedwithoZ.However,whathappensifwechangethepositionoftheplaneinthescenesothatthenormaltoitwillbealignedwiththepositivesemi-axisoY?
Thelightingturnedouttobecompletelywrong!Andthereasonissimple:thenormalsamplesfromthemapallalsoreturnvectorsorientedalongthepositivesemi-axisoZ,althoughinthiscasetheyshouldbeorientedinthedirectionofthepositivesemi-axisoYofthesurfacenormal.Atthesametime,thecalculationofilluminationproceedsasifthesurfacenormalsarelocatedasiftheplaneisstillorientedtowardsthepositiveoZsemi-axis,whichgivesanincorrectresult.Thefigurebelowmoreclearlyshowstheorientationofthesurfacenormalsreadfromthenormalmap:
ItcanbeseenthatthenormalsaregenerallyalignedalongtheoZpositivesemiaxis,althoughtheyshouldbealignedalongthenormaltothesurface,whichisdirectedalongtheoYpositivesemiaxis.
Apossiblesolutionwouldbetospecifyaseparatenormalmapforeachorientationofthesurfaceunderconsideration.Foracube,itwouldtakesixnormalmaps,andformorecomplexmodelsthenumberofpossibleorientationsmaybetoohighandnotsuitableforimplementation.
Thereisanother,mathematicallymorecomplexapproach,whichproposestocarryoutcalculationsofilluminationinanothercoordinatesystem:suchthatthenormalvectorsinitalwaysapproximatelycoincidewiththepositivesemi-axisoZ.Othervectorsrequiredforlightingcalculationsarethenconvertedtothiscoordinatesystem.Thismethodmakesitpossibletouseonenormalmapforanyorientationoftheobject.Andthisspecificcoordinatesystemiscalledtangentspaceortangentspace.Tangentspace
Itshouldbenotedthatthenormalvectorinthenormalmapisexpresseddirectlyinthetangentspace,i.e.insuchacoordinatesystemthatthenormalisalwaysdirectedapproximatelyinthedirectionofthepositivesemi-axisoZ.Thetangentspaceisdefinedasacoordinatesystemlocaltotheplaneofthetriangleandeachnormalvectorisdefinedwithinthiscoordinatesystem.Itispossibletoimaginethissystemasalocalcoordinatesystemforthenormalmap:allvectorsinitaresetdirectedtowardsthepositivesemi-axisoZ,regardlessofthefinalorientationofthesurface.Usingspeciallypreparedtransformationmatrices,onecantransformthenormalvectorsfromthislocaltangentcoordinatesystemintoworldorspeciescoordinates,orientingtheminaccordancewiththefinalpositionofthesurfacessubjectedtotexturing.
Considerthepreviousexamplewiththeincorrectapplicationofnormalmapping,wheretheplanewasorientedalongthepositivesemi-axisoY.Sincethenormalmapisgiveninthetangentspace,oneofthecorrectionoptionsisthecalculationofthematrixofthetransitionofthenormalsfromthetangentspacetosuchthattheywouldbecomeorientedalongthenormaltothesurface.ThiswouldcausethenormalstobecomealignedalongthepositivesemiaxisoY.Aremarkablepropertyofthetangentspaceisthefactthatbycalculatingsuchamatrixwecanreorientthenormalstoanysurfaceanditsorientation.
SuchamatrixisabbreviatedasTBN,whichisanabbreviationforthenameofthetripletvectorsTangent,Bitangent,andNormal.Weneedtofindthesethreevectorsinordertoformthisbasischangematrix.Suchamatrixmakesthetransitionofthevectorfromthetangentspacetosomeotherone,andforitsformation,threemutuallyperpendicularvectorsareneeded,theorientationofwhichcorrespondstotheorientationoftheplaneofthenormalmap.Thisisadirectionvectorup,rightandforward,asetfamiliartousfromthelessonaboutthevirtualcamera.
Withthetopallclearatonce-thisisournormalvector.Thevectortotherightandforwardarecalledtangent(tangent)andbitwise(bitangent),respectively.Thefollowingfiguregivesanideaoftheirrelativepositionontheplane:
Thecalculationofthetangentandthebitmapisnotasobviousasthecalculationofthenormalvector.Inthefigure,youcanseethatthedirectionofthetangentandbi-tangentnormalmapisalignedwiththeaxesdefiningthesurfacetexturecoordinates.Thisfactisthebasisforthecalculationofthesetwovectorswhichwillrequiresomeskillwithmathematics.Lookatthepicture:
ChangestotexturecoordinatesalongatrianglefaceE2designatedasΔU2andΔV2expressedinthesamedirectionsasthetangentvectorsTandbikasatelnoyBedand.Basedonthisfact,onecanexpressthefacesofatriangleE1andE2intheformofalinearcombinationoftangentandbi-tangentvectors:E1=ΔU1T+ΔV1BE2=ΔU2T+ΔV2B
Convertingintoelement-wiserecordingweget:(E1x,E1y,E1z)=ΔU1(Tx,Ty,Tz)+ΔV1(Bx,By,Bz)(E2x,E2y,E2z)=ΔU2(Tx,Ty,Tz)+ΔV2(Bx,By,Bz)Eiscalculatedasthevectorofthedifferenceoftwovectors,andΔUandΔVasthedifferenceoftexturecoordinates.Itremainstofindtwounknownsintwoequations:thetangentTandbicantBedand.Ifyoustillrememberthelessonsofalgebra,thenyouknowthatsuchconditionsmakeitpossibletosolvethesystemforTandforBedand.
Thelatterformofequationsallowsustorewriteitintheformofmatrixmultiplication:[E1xE1yE1zE2xE2yE2z]=[ΔU1ΔV1ΔU2ΔV2][TxTyTzBxByBz]
Trytomentallyperformamatrixmultiplicationtomakesuretherecordiscorrect.WritingthesysteminmatrixformmakesitmucheasiertounderstandtheapproachtofindingTand.Multiplybothsidesoftheequationbytheinverse:
Wegetadecisionregardingandwhich,however,requiresthecalculationoftheinversematrixofchangesintexturecoordinates.Wewillnotgointothedetailsofcalculatinginversematrices-theexpressionfortheinversematrixlooksliketheproductofthenumberinversetothedeterminantoftheoriginalmatrix,andtheadjointmatrix:
Thisexpressionistheformulaforcalculatingthetangentvectorandbikasatelnoybasedonthecoordinatesofthefacesofthetriangleandthecorrespondingtexturecoordinates.
Donotworryiftheessenceoftheabovemathematicalcalculationseludesyou.Ifyouunderstandthatwegetthetangentandthebinaryonthebasisofthecoordinatesofthetriangle'sverticesandtheirtexturecoordinates(sincethetexturecoordinatesalsobelongtothetangentspace)-thisishalfthebattle.Calculationoftangentsandbitangts
Intheexampleofthislesson,wetookasimpleplane,lookinginthedirectionofthepositivesemi-axisoZ.Nowwewilltrytoimplementnormalmappingusingtangentspaceinordertobeabletoorienttheplaneintheexampleaswelike,withoutdestroyingtheeffectofnormalmapping.Usingtheabovecalculation,wewillmanuallyfindthetangentandbicassivetothesurfaceunderconsideration.
Letusassumethattheplaneiscomposedofthefollowingverticeswithtexturecoordinates(twotrianglesaregivenbyvectors1,2,3and1,3,4)://координатывершин
glm::vec3pos1(-1.0,1.0,0.0);
glm::vec3pos2(-1.0,-1.0,0.0);
glm::vec3pos3(1.0,-1.0,0.0);
glm::vec3pos4(1.0,1.0,0.0);
//текстурныекоординаты
glm::vec2uv1(0.0,1.0);
glm::vec2uv2(0.0,0.0);
glm::vec2uv3(1.0,0.0);
glm::vec2uv4(1.0,1.0);
//векторнормали
glm::vec3nm(0.0,0.0,1.0);
First,wecalculatethevectorsdescribingthefacesofthetriangle,aswellasthedeltasofthetexturecoordinates:glm::vec3edge1=pos2-pos1;
glm::vec3edge2=pos3-pos1;
glm::vec2deltaUV1=uv2-uv1;
glm::vec2deltaUV2=uv3-uv1;
Havingonhandthenecessaryinitialdatawecanproceedtothecalculationofthetangentandthebicantdirectlybytheformulasfromtheprevioussection:floatf=1.0f/(deltaUV1.x*deltaUV2.y-deltaUV2.x*deltaUV1.y);
tangent1.x=f*(deltaUV2.y*edge1.x-deltaUV1.y*edge2.x);
tangent1.y=f*(deltaUV2.y*edge1.y-deltaUV1.y*edge2.y);
tangent1.z=f*(deltaUV2.y*edge1.z-deltaUV1.y*edge2.z);
tangent1=glm::normalize(tangent1);
bitangent1.x=f*(-deltaUV2.x*edge1.x+deltaUV1.x*edge2.x);
bitangent1.y=f*(-deltaUV2.x*edge1.y+deltaUV1.x*edge2.y);
bitangent1.z=f*(-deltaUV2.x*edge1.z+deltaUV1.x*edge2.z);
bitangent1=glm::normalize(bitangent1);
[...]//аналогичныйкоддлярасчетакасательныхвтороготреугольникаплоскости
Firstweputthefractionalcomponentofthefinalexpressionintoaseparatevariablef.Thenforeachcomponentofthevectorsweperformthecorrespondingpartofthematrixmultiplicationandmultiplybyf.Bycomparingthiscodewiththefinalcalculationformula,youcanseethatthisisliterallyitsarrangement.Donotforgettocarryoutnormalizationattheendsothatthevectorsfoundaresingle.
Sincethetriangleisaflatfigure,itisenoughtocalculatethetangentandthecutoutoncepertriangle-theywillbethesameforallvertices.Itshouldbenotedthatmostoftheimplementationsofworkingwithmodels(suchasloadersorlandscapegenerators)usesuchanorganizationoftriangles,wheretheyshareverticeswithothertriangles.Insuchcases,developersusuallyresorttoaveragingtheparametersincommonvertices,suchasthenormalvector,tangentandbiting,togetasmootherresult.Thetrianglesthatmakeupourplanealsoshareseveralvertices,butsincebothofthemlieinthesameplane,averagingisnotrequired.Yetitisusefultorememberthatsuchanapproachisavailableinreal-worldapplicationsandtasks.
Theresultingtangentandbi-vectorvectorsshouldhavethevalues(1,0,0)and(0,1,0),respectively.That,togetherwiththenormalvector(0,0,1)formtheorthogonalmatrixTBN.Ifyouvisualizetheresultingbasisalongwiththeplane,yougetthefollowingimage:
Now,havingthecalculatedvectors,youcanstartthefullimplementationofnormalmapping.Normalmappingintangentspace
FirstyouneedtocreateamatrixTBNinshaders.Forthispurpose,wewilltransferthepreviouslypreparedtangentandbitwisevectorstothevertexshaderthroughthevertexattributes:#version330core
layout(location=0)invec3aPos;
layout(location=1)invec3aNormal;
layout(location=2)invec2aTexCoords;
layout(location=3)invec3aTangent;
layout(location=4)invec3aBitangent;
Inthecodeofthevertexshaderitself,wewillformthematrixdirectly:voidmain(){
[...]
vec3T=normalize(vec3(model*vec4(aTangent,0.0)));
vec3B=normalize(vec3(model*vec4(aBitangent,0.0)));
vec3N=normalize(vec3(model*vec4(aNormal,0.0)));
mat3TBN=mat3(T,B,N)
}
Inthefirstcodetransformallvectorbasisofthetangentspacecoordinatesysteminwhichitisconvenienttowork-inthiscase,theworldcoordinatesystem,andwemultiplyavectorbyamatrixmodelmodel.Next,wecreatetheTBNmatrixitselfbysimplypassingallthreerelevantvectorstothemat3constructor.Payattentionthatforthecompletecorrectnessoftheorderofcalculations,itisnecessarytomultiplythevectorsnotbythemodelmatrix,butbythenormalmatrix,sinceweareonlyinterestedintheorientationofthevectors,butnotintheirdisplacementorscalingStrictlyspeaking,itisnotatallnecessarytotransmitavectortoashader.
SincethetripletofTBNvectorsaremutuallyperpendicular,thequicantcanbetriviallyfoundintheshaderthroughvectormultiplication:vec3B=cross(N,T)
SotheTBNmatrixisobtained,howdoweuseit?Infact,therearetwoapproachestoitsuseinnormalmapping:UsetheTBNmatrixtotransformallthenecessaryvectorsfromthetangentspacetotheworldone.Transfertheresultstothefragmentshader,where,alsousingthematrix,convertthevectorfromthenormalmaptotheworldspace.Asaresult,thenormalvectorwillbeinthespacewhereallthelightingiscalculated.TakethematrixinversetoTBNandtransformallthenecessaryvectorsfromworldspacetotangent.Those.usethismatrixtoconvertvectorsinvolvedinlightingcalculationsintotangentspace.Thenormalvectorinthiscasealsoremainsinthesamespaceastheotherparticipantsinthecalculationoftheillumination.
Let'sconsiderthefirstoption.Thenormalvectorfromthecorrespondingtextureisgiveninthetangentspace,whiletheothervectorsusedinthecalculationoftheilluminationaregiveninworldspace.BytransferringtheTBNmatrixtothefragmentshader,wecouldconvertthenormalvectorobtainedbysamplingfromthetexturefromthetangentspacetotheworldspace,ensuringtheunityofthecoordinatesystemsforallelementsoftheilluminationcalculation.Inthiscase,allcalculations(especiallyscalarmultiplicationsofvectors)willbecorrect.
TransferringtheTBNmatrixisdoneinthesimplestway:outVS_OUT{
vec3FragPos;
vec2TexCoords;
mat3TBN;
}vs_out;
voidmain(){
[...]
vs_out.TBN=mat3(T,B,N);
}
Inthecodeofthefragmentshader,respectively,wesettheinputvariableofthemat3type:inVS_OUT{
vec3FragPos;
vec2TexCoords;
mat3TBN;
}fs_in;
Withthematrixinhand,youcanspecifythecodeforobtainingthenormalbyexpressingthetranslationfromthetangentintotheworldspace:normal=texture(normalMap,fs_in.TexCoords).rgb;
normal=normalize(normal*2.0-1.0);
normal=normalize(fs_in.TBN*normal);
Sincetheresultingnormalisnowsetinworldspace,thereisnoneedtochangeanythingelseintheshadercode.Theilluminationcalculationsassumethenormalvectorgiveninworldcoordinates.
Let'salsolookatthesecondapproach.ItwillrequireobtainingtheinverseTBNmatrix,aswellastransferringallthevectorsinvolvedintheilluminationcalculationfromtheworldcoordinatesystemtotheonethatcorrespondstothenormalvectorsobtainedfromthetexture-thetangent.Inthiscase,theformationoftheTBNmatrixremainsunchanged,butbeforetransferringtothefragmentshader,weneedtogetaninversematrix:vs_out.TBN=transpose(mat3(T,B,N));
Noticethatthetranspose()functionisusedinsteadofinverse().Suchasubstitutionisvalid,sincefororthogonalmatrices(whereallaxesarerepresentedbyunitmutuallyperpendicularvectors),obtainingtheinversematrixgivestheresultidenticaltothetransposition.Andthisisveryopportunely,since,inthegeneralcase,thecalculationoftheinversematrixismuchmorecomputationallyexpensiveincomparisonwithtransposition.
Inthecodeofthefragmentshader,wewillnotconvertthenormalvector,butinsteadconvertfromtheworldcoordinatesystemtothetangentotherimportantvectors,namely,lightDirandviewDir.Thissolutionalsobringsalltheelementsofthecalculationsintoasinglecoordinatesystem,thistimethetangent.voidmain(){
vec3normal=texture(normalMap,fs_in.TexCoords).rgb;
normal=normalize(normal*2.0-1.0);
vec3lightDir=fs_in.TBN*normalize(lightPos-fs_in.FragPos);
vec3viewDir=fs_in.TBN*normalize(viewPos-fs_in.FragPos);
[...]
}
Thesecondapproachseemstobemorelaboriousandrequiresmorematrixmultiplicationsinthefragmentshader(whichgreatlyaffectsperformance).Whydidweeventakeitapart?
Thefactisthattransferringvectorsfromworldcoordinatestotangentsprovidesanadditionaladvantage:infact,wecantakeoutallthetransformationcodefromthefragmenttothevertexshader!ThisapproachisworkingbecauselightPosandviewPosdonotchangefromfragmenttofragment,andthevalueoffs_in.FragPoswecanalsoconverttothetangentspaceinthevertexshader,theinterpolatedvalueattheinputtothefragmentshaderwillbequitecorrect.Thus,forthesecondapproachthereisnoneedtotranslateallthesevectorsintothetangentspaceinthecodeofthefragmentshader,whilethefirstrequiresit-thenormalisuniqueforeachfragment.
Asaresult,wemoveawayfromthetransferoftheinversematrixtotheTBNtothefragmentshaderandinsteadgiveitthepositionvectorofthevertex,thelightsourceandtheobserverinthetangentspace.Sowewillgetridofcostlymatrixmultiplicationsinthefragmentshader,whichwillbeasignificantoptimization,becausethevertexshaderisexecutedmuchlessfrequently.Itisthisadvantagethatmakesthesecondapproachoneofthepreferredinmostcasesofuse.outVS_OUT{
vec3FragPos;
vec2TexCoords;
vec3TangentLightPos;
vec3TangentViewPos;
vec3TangentFragPos;
}vs_out;
uniformvec3lightPos;
uniformvec3viewPos;
[...]
voidmain(){
[...]
mat3TBN=transpose(mat3(T,B,N));
vs_out.TangentLightPos=TBN*lightPos;
vs_out.TangentViewPos=TBN*viewPos;
vs_out.TangentFragPos=TBN*vec3(model*vec4(aPos,0.0));
Inthefragmentshader,weturntotheuseofnewinputvariablesinthecalculationsoflightingintangentspace.Sincethenormalsareconditionallygiveninthisspace,allcalculationsremaincorrect.
Nowthatallnormalmappingcalculationsareperformedinatangentspace,wecanchangetheorientationofthetestsurfaceintheapplicationaswewantandthelightingwillremaincorrect:glm::mat4model(1.0f);
model=glm::rotate(model,(float)glfwGetTime()*-10.0f,glm::normalize(glm::vec3(1.0,0.0,1.0)));
shader.setMat4("model",model);
RenderQuad();
Indeed,outwardly,everythinglooksasitshould:
Thesourcesarehere.Complexobjects
So,wefiguredouthowtoperformanormalmappinginatangentspaceandhowtoindependentlycalculatethetangentandbi-tangentvectorsforthis.Fortunately,suchamanualcalculationisnotsomethingthatoftenarises:forthemostpart,thiscodeisimplementedbydeveloperssomewhereinthedepthsofthemodelloader.Inourcase,thisistruefortheusedAssimploader.
Assimpprovidesaveryusefuloptionsflagwhenloadingmodels:aiProcess_CalcTangentSpace.WhenitistransferredtotheReadFile()function,thelibraryitselfwillbeengagedincalculatingthesmoothedtangentsandbitmapsforeachoftheloadedvertices-aprocesssimilartotheoneconsideredhere.constaiScene*scene=importer.ReadFile(
path,aiProcess_Triangulate|aiProcess_FlipUVs|aiProcess_CalcTangentSpace
);
Afterthat,youcandirectlyaccessthecalculatedtangents:vector.x=mesh->mTangents[i].x;
vector.y=mesh->mTangents[i].y;
vector.z=mesh->mTangents[i].z;
vertex.Tangent=vector;
Youwillalsoneedtoupdatethebootcodesothatittakesintoaccountthereceiptofnormalmapsfortexturedmodels.WavefrontObjectformat(.obj)exportsnormalmapsinsuchawaythattheAssimpaiTextureType_NORMALflagdoesnotensurecorrectloadingofthesemaps,whilewiththeaiTextureType_HEIGHTflageverythingworkscorrectly.Sopersonally,Iusuallyloadnormalmapsinthefollowingway:vector
延伸文章資訊
- 1Tutorial 13 : Normal Mapping
The basic idea of normal mapping is to give normals similar variations. Normal textures. A “norma...
- 2Normal Mapping - LearnOpenGL
The normal map is defined in tangent space, so one way to solve the problem is to calculate a mat...
- 3Implementing Normal Mapping using OpenGL/GLSL - Stack ...
That normal map is in tangent-space, but you are treating it as object-space. You need a bitangen...
- 4Normal Mapping - OpenGL ES SDK for Android - GitHub Pages
A normal map is a regular texture but instead of defining what colour a pixel will be on screen, ...
- 5OpenGL 2.1 - GLSL normal mapping - 3D C/C++ tutorials
The normal map used in this tutorial is a Direct3D normal map and before it can be mapped on tria...