Mesh - LearnOpenGL

文章推薦指數: 80 %
投票人數:10人

What we eventually want is to transform that data to a format that OpenGL understands so that we can render the objects. We learned from the previous chapter ... Ifyou'rerunningAdBlock,pleaseconsiderwhitelistingthissiteifyou'dliketosupportLearnOpenGL;andnoworries,Iwon'tbemadifyoudon't:) IntroductionGettingstartedOpenGLCreatingawindowHelloWindowHelloTriangleShadersTexturesTransformationsCoordinateSystemsCameraReviewLightingColorsBasicLightingMaterialsLightingmapsLightcastersMultiplelightsReviewModelLoadingAssimpMeshModelAdvancedOpenGLDepthtestingStenciltestingBlendingFacecullingFramebuffersCubemapsAdvancedDataAdvancedGLSLGeometryShaderInstancingAntiAliasingAdvancedLightingAdvancedLightingGammaCorrectionShadowsShadowMappingPointShadowsNormalMappingParallaxMappingHDRBloomDeferredShadingSSAOPBRTheoryLightingIBLDiffuseirradianceSpecularIBLInPracticeDebuggingTextRendering2DGameBreakoutSettingupRenderingSpritesLevelsCollisionsBallCollisiondetectionCollisionresolutionParticlesPostprocessingPowerupsAudioRendertextFinalthoughtsGuestArticlesHowtopublish2020OITIntroductionWeightedBlendedSkeletalAnimation2021CSMSceneSceneGraphFrustumCullingTessellationHeightmapTessellationDSACoderepositoryTranslationsAbout BTC 1CLGKgmBSuYJ1nnvDGAepVTKNNDpUjfpRa ETH/ERC20 0x1de59bd9e52521a46309474f8372531533bd7c43 Mesh Model-Loading/Mesh WithAssimpwecanloadmanydifferentmodelsintotheapplication,butonceloadedthey'reallstoredinAssimp'sdatastructures.WhatweeventuallywantistotransformthatdatatoaformatthatOpenGLunderstandssothatwecanrendertheobjects.Welearnedfromthepreviouschapterthatameshrepresentsasingledrawableentity,solet'sstartbydefiningameshclassofourown. Let'sreviewabitofwhatwe'velearnedsofartothinkaboutwhatameshshouldminimallyhaveasitsdata.Ameshshouldatleastneedasetofvertices,whereeachvertexcontainsapositionvector,anormalvector,andatexturecoordinatevector.Ameshshouldalsocontainindicesforindexeddrawing,andmaterialdataintheformoftextures(diffuse/specularmaps). NowthatwesettheminimalrequirementsforameshclasswecandefineavertexinOpenGL: structVertex{ glm::vec3Position; glm::vec3Normal; glm::vec2TexCoords; }; WestoreeachoftherequiredvertexattributesinastructcalledVertex.NexttoaVertexstructwealsowanttoorganizethetexturedatainaTexturestruct: structTexture{ unsignedintid; stringtype; }; Westoretheidofthetextureanditstypee.g.adiffuseorspeculartexture. Knowingtheactualrepresentationofavertexandatexturewecanstartdefiningthestructureofthemeshclass: classMesh{ public: //meshdata vectorvertices; vectorindices; vectortextures; Mesh(vectorvertices,vectorindices,vectortextures); voidDraw(Shader&shader); private: //renderdata unsignedintVAO,VBO,EBO; voidsetupMesh(); }; Asyoucansee,theclassisn'ttoocomplicated.Intheconstructorwegivethemeshallthenecessarydata,weinitializethebuffersinthesetupMeshfunction,andfinallydrawthemeshviatheDrawfunction.NotethatwegiveashadertotheDrawfunction;bypassingtheshadertothemeshwecansetseveraluniformsbeforedrawing(likelinkingsamplerstotextureunits). Thefunctioncontentoftheconstructorisprettystraightforward.Wesimplysettheclass'spublicvariableswiththeconstructor'scorrespondingargumentvariables.WealsocallthesetupMeshfunctionintheconstructor: Mesh(vectorvertices,vectorindices,vectortextures) { this->vertices=vertices; this->indices=indices; this->textures=textures; setupMesh(); } Nothingspecialgoingonhere.Let'sdelverightintothesetupMeshfunctionnow. Initialization Thankstotheconstructorwenowhavelargelistsofmeshdatathatwecanuseforrendering.Wedoneedtosetuptheappropriatebuffersandspecifythevertexshaderlayoutviavertexattributepointers.Bynowyoushouldhavenotroublewiththeseconcepts,butwe'vespiceditupabitthistimewiththeintroductionofvertexdatainstructs: voidsetupMesh() { glGenVertexArrays(1,&VAO); glGenBuffers(1,&VBO); glGenBuffers(1,&EBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER,VBO); glBufferData(GL_ARRAY_BUFFER,vertices.size()*sizeof(Vertex),&vertices[0],GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER,indices.size()*sizeof(unsignedint), &indices[0],GL_STATIC_DRAW); //vertexpositions glEnableVertexAttribArray(0); glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),(void*)0); //vertexnormals glEnableVertexAttribArray(1); glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),(void*)offsetof(Vertex,Normal)); //vertextexturecoords glEnableVertexAttribArray(2); glVertexAttribPointer(2,2,GL_FLOAT,GL_FALSE,sizeof(Vertex),(void*)offsetof(Vertex,TexCoords)); glBindVertexArray(0); } Thecodeisnotmuchdifferentfromwhatyou'dexpect,butafewlittletrickswereusedwiththehelpoftheVertexstruct. StructshaveagreatpropertyinC++thattheirmemorylayoutissequential.Thatis,ifweweretorepresentastructasanarrayofdata,itwouldonlycontainthestruct'svariablesinsequentialorderwhichdirectlytranslatestoafloat(actuallybyte)arraythatwewantforanarraybuffer.Forexample,ifwehaveafilledVertexstruct,itsmemorylayoutwouldbeequalto: Vertexvertex; vertex.Position=glm::vec3(0.2f,0.4f,0.6f); vertex.Normal=glm::vec3(0.0f,1.0f,0.0f); vertex.TexCoords=glm::vec2(1.0f,0.0f); //=[0.2f,0.4f,0.6f,0.0f,1.0f,0.0f,1.0f,0.0f]; ThankstothisusefulpropertywecandirectlypassapointertoalargelistofVertexstructsasthebuffer'sdataandtheytranslateperfectlytowhatglBufferDataexpectsasitsargument: glBufferData(GL_ARRAY_BUFFER,vertices.size()*sizeof(Vertex),vertices[0],GL_STATIC_DRAW); Naturallythesizeofoperatorcanalsobeusedonthestructfortheappropriatesizeinbytes.Thisshouldbe32bytes(8floats*4byteseach). Anothergreatuseofstructsisapreprocessordirectivecalledoffsetof(s,m)thattakesasitsfirstargumentastructandasitssecondargumentavariablenameofthestruct.Themacroreturnsthebyteoffsetofthatvariablefromthestartofthestruct.ThisisperfectfordefiningtheoffsetparameteroftheglVertexAttribPointerfunction: glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,sizeof(Vertex),(void*)offsetof(Vertex,Normal)); Theoffsetisnowdefinedusingtheoffsetofmacrothat,inthiscase,setsthebyteoffsetofthenormalvectorequaltothebyteoffsetofthenormalattributeinthestructwhichis3floatsandthus12bytes. Usingastructlikethisdoesn'tonlygetusmorereadablecode,butalsoallowsustoeasilyextendthestructure.Ifwewantanothervertexattributewecansimplyaddittothestructandduetoitsflexiblenature,therenderingcodewon'tbreak. Rendering ThelastfunctionweneedtodefinefortheMeshclasstobecompleteisitsDrawfunction.Beforerenderingthemesh,wefirstwanttobindtheappropriatetexturesbeforecallingglDrawElements.However,thisissomewhatdifficultsincewedon'tknowfromthestarthowmany(ifany)texturesthemeshhasandwhattypetheymayhave.Sohowdowesetthetextureunitsandsamplersintheshaders? Tosolvetheissuewe'regoingtoassumeacertainnamingconvention:eachdiffusetextureisnamedtexture_diffuseN,andeachspeculartextureshouldbenamedtexture_specularNwhereNisanynumberrangingfrom1tothemaximumnumberoftexturesamplersallowed.Let'ssaywehave3diffusetexturesand2speculartexturesforaparticularmesh,theirtexturesamplersshouldthenbecalled: uniformsampler2Dtexture_diffuse1; uniformsampler2Dtexture_diffuse2; uniformsampler2Dtexture_diffuse3; uniformsampler2Dtexture_specular1; uniformsampler2Dtexture_specular2; Bythisconventionwecandefineasmanytexturesamplersaswewantintheshaders(uptoOpenGL'smaximum)andifameshactuallydoescontain(somany)textures,weknowwhattheirnamesaregoingtobe.Bythisconventionwecanprocessanyamountoftexturesonasinglemeshandtheshaderdeveloperisfreetouseasmanyofthoseashewantsbydefiningthepropersamplers. Therearemanysolutionstoproblemslikethisandifyoudon'tlikethisparticularsolutionitisuptoyoutogetcreativeandcomeupwithyourownapproach. Theresultingdrawingcodethenbecomes: voidDraw(Shader&shader) { unsignedintdiffuseNr=1; unsignedintspecularNr=1; for(unsignedinti=0;i



請為這篇文章評分?