Drawing a line in modern OpenGL - c++ - Stack Overflow
文章推薦指數: 80 %
Create an array with the corners points of the line strip. The first and the last point define the start and end tangents of the line strip. So ...
Home
Public
Questions
Tags
Users
Companies
Collectives
ExploreCollectives
Teams
StackOverflowforTeams
–Startcollaboratingandsharingorganizationalknowledge.
CreateafreeTeam
WhyTeams?
Teams
CreatefreeTeam
Collectives™onStackOverflow
Findcentralized,trustedcontentandcollaboratearoundthetechnologiesyouusemost.
LearnmoreaboutCollectives
Teams
Q&Aforwork
Connectandshareknowledgewithinasinglelocationthatisstructuredandeasytosearch.
LearnmoreaboutTeams
DrawingalineinmodernOpenGL
AskQuestion
Asked
2years,6monthsago
Modified
3monthsago
Viewed
12ktimes
5
7
Isimplywanttodrawalinetothescreen.I'musingOpenGl4.6.AlltutorialsIfoundusedaglVertexPointer,whichisdeprecatedasfarasIcantell.
Iknowhowyoucandrawtrianglesusingbuffers,soItriedthatwithaline.Itdidn'twork,merelydisplayingablackscreen.(I'musingGLFWandGLEW,andIamusingavertex+fragmentshaderIalreadytestedonthetriangle)
//Makeline
floatline[]={
0.0,0.0,
1.0,1.0
};
unsignedintbuffer;//TheID,kindofapointerforVRAM
glGenBuffers(1,&buffer);//Allocatememoryforthetriangle
glBindBuffer(GL_ARRAY_BUFFER,buffer);//Setthebufferastheactivearray
glBufferData(GL_ARRAY_BUFFER,2*sizeof(float),line,GL_STATIC_DRAW);//Fillthebufferwithdata
glVertexAttribPointer(0,2,GL_FLOAT,GL_FALSE,2*sizeof(float),0);//Specifyhowthebufferisconvertedtovertices
glEnableVertexAttribArray(0);//Enablethevertexarray
//Loopuntiltheuserclosesthewindow
while(!glfwWindowShouldClose(window))
{
//Clearprevious
glClear(GL_COLOR_BUFFER_BIT);
//Drawtheline
glDrawArrays(GL_LINES,0,2);
//Swapfrontandbackbuffers
glfwSwapBuffers(window);
//Pollforandprocessevents
glfwPollEvents();
}
AmIgoingintherightdirection,orisacompletelydifferentapproachthecurrentbestpractice?
IfIam,howdoIfixmycode?
c++openglglfw
Share
Follow
editedMar7at20:45
genpfault
49.8k1010goldbadges8181silverbadges130130bronzebadges
askedFeb27,2020at19:43
CheeseCrusteryCheeseCrustery
76111goldbadge77silverbadges1717bronzebadges
7
IfyouuseacompatibilityprofileOpenGLContext,thenyoucanstilluseglVertexAttribPointer.IfyouhavetouseacoreprofilecontextthanyouhavetouseaShaderprogramandaVertexArrayObjectandyou'llneedagoodtutorial(e.g.LearnOpenGL)
– Rabbid76
Feb27,2020at19:47
@Rabbidthanks,butIwanttolearnmodernOpenGLstraightaway,notrelyingoncodethatisalreadyoutdated.ButIamatotalbeginner,somaybeusingthisfunctionistheintendedwayafterall?
– CheeseCrustery
Feb27,2020at19:51
AsImentioned,readatutorial.Toexplainshadersandvertexarrayobjectsistobroadforasinglestackoverflowquestion.
– Rabbid76
Feb27,2020at19:52
@RabbidIt'snotthatIhavenoideawhatthiscodedoes.Ijustaskedforhelpinfindingtheerror.
– CheeseCrustery
Feb27,2020at19:59
YoucanusethelatestOpenGLtodowhatyouwant,butifyou'reconcernedaboutbeingveryup-to-date,whichyouseemtobe,VulkanisthemostmodernofferingfromtheKhronosGroup,whichisalsoresponsibleforOpenGL.Forinstance,Vulkanisreadyformultithreadedrendering,whereasthisishardinOpenGL.(OpenGLisstillwidelysupported,butApplehasdeprecatedsupportforit,forinstance.)
– metal
Feb27,2020at20:09
|
Show2morecomments
1Answer
1
Sortedby:
Resettodefault
Highestscore(default)
Trending(recentvotescountmore)
Datemodified(newestfirst)
Datecreated(oldestfirst)
21
TheissueisthecalltoglBufferData.The2ndargumentisthesizeofthebufferinbytes.Sincethevertexarrayconsistsof2coordinateswith2components,thesizeofthebufferis4*sizeof(float)ratherthan2*sizeof(float):
glBufferData(GL_ARRAY_BUFFER,2*sizeof(float),line,GL_STATIC_DRAW);
glBufferData(GL_ARRAY_BUFFER,4*sizeof(float),line,GL_STATIC_DRAW);
Butnotethatisstillnot"modern"OpenGL.IfyouwanttousecoreprofileOpenGLContext,thenyouhavetouseaShaderprogramandaVertexArrayObject
However,ifyouareusingacoreOpenGLcontextandtheforwardcompatibilitybitisset,thewidthofaline(glLineWidth),cannotbegraterthan1.0.
SeeOpenGL4.6APICoreProfileSpecification-E.2DeprecatedandRemovedFeatures
Widelines-LineWidthvaluesgreaterthan1.0willgenerateanINVALID_VALUEerror.
Youhavetofindadifferentapproach.
IrecommendtouseaShader,whichgeneratestriangleprimitivesalongalinestrip(orevenalineloop).
Thetaskistogeneratethicklinestrip,withaslessCPUandGPUoverheadaspossible.ThatmeanstoavoidcomputationofpolygonsontheCPUaswellasgeometryshaders(ortessellationshaders).
Eachsegmentofthelineconsistofaquadrepresentedby2triangleprimitivesrespectively6vertices.
025
+-------++
|//|
|//|
|//|
++-------+
134
Betweenthelinesegmentsthemiterhasttobefoundandthequadshavetobecuttothemiter.
+----------------+
|/|
|segment1/|
|/|
+--------+|
|segment2
||
||
+-------+
Createanarraywiththecornerspointsofthelinestrip.Thefirstandthelastpointdefinethestartandendtangentsofthelinestrip.Soyouneedtoadd1pointbeforethelineandonepointaftertheline.Ofcourseitwouldbeeasy,toidentifythefirstandlastelementofthearraybycomparingtheindexto0andthelengthofthearray,butwedon'twanttodoanyextrachecksintheshader.
Ifalineloophastobedraw,thenthelastpointhastobeaddtothearrayheadandthefirstpointtoitstail.
ThearrayofpointsisstoredtoaShaderStorageBufferObject.Weusethebenefit,thatthelastvariableoftheSSBOcanbeanarrayofvariablesize.InolderversionsofOpenGL(orOpenGLES)aUniformBufferObjectorevenaTexturecanbeused.
Theshaderdoesn'tneedanyvertexcoordinatesorattributes.Allwehavetoknowistheindexofthelinesegment.Thecoordinatesarestoredinthebuffer.Tofindtheindexwemakeuseofthetheindexofthevertexcurrentlybeingprocessed(gl_VertexID).
TodrawalinestripwithNsegments,6*(N-1)verticeshavetpobeprocessed.
Wehavetocreatean"empty"VertexArrayObject(withoutanyvertexattributespecification):
glGenVertexArrays(1,&vao);
glBindVertexArray(vao);
Andtodraw2*(N-1)triangle(6*(N-1)vertices):
glDrawArrays(GL_TRIANGLES,0,6*(N-1));
ForthecoordinatearrayintheSSBO,thedatatypevec4isused(Pleasbelieveme,youdon'twanttousevec3):
layout(std430,binding=0)bufferTVertex
{
vec4vertex[];
};
Computetheindexofthelinesegment,wherethevertexcoordinatebelongstooandtheindexofthepointinthe2triangles:
intline_i=gl_VertexID/6;
inttri_i=gl_VertexID%6;
SincewearedrawingN-1linesegments,butthenumberofelementsinthearrayisN+2,theelementsformvertex[line_t]tovertex[line_t+3]canbeaccessedforeachvertexwhichisprocessedinthevertexshader.
vertex[line_t+1]andvertex[line_t+2]arethestartrespectivelyendcoordinateofthelinesegment.vertex[line_t]andvertex[line_t+3]arerequiredtocomputethemiter.
Thethicknessofthelineshouldbesetinpixelunit(uniformfloatu_thickness).Thecoordinateshavetobetransformedfrommodelspacetowindowspace.Forthattheresolutionoftheviewporthastobeknown(uniformvec2u_resolution).Don'tforgettheperspectivedivide.Thedrawingofthelinewillevenworkatperspectiveprojection.
vec4va[4];
for(inti=0;i<4;++i)
{
va[i]=u_mvp*vertex[line_i+i];
va[i].xyz/=va[i].w;
va[i].xy=(va[i].xy+1.0)*0.5*u_resolution;
}
Themitercalculationevenworksifthepredecessororsuccessorpointisequaltothestartrespectivelyendpointofthelinesegment.Inthiscasetheendofthelineiscutnormaltoitstangent:
vec2v_line=normalize(va[2].xy-va[1].xy);
vec2nv_line=vec2(-v_line.y,v_line.x);
vec2v_pred=normalize(va[1].xy-va[0].xy);
vec2v_succ=normalize(va[3].xy-va[2].xy);
vec2v_miter1=normalize(nv_line+vec2(-v_pred.y,v_pred.x));
vec2v_miter2=normalize(nv_line+vec2(-v_succ.y,v_succ.x));
Inthefinalvertexshaderwejustneedtocalculateeitherv_miter1orv_miter2dependentonthetri_i.Withthemiter,thenormalvectortothelinesegmentandthelinethickness(u_thickness),thevertexcoordinatecanbecomputed:
vec4pos;
if(tri_i==0||tri_i==1||tri_i==3)
{
vec2v_pred=normalize(va[1].xy-va[0].xy);
vec2v_miter=normalize(nv_line+vec2(-v_pred.y,v_pred.x));
pos=va[1];
pos.xy+=v_miter*u_thickness*(tri_i==1?-0.5:0.5)/dot(v_miter,nv_line);
}
else
{
vec2v_succ=normalize(va[3].xy-va[2].xy);
vec2v_miter=normalize(nv_line+vec2(-v_succ.y,v_succ.x));
pos=va[2];
pos.xy+=v_miter*u_thickness*(tri_i==5?0.5:-0.5)/dot(v_miter,nv_line);
}
Finallythewindowcoordinateshavetobetransformedbacktoclipspacecoordinates.Transformfromwindowspacetonormalizeddevicespace.Theperspectivedividehastobereversed:
pos.xy=pos.xy/u_resolution*2.0-1.0;
pos.xyz*=pos.w;
PolygonscreatedwithglPolygonMode(GL_FRONT_AND_BACK,GL_FILL)andglPolygonMode(GL_FRONT_AND_BACK,GL_LINE):
DemoprogramusingGLFWAPIforcreatingawindow,GLEWforloadingOpenGLandGLM-OpenGLMathematicsforthemath.(Idon'tprovidethecodeforthefunctionCreateProgram,whichjustcreatesaprogramobject,fromthevertexshaderandfragmentshadersourcecode):
#include
延伸文章資訊
- 1performance drop when drawing a line in OpenGL
There is no any function in modern OpenGL to draw a sphere using a simple one line command. You n...
- 2Drawing thin 3D lines with modern OpenGL - Reddit
Drawing thin 3D lines with modern OpenGL. I'm a bit confused on how render thin 3D lines without ...
- 3OpenGL Tutorial 7 - Drawing A Line - YouTube
- 4Drawing a line in modern OpenGL - c++ - Stack Overflow
Create an array with the corners points of the line strip. The first and the last point define th...
- 5Drawing Antialiased Lines with OpenGL | by Mapbox
I worked on an experiment that uses only two vertices per line segment, but this way of drawing l...